首页 > 解决方案 > 为什么嵌入到 PDF 中的 JPEG 呈现与原始文件略有不同?

问题描述

PDF 容器允许将完整的 JPEG 文件(包括标题和所有文件)嵌入到文档中。但是,即使存储在 PDF 中的 JPEG 与原始文件逐位相同,它的渲染也会与原始 JPEG 略有不同。我想知道为什么会这样以及如何使 PDF 中的 JPEG 像原始 JPEG 文件一样呈现。以下是如何重现我的发现:

设置

拿这个测试图像(md5sum: 5085774e481966b3359df0745c57daca

测试图像

curl https://i.stack.imgur.com/fRHo8.jpg > test.jpg

并将其放入pdf容器中。您可以使用工具img2pdf

img2pdf --producer="" --nodate test.jpg > test.pdf

或者您可以使用 PDF 的这个 gzipped base64 表示:

H4sICHImeFsAA291dC5wZGYAlVZ7PFT7Fp8xM8yMPMYrFDbK4wgzxgw5Ut6mkWEMyqMaY8cwZsxD
Ht2euKfI60QkeVPqFJEi1emirh6SmLx6EQp5HKXELWePHrqf7j93ffZn77W/67u+a63fP7+11tPJ
xZRgRsSuHXzZ3oklAHiAFxyOtbW1s8OC3BCJb/EdM/dkhoJCgAgBdMCcERcFAuaOTBGTwwtdphOX
6Y68aK4IIADmVHaIEAiwlOQFfUtc0lpOs/wxjSsCuSIhQPpSaAsYwmY68GKBADwEWJKgJ0iSL4BI
35qhg0JetIAFCrEAAElspQWHgyyRxKVE4gGyhGQH2Y/Fl2uTlmu7g9xQURhgaQ1FhSIByIzE8rGW
JDM8ZMCX8l/9//qwIrFLhZx4WC+J6tfUr/rkZX0HtkjoCQoceZFRPK6kf2voCHkcnsA7ismCGnMC
d7NZIN3VATB3YXNEoACCHBlOIIsXAkXdQHZomAgakYwHvrVKsFoP/XhHB4uWJqNEQqN9G/PbMZj7
sUMgKhm/PNViz2I/zBGGkJKY5I2ADCmNlBhaWholjUFjsRg0BoNdobACKysvi8HI4eTkFRQVcYrY
FUrKSorKkK8oEYFLMhFINJSoKIuRVfy/bfEmDIeG2cJsEXAcTAoHR+Dgiy0wLRhMCo6Cw2HfTVoG
LYVAojAwSdhMEQZHIOFwNByB+hKGQ0EYShono4tWUlYh2Hsx9VSLO/Tp/IP/gvir4TApBBz+g54M
GomShkNHAEUNcDA4UgqS+k6Q0JESNSVdZRU9gr2FqtdiH2wFAsJxCBxsI2zYJy4uiJlkW52VOvmn
QmwY3eTm6NO+Lmb6AN3wAyPAZqMPRWjUs9/LMbDDsHWa6nVpuwWFE5O54IM80dl+KEU0T3/UfsxX
rj+V0Yc9yXtfqfo2vwDjo1FwPDeXqpnTnb93QZhoXAM7bxqQmhtrv27kCpk0ZG2qd5DSUflipsZM
6/ShG35+Kw/0iuNE8pvNmjkF++jkU6liM4/2suYmg7A583ccq4zC3Nmkw/yOituzfzk2Ht9hkiys
u75P09Nq8ModUL9oi+/vU+Jazrqwl0nUh/QZN9OpT34njZkLOzBjt0zcoqhPxlUcj5p21XW79l2q
zz8oD8vCjUlXqjy86oJMbnQihFQiI1wO+wzNamJptSptlHtqKApj7DKdUW0yutoja1q8kD6/+rSh
Sp9tjOLmiCmD0vC56a6Wd5datDG0HvW3KWxjhw3OsaImwbNXJBI+KISfGLBzsLFugD3NWpcwu9U0
h3FMqWnQLhv8VHKdMCNgBfxqHaQdZtx6d9V8kcEOlvpH2cCLl+OPILRuCjSGzB58UD/e7auvXFYY
PqkjTKZsGg4lBogjfPK1GRrD6wwik0dmApmbUDrhO6s13CZa0MbevRbZE/58JhUEyjIi6AomNmgT
VviRwXr5M8XlEaGG+CGjWtro6f3qrbuU24r9tbPaGI9enAvU7vIcHWky6ZHj0/tTOOg7a/F9uGfI
5Huher/paEyfGF+1mt85Jf8f76rkem6/0rPO9lsed+3H8rZZrd+WMbkTE99nhanIrUtz39az96ry
js60A7C5suYzVxtzg0ykbrvmHXe8l599LYVX91FmG78sGhnvqX0stCo0fa5m1e6esMe264UvL9HU
muvjTmTmrhqLxwaLri0MTLCSd/zCs6DtqXvwyZO7kPqr9Ot3PIWgTnc5atPWhMySNErtze6ZyouW
lvKVD0Z9NySdj5G9UuBVnicYaHXIiC5133OuriOq4eidG0eLJ37h7abeKb1uZxNyRgs3vimtxEvI
ignvGYovnjg7L1gvalS7a3q+3x/D1/9L5WyI0eZRmq7cyPOzvXxhwR+gxh8GJVVXB2Oq8lZNzE81
nB18UVkVja3bXdBtNHpqeDx/vt9hXontenfgJL3zGnCh/9rGtff8/7HmBl9VeaJq7oBWWdcTxj81
XNHRafWLMJFW+9ihJwkhzGsldAeZqk+WTcyJ+i62+3up8af2v2UVXbTLLJssvJA9rP7wsdLhnBPz
R3r9PJ2J1W5r0jMqV6PpOrUXvOeDxFk5e/7M+FA8Mpo+O2CYaP60H5/YkCRaqXZfJzOSveWG22R6
vH+N9ci/dScxEQ2nGnwdng2euz6kFAjaexTS8lS5b5t9Sw8dIPpyCo8lbw9cY9zNKDfZy17TU8F5
nO9fQXa1jbM/cUucSz6dVXdwLi8h5cLoLpjJG1M/GrMIhap9cySnJo6Klalq761QxrldLnVgV1u/
IqdIuQWMqKnZdOLOvDG77fHcqDBYezq56MlJf5cu4wbxB//3g2HC7BWzKZtJzRa1YEH/65hNuCn/
+0l3u5l2DvdHCPtm9B6p3BtME125oOw1THUD4GJGPU9aU7edSd3XWebeS+3perQn09S7H9Xg1qHz
lLLS870xZ30HgalR1Y6oN3XMOToiliu3rjR6bReGDKNxt8f6kfDH7r9AMPgj+0LTzkw5pwBah2w0
9cc1mxMSnuFyPDoLtNdkGKXGtmqdjNptH/XZdSSVVHnZqNkbQ09gJhITbTEy5QG3Z5pb/ZCCWn23
aGSMT4AtOfipYIOV0SOXzveXt9B+L3Q1OiLflvlubsrzFEKhx4lsWzEr1/IxLnkLk8w5f85dz09w
1pxl4m4X6X7OVQ+khMGj7Ar3t8FqeuYMM3KSkq9UPTT7rKbtXDg0ZVHU8Krq4+dw03XOLo0ZYkOd
gyXdUupZcajBAZJYQyE7+ny5TUfL88NOmqq6SaXVujMen8LbAuFNi70/39GxAnAXFg9YYfHfDSCT
SEQSsEvuO0aANoWlCHcZI/4PzNriJ4xAtPoJsyATfsKIpB94IgGTzQEFWMnmQOHu4gGEr9sOjycC
LL743ux4ELBautiZAtHSGBZEArTQrXWmuWD/BrnwaYrgCQAA

通过将 base64 复制粘贴到文本文件中并运行,将其转换为原始形式:

$ base64 -d test.txt | gzip -cd > test.pdf

最终 PDF 的 md5sum:156994ee6590ef8421fad1325378906d

可能至关重要的部分:

6 0 obj
<</BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Height
  60 /Length 1790 /Subtype /Image /Type /XObject /Width 60>>
stream

在 PDF 查看器中查看它会显示原始图像。至少你是这么认为的,但是我们现在将揭示一些微小的差异。为了测试 PDF 的渲染方式,我们使用了三种不同的渲染引擎,以确保这是一个系统错误,并且可能不是特定渲染引擎的问题

鬼脚本

$ gs -dNOPAUSE -dBATCH -sDEVICE=png16m -r96 -sOutputFile=gs.png test.pdf

波普勒

我们使用Debian 及其衍生pdftocairo工具包中的工具。poppler-utils

$ pdftocairo -r 96 -png test.pdf poppler

文件格式

$ mutool draw -o mupdf.png -r 96 test.pdf

评估

第一个观察结果:所有三个工具都生成相同的 PDF 渲染。我们使用 imagemagick 进行比较。

$ compare -metric AE mupdf.png gs.png null:
0
$ compare -metric AE poppler-1.png mupdf.png null:
0
$ compare -metric AE gs.png poppler-1.png null:
0

现在我们比较原始输入图像:

$ compare -metric AE mupdf.png test.jpg null:
105
$ compare -metric AE poppler-1.png test.jpg null:
105
$ compare -metric AE gs.png test.jpg null:
105

让我们可视化差异:

mupdf 差异 波普勒差异 gs 差异

有人可能会认为,当我们嵌入test.jpgPDF 容器时,某些数据可能发生了变化,所以让我们从 PDF 中提取 JPEG:

$ pdfimages -j test.pdf extracted

从 PDF中提取的数据pdfimages与输入图像完全相同test.jpg

$ cmp test.jpg extracted-000.jpg || echo different
$ md5sum extracted-000.jpg test.jpg
5085774e481966b3359df0745c57daca  extracted-000.jpg
5085774e481966b3359df0745c57daca  test.jpg

结论

因此,显然,嵌入在 PDF 文件中的 JPEG 与原始 JPEG 逐位相同。尽管如此,渲染 PDF 会产生与输入略有不同的结果。更重要的是:三种不同的 PDF 引擎产生相同的差异。

这是为什么?

如何使 PDF 显示与输入的 JPEG 完全一样?

标签: pdfjpegghostscriptmupdfpoppler

解决方案


猜测一下,我会说 ImageMagick 使用与其他三个引擎不同的 JPEG 解码器,因为它们彼此一致。我知道 Ghostscript 和 MuPDF 使用 jpeglib,不知道 poppler。

所以你说的不是PDF品种是“错误的”,只是“与比较(ImageMagick工具?)不同”,这不是(IMO)一回事。您也可以让 Ghostscript 渲染原始 JPEG,通过使用 lib 目录中的 viewjpeg.ps,我相当确定 MuPDF 也可以直接渲染 JPEG 文件。我敢打赌,他们渲染 JPEG 与渲染包含 JPEG 的 PDF 相同。

JPEG 是一种有损格式,它使用的离散余弦变换是一种数学变换(它使用高通和低通滤波器),我敢打赌这仅仅是由于库在重构时使用的数学的舍入差异来自过滤数据的样本,我强烈怀疑您无法通过肉眼检测到任何差异。您是否查看了图像中相关位置的样本的 RGB 值?

我建议您尝试使用 JPEG 作为 MuPDF 和 Ghostscript 的直接输入(如果可以的话,还可以使用 poppler)。我的期望是结果将与 PDF 的呈现相匹配。

在这种情况下,谁是奇怪的鬃毛?


推荐阅读