This is a suite of tools and libraries to make rendering LaTeX equations to images easy from Haskell and Pandoc. For an example of what they’re capable of, take a look at articles on my blog.
It contains three parts,
latex-formulae-image
- A library which uses LaTeX,dvips
and ImageMagick to convert a latex formula into an image, and does baseline detection so that the image can be positioned correctly when inline with other text.latex-formulae-pandoc
- Provides some functions onPandoc
documents that renders embedded math to images intended for HTML output. These functions can be easily used to create small pandoc filter programs that can be run withpandoc
as a standalone application. An example executable is provided with the library. The library is capable of storing the images in separate files or embedding them inside the page with data URIs.latex-formulae-hakyll
- Provides simple compilers that can be integrated with Hakyll, to render all equations in Pandoc-compiled pages inside Hakyll websites. Includes a simple LRU cache so that thewatch
server only recompiles changed equations.
These libraries also give you precise control over the output DPI and over the dimensions of the image in the HTML output, so it can be configured to give crisp images even on high DPI displays, like Retina displays.
Because they use just regular LaTeX, any of the packages available to your system LaTeX installation are also available
in these formulae. Just add the necessary usepackage
invocations to the preamble inside your FormulaOptions
value.
You must have a LaTeX installation available, which includes latex
and dvips
. ImageMagick’s convert
is also required,
and must be able to understand PostScript (for example, using gs
). Most recent binary distributions of LaTeX and ImageMagick
satisfy these dependencies.
If you’re using stack
, it should just be a matter of stack build
, and stack install
if you want to use the example pandoc filter,
latex-formulae-filter
.
Users of cabal
will have to build each package using the usual cabal
ceremony:
cabal update
cabal configure
cabal build
cabal install
As always, see the Haddocks for more thorough details. Here are some simple example usages.
The latex-formulae-image
package really only has one major function,
imageForFormula
. You can use it like so:
import Image.LaTeX.Render (imageForFormula, defaultEnv, displaymath)
import Codec.Picture (writeDynamicPng) -- JuicyPixels
main = do x <- imageforFormula defaultEnv displaymath "y = mx + b"
case x of
Left e -> return ()
Right (baseline, img) -> do
_ <- writeDynamicPng "image.png" img
return ()
Settings such as where to find LaTeX etc. can be set by altering the EnvironmentOptions
value, in this case we just use
defaultEnv
defaults. Settings such as the LaTeX environment
to use, the preamble, and the DPI can be set in the FormulaOptions
value, in this case we use the displaymath
defaults.
If you want to integrate with pandoc
programmatically, you can use the latex-formulae-pandoc
package. This package includes
functions that allow you to transform pandoc
documents. If you’re happy to embed the images directly inside the HTML,
then convertAllFormulaeDataURI
is easiest:
imagesForFormulae :: Pandoc -> IO Pandoc
imagesForFormulae doc = convertAllFormulaeDataURI defaultEnv defaultPandocFormulaOptions doc
The above example function can be inserted between any Pandoc
reader and an HTML writer, producing embedded images inside
the HTML output using data URIs.
If you would rather they be stored as separate PNG images in a directory called static
, convertAllFormulaeFiles
can be used:
imagesForFormulae :: Pandoc -> IO Pandoc
imagesForFormulae doc = do ns <- newNameSupply
convertAllFormulaeFiles ns "static" defaultEnv defaultPandocFormulaOptions doc
There are also more general versions of the convertFormula*
functions, named `convertFormula*With`, which allow the
actual function that does the rendering of formulae to be altered. This is so that you can insert image caching or
other image postprocessing into the renderer.
Currently only Data URI embedding is supported for Hakyll, but using it should be as simple as the following minimal example:
main = do
renderFormulae <- initFormulaCompilerDataURI 1000 defaultEnv
hakyll $
match "posts/*.markdown" $ do
route $ setExtension "html"
compile $ pandocCompilerWithTransformM defaultHakyllReaderOptions defaultHakyllWriterOptions
$ renderFormulae defaultPandocFormulaOptions
If for whatever reason you don’t want to have formula caching for @watch@ servers, you can just use this simpler form:
main =
hakyll $
match "posts/*.markdown" $ do
route $ setExtension "html"
compile $ pandocCompilerWithTransformM defaultHakyllReaderOptions defaultHakyllWriterOptions
$ compileFormulaeDataURI defaultEnv defaultPandocFormulaOptions
The latex-formulae-pandoc
library comes with a simple example filter executable, called latex-formulae-filter
. If you
stack install
or cabal install
it to your $PATH
, you can use it with pandoc
like so:
pandoc -s --filter=latex-formulae-filter -o output.html input.html
The source code for this program is very simple:
import Image.LaTeX.Render.Pandoc
import Image.LaTeX.Render
import Text.Pandoc.JSON
main :: IO ()
main = toJSONFilter $ convertFormulaDataURI defaultEnv defaultPandocFormulaOptions
This filter embeds the images with data URIs. To use files, follow the same routine as above:
import Image.LaTeX.Render.Pandoc
import Image.LaTeX.Render
import Text.Pandoc.JSON
main :: IO ()
main = do ns <- newNameSupply
toJSONFilter $ convertFormulaFiles ns "static" defaultEnv defaultPandocFormulaOptions
Adjust the various options by altering the defaultPandocFormulaOptions
and defaultEnv
terms in this program,
as described in the Haddock documentation.
Writing the following markdown:
Lines (that is, $f(x) = mx + b$) are of degree 1, whereas quadratics (that is,
$f(x) = ax^2 + bx + c$) are of degree 2. Solve quadratics with the quadratic
formula:
$$x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}$$
Enough high school algebra for now!
Leads to this output! Pretty nifty :)
I would like to add files support for Hakyll websites, but it’s not clear how this would interact with Hakyll’s compiler system.