UP | HOME

Org Teach Export Macros

After using James Howell's Org Teach for a number of semesters, there was one thing that was bothering me with the reproduction of images (and code) between slides and handouts. Chiefly, images may have different scaling requirements depending on whether the target output is the slide deck or the handout. Initially, I simply built each document, manually replacing the appropriate #+ATTR_LATEX lines to suit. Of course, this cannot stand.

Org mode has excellent export options, particularly for PDF output via LaTeX. Combined with some macros and standard files, and Org mode provides some significant functionality for creating and publishing documents in multiple formats. To that end, I have used Org Teach since I started teaching, and I have thoroughly enjoyed the experience. More importantly, my students have overwhelmingly preferred it, one student asking me to tell the other lecturers to similarly structure their content.

Including images into the final output is as easy as linking to the image file using the standard Org linking syntax, e.g., [[URL][Description]]. Furthermore, we can provide customized LaTeX options to these links using #+ATTR_LATEX lines immediately preceding these image links. Similarly Org supports #+ATTR_BEAMER which differentiates options only available when exporting Beamer slides.

Unfortunately, not all export elements go through the same code. For example, using #+ATTR_BEAMER with images or code fragments does not in fact modify the behavior since it is not merged into the dictionary of options by the different translation functions within Org mode. Thus, when an image is particularly tall for a slide, perhaps we want to cap its height with :height 0.7\textheight. However, for the handout, this would mean the image is now 70% of the page. Thus, we need a mechanism to set the height for both export targets without going crazy.

To be clear, a better solution is to patch these functions within Org such that it merges #+ATTR_BEAMER and #+ATTR_LATEX in a sensible way depending on the backend. In other words, when exporting to a regular LaTeX PDF, e.g., handouts, the exporter ignores #+ATTR_BEAMER lines. However, when exporting to Beamer, the exporter merges and replaces any values in the original #+ATTR_LATEX with the values found in #+ATTR_BEAMER. Unfortunately, this is beyond my time capacity.

Instead of leveraging a proper solution, I wrote a set of (quite simple) macros to accomplish 80% of the desired result (the remaining 20% to resolve is the unfortunate but necessary duplication of common values between the two macros' arguments).

That is, I have defined the following macros:

#+MACRO: opts-if-beamer (eval (if (eq org-export-current-backend 'beamer) (format "#+ATTR_LATEX: %s" $1) "#+ATTR_LATEX:"))
#+MACRO: opts-if-latex  (eval (if (eq org-export-current-backend 'latex) (format "#+ATTR_LATEX: %s" $1) "#+ATTR_LATEX:"))

They are used as shown in the following example:

{{{opts-if-beamer(:placment [H] :center t :alt "")}}}
{{{opts-if-latex(:placment [H] :center t :alt "")}}}
./link/to/image.png

Both macros take an argument and format it into the output Org source immediately before the export engine takes over (you know, because macro expansion is a preprocessing step of translation). Considering first the org-if-beamer macro, if the target backend is Beamer, its eval returns the appropriate #+ATTR_LATEX line with the arguments included. Otherwise, if it is not, then it simply inserts a blank #+ATTR_LATEX line. Dually so for the the opts-if-latex macro.

The blank #+ATTR_LATEX is necessary as the exporter merges all grouped #+ATTR_LATEX lines together. Thus, without this line, the output is likely to have a spurious blank line separating the ATTR lines, yielding undesired outputs.

These macros look like a lot of text to add each time an image needs insertion, and that is true. However, I have added a Yasnippet for Org files to alleviate this specific suffering. Now, I simply type <ins-image>TAB and I get the above macro lines.

As an added benefit, I have found that these macros work quite well for source listings as well. Sometimes, I would like to display lots of source lines (~20 lines). However, this many lines do not fit well onto a Beamer slide. Thus, the font needs down scaling for the specific listing. However, the scaling should remain for the handout. Without any changes, we can use the same macros to accomplish this.

{{{opts-if-beamer(:options fontsize=\tiny)}}}
{{{opts-if-latex()}}}
#+begin_src scheme
(define (sum seq)
  (if (null? seq)
      0
      (+ (car seq) (sum (cdr seq)))))

(display (sum '(5 6 1 8 3 7)))
(display "\n")
#+end_src

Moving forward, while I enjoy the ability to easily create two kinds of documents: one for presenting and one for handouts, I am reflecting on the delivery modality some. That is, I may be experimenting with this process more. Furthermore, given the recent dumpster fire Canvas outage, I have put some thought into posting the handouts through GitHub or GitLab pages. Unfortunately, this would mean I need to support another export backend. So far, this seems doable by switching to a cond instead, but would mean there is now an ordering requirement between the macros, gross.