1

Recently, I have been having some issues with TikZ in LaTeX. I want to convert my PhD dissertation, written in LaTeX, to .docx using pandoc. I am able to use lua filters to have pandoc convert TikZ images, thanks to help here.

However, a small problems remains. In the .docx file, the TikZ images are not centered. Nor are my captions included: it seems like pandoc simply ignores \begin{figure} whereafter I have included these commands.

Question

How to give a caption to and how to center TikZ figures in a .docx file converted with pandoc?

I am probably looking right over the solution, but as I am inexperienced with programming I do not know how to fix this.

Here is my .tex file:

\documentclass[a4paper,12pt]{book}
\usepackage{graphicx}
\usepackage[english]{babel}

\usepackage{tikz}

\begin{document}

 \begin{figure}
    
   \centering

    \begin{tikzpicture}

             \draw circle(5cm);
    
    \end{tikzpicture}
    
  \caption{Admire my circle!}

\end{figure}

\end{document}

Here is my .lua file, taken from here, which functions as a filter:

local function file_exists(name)
  local f = io.open(name, 'r')
  if f ~= nil then io.close(f); return true
  else return false end
end

--- Create a standalone LaTeX document which contains only the TikZ picture.
--- Convert to png via Imagemagick.
local function tikz2image(src, outfile)
  local tmp = os.tmpname()
  local tmpdir = string.match(tmp, "^(.*[\\/])") or "."
  -- local tmpdir = "."
  local f = io.open(tmp .. ".tex", 'w')
  f:write("\\documentclass{standalone}\n")
  -- include all packages needed to compile your images
  f:write("\\usepackage{tikz}\n\\usepackage{stanli}\n\\usetikzlibrary{arrows.meta,positioning}\n")
  f:write("\\begin{document}\n")
  f:write(src)
  f:write("\n\\end{document}\n")
  f:close()
  os.execute("pdflatex -output-directory " .. tmpdir  .. " " .. tmp)
  -- os.execute("convert " .. tmp .. ".pdf " .. "-colorspace RGB " .. outfile)
  os.execute("pdftoppm -png " .. tmp .. ".pdf " .. "> " .. outfile)
  os.remove(tmp .. ".tex")
  os.remove(tmp .. ".pdf")
  os.remove(tmp .. ".log")
  os.remove(tmp .. ".aux")
end

function RawBlock(el)
  -- Don't alter element if it's not a tikzpicture environment
  if not el.text:match'^\\begin{tikzpicture}' then
    return nil
    -- Alternatively, parse the contained LaTeX now:
    -- return pandoc.read(el.text, 'latex').blocks
  end  
  local fname = pandoc.sha1(el.text) .. ".png"
  if not file_exists(fname) then
    tikz2image(el.text, fname)
  end
  return pandoc.Para({pandoc.Image({}, fname)})
end

Here is the command I enter in the terminal:

pandoc -s --from latex+raw_tex --lua-filter=tikz.lua test.tex -o test.docx
1
  • 1
    If you are trying to convert a large project, that includes many elements that are not represented in pandoc's AST, you will run into many problems. Maybe it's easier to use another tool, I'd suggest tex4ht: tug.org/tex4ht – DG' Oct 27 '20 at 9:47
1

I have done something similar, starting from the example at pandoc.org/lua-filters.html#building-images-with-tikz.

The main thing is that the filter looks for a raw LaTeX block that starts with '\begin{tikzpicture}', and your blocks start with '\begin{figure}'. You can replace the former with the latter.

I then modified the 'tikz_doc_template' for my use.

Here is the filter that I use: gitlab.com/twsh/pandoc-lua-filters/-/blob/master/tikz-qtree.lua

--[[ Turn figure environments into SVG images
Links are relative
Only one tikzpicture per block
If there is a \caption{...}, set the title text to ...;
pandoc will turn this into a <figcaption> for HTML.
It is assumed that the caption finishes at a line break ]]

local system = require 'pandoc.system'

local tikz_doc_template =
[[
\documentclass{standalone}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{tikz-qtree}
\usepackage{amsmath}
\begin{document}
%s
\end{document}
]]

local function tikz2image(src, outfile)
    system.with_temporary_directory(
        'tikz2image',
        function(tmpdir)
            system.with_working_directory(
                tmpdir,
                function()
                    local f = io.open('tikz.tex', 'w')
                    f:write(tikz_doc_template:format(src))
                    f:close()
                    os.execute('pdflatex tikz.tex')
                    os.execute('pdf2svg tikz.pdf ' .. outfile)
                end
            )
        end
    )
end

local function file_exists(name)
    local f = io.open(name, 'r')
    if f ~= nil then
        io.close(f)
        return true
    else
        return false
    end
end

function RawBlock(el)
    tikz = el.text:match('\\begin{tikzpicture}(.+)\\end{tikzpicture}')
    if tikz then
        local fname = pandoc.sha1(tikz) .. '.' .. 'svg'
        local fpath = system.get_working_directory() .. '/' .. fname
        if not file_exists(fpath) then
            tikz2image(tikz, fpath)
        end
        local caption = el.text:match('\\caption{(.+)}\n')
        if caption then
            local caption_text = pandoc.utils.stringify(pandoc.read(caption, 'latex').blocks)
            return pandoc.Para({pandoc.Image({pandoc.Str(caption_text)}, fname, 'fig:')})
        else
            return pandoc.Para({pandoc.Image({}, fname, 'fig:')})
        end
    else
        return el
    end
end
2
  • I see that this answer covers some of the same ground: tex.stackexchange.com/a/431843/451 – twsh Oct 28 '20 at 0:13
  • +1 nice! Maybe you could post the modified filter here as well – DG' Oct 29 '20 at 21:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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