10

In org export, I want to place two images side by side. I want them to be side by side in both LaTeX export and HTML export. In the example below, the first pair works for LaTeX and the second pair for HTML but not both.

#+NAME: a
#+BEGIN_SRC dot :file /tmp/a.png
  digraph {
    1 -> 2;
    2 -> 3;
  }
#+END_SRC

#+NAME: b
#+BEGIN_SRC dot :file /tmp/b.png
  digraph {
    1 -> 3;
    2 -> 3;
  }
#+END_SRC

* LaTeX

#+BEGIN_CENTER
#+ATTR_LATEX: :height 0.4\textwidth :center
#+RESULTS: a
[[file:/tmp/a.png]]
#+ATTR_LATEX: :height 0.4\textwidth :center
#+RESULTS: b
[[file:/tmp/b.png]]
#+END_CENTER

* HTML

#+ATTR_HTML: :align center :height 300
[[/tmp/a.png]]
[[/tmp/b.png]]

3 Answers 3

3
+50

EDIT

As mentioned in the comments, the 'original' solution does not exclude the 'HTML/LaTeX' headlines from the HTML TOC.

This can be fixed by filtering the arguments passed to the org-html--toc-text function via an advice as follows.

(defun org-filter-toc (blabla)
  (mapcar (lambda (e)
            (seq-filter (lambda (s)
                          (let* ((positions (nth 1 (object-intervals (car s))))
                                 (title (org-element-property
                                         :title
                                         (get-text-property (car positions) :parent (car s)))))
                            (not (member (car title) '("HTML" "LaTeX")))))
                        e))
          blabla))

(advice-add 'org-html--toc-text :filter-args #'org-filter-toc)

It now is required that the headlines match the strings in the list passed to member exactly (upper/lower cases should match).

Unfortunately, due to the 'complex' structure of the data passed to the org-html--toc-text the filter code becomes quite cumbersome. Also, again, the code probably is not very robust, but if something is not working then it can probably get fixed via a small modification.

There is a significant chance that adding support for conditionally exporting side by side images directly to org would have been easier (it is just harder to find out where to start).

END EDIT

For this particular case, you could use an export filter to filter out the unwanted headlines for a specific backend, and subsequently only return the body of the exported headlines, e.g. as follows:

(defun my-org-exclude-headlines (text backend info)
  "Filter out unwanted headlines on export."
  ;; filter unwanted headlines
  (if (string-match-p (pcase backend
                        ('latex "{html}")
                        ('html "latex")) 
                      text)
      ""
    ;;filter out headline titles
    (let ((lines (string-split text "\n")))
      (mapconcat #'identity (pcase backend
                              ('latex (seq-subseq lines 3))
                              ('html (seq-subseq lines 3 -3))
                              (_ lines))
                 "\n"))))

(add-to-list 'org-export-filter-headline-functions
             'my-org-exclude-headlines)

You could evaluate this manually before export, but the link included above also explains how to define filters for individual files.

The code is quite self-explanatory, and you could wrap the text in a print statement if you'd like to better understand the chosen 'match patterns'.

If you don't need to filter out the titles of the headlines, then you could as well use the solution provided here.

The code is not very robust (i.e. the filters), but it can be easily improved.

Of course, it would be nicer, if an export backend automatically exported the images using the with the backend 'corresponding' attributes. I guess you could just request such feature using M-x org-submit-bug-report (you might even receive an answer, including explanation, that it already exists).

5
  • 1
    This is the best response so far and I mean absolutely no offense, but I can't say that I'm very happy with the solution. To that end, I did register a bug on the mailing list here, I guess we'll see if it will garner any further interest.
    – Xaldew
    Jan 28, 2023 at 12:42
  • Yeah, I understand this is no ideal solution. I think it is a useful feature, which is probably not too difficult/much work to implement. So great to have a bug report for it (and having the link to it here). I hope in the meantime, the solution here is 'pragmatic enough' :) Jan 30, 2023 at 8:46
  • 1
    That it definitely is! Thanks a lot for your efforts :)
    – Xaldew
    Jan 30, 2023 at 10:15
  • Only now really tried to use this and noted a minor issue: The "fake" LaTeX, HTML headlines are still present in the Table of Contents for HTML export. Curiously, this is not the case for LaTeX.
    – Xaldew
    Feb 1, 2023 at 15:08
  • 1
    Okay, I see. Indeed, the headlines do not get filtered out from the html when/before creating the TOC (in latex the TOC is created during the latex compilation because of the \tableofcontents line). It can be fixed by filtering the arguments for the org-html--toc-text function via an advice. Because of the data structures passes to org-filter-toc the filter is quite cumbersome. Additionally, the original code anyway also required a small fix. I have updated the answer. Feb 3, 2023 at 12:36
2

A slightly more manual process, but one that does not require any additional mechanism is to use tags and the variable org-export-exclude-tags whose default value is the list ("noexport"). Basically, if you tag any subtree with the tag :noexport:, it will not be exported with the default value of this variable.

The convenient thing is that you can change the value of this variable and you can do so through a buffer setting, using the keyword #+EXCLUDE_TAGS. E.g. if you add

#+EXCLUDE_TAGS: private

at the top of the file, then any heading that is tagged :private: (and all its subheadings) will not be exported.

So the idea is that you tag the LaTeX sections with an :exclude_latex: tag and the HTML sections with an :exclude_html: tag and then add #+EXCLUDE_TAGS: lines at the top of the file, picking one or the other to exclude:

# for HTML export, uncomment the first EXCLUDE_TAGS line 
# and comment out the second EXCLUDE_TAGS line  
#+EXCLUDE_TAGS: exclude_latex noexport

# for LaTeX export, comment out the first EXCLUDE_TAGS line
# and uncomment the second EXCLUDE_TAGS line
# #+EXCLUDE_TAGS: exclude_html noexport

and comment out one or the other as needed (that's the manual part). We include the noexport tag in both cases here just so that we can exclude a section unconditionally, but that's optional.

If you sequence your actions wisely, you should be able to do all the work with one backend and, once you are happy with that export, switch and do the other backend. But you do have to remember to check and possibly do the switcheroo before you export (which admittedly is a pain).

9
  • This is also a nice way to achieve it (very similar, but slightly nicer than John Kitchin's alternative solution I have linked to in my answer). However, as mentioned in my answer, this solution includes the headline title on export (which seems a little silly behavior to me. It seems to me that the title is only included here to indicate which image definition belongs to which 'export backend'). Jan 27, 2023 at 19:11
  • " this solution includes the headline title on export" - IIUC, it most certainly does not.
    – NickD
    Jan 27, 2023 at 19:18
  • I didn't look at John Kitchin's solution before I posted, but now that I looked at his solution, I think it's nicer (precisely because he avoids the manual commenting/uncommenting part which as I said is a pain :-0 ). OTOH, I get errors when trying to execute his source blocks so it may have bit-rotted and needs some TLC to make it work again (or my setup may be at fault - I don't know yet). But tag exclusion gets rid of the whole tagged section, including the headline. I'm not sure why you say the headline title is included in the export.
    – NickD
    Jan 27, 2023 at 19:27
  • 1
    OK - I think I understand what you mean now and I can say "guilty as charged": the whole section (including its headline) is tagged, so if exported, the headline is part of the export; if not, the whole section including the headline disappears. If the headline is not desired, then a filter is the best solution.
    – NickD
    Jan 27, 2023 at 19:47
  • 1
    Yes, this method is based on tagging sections and the headline is part of the section, so it is retained as part of a retained section. As mentioned, a filter is probably the best way to get rid of it.
    – NickD
    Feb 1, 2023 at 16:50
1

Just adding my own 'solution' here as well in case it helps anyone.

Instead of trying to show/hide tags or strip out specific headlines, we do the following before parsing or processing the file:

  1. Scan the document, remove all sections not relevant for the current backend.
  2. Scan the document again, removing the headlines we do not care about.

This is done in the following "solution" org-mode file:

#+TITLE: Side-by-Side Test

* Export Configuration                                             :noexport:

  #+begin_src emacs-lisp :results output :session :exports none
    (defun my-org-backend-config (backend)
      "Set specific settings depending on which org-mode backend is used."
      (pcase backend
        ((or 'latex 'beamer)
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-tag "latex")
         (setq my-remove-sections-tags '("html")))
        ('html
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-tag "html")
         (setq my-remove-sections-tags '("latex")))
        (_
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-tag nil)
         (setq my-remove-sections-tags '("latex" "html"))))
      ;; Remove sections marked by 'my-remove-sections-re'.
      (setq match-expr (mapconcat #'identity my-remove-sections-tags "|"))
      (org-map-entries
       (lambda ()
         (let ((beg (point))
               (end (save-excursion (org-end-of-subtree t t))))
           (delete-region (point) end)
           (setq org-map-continue-from beg)))
       match-expr)
      ;; Remove headlines marked by 'my-remove-headlines-re'.
      (when my-remove-headlines-tag
        (org-map-entries
         (lambda ()
           (delete-region (point) (line-end-position)))
         my-remove-headlines-tag))
      )
    (add-hook 'org-export-before-parsing-hook #'my-org-backend-config)
  #+end_src

  #+RESULTS:


* Regular Header 1

  This is just some regular test content.

  #+NAME: a
  #+BEGIN_SRC dot :file /tmp/a.png
    digraph {
    1 -> 2;
    2 -> 3;
    }
  #+END_SRC

  #+NAME: b
  #+BEGIN_SRC dot :file /tmp/b.png
    digraph {
    1 -> 3;
    2 -> 3;
    }
  #+END_SRC

* HTML                                                                 :html:

  #+ATTR_HTML: :align center :height 300
  [[/tmp/a.png]]
  [[/tmp/b.png]]

* LaTeX                                                               :latex:

  #+BEGIN_CENTER
  #+ATTR_LATEX: :height 0.4\textwidth :center
  #+RESULTS: a
  [[file:/tmp/a.png]]
  #+ATTR_LATEX: :height 0.4\textwidth :center
  #+RESULTS: b
  [[file:/tmp/b.png]]
  #+END_CENTER


* Regular Header 2

  Testing a regular header, again.

Most of the credit goes to @NickD though, who found the problems I was having with it:

Org-mode: Selectively Stripping Sections/Subtrees Depending on Backend

Still not very "happy" with the solution though, feels awfully complex for what I wanted to achieve

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.