and solutions for an equation editor: the baseline problem corrected

Abstract

All Snippet Editors use templates to mold the code the user enters into a form that will give a reasonable typeset result, and adhere to standards set by the user (typefaces, sizes, colors, …). This overview explores some of the common pitfalls, and examines in what direction to travel next.

Some of the issues that need to be solved include: baseline correction, speed, compatability.

Maarten Sneep

At the moment I write this piece, there are four snippet editors: programs designed to take a small piece of code, and run it through , producing a small pdf to use as an equation in another application. All four have their limitations, and at the moment, none of them really fills all gaps. Some of the gaps can be traced back to the template and sequence of commands used to typeset them. It is the aim of this text to explore the limitations and possible solutions.

David Kastrup has written the preview package for use with . This package itself already does much of what is needed, and may in fact be all we need. However, I haven’t been able to find a way to obtain a baseline offset, or – in parlance – the depth of the equation [1].

The simple approach

The easy way to obtain the basic functionlity is to use something similar to the following code [2]:

\documentclass[10pt]{article}
\usepackage{amsmath} %% always use amsmath
\pagestyle{empty}    %% do not display a page number
\begin{document}
\begin{equation*}
  \sigma_{\lambda} = 
  \frac{24 \pi^3}{\lambda^4 N^2}
  \left(\frac{n^2-1}{n^2+2}\right)^{\!2}
\end{equation*}
\end{document}

After running this through a simple shell script:

#!/bin/bash
src=$1
dvi=${1%.tex}.dvi
eps=${1%.tex}.eps
pdf=${1%.tex}.pdf

latex $src && \
  dvips -E -Ppdf -o $eps $dvi && \
  epstopdf $eps -o $pdf

one obtains a small pdf file with the resulting equation. This can be used as a stand-alone equation, provided one doesn’t need to display anything on the same line, the reason for that limitation is shown below.

And this … A mathematical expression … is the baseline problem.

And this … A mathematical expression … is cool [3].

Baselines

From the sample above it is clear that this simple approach will suffice only in cases where there is no surrounding indication of the baseline — labels in an illustration program or displayed equations and such. Manual positioning may be possible in some cases, but in general it is inaccurate, awkward, error-prone and labour intensive.

To do this in some automated fashion, one has to know some of the dimensions of the equation. The first step is to extract the actual depth of the equation, that is: the distance the equation has to be dropped to appear at the right location. This requires some serious changes in the template.

The first step is to typeset the whole equation in a box, so that we can ask to print out the required information.

\documentclass[10pt]{article}
\usepackage{amsmath}
\pagestyle{empty}
\newsavebox{\mybox}

\newlength{\mywidth}
\newlength{\myheight}
\newlength{\mydepth}

\begin{lrbox}{\mybox}
$\displaystyle
  \sigma_{\lambda} = 
  \frac{24 \pi^3}{\lambda^4 N^2}
  \left(\frac{n^2-1}{n^2+2}\right)^{\!2}
$
\end{lrbox}

\settowidth {\mywidth}  {\usebox{\mybox}}
\settoheight{\myheight} {\usebox{\mybox}}
\settodepth {\mydepth}  {\usebox{\mybox}}

\newwrite\foo
\immediate\openout\foo=\jobname.sizes
    \immediate\write\foo{Depth = \the\mydepth}
    \immediate\write\foo{Height = \the\myheight}
    \addtolength{\myheight} {\mydepth}
    \immediate\write\foo{TotalHeight = \the\myheight}
    \immediate\write\foo{Width = \the\mywidth}
\closeout\foo

\begin{document}
\usebox{\mybox}
\end{document}

Run this through the same shell script, and you’ll end up with the same result as displayed above, but also with a simple file that shows you all sizes of the equation:

Depth = 9.50012pt
Height = 16.94402pt
TotalHeight = 26.44414pt
Width = 100.24094pt

This provides us with everything we need to know to include the resulting image at the right baseline. Note that these sizes are in -points, not PostScript points. In the vertical position can be corrected with a \raisebox command:

\raisebox{-9.50012pt}{\includegraphics{equation}}

There is one additional enhancement that can be made at this stage. Since already knows the size of the equation, we can also set the paper to this size from within itself. This sample uses \usepackage{geometry} to do the page scaling. Some of the related lengths need to be set to zero to avoid extraneous spacing.

\documentclass[10pt]{article}
\usepackage{geometry}
\usepackage{amsmath}
\pagestyle{empty}
\newsavebox{\mybox}

\newlength{\mywidth}
\newlength{\myheight}
\newlength{\mydepth}

\setlength{\topskip}{0pt}
\setlength{\parindent}{0pt}
\setlength{\abovedisplayskip}{0pt}
\setlength{\belowdisplayskip}{0pt}

