使用 XeTeX 进行即时转换以包含图形

使用 XeTeX 进行即时转换以包含图形

我想对\inclugraphics{file.ext}不支持格式的图形文件执行即时转换,.ext例如.svg.gif

这种用例至少在软件包中发生过moodle.sty,用户可能希望包含适合网络的本地图形文件(SVG、GIF),并将它们按原样传递到 XML 输出。此 XML 输出包含一个问题库,可导入 Moodle LMS 中以构建测验。为了让用户尽可能简化流程,我希望避免要求在本地手动同步两个版本的图形文件(一个用于 XML,一个用于标准 LaTeX 输出文件)。

这是一个可以无错误编译并按照我的预期运行的 MWE:Linux、用于转换的 ImageMagick、TeX Live 2020 以及编译调用pdflatex -shell-escape MWE.texlualatex -shell-escape MWE.tex

\documentclass{minimal}
\usepackage{graphicx}
\makeatletter
\edef\Gin@extensions{\Gin@extensions,.svg}%
\DeclareGraphicsRule{.svg}{png}{.png}{%
    `convert '#1' \noexpand\[email protected]
}%
\makeatother
\begin{document}
\begin{filecontents*}{pict.svg}
<?xml version="1.0" encoding="UTF-8"?>
<svg width="10" height="10" version="1.1" viewBox="0 0 10 10" 
xmlns="http://www.w3.org/2000/svg">
<circle cx="5" cy="5" r="4"/>
</svg>
\end{filecontents*}
This is a black disk: \includegraphics{pict}
\end{document}

不幸的是,我无法使用 XeTeX 来实现这一点。以下是使用时日志文件的部分内容\tracingmacros1

This is XeTeX, Version 3.14159265-2.6-0.999992 (TeX Live 2020/Debian) (preloaded format=xelatex 2020.10.2)  11 DEC 2020 11:20
entering extended mode
 \write18 enabled.
 %&-line parsing enabled.
**MWE.tex
(./MWE.tex
LaTeX2e <2020-02-02> patch level 5
L3 programming layer <2020-07-17>
...
\Gin@ext ->.svg

\Gin@[email protected] #1->{png}{.png}{`convert '#1' \Gin@base -svg-converted-to.png }
#1<-\Gin@base \Gin@ext 

\Gin@setfile #1#2#3->\ifx \\#2\\\Gread@false \fi \ifGin@bbox \else \ifGread@ \c
sname Gread@\expandafter \ifx \csname Gread@#1\endcsname \relax eps\else #1\fi 
\endcsname {\Gin@base #2}\else \Gin@nosize {#3}\fi \fi \Gin@viewport@code \Gin@
nat@height \Gin@ury bp\advance \Gin@nat@height -\Gin@lly bp\Gin@nat@width \Gin@
urx bp\advance \Gin@nat@width -\Gin@llx bp\Gin@req@sizes \expandafter \ifx \csn
ame Ginclude@#1\endcsname \relax \Gin@drafttrue \expandafter \ifx \csname Gread
@#1\endcsname \relax \@latex@error {Can not include graphics of type: #1}\@ehc 
\global \expandafter \let \csname Gread@#1\endcsname \@empty \fi \fi \leavevmod
e \ifGin@draft \hb@xt@ \Gin@req@width {\vrule \hss \vbox to \Gin@req@height {\h
rule \@width \Gin@req@width \vss \edef \@tempa {#3}\rlap { \ttfamily \expandaft
er \strip@prefix \meaning \@tempa }\vss \hrule }\hss \vrule }\else \@addtofilel
ist {#3}\ProvidesFile {#3}[Graphic file (type #1)]\setbox \z@ \hbox {\csname Gi
nclude@#1\endcsname {#3}}\dp \z@ \z@ \ht \z@ \Gin@req@height \wd \z@ \Gin@req@w
idth \box \z@ \fi 
#1<-png
#2<-.png
#3<-`convert '\Gin@base \Gin@ext ' \Gin@base -svg-converted-to.png 

\Gread@eps #1->\Gread@generic {#1}\Gread@eps@aux 
#1<-\Gin@base .png
...
->\errmessage  LaTeX Error: File `\Gin@base .png' not found.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help\@err@                                     
                              

\Gin@base ->pict

\@err@                                                                  ->
! LaTeX Error: File `pict.png' not found.

由于文件尚未创建,因此我猜测没有进行pict.png调用。convert

这是我尝试过但没有成功的方法:

  • -svg-converted-to删除其中的部分\DeclareGraphicsRule没有帮助(我猜仍然没有进行转换调用)
  • epstopdf 似乎没有帮助
  • 涉及 QuickTime 库的解决方案似乎仅适用于 macOS,请参阅这里那里

我的问题是:

  • 我是否遗漏了一些显而易见的东西?
  • 为什么使用 XeTeX 编译时没有进行转换调用?
  • 我们是否可以专门针对 XeTeX 做些什么来实现 MWE 对 pdfTeX 和 LuaTeX 所做的事情?

答案1

在得到 Ulrike Fisher 和 David Carlisle 的帮助后,我尝试回答自己的问题。

免责声明:使用该选项运行 TeX 引擎-shell-escape对于一般用途而言是危险的。执行此操作时,您应该信任系统上的文件和可执行文件,或者使用沙盒环境进行编译。

我是否遗漏了一些显而易见的东西?

嗯……也许我会学会不要对没有记录的东西抱有太多的期望。格夫指南表示的最后一个参数\DeclareGraphicsRule通常为空,并展示了一个示例,其中该参数是一个zcat...以反引号 (`) 开头的系统命令 ( )。但并未说明它可以与任何命令或任何 TeX 引擎一起使用。

为什么使用 XeTeX 编译时没有进行转换调用?

大卫·卡莱尔和约瑟夫·赖特指出,反引号语法在 XeTeX 中从来都不起作用。此引擎默认不执行图形转换,并输出 XDV 格式的文件。经过 处理后,将获得 PDF 文件dvipdfmx。在此单独的过程中,如果需要,将转换图形。该graphics包没有定义将转换命令从 TeX 传递到 的接口dvipdfmx

我们是否可以专门针对 XeTeX 做些什么来实现 MWE 对 pdfTeX 和 LuaTeX 所做的事情?

通过graphics内部操作,我想出了一个似乎适用于 latex、pdflatex、xelatex 和 lualatex 的解决方案。该命令的界面\DeclareGraphicsAlien灵感\DeclareGraphicsRule来自epstopdf\epstopdfDeclareGraphicsRule。这三个参数是:

  1. 声明的外来扩展(包括前导点),
  2. 要映射到的目标本机扩展(包括前导点),
  3. 系统命令用于转换使用\SourceFile\OutputFile用于引用源文件(外来格式)和转换过程的结果(本机格式)。
\usepackage{graphicx}% including pictures
\usepackage{shellesc}% run system commands from TeX engine
\usepackage{etoolbox}% for \csdef, \csletcs
\makeatletter
\def\@firstofthree#1#2#3{#1}%
\def\@secondofthree#1#2#3{#2}%
\newcommand{\DeclareGraphicsAlien}[3]{%
  \edef\Gin@extensions{#1,\Gin@extensions}%
  \DeclareGraphicsRule{#1}{\@gobble#1}{#1}{}%
  \csdef{Gread@\@gobble#1}##1{%
    \edef\SourceFile{\Gin@base\Gin@ext}%
    \edef\Gin@base{\Gin@base-\@gobble#1-converted-to}%
    \edef\Gin@ext{#2}%
    \edef\OutputFile{\Gin@base\Gin@ext}%
    \edef\targetfmt{\expandafter\expandafter\expandafter
                    \@firstofthree\csname Gin@rule@\Gin@ext\endcsname\relax}%
    \edef\targetext{\expandafter\expandafter\expandafter
                    \@secondofthree\csname Gin@rule@\Gin@ext\endcsname\relax}%
    \IfFileExists{\SourceFile}{\ShellEscape{#3}}{}%
    \csletcs{Ginclude@\@gobble#1}{Ginclude@\targetfmt}%
    \csname Gread@\targetfmt\endcsname{\Gin@base\targetext}%
  }%
}%
\makeatother

(保证 100% Cargo Cult 编程,可能会有错误和改进空间)

现在,我们可以 1) 声明一种外来格式,2) 将其与所使用的 TeX 引擎的本机格式配对,以及 3) 指定用于转换的命令行。

下面是一个使用两把 FOSS 瑞士军刀的示例:ImageMagick 和 Inkscape,分别用于光栅和矢量图像。我使用了问题中的 SVG 文件(vector.svg此处命名)和这个动画 GIFraster.svg)。

\usepackage{iftex}% determine TeX engine
\ifnum 0\ifPDFTeX 1\fi\ifpdf 0\fi=1% EPS is a native format with latex
  \DeclareGraphicsAlien{.svg}{.eps}{%
    inkscape --export-type=eps --export-area-page '\SourceFile' -o 
    '\OutputFile' 2>/dev/null}%
  \DeclareGraphicsAlien{.gif}{.eps}{convert '\SourceFile[0]' '\OutputFile'}%
\else% PDF and PNG are native formats with pdftex, xetex, and luatex.
  \DeclareGraphicsAlien{.svg}{.pdf}{%
    inkscape --export-type=pdf --export-area-page '\SourceFile' -o 
    '\OutputFile' 2>/dev/null}%
  \DeclareGraphicsAlien{.gif}{.png}{convert '\SourceFile[0]' \OutputFile}%
\fi
\begin{document}
\begin{itemize}
\item Vector graphic \includegraphics{vector.svg}
\item Rasterized graphic \includegraphics{raster.gif}
\end{itemize}
\end{document}

必须检测对的调用,因为latex对于此引擎,PDF 和 PNG 不是原生图形格式,与和相反pdflatexxelatexlualatex

仅转换动画 GIF 的第一帧(请注意[0]向 ImageMagick 询问此操作的语法convert)并传递给结果文档。

补充说明我可能应该定义一下我所说的原生图形格式。我对此感到不舒服。假设在您的 TeX 图形引擎驱动程序(dvips.def、、或)中,您发现类似这样的行pdftex.def。我会说原生格式会显示其(非空)扩展名。例如,我无法使用使 BMP 作为原生格式工作。xetex.defluatex.def\@namedef{Gin@rule@.<XYZ>}#1{{<FMT>}{.<EXT>}{#1}}.<EXT>latex/dvips

相关内容