我有一个 LaTeX 文档,其中包含以下代码,该代码使用 TiKZ 生成图片。 (此处为最小工作示例)
\documentclass{article}
\usepackage{amsmath,stanli}
\begin{document}
Analyse the plane frame shown in the figure by using FEM. Consider $E = 400\ GPa$, $I = 1 \times 10^{-4}\ m^4$, and $A = 2 \times 10^{-2}\ m^2$.
\begin{center}
\begin{tikzpicture}
\point{a}{0}{0}
\point{b}{5}{0}
\point{c}{9}{-3}
\point{a1}{2.5}{1.5}
\beam{2}{a}{b}[0][1]
\beam{2}{b}{c}[0][1]
\support{3}{a}[270]
\support{3}{c}
\lineload{1}{a}{b}[1][1]
\dimensioning{1}{a}{b}{-3.5}[$5m$]
\dimensioning{1}{b}{c}{-3.5}[$4m$]
\dimensioning{2}{b}{c}{5}[$3m$]
\notation{1}{a1}{$5 kN/m$}
\end{tikzpicture}
\end{center}
\end{document}
如果我使用以下命令
pandoc -s latex.tex -o sample.docx
TikZ 图片没有嵌入到 DOCX 文件中。如何缓解这个问题?
答案1
Pandoc 不知道如何处理 TikZ 环境。不过,你可以使用Lua 过滤器教授 pandoc。具体来说,可以使用使用 TikZ 构建图像示例。该示例假设输入是 Markdown 与 LaTeX 混合,因此您需要进行一些调整才能使其与纯 LaTeX 输入配合使用。
首先,我们希望 pandoc 保留它无法读取的任何 LaTeX,而不是尽力转换它。通过添加--from latex+raw_tex
到命令中来执行此操作。
接下来,我们只想在看起来像tikzpicture
环境的 LaTeX 片段上运行图像生成器,并且前提是我们尚未完成此转换。
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)
-- 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
最后,我们包含实际的图像转换代码
--- 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 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")
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 " .. outfile)
os.remove(tmp .. ".tex")
os.remove(tmp .. ".pdf")
os.remove(tmp .. ".log")
os.remove(tmp .. ".aux")
end
将上述所有代码放入名为tikz-转-png.lua并通过使用该--lua-filter=tikz-to-png.lua
选项调用 pandoc 来运行它。请注意,您需要convert
在路径中包含 ImageMagick 的程序。
答案2
Lua 过滤器的另一种方法是使用pandocfilters以及较新的排箫Python 包。至少对于那些不了解 Lua 的人来说,这提供了一种更简单的编写过滤器的方法。稍微调整一下此过滤器做了这个伎俩:
"""
Pandoc filter to process raw latex tikz environments into images.
Assumes that pdflatex is in the path, and that the standalone
package is available. Also assumes that ImageMagick's convert
is in the path. Images are put in the tikz-images directory.
"""
import hashlib
import re
import os
import sys
import shutil
import panflute as pf
from subprocess import Popen, PIPE, call
from tempfile import mkdtemp
imagedir = "tikz-images"
def sha1(x):
return hashlib.sha1(x.encode(sys.getfilesystemencoding())).hexdigest()
def tikz2image(tikz, filetype, outfile):
tmpdir = mkdtemp()
olddir = os.getcwd()
os.chdir(tmpdir)
f = open('tikz.tex', 'w')
f.write("""\\documentclass{standalone}
\\usepackage{tikz}
\\begin{document}
""")
f.write(tikz)
f.write("\n\\end{document}\n")
f.close()
p = call(["pdflatex", 'tikz.tex'], stdout=sys.stderr)
os.chdir(olddir)
if filetype == 'pdf':
shutil.copyfile(tmpdir + '/tikz.pdf', outfile + '.pdf')
else:
call(["convert", tmpdir + '/tikz.pdf', outfile + '.' + filetype])
shutil.rmtree(tmpdir)
def action(elem, doc):
"""
return None -> element unchanged
return [] -> delete element
"""
if type(elem) == pf.RawBlock and elem.format == "latex":
code = elem.text
if code.strip().startswith(r"\begin{tikzpicture}"):
outfile = imagedir + '/' + sha1(code)
filetype = {'html': 'png', 'latex': 'pdf'}.get(doc.format, 'png')
src = outfile + '.' + filetype
if not os.path.isfile(src):
try:
os.mkdir(imagedir)
sys.stderr.write('Created directory ' + imagedir + '\n')
except OSError:
pass
tikz2image(code, filetype, outfile)
sys.stderr.write('Created image ' + src + '\n')
return pf.Para(pf.Image(url=src))
else:
return pf.convert_text(code, input_format="latex")
def main(doc=None):
return pf.run_filter(action, doc=doc)
if __name__ == "__main__":
main()
特别是,该行return pf.convert_text(code, input_format="latex")
提供了额外的好处,确保所有其他 raw_tex 都以标准 pandoc 方式处理(使用时--from latex+raw_tex
),正如我在另一个问题中讨论的那样这里。