\begin{lrbox}{\mybox}
$\displaystyle
  \sigma_{\lambda} = 
  \frac{24 \pi^3}{\lambda^4 N^2}
  \left(\frac{n^2-1}{n^2+2}\right)^{\!2}
$
\end{lrbox}

\settowidth {\mywidth}  {\usebox{\mybox}}
\settoheight{\myheight} {\usebox{\mybox}}
\settodepth {\mydepth}  {\usebox{\mybox}}

\newwrite\foo
\immediate\openout\foo=\jobname.sizes
    \immediate\write\foo{Depth = \the\mydepth}
    \immediate\write\foo{Height = \the\myheight}
    \addtolength{\myheight} {\mydepth}
    \immediate\write\foo{TotalHeight = \the\myheight}
    \immediate\write\foo{Width = \the\mywidth}
\closeout\foo

% set the paper-size and do everything in one pdflatex run
\geometry{paperwidth=\mywidth,
    paperheight=\myheight,margin=0pt}

\begin{document}
\usebox{\mybox}
\end{document}

And again we obtain the sizes we need for positioning things correctly, and they are the same:

Depth = 9.50012pt
Height = 16.94402pt
TotalHeight = 26.44414pt
Width = 100.24094pt

The difference is that this second example doesn’t need the extra tools, just a single run of pdf. On this simple equation the run-time of the complete script is 0.808 s, while the dvips-route takes 1.360 s, an improvement of about 40 %, with exactly the same end-result.

Is this trick generally applicable? No, unfortunately not. In the samples shown so far, the displayed equation really is an in-line equation, pretending to be displayed. In many cases you’ll get away with this, but not in all cases. I’ll show some cases below.

Magnification

When using equations in a Keynote presentation, the default font-sizes are much too small. So most existing tools offer some easy way of scaling the output to an effective size. In general this is mechanical scaling, as opposed to the optical scaling used in the computer modern typeface (the default in and ). Since the Times typeface is most likely used on the rest of the presentation, you probably want to change the default anyway.

But, yes, scaling is possible. I start out with a 10 pt font-size for the equation, and blow it up by a factor 2.4 to have an equation in pseudo 24 pt size.

\documentclass[10pt]{article}
\usepackage{graphics}
\usepackage{geometry}
\usepackage{amsmath}

\newcommand{\scalefactor}{2.4}

\pagestyle{empty}
\newsavebox{\mybox}

\newlength{\mywidth}
\newlength{\myheight}
\newlength{\mydepth}

\setlength{\topskip}{0pt}
\setlength{\parindent}{0pt}
\setlength{\abovedisplayskip}{0pt}
\setlength{\belowdisplayskip}{0pt}

\begin{lrbox}{\mybox}
$\displaystyle
  \sigma_{\lambda} = 
  \frac{24 \pi^3}{\lambda^4 N^2}
  \left(\frac{n^2-1}{n^2+2}\right)^{\!2}
$
\end{lrbox}

\settowidth {\mywidth}  
    {\scalebox{\scalefactor}{\usebox{\mybox}}}
\settoheight{\myheight}
    {\scalebox{\scalefactor}{\usebox{\mybox}}}
\settodepth {\mydepth}
    {\scalebox{\scalefactor}{\usebox{\mybox}}}

\newwrite\foo
\immediate\openout\foo=\jobname.sizes
    \immediate\write\foo{Depth = \the\mydepth}
    \immediate\write\foo{Height = \the\myheight}
    \addtolength{\myheight} {\mydepth}
    \immediate\write\foo{TotalHeight = \the\myheight}
    \immediate\write\foo{Width = \the\mywidth}
\closeout\foo

% set the paper-size and do everything in one pdflatex run
\geometry{paperwidth=\mywidth,
    paperheight=\myheight,margin=0pt}

\begin{document}
\scalebox{\scalefactor}{\usebox{\mybox}}
\end{document}

When done in this way, the sizes come out correctly:

Depth = 22.80023pt
Height = 40.66553pt
TotalHeight = 63.46576pt
Width = 240.57762pt

And we get a well-sized equation — although it isn’t really visible here: scaling on web-pages is a bit tricky. The second equation uses the same code, but it starts from 12 pt, and scales by a factor two. The effect of optical scaling is clearly visible, and in these cases starting out with the biggest possible font size is preferred [4].

Scaled Equation (based on 10 pt fonts)
Equation based on 10 pt fonts (computer modern).

Scaled Equation (based on 12 pt fonts)
Equation based on 12 pt fonts (computer modern), scaled in the same way as the other one.

these enlargements reveal a problem with our methods: the bounding box is not calculated entirely correctly, the ‘2’ in the power is clipped. Why this happens in this case, I’m not sure, the figure ‘2’ doesn’t have any parts outside its bounding box, but there are typefaces that do this (Zapfino is a clear example). There are some solutions: add an extra safety margin in the -code:

\geometry{paperwidth=\mywidth,
    paperheight=\myheight,margin=1pt}

(or some other margin of course). Another solution would be to cut the pdf to size at a later moment, using GhostScript to determine the size, and then use pdftk to change the size of the pdf (this is part of a larger script that also attaches the source to the pdf for later retrieval, some details are discussed in Attaching the source to the pdf: other possibilities):

boundingbox=`gs -dNOPAUSE -sDEVICE=bbox \
    -dBATCH -q $pdfin 2>&1 | \
  awk -F: '/%%HiResBoundingBox/{printf "[%s]", \
    substr($2, 2, length($2)-1)}'`

pdftk $pdfin output - uncompress | \
  sed "/MediaBox/s/\\[[0-9\\. \\]*]/$boundingbox/g" | \
  pdftk - attach_files ${texsource%.tex}.tex \
    output $pdfout compress

Displayed equations

Since normal displayed equations are not typeset in lr-mode, we have to ‘abuse’ an inline equation, and force it to produce a displayed equation. We need to be in lr-mode to be able to build a box with the material which is needed to extract the baseline offset. This can be done sufficiently well with the $\displaystyle . . . $ method.

Displayed multi-line equations

Trouble starts when we arrive at multi-line equations. The first one is conceptual: there are several baselines in a multi-line equation, so which one do you choose? Is there such a thing as a baseline for a multi-line equation? Do we need that functionality at all?

The second problem is practical: The amsmath multi-line constructs are simply unavailable in an inline equation. Perhaps some sizes can be extracted by someone with knowledge of the internals of the amsmath package, but that someone isn’t me. This doesn’t mean I’m not interested in a solution that gets the box information and works with displayed material, it just means that I’m at a loss where to start to obtain this information.

I would like to extract the size information from the run anyway. To see why, one has to consider the several different issues surrounding this problem:

  1. Showing equations that are too long to fit on a single line
  2. Showing a set of related equations, all at once
  3. Showing a sequence of related steps, one at a time

Issue 1 is relatively simple, and can be handled with the ‘simple’ approach outlined at the start of this document. You will not have the baseline information available, but for these inherently long and displayed equations, that may be less of an issue: in general no other material will be shown on the same line, except perhaps for a number. I guess that in most cases you could get away with vertically centering both. Issue 2 can probably be handled in the same way, although numbering might need to be handled by in some way.

The last issue is the tough one: not only would a baseline offset be needed, also the horizontal offset would be needed, along with treating the parts of the equation as separate units, to enable piecewise build-up of the slide. I’m almost inclined to refer you to use P4 for this, but our objective is to provide a complete solution. Maybe some added (transparent) space whould do the trick. The preview package does work for displayed equations. It will not split displayed sequences (case 3) though.

A mathematical expression

As one can see: the baseline problem just re-appeared [5], but multi-line displayed equations, and displayed equations in general are handled by a single pdf run.

There is one other thing preview- does: it will process multiple equation environments in a single file, putting each one on a different page, with the correct size. This may be useful for batch processing, or appending numbers to equations.

Other material

All of the existing solutions offer a way of typesetting arbitrary material. Given the demands on the output we’d like to fulfil, it seems unlikely we’ll ever be able to get there. Some classes of material may be supported.

Ordinary text
This can be placed in an ordinary lrbox environment, if the material is sufficiently short.
A whole paragraph
In this case the baseline is less important, and the whole item can probably be placed in a \parbox or a minipage environment. In these cases a column-width must be specified somehow.
A table
This could be placed in a minipage, which can be stored in a box (somehow). This could be done in pdf.

There may be a need to process the different classes with different toolchains. Perhaps the exact toolchain should be indicated in the source (as a special comment).

Conclusions

Preview seems to be a very good solution, apart from the fact that it doesn’t lend itself to extraction of the baseline – although the documentation says it offers this information.

The other solution is a hack, but in a subset of situations, it will work, and it readily provides baseline offset information – essential for inline use.

Another option I haven’t explored yet is the use of metapost as a container. It seems metafun has solved the problems surrounding this issue already, and that it could be used as a basis. The result will be relatively slow.

Two-way communication

Typesetting a single equation and putting it into Keynote, or somewhere else for that matter, is all fine. However, it is a one-way trip: once the equation is in its destination location, it can’t come back to correct mistakes – or can it?

Linkback

We’re not alone in wanting two-way communication for copy and paste operations. The Linkback Project is an open source library that aims to solve just this problem. From their website:

LinkBack is an open source framework for Mac OS X that helps developers integrate content from other applications into their own. A user can paste content from any LinkBack-enabled application into another and reopen that content later for editing with just a double-click. Changes will automatically appear in the original document again when you save.

The list of applications that support Linkback – or have announced they will support it in the near future – is already rather impressive. One important application is Keynote: a plugin for keynote has been created that allows Linkback to be used with Keynote. After using it for a presentation for a job-interview [6], I can only say that it is highly addictive.

At the moment Type and It both have support for this library.

Other possbilities

There will be some applications where Linkback is not an option, perhaps due to cross platform concerns where the developer doesn’t want to enable Linkback. The PDF file format however is flexible enough to store a lot of other information as well, including the source used to produce the PDF.

The following piece of code will store the entire source file in the first object of the PDF file. Since we also tell pdf to turn compression off for this object, the source text will be inserted unaltered. This doesn’t work when there is an intermediate step involved – like going through dvips. Extracting the source seems easy enough: if all else fails one can add a special comment at the beginning an the end of the file, and scan the pdf for that pattern. Then all that’s left to do is copy everything in between.

\usepackage{ifpdf}
\ifpdf
\begingroup
  \pdfcompresslevel=0
  \immediate%
  \pdfobj stream attr {/Type /Source /Subtype /LaTeX}
  file{\jobname.tex}
  \pdfcatalog{/LaTeXSource \the\pdflastobj\space 0 R}
\endgroup
\fi

PDF files can contain file-attachments. This sounds like it was invented for adding source to a document. pdf can add these attachments itself with the ‘attachfile’ package and there are some tools out there that can do this for you after the fact: pdftk is one of them. The bash code below shows how to add or extract the attachment with pdftk (and correct the bounding box in the process). This is part of a larger shell script which will become available once I figure out how this sourceforge site actually works.

if [ "$create" = "yes" ]
then
  # run pdflatex
  pdflatex -interaction=scrollmode -output-format=pdf \
    $texmasterfile > /dev/null
  if [ $? -ne 0 ]; then
    echo "pdflatex failed." > /dev/stderr
    cat ${texmasterfile%.tex}.log > /dev/stdout
    exit 1
  fi
  
  # obtain the tight bounding box, 
  # use the Hires bounding box.
  boundingbox=`gs -dNOPAUSE -sDEVICE=bbox -dBATCH -q \
    $intermediatepdf 2>&1 | \
    awk -F: '/%%HiResBoundingBox/{printf "[%s]",\
      substr($2,2,length($2)-1)}'`
  
  # if we want xml, create it first.
  if [ "$make_xml" = "yes" ]
  then
    mathmlsource="${texsource%.tex}.xml"
    mk4ht xhmlatex $texmasterfile > /dev/null 2>&1
    if [ $? -ne 0 -a ! -s "${intermediatebase}.html" ]; then
      echo "xhmlatex failed." > /dev/stderr
      exit 1
    fi
    mv ${intermediatebase}.html $mathmlsource
    
    # OK, here is the trickery to correct the bounding box
    # and attach the tex & xml representations 
    pdftk $intermediatepdf output - uncompress | \
      sed "/MediaBox/s/\\[[0-9\\. \\]*]/$boundingbox/g" | \
      pdftk - attach_files ${texsource%.tex}.tex \
        $mathmlsource output ${outfile} compress
  else
    pdftk $intermediatepdf output - uncompress | \
      sed "/MediaBox/s/\\[[0-9\\. \\]*]/$boundingbox/g" | \
      pdftk - attach_files ${texsource%.tex}.tex output \
        ${outfile} compress
  fi
  cp $tmpdir/${outfile} ${outfile}
else # extract the sources
  if [ ! -f "$pdfsource" ]; then
    echo "Input file must be given." > /dev/stderr
    exit 1;
  fi
  
  pdftk $pdfsource unpack_files output "$tmpdir"
fi

Mac OS X 10.4 (Tiger) itself may provide the framework to do this directly, but a coarse glance through the documentation of tiger’s all new PDFView didn’t reveal an obvious method of doing so, or of obtaining the attachment.

A final method is employed by Equation Service: “just” add the source to a PDF comment field. Sounds easy, but a lot of special characters have to be encoded, so this is rather hard. This implementation shows the value of an alternate method, and pre-dates Linkback by several years.

The all important user interface

This is a conceptually simple task, and as such it requires a simple tool. However: writing simple software probably is the hardest task of them all. The four available tools are all very similar, and provide some direction on what works and what doesn’t. I’d say that most have cracked the problem pretty well. Care must be taken not to overwhelm the uninitiated user, while still explaining what each template does.

This is a short list of some of the desired features I haven’t touched before.

Existing solutions

There are already four five tools available on the internet that typeset small pieces of code and return a PDF file with the finished result. This was one of the reasons to start the Mac OS X Toolbox project.

In random order: