pdflatex
(以及lualatex
和xelatex
)无法处理由我的 ImageMagick 创建的(一些) JPEG 图像。
我在 OSX Mavericks 上使用图像魔术师v6.9.0-0 Q16 x86_64
通过 MacPorts 提供。
我的LaTeX 版本安装是这样的:
$ latex --version
pdfTeX 3.14159265-2.6-1.40.15 (TeX Live 2014/MacPorts 2014_8)
kpathsea version 6.2.0
[....]
Compiled with libpng 1.6.17; using libpng 1.6.17
Compiled with zlib 1.2.8; using zlib 1.2.8
Compiled with poppler version 0.32.0
我尝试构建一个最小工作示例,以便每个人都能重现该问题。如果您不能,请告知您运行的 IM 和 LaTeX 的具体版本。
准备
这是两张 JPEG,均由 ImageMagick 创建。
左边的不起作用,右边的起作用:(请参阅图片下方的更新!)
更新:Imgur 托管似乎删除了一些元数据,因此文件不再处于原始状态。请使用此 在 GoogleDrive 上链接到 mini-tarball. 它包含原始 JPEG。
我使用以下命令来创建它们:
$ convert wizard: wiz-standard.jpg # (left image)
$ convert wizard: -density 300 wiz-300densi.jpg # (right image)
关于两个 JPEG 的数据点
以下是有关它们之间的差异的一些数据点。
文件大小
$ ls -l wiz-300densi.jpg wiz-standard.jpg
-rw-r--r-- 1 kp staff 62177 7 Mai 12:09 wiz-300densi.jpg
-rw-r--r-- 1 kp staff 62177 7 Mai 12:09 wiz-standard.jpg
如您所见,文件大小完全相同。
像素尺寸
$ identify wiz-300densi.jpg wiz-standard.jpg
wiz-300densi.jpg JPEG 480x640 480x640+0+0 8-bit sRGB 62.2KB 0.000u 0:00.000
wiz-standard.jpg[1] JPEG 480x640 480x640+0+0 8-bit sRGB 62.2KB 0.000u 0:00.000
如您所见,图像尺寸完全相同。
像素/颜色差异
$ for i in $(compare -list metric); do
> echo -n " Metric $i : ";
> compare -metric $i wiz-300densi.jpg wiz-standard.jpg null: ;
> echo;
> done
Metric AE : 0
Metric Fuzz : 0 (0)
Metric MAE : 0 (0)
Metric MEPP : 0 (0, 0)
Metric MSE : 0 (0)
Metric NCC : 1
Metric PAE : 0 (0)
Metric PHASH : 0
Metric PSNR : inf
Metric RMSE : 0 (0)
如您所见,根据每个可用度量,比较每个像素的颜色值不会产生任何差异。
图像元数据
$ identify -verbose wiz-300densi.jpg > wiz-300densi.log
$ identify -verbose wiz-standard.jpg > wiz-standard.log
$ sdiff -sbB wiz-densi300.log wiz-standard.log
Image: wiz-300densi.jpg | Image: wiz-standard.jpg
Resolution: 300x300 <
Print size: 1.6x2.13333 <
date:create: 2015-05-07T12:09:45+02:00 | date:create: 2015-05-07T12:09:20+02:00
date:modify: 2015-05-07T12:09:45+02:00 | date:modify: 2015-05-07T12:09:20+02:00
filename: wiz-300densi.jpg | filename: wiz-standard.jpg
这是第一个区别:“不起作用”的 JPEG 在其元数据中不包含有关它希望在输出设备上呈现的首选分辨率的任何提示。
$ exiftool wiz-standard.jpg | grep Resolution
Resolution Unit : inches
X Resolution : 1
Y Resolution : 1
$ exiftool wiz-300densi.jpg | grep Resolution
Resolution Unit : inches
X Resolution : 300
Y Resolution : 300
Exiftool 也报告了一个差异:但是,它报告的不是空值(就像identify -verbose
“不工作”的 JPEG 那样),而是一个值1
。我不知道这是否真的存在于文件的数据中,或者exiftool
只是假设并报告缺少的元数据条目的该值。
LaTeX 代码(MWE)
这是我的 LaTeX 代码:
\documentclass[]{article}
\usepackage{graphicx}
\begin{document}
\begin{figure}[htbp]
\centering
\includegraphics{./wiz-standard.jpg}
\end{figure}
\end{document}
pdflatex
运行+输出
运行pdflatex
后会出现以下消息:
This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014/MacPorts 2014_8) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./mini.tex
LaTeX2e <2014/05/01>
Babel <3.9k> and hyphenation patterns for 50 languages loaded.
(/opt/local/share/texmf-texlive/tex/latex/base/article.cls
Document Class: article 2007/10/19 v1.4h Standard LaTeX document class
(/opt/local/share/texmf-texlive/tex/latex/base/size10.clo))
(/opt/local/share/texmf-texlive/tex/latex/graphics/graphicx.sty
(/opt/local/share/texmf-texlive/tex/latex/graphics/keyval.sty)
(/opt/local/share/texmf-texlive/tex/latex/graphics/graphics.sty
(/opt/local/share/texmf-texlive/tex/latex/graphics/trig.sty)
(/opt/local/share/texmf-texlive/tex/latex/latexconfig/graphics.cfg)
(/opt/local/share/texmf-texlive/tex/latex/pdftex-def/pdftex.def
(/opt/local/share/texmf-texlive/tex/generic/oberdiek/infwarerr.sty)
(/opt/local/share/texmf-texlive/tex/generic/oberdiek/ltxcmds.sty))))
(./mini.aux) (/opt/local/share/texmf-texlive/tex/context/base/supp-pdf.mkii
[Loading MPS to PDF converter (version 2006.09.02).]
) (/opt/local/share/texmf-texlive/tex/generic/oberdiek/pdftexcmds.sty
(/opt/local/share/texmf-texlive/tex/generic/oberdiek/ifluatex.sty)
(/opt/local/share/texmf-texlive/tex/generic/oberdiek/ifpdf.sty))
(/opt/local/share/texmf-texlive/tex/latex/oberdiek/epstopdf-base.sty
(/opt/local/share/texmf-texlive/tex/latex/oberdiek/grfext.sty
(/opt/local/share/texmf-texlive/tex/generic/oberdiek/kvdefinekeys.sty))
(/opt/local/share/texmf-texlive/tex/latex/oberdiek/kvoptions.sty
(/opt/local/share/texmf-texlive/tex/generic/oberdiek/kvsetkeys.sty
(/opt/local/share/texmf-texlive/tex/generic/oberdiek/etexcmds.sty)))
(/opt/local/share/texmf-texlive/tex/latex/latexconfig/epstopdf-sys.cfg))
pdfTeX warning: pdflatex: arithmetic: number too big
pdfTeX warning: pdflatex: arithmetic: number too big
<./wiz-standard.jpg, id=1, --32768.0pt x 0.0pt> <use ./wiz-standard.jpg>
[1{/opt/local/var/db/texmf/fonts/map/pdftex/updmap/pdftex.map} <./wiz-standard.
jpg>] (./mini.aux) )</opt/local/share/texmf-texlive/fonts/type1/public/amsfonts
/cm/cmr10.pfb>
Output written on mini.pdf (1 page, 70603 bytes).
Transcript written on mini.log.
因此,从上面的 MWE-LaTeX 来看,pdflatex
至少确实生成了 70 KiBytes 的输出 PDF,同时给出了一些警告,但是......
空白页
...但 PDF 只显示“空白”的白色页面。(不过我不会展示它的屏幕截图 :)
pdfimages
报告此 PDF 中嵌入的图像:
$ pdfimages -list mini.pdf
page num type width height color comp bpc enc interp object ID x-ppi y-ppi size ratio
--------------------------------------------------------------------------------------------
1 0 image 480 640 rgb 3 8 jpeg no 1 0 2 2 60.7K 6.7%
它甚至可以从 PDF 中再次提取 JPEG,并且它保持其原始形状:
$ pdfimages -j mini.pdf mini---
$ ls -ltar mini----000.jpg wiz-standard.jpg
-rw-r--r-- 1 kp staff 62177 7 Mai 12:09 wiz-standard.jpg
-rw-r--r-- 1 kp staff 62177 8 Mai 02:09 mini----000.jpg
请注意,在其他情况下,使用非最小 TeX 文件时我也会遇到不同的pdflatex
消息,并且运行无法完成,并且根本没有创建任何 PDF(甚至没有空白页):
pdflatex
在非 MWE LaTeX 上出现错误(不仅仅是警告)
pdfTeX warning: pdflatex: arithmetic: number too big
pdfTeX warning: pdflatex: arithmetic: number too big
<./wiz-standard.jpg, id=4, --32768.0pt x 0.0pt>
! Package graphics Error: Division by 0.
See the graphics package documentation for explanation.
Type H <return> for immediate help.
...
l.63 \includegraphics{./wiz-standard.jpg}
?
注意Division by 0.
-message...
lualatex
没有完成与上方 MWE 的运行
我也尝试了lualatex
。这会报告一条略有不同的消息:
LuaTeX warning: arithmetic: number too big
LuaTeX warning: arithmetic: number too big
! Dimension too large.
<recently read> \dimen@
l.8 \includegraphics{./wiz-standard.jpg}
?
没有创建任何 PDF lualatex
,甚至没有空白页。
xelatex
没有完成与上方 MWE 的运行
以下是xelatex
MWE 上的 消息:
! Dimension too large.
<to be read again>
b
l.8 \includegraphics{./wiz-standard.jpg}
?
没有创建任何 PDF xelatex
,甚至没有空白页。
问题
请注意,包含分辨率提示的替代 JPEG 已成功嵌入,并且可以通过任一{pdf,lua,xe}latex
命令创建 PDF。
我的问题是:
- 您能用您的 LaTeX 和 ImageMagick 版本重现这个问题吗?
- 为什么要
{pdf,lua,xe}latex
如此依赖 JPEG 内部的某些元数据,以致当这些元数据错误(或丢失)时它甚至会自我终止,而不是简单地使用那里存在的真实光栅像素数据? - 这难道不是相应组件中的错误吗(即使我们接受 JPEG 本身可能有“错误”)?!?
更新 1:
(回应 Mike Renfro 的评论……)
我的非 MWE LaTeX 代码包含此代码片段:
\usepackage{graphicx}
% Redefine \includegraphics so that, unless explicit options are
% given, the image width will not exceed the width of the page.
% Images get their normal width if they fit onto the page, but
% are scaled down if they would overflow the margins.
\makeatletter
\def\ScaleIfNeeded{%
\ifdim\Gin@nat@width>\linewidth
\linewidth
\else
\Gin@nat@width
\fi
}
\makeatother
\let\Oldincludegraphics\includegraphics
{%
\catcode`\@=11\relax%
\gdef\includegraphics{\@ifnextchar[{\Oldincludegraphics}{\Oldincludegraphics[width=\ScaleIfNeeded]}}%
}%
所以这应该可以解决扩展问题,不是吗?
更新 2:
我最初链接的图像已被剥离元数据并且不再是其原始形状。
这里有一个在 GoogleDrive 上链接到 mini-tarball包含原始 JPEG。
更新 3
我忘了说了:我还测试过
$ convert wizard: -density 1 wiz-001densi.jpg
因此生成的文件确实包含相应的元数据,并且
exiftool
报告{X,Y} Resolution : 1
,以及identify -verbose
報告Resolution: 1x1
。
(我之前在ImageMagick 论坛以及Pandoc 论坛。
所以这个事实在某种程度上与下面一些答案中给出的一些猜测相矛盾......
(为了解决 JPEG 本身是否有缺陷的问题,我也在合适的 ImageMagick 论坛)。
(更新:刚刚看到一个新ImageMagick“Bugs”论坛上的留言Dirk Lemstra 说道:“我刚刚向我们的 SVN 存储库提交了一个补丁,以确保默认密度单位设置为 0(未知)而不是 1(每英寸像素数)。”)
答案1
碰巧我上周偶然发现了同样的问题,下一个版本的 LuaTeX 将检测到这些图像并发出警告:
LuaTeX warning (file wiz-standard.jpg): The image specifies an unusual resolution of 1dpi by 1dpi.
pdfTeX/luaTeX 按字节读取 jpeg(不涉及 exif)和此类图像真的指定 1dpi x 1dpi 的分辨率(参见JFIF 规范,第 5 页)。这通常会使图像过大,TeX 无法处理(请参阅\maxdimen
;限制约为 200 x 200 像素)。wiz-standard.jpg 有 480x640 像素,因此 TeX 认为您想要包含 480 英寸 x 640 英寸的图像 - 这太大了。
答案2
该图像wiz-standard.jpg
没有设置任何分辨率DPI设置(另一张图像设置为300和300)。
一些图像软件包没有正确设置这个值,因为它很少使用(据我所知包括 TeX),但出于某些奇怪的原因,TeX 要求将其设置为(任何你喜欢的值 - 因为它没有被使用 - 无论你选择 100x100 还是 400x400,你都会得到相同的 LaTeX 输出)。
它被称为 JFIF 标头,实际上它不需要存在于 JPEG 中 - 所以就我而言,它是 LaTeX 中的一个错误。
您可以通过重新保存文件来更正它(以有损的方式);但您也可以通过简单地将 DPI 值添加到标题来无损地完成它。
这在 Windows 中有效,但也可能在其他平台上有效:
用作
exiftool
命令行工具(您可以通过按钮执行此操作exiftoolgui
)exiftooldirect
来添加特殊标题。这些是命令行参数
exiftool
:-jfif:Xresolution=300 -jfif:Yresolution=300 -jfif:ResolutionUnit=inches
可以用或
inches
替换,以插入相应字段的另外两个有效值。cm
None
补充信息:显然,如果没有指定尺寸, \includegraphics 会使用 DPI 信息 - 我做了一些实验,如果有 JFIF 标头,并且图像设置为其“自然”分辨率,则
\includegraphics{xxxx.jpg}
那么编译后的 PDF 中的图像大小确实取决于 DPI。但是,如果设置了任何选项来限制高度或宽度,则 DPI 设置将被忽略。在我看来,如果 DPI 缺失但未使用,编译应该不会失败,这是合理的,因为它无关紧要。有趣的是,该选项[resolution=300,width=0.3\textwidth]
不会纠正错误,因为(我认为)分辨率选项\includegraphics
仅在 JFIF 不存在时才有效(而不是在没有 DPI 设置的情况下存在)
答案3
经过一系列测试,以及对官方的进一步研究后,我得出了自己的结论JFIF 规格(JPEG 文件交换格式)文件格式(PDF)是这样的:
ImageMagick 没有错。
pdflatex
、lualatex
和全部xelatex
都是错误的,当它们没有正确地将 JPEG 嵌入 PDF 页面时,就会出现错误。
JFIF 规格
JFIF 规范描述了 JPEG 标头中的 3 个字段:
- 在字节偏移处是
0x0d
“单位”字段。此字段长度为 1 字节。它可以容纳 3 个值。这些值描述“X 和 Y 密度的单位”。0
, 方法:“没有单位,X 和 Y 描述像素的长宽比”。1
, 方法:“X 和 Y 是每英寸点数”;2
, 方法:“X 和 Y 是每厘米点数”。
- 在字节偏移处是
0x0e
“XDensity”字段。该字段长度为 2 个字节。它描述了“水平像素密度”。 在字节偏移处,
0x10
“YDensity”字段。其长度为 2 个字节。它描述了“垂直像素密度”。+---------------+---------+-----------------+---------------------+ | Byte-Offset | 0x0d | 0x0e | 0x10 | +---------------+---------+-----------------+---------------------+ | Field-Name | "Units" | "XDensity" | "YDensity" | +---------------+---------+-----------------+---------------------+ | Value/Meaning | 0 | "X and Y describe pixel aspect ratio" | +---------------+---------+-----------------+---------------------+ | Value/Meaning | 1 | "X and Y are dots per inch" | +---------------+---------+-----------------+---------------------+ | Value/Meaning | 1 | "X and Y are dots per cm" | +---------------+---------+-----------------+---------------------+
测试脚本
我创建了一个测试脚本(Bash),它执行以下操作:
- 从同一源创建 JPEG 文件,并传递不同的
-density
参数convert
。 - 在文本文件中记录 JPEG 文件的不同属性。
- 在由同一脚本创建的 LaTeX 文档 (MWE) 中使用相应的 JPEG 文件。
- 运行每个程序
{pdf,xe,lua}latex
以创建 PDF。 - 在文本文件中记录 PDF 文件的一些属性。
- 解压缩 PDF
/Content
流以供手动检查。
脚本代码如下:
#!/bin/bash
# Script written by <kurt AT pfeifle DOT mykolab AT com>
# No warranty --
# -- feel free to use/modify for whatever purpose --
# -- use at your own risk.
mkdir jpeg-imagemagick-latex-pdflatex-lualatex-xelatex-testing
cd jpeg-imagemagick-latex-pdflatex-lualatex-xelatex-testing
rm -rf testwiz.jpg wiz-*
cat << _EOFHERE_ > mini.tex
\documentclass[a4paper]{article}
\usepackage{graphicx}
\begin{document}
\thispagestyle{empty}
\begin{figure}[htbp]
\centering
\includegraphics{./testwiz.jpg}
\end{figure}
\end{document}
_EOFHERE_
for density in 000 0.2 0.5 0.8 001 1.2 1.5 1.8 002 2.2 2.5 2.6 010 100 ; do
convert wizard: -density ${density} wiz-${density}densi.jpg
md5sum wiz-${density}densi.jpg >> wiz-md5sums.txt
ls -l wiz-${density}densi.jpg >> wiz-filesizes.txt
mkdir pdfoutdir-${density}densi
ln -fs wiz-${density}densi.jpg testwiz.jpg
file wiz-${density}densi.jpg >> wiz-filemagic.txt
echo "wiz-${density}densi.jpg :" >> wiz-identify-verbose-densi.txt
identify -verbose wiz-${density}densi.jpg \
| grep -E '(Resolution:|Print size:|filename:)' \
| gsed 's#^# #' >> wiz-identify-verbose-densi.txt
echo "" >> wiz-identify-verbose-densi.txt
for latexengine in pdflatex lualatex xelatex; do
echo
echo mkdir pdfoutdir-${density}densi/${latexengine}
echo "================================================="
echo
mkdir pdfoutdir-${density}densi/${latexengine}
${latexengine} -interaction=nonstopmode \
-output-directory=pdfoutdir-${density}densi/${latexengine} mini.tex
ls -l pdfoutdir-${density}densi/${latexengine}/mini.pdf >> wiz-pdfsizes.txt
qpdf --qdf --object-streams=disable \
pdfoutdir-${density}densi/${latexengine}/mini.pdf \
pdfoutdir-${density}densi/${latexengine}/qdf---mini.pdf
ls -l pdfoutdir-${density}densi/${latexengine}/qdf---mini.pdf \
>> wiz-qdfsizes.txt
done
done
for density in std ; do
convert wizard: wiz-${density}densi.jpg
md5sum wiz-${density}densi.jpg >> wiz-md5sums.txt
ls -l wiz-${density}densi.jpg >> wiz-filesizes.txt
mkdir pdfoutdir-${density}densi
ln -fs wiz-${density}densi.jpg testwiz.jpg
file wiz-${density}densi.jpg >> wiz-filemagic.txt
echo "wiz-${density}densi.jpg :" >> wiz-identify-verbose-densi.txt
identify -verbose wiz-${density}densi.jpg \
| grep -E '(Resolution:|Print size:|filename:)' \
| gsed 's#^# #' >> wiz-identify-verbose-densi.txt
echo "" >> wiz-identify-verbose-densi.txt
for latexengine in pdflatex lualatex xelatex; do
echo
echo mkdir pdfoutdir-${density}densi/${latexengine}
echo "================================================="
echo
mkdir pdfoutdir-${density}densi/${latexengine}
${latexengine} -interaction=nonstopmode \
-output-directory=pdfoutdir-${density}densi/${latexengine} mini.tex
ls -l pdfoutdir-${density}densi/${latexengine}/mini.pdf >> wiz-pdfsizes.txt
qpdf --qdf --object-streams=disable \
pdfoutdir-${density}densi/${latexengine}/mini.pdf \
pdfoutdir-${density}densi/${latexengine}/qdf---mini.pdf
ls -l pdfoutdir-${density}densi/${latexengine}/qdf---mini.pdf \
>> wiz-qdfsizes.txt
done
done
echo
echo wiz-pdfsizes.txt
echo ================
cat wiz-pdfsizes.txt
echo
echo wiz-qdfsizes.txt
echo ================
cat wiz-qdfsizes.txt
echo
echo wiz-filesizes.txt
echo =================
cat wiz-filesizes.txt
echo
echo wiz-filemagic.txt
echo =================
cat wiz-filemagic.txt
echo
echo wiz-identify-verbose-densi.txt
echo ==============================
cat wiz-identify-verbose-densi.txt
echo
echo wiz-md5sums.txt
echo ===============
cat wiz-md5sums.txt | sort
cd -
ImageMagick 的不同输出
我基于 ImageMagick 的内置演示wizard:
图像生成 JPEG 的测试脚本产生了 3 种不同的结果:
- JFIF 标头的“单位”字段设置为
0
(“像素纵横比”)并且0
每个字段都设置为“X/Y 密度”。 - JFIF 标头的“单位”字段设置为
0
(“像素纵横比”)并且“X/Y 密度”1
各自设置为或更大。 - JFIF 标头的“单位”字段设置为
1
(“每英寸点数”),并且每个字段都设置为“X/Y 密度” 。 (当“单位”设置为与 JFIF 标头中的默认值相等1
时,我无法成功地为这些字段设置更高的值)。PixelsPerInch
1
{pdf,xe,lua}latex
行为
将相应的 JPEG 插入 LaTeX-PDF 时,JFIF 标头字段中上述三种内容组合都会导致不同的结果。(我没有测试“X 和 Y 是每厘米“变体,可以通过-units PixelsPerCentimeter
在命令行上额外传递来生成。默认情况下,ImageMagick 会默默使用-units PixelsPerInch
。)
以下是详细信息:
Units == 0
(“X 和 Y 描述像素纵横比”)XxY == 0x0
(X密度 x Y密度):- 这会导致
xelatex
页面上的图像位置和比例出现错误。图像将仅部分可见。 pdflatex
这里没有问题并创建了正确的 PDF 页面。lualatex
这里没有问题并创建了正确的 PDF 页面。- JPEG 中的条件是使用此命令创建的:(
convert wizard: -density 0.2 wiz-0.2densi.jpg
请注意,我通过传递“滥用”了参数-density 0.2
——像素通常不会以分数形式出现……:)
- 这会导致
Units == 0
(“X 和 Y 描述像素纵横比”)XxY == 1x1
或者XxY == 2x2
或者XxY == 3x3
或 ... (X密度 x Y密度):- 这对于两者都不构成问题
{pdf,xe,lua}latex
。 - 所有 PDF 页面在此处均显示正确。它们彼此也完全相同。
- 因此,只要这两个字段的实际值不是 ,它们就无关紧要
0 / 0
。(不过,我没有用0 / 1
或1 / 0
或0 / 2
或2 / 0
或任何类似的组合进行测试。) - JPEG 中的这个条件是使用以下命令创建的:(
convert wizard: -density 001 wiz-001densi.jpg
请注意,尽管使用“分数”作为像素设置,但传递的-density 0.5
-- 或0.8
或1
或1.2
-- 全部也插入1/1
到“X/YDensity”字段中……)
- 这对于两者都不构成问题
Units == 1
(“X 和 Y 是每英寸点数”)XxY == 1x1
(X密度 x Y密度):- 这会导致每个
{pdf,xe,lua}latex
PDF 都创建一个空白页。 - 每个 PDF 生成器在运行期间都会发出不同的警告或错误消息。
- 我可以使用两个不同的命令在 JPEG 中创建这种情况:
convert wizard: wiz-001densi.jpg
或
convert wizard: -density 0 wiz-001densi.jpg
- 这会导致每个
在所有情况下,如果生成的 PDF 只有白页或图像仅部分可见,则 JPEG 图像数据已完全嵌入并且...
- ...我可以再次借助
pdfimages
命令行工具提取有效且未损坏的 JPEG 图像; - ...我可以解压缩
/Contents
相应 PDF 中的流,更改操作员的一些参数cm
并使图像变得可见。
以下是流程中需要改变的内容/Contents
:
1. PPDF 文件由pdflatex
创建于
wiz-stddensi.jpg
或来自wiz-000densi.jpg
:+--------------+------------------------------------------------+---------------------+ | | PDF source code line | Image on PDF page | +--------------+------------------------------------------------+---------------------+ | In PDF obj 5 | -32645.5791 0 0 -32645.5791 357.908 706.129 cm | invisible (outside) | | Change to | 480 0 0 640 124.802 76.093 cm | Image now visible | +--------------+------------------------------------------------+---------------------+
从所有其他 JPEG 创建:PDF 没问题。
2. PDF 文件由xelatex
创建于
wiz-stddensi.jpg
或来自wiz-000densi.jpg
:+--------------+-----------------------------------------+---------------------+ | | PDF source code line | Image on PDF page | +--------------+-----------------------------------------+---------------------+ | In PDF obj 5 | 34560 0 0 46080 52.8 -63.76 cm /Im0 Do | invisible (outside) | | Change to | 480 0 0 640 52.8 -693.8 cm /Im0 Do | Image now visible | +--------------+-----------------------------------------+---------------------+
创建于
wiz-0.2densi.jpg
:*+--------------+-----------------------------------------+---------------------+ | | PDF source code line | Image on PDF page | +--------------+-----------------------------------------+---------------------+ | In PDF obj 5 | 480 0 0 640 52.8 -63.76 cm /Im0 Do | partially outside | | Change to | 480 0 0 640 52.8 -693.8 cm /Im0 Do | Image now visible | +--------------+-----------------------------------------+---------------------+
从所有其他 JPEG 创建:PDF 没问题。
3. PDF 文件由lualatex
创建于
wiz-stddensi.jpg
或来自wiz-000densi.jpg
:+--------------+--------------------------------------------------------+---------------------+ | | PDF source code line | Image on PDF page | +--------------+--------------------------------------------------------+---------------------+ | In PDF obj 5 | -32645.5776 0 0 -32645.5776 124.802 706.129 cm /Im1 Do | invisible (outside) | | Change to | 481 0 0 640 124.802 76.093 cm /Im1 Do | Image now visible | +--------------+--------------------------------------------------------+---------------------+
从所有其他 JPEG 创建:PDF 没问题。
使用 exiftool 插入其他 JFIF 标头值
在我将 JFIF 标头的其他各种值插入 JPEG 文件(借助exiftool
)后,结果发现每个*latex
PDF 生成器:
- ...成功将 JPEG 嵌入到其页面中,创建了有效的 PDF,但是
- ...实际上似乎并不关心标题所要求的缩放比例、分辨率和纵横比。
只有在以下条件下,所有生成器似乎才会因 JFIF 标头而绊倒:
+-------------+-------------------------+------------+------------+
| Byte-Offset | 0x0d | 0x0e | 0x10 |
+-------------+-------------------------+------------+------------+
| Field-Name | "Units" | "XDensity" | "YDensity" |
+-------------+-------------------------+------------+------------+
| Value | 1 | 1 | 1 |
+-------------+-------------------------+------------+------------+
| Meaning | "X/YDensities are DPI" | 1 dpi | 1 dpi |
+-------------+-------------------------+------------+------------+
有趣的是,以下条件不会让任何 PDF 生成器触发。尽管“X/YDensity”的“更极端”设置0
并 生成一个有效的 PDF pdflatex
,lualatex
看起来应该如此。
xelatex
但是,图像的大部分位于页面之外/MediaBox
:
+-------------+-----------------------------+------------+------------+
| Byte-Offset | 0x0d | 0x0e | 0x10 |
+-------------+-----------------------------+------------+------------+
| Field-Name | "Units" | "XDensity" | "YDensity" |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 0 | 0 |
+-------------+-----------------------------+------------+------------+
| Meaning | "X/YDensities pixel ratios" | 0 px | 0 px |
+-------------+-----------------------------+------------+------------+
“X/YDensities 像素比率”
全部下列的条件允许pdflatex
并lualatex
工作会产生有效的 PDF。无论实际的 X/YDensity 值如何,每个 PDF 看起来都相同。没有任何 PDF 以任何方式缩放、弯曲或拉伸。每个 JPEG 都以 72 PPI 的分辨率显示在 PDF 页面上。
+-------------+-----------------------------+------------+------------+
| Byte-Offset | 0x0d | 0x0e | 0x10 |
+-------------+-----------------------------+------------+------------+
| Field-Name | "Units" | "XDensity" | "YDensity" |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 7 | 7 |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 100 | 100 |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 200 | 200 |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 300 | 300 |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 100 | 300 |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 300 | 100 |
+-------------+-----------------------------+------------+------------+
| Value | 0 | 300 | 1 |
+-------------+-----------------------------+------------+------------+
| Meaning | "X/YDensities pixel ratios" | <above> px | <above> px |
+-------------+-----------------------------+------------+------------+
大多数情况xelatex
下也会产生相同的输出。在最后一个极端情况下,XDensity 设置为 300,YDensity 设置为 1,xelatex
将图像的最大部分移到了 之外/MediaBox
。
“X/Y 密度为 DPI”
全部下列的条件允许所有三个、xelatex
和pdflatex
工作lualatex
产生有效的 PDF。这三个工具的结果略有不同,但似乎实际上遵循给定的 X/YDensity 值。如果“XDensity”的值与“YDensity”的值不同,则图像会缩放或弯曲。对于两个字段之间的相同值,图像会相应地缩放以保持纵横比:较小的值会放大图像,较大的值会缩小图像。
+-------------+-----------------------------+------------+------------+
| Byte-Offset | 0x0d | 0x0e | 0x10 |
+-------------+-----------------------------+------------+------------+
| Field-Name | "Units" | "XDensity" | "YDensity" |
+-------------+-----------------------------+------------+------------+
| Value | 1 | 7 | 7 |
+-------------+-----------------------------+------------+------------+
| Value | 1 | 100 | 100 |
+-------------+-----------------------------+------------+------------+
| Value | 1 | 200 | 200 |
+-------------+-----------------------------+------------+------------+
| Value | 1 | 300 | 300 |
+-------------+-----------------------------+------------+------------+
| Value | 1 | 100 | 300 |
+-------------+-----------------------------+------------+------------+
| Value | 1 | 300 | 100 |
+-------------+-----------------------------+------------+------------+
| Value | 1 | 300 | 1 |
+-------------+-----------------------------+------------+------------+
| Meaning | "X/YDensities are DPI" | <above> px | <above> px |
+-------------+-----------------------------+------------+------------+
此漏洞的影响范围
ImageMagick 不会更改其处理的 JPEG 的 JFIF 标头,除非在命令行上指定。
因此,当许多人通过 LaTeX 创建包含其珍贵的数码照片的 PDF 时,遇到此错误可能不会有危险。
这个错误最初出现是因为我使用内置 IM 特殊文件名wizard:
作为源来创建 JPEG。这触发了这个错误的极端情况,因为不幸的是,ImageMagick 对其输出文件使用了默认 DPI 值“1”(这本身可能就是 ImageMagick 的一个错误)。
-density 72
可以在 ImageMagick 中通过在命令行中添加 fe 来解决这种情况。
*latex
然而, PDF 生成工具是否使用 JFIF 头元数据仍然值得怀疑。完全用于将 JPEG 图像嵌入到页面中。因为:
- 大多数用户不知道这些 JFIF 标头
- 大多数用户不知道如何更改这些标题
- 这些标题仅控制 PDF 页面上 JPEG 的缩放比例间接
- 大多数用户希望通过不同的(LaTeX 提供的)方式来控制 PDF 输出中图像的缩放比例直接地
- 各种 JFIF 标头的处理不一致:
- 如果设置为“X/密度是 DPI”,则不是受人尊敬。
- 如果设置为“X/YDensities 是像素比率”,它们会(以某种方式)受到尊重。
执行摘要
LaTeX 系列 PDF 生成器在这里表现得完全不合理。一方面,无论“XDensity”和“YDensity”字段的值是多少(如果它们被指定为“DPI”),它们都是不是尊重。另一方面,如果“XDensity”和“YDensity”字段包含表示“像素纵横比”的值,则它们是影响页面上图像的缩放,但是是以意想不到的方式。
LaTeX PDF 生成器应完全忽略 JFIF 字段,仅遵循文档 LaTeX 代码给出的语句。
如果没有此类代码,PDF 生成器应假设 72 DPI。