Skip to content

Instantly share code, notes, and snippets.

@lierdakil
Last active February 19, 2022 07:29
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save lierdakil/6a95278d02256a74a0fc to your computer and use it in GitHub Desktop.
Save lierdakil/6a95278d02256a74a0fc to your computer and use it in GitHub Desktop.
Pandoc filter to convert math to inline svg using latex and dvisvgm
{-# LANGUAGE OverloadedStrings #-}
import Text.Pandoc.JSON
import System.Directory
import System.FilePath ((</>))
import qualified Data.Hash.MD5 as MD5
import qualified Data.Text as T
import System.IO.Temp
import System.Process
import Control.Monad (unless)
main :: IO ()
main = toJSONFilter mathToSvg
mathToSvg :: Inline -> IO Inline
mathToSvg m@(Math mathType x) = do
let wrap = T.unpack . removeNewline . case mathType of
InlineMath -> \x' -> "\\(" <> x' <> "\\)"
DisplayMath -> \x' -> "\\[" <> x' <> "\\]"
preamble =[
"\\documentclass[border=1pt,varwidth]{standalone}",
"\\usepackage{standalone}" <>
"\\usepackage{amsmath}" <>
"\\usepackage{amssymb}" <>
"\\usepackage{cancel}" <>
"\\begin{document}"
]
postamble = [ "\\end{document}" ]
removeNewline = T.filter (`notElem` ("\r\n" :: [Char]))
tempDir <- getTemporaryDirectory
let cacheDir = tempDir </> "pandoc.texsvg.cache"
createDirectoryIfMissing True cacheDir
let mathHash = MD5.md5s $ MD5.Str $ show m
outfilename = cacheDir </> mathHash <> ".svg"
fileExists <- doesFileExist outfilename
unless fileExists $
withSystemTempDirectory "pandoc.dir" $ \tmpDir ->
do
origDir <- getCurrentDirectory
setCurrentDirectory tmpDir
_ <- readProcess "latex" (preamble <> [wrap x] <> postamble) []
_ <- readProcess "dvisvgm"
["-b2pt", "-Z1.2", "-n", "-o", outfilename, "standalone.dvi"] []
setCurrentDirectory origDir
svg <- T.pack <$> readFile outfilename
return $ RawInline (Format "html") $ case mathType of
InlineMath -> svg
DisplayMath -> "<p>" <> svg <> "</p>"
mathToSvg x = return x
@pazz
Copy link

pazz commented Sep 10, 2020 via email

@PassionPenguin
Copy link

PassionPenguin commented Feb 14, 2022

Hi @lierdakil i try to make a lua filter, but i am a newer in either lua or haskell, and i failed to install pandoc via cabal...thus i try to make a lua version:

local default_template = [[
\documentclass[12pt,preview]{standalone}
{{ preamble }}
\begin{document}
\begin{preview}
{{ code }}
\end{preview}
\end{document}
]]

local default_preamble = [[
\usepackage[utf8x]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{amstext}
\usepackage{newtxtext}
\usepackage{mhchem}
\usepackage{chemfig}
\usepackage[libertine]{newtxmath}
\DeclareOldFontCommand{\rm}{\normalfont\rmfamily}{\mathrm}
\DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf}
\DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt}
\DeclareOldFontCommand{\bf}{\normalfont\bfseries}{\mathbf}
\DeclareOldFontCommand{\it}{\normalfont\itshape}{\mathit}
\DeclareOldFontCommand{\sl}{\normalfont\slshape}{\@nomath\sl}
\DeclareOldFontCommand{\sc}{\normalfont\scshape}{\@nomath\sc}
\newcommand{\N}{\mathbb{N}}
\newcommand{\R}{\mathbb{R}}
\newcommand{\Z}{\mathbb{Z}}
]]

function exec_math (elem)
    -- Convert Math El -> DVI via latex --
    mathEq = default_template:gsub("{{ preamble }}", default_preamble):gsub("{{ code }}", elem.text)
    local tex = io.open("input.tex", "w")
    tex:write(mathEq)
    io.close(tex)
    os.execute("latex input.tex")
    os.execute("dvisvgm --no-fonts input.dvi output.svg")
    local svg = io.open("output.svg", "rb")
    if not svg then
        return nil
    end
    local content = svg:read "*a"
    local output
    if elem.mathtype == 'InlineMath' then
        output = content
    else
        output = "<p>" .. content .. "<p>"
    end
    elem = pandoc.RawInline('html', output)
    return elem
end

return {
    { Math = exec_math }
}

but after generating svg with markdown math $\chemfig{C([2]-H)([6]=H)}$ and return a RawInline elem, it still renders a <span class="math inline">$\chemfig{C([2]-H)([6]=H)}$</span>, and log a warning in the console:

[WARNING] Could not convert TeX math \chemfig{C([2]-H)([6]=H)}, rendering as TeX:
  \chemfig{C([2]-H)([6]=H)}
          ^
  unexpected control sequence \chemfig
  expecting "%", "\\label", "\\tag", "\\nonumber" or whitespace

Do you have any idea how to fix it?.....

@PassionPenguin
Copy link

PassionPenguin commented Feb 14, 2022

a google group link pubed by myself.. https://groups.google.com/g/pandoc-discuss/c/4CirnNd-ETs

@lierdakil
Copy link
Author

To begin with, your call to dvisvgm is not quite right... Try using dvisvgm --no-fonts input.dvi -o output.svg. Besides, I'm pretty sure that call to table.insert will fail, since neither argument is a table. I don't think you need it to begin with.

@PassionPenguin
Copy link

PassionPenguin commented Feb 18, 2022

sorry but i find that you're right... as i have read a wrong document... thx:)

Here's my gist https://gist.github.com/PassionPenguin/43fc09b942cedc428ae246bff8b6e193 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment