Почему JPEG, встроенный в PDF, отображается немного иначе, чем оригинал?

Контейнер PDF позволяет встроить в документ полный файл JPEG (включая заголовок и все остальное). Но даже если JPEG, хранящийся в PDF-файле, побитно идентичен исходному файлу, он будет отображаться немного иначе, чем исходный JPEG. Я хочу знать, почему это так, и как сделать так, чтобы JPEG в PDF отображал точно так же, как исходный файл JPEG. Вот как воспроизвести мои выводы:

Настраивать

Возьмите это тестовое изображение (md5sum: 5085774e481966b3359df0745c57daca)

тестовое изображение

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

И поместите его в контейнер pdf. Вы можете использовать инструмент img2pdf

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

или вы можете использовать это представление PDF-файла в формате gzip base64:

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

Превратите его в исходную форму, скопировав base64 в текстовый файл и запустив:

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

md5 сумма окончательного PDF: 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

поплер

Мы используем инструмент pdftocairo из пакета poppler-utils в Debian и производных.

$ pdftocairo -r 96 -png test.pdf poppler

mupdf

$ 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 diff  poppler diff gs diff

Можно подумать, что некоторые данные, вероятно, были изменены, когда мы встраивали test.jpg в контейнер PDF, поэтому давайте извлечем JPEG из PDF:

$ pdfimages -j test.pdf extracted

Данные, которые pdfimages извлекаются из PDF-файла, в точности идентичны входному изображению test.jpg:

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

Вывод

Таким образом, очевидно, что JPEG, встроенный в файл PDF, побитно совпадает с исходным JPEG. Тем не менее, рендеринг PDF дает несколько иной результат, чем ввод. Более того: три разных движка PDF дают одинаковую разницу.

Это почему?

Как сделать так, чтобы PDF-файл отображался точно так же, как входной JPEG?


person josch    schedule 18.08.2018    source источник
comment
Попробуйте расшифровать оригинал с помощью djpeg -dct int, djpeg -dct fast и djpeg -dct float   -  person    schedule 18.08.2018
comment
Процесс декодирования jpeg имеет некоторую свободу выбора некоторых значений. Возьмем, к примеру, проект Google Knusperli, который использует это и пытается декодировать файлы jpeg в менее блочные Посмотреть.   -  person Robert    schedule 18.08.2018
comment
@ WumpusQ.Wumbley Ваш комментарий подтолкнул меня в правильном направлении. К сожалению, djpeg не смог точно воспроизвести декодирование gs / poppler / mupdf, но jpegtopnm смог это сделать. Вариант -dct int сработал. Как ни странно, djpeg и jpegtopnm дают разные результаты с этой опцией ...   -  person josch    schedule 19.08.2018
comment
@Robert Конечно, я знал, что преобразование растрового изображения в JPEG происходит с потерями, но как-то наивно я думал, что после завершения кодирования есть только один способ правильно интерпретировать эти данные. Спасибо, что научили меня чему-то новому! :)   -  person josch    schedule 19.08.2018


Ответы (2)


Предположительно, я бы сказал, что ImageMagick использует другой декодер JPEG для трех других движков, поскольку они согласны друг с другом. Я знаю, что Ghostscript и MuPDF используют jpeglib, про попплер не знаю.

Итак, то, что вы говорите, не в том, что разновидности PDF «неправильны», просто «не то же самое, что сравнить (инструмент ImageMagick?)», Что (IMO) не одно и то же. Вы также можете заставить Ghostscript визуализировать исходный JPEG, используя viewjpeg.ps в каталоге lib, я уверен, что MuPDF также может напрямую визуализировать файл JPEG. Могу поспорить, что они визуализируют JPEG так же, как они делают PDF-файл, содержащий JPEG.

JPEG - это формат с потерями, а дискретное косинусное преобразование, которое он использует, является математическим преобразованием (он использует фильтр высоких и низких частот), я готов поспорить, что это просто из-за разницы в округлении в математике, используемой библиотеками при воссоздании Я сильно подозреваю, что вы не сможете обнаружить какие-либо различия на глаз, если брать образцы отфильтрованных данных. Вы смотрели значения RGB образца в соответствующих местах на изображениях?

Я предлагаю вам попробовать использовать JPEG в качестве прямого ввода в MuPDF и Ghostscript (и poppler, если он это сделает). Я ожидаю, что результат будет соответствовать рендерингу PDF.

В таком случае, кто будет лишним?

person KenS    schedule 18.08.2018
comment
Проблема была действительно в декодере. Просто случайно (я думаю) ghostscript, poppler и mupdf выбирают один и тот же способ декодирования данных JPEG. Чтобы воспроизвести их способ декодирования JPEG, можно использовать: jpegtopnm -dct int. Как ни странно, djpeg -dct int не даст тот же результат. - person josch; 19.08.2018

Оба являются цветовым пространством sRGB. Но одно отличие состоит в том, что ваш test.jpg не имеет цветового профиля. Но test.pdf имеет профиль sRGB.icc, по крайней мере, при преобразовании с Imagemagick как convert test.jpg test.pdf. Добавление цветового профиля обычно может изменить просмотр изображений, даже если данные идентичны, но просмотр может зависеть от зрителя и от того, предполагает ли он профиль sRGB, даже если его нет, или игнорирует профиль. Используя Imagemagick identify -verbose, я вижу

test.jpg

 Properties:
    date:create: 2018-08-18T09:57:16-07:00
    date:modify: 2018-08-18T09:57:16-07:00
    jpeg:colorspace: 2
    jpeg:sampling-factor: 1x1,1x1,1x1
    signature: fa0b78710e2c79f1cc852e0ae805393ea96d1f51769beb9d1729ec330da71303
  Artifacts:
    filename: test.jpg
    verbose: true
  Tainted: False
  Filesize: 1790B
  Number pixels: 3600
  User time: 0.000u
  Elapsed time: 0:01.000
  Version: ImageMagick 6.9.10-10 Q16 x86_64 2018-08-14 https://www.imagemagick.org


test.pdf

 Properties:
    date:create: 2018-08-18T09:59:37-07:00
    date:modify: 2018-08-18T09:59:37-07:00
    icc:copyright: Copyright Artifex Software 2011
    icc:description: Artifex Software sRGB ICC Profile
    pdf:HiResBoundingBox: 60x60+0+0
    pdf:Version: PDF-1.3  1 0 obj << 
    signature: b3783659c15300ffb14e4da501db28afcc0e0b0060286effa74823327a24abd6
  Profiles:
    Profile-icc: 2576 bytes
  Artifacts:
    filename: test.pdf
    verbose: true
  Tainted: False
  Filesize: 8415B
  Number pixels: 3600
  Pixels per second: 360000B
  User time: 0.000u
  Elapsed time: 0:01.009
  Version: ImageMagick 6.9.10-10 Q16 x86_64 2018-08-14 https://www.imagemagick.org


Попробуйте добавить профиль sRGB.icc в файл test.jpg перед преобразованием в PDF. Посмотрим, поможет ли это.

person fmw42    schedule 18.08.2018
comment
Нет, встраивание профиля ICC в JPEG (например, с помощью convert для преобразования PDF в JPEG) не решает проблему. Он только меняет пиксель, который теперь отличается. - person josch; 18.08.2018
comment
Это могут быть разные профили sRGB.icc. Как вы оцениваете различия - какой зритель? Если я прочитал вашу заметку выше, сравнение Imagemagick не покажет разницы. Значит, данные пикселей должны быть одинаковыми. Различаются только метаданные, обычно это профили. Какую версию Imagemagick и какую платформу вы используете? Что произойдет при использовании профиля convert test.jpg -profile sRGB.icc test.pdf, если вы извлечете jpg из файла pdf, используя что-то вроде pdfimages? - person fmw42; 19.08.2018
comment
Я выделил два jpg и pdf без добавления профиля, используя Mac Preview и Imagemagick 6.9.10.10, используя анимацию, и я не вижу никакой визуальной разницы. - person fmw42; 19.08.2018
comment
Думаю, вы неправильно читаете мой вопрос в нескольких частях. Я не рассматриваю различия, поскольку они крошечные (см. Раздел «Визуализируем различия»). Я не конвертирую JPEG в PDF с помощью imagemagick, потому что это обязательно изменит информацию, потому что imagemagick перекодирует изображение JPEG. Подводя итог моему вопросу: я встраиваю JPEG в контейнер PDF (он бит за бит идентичен), но они отображаются по-разному (как видно из сравнения их с imagemagick). - person josch; 19.08.2018
comment
Извините за недопонимание. Поскольку вы не используете Imagemagick и проблема не в просмотре, мне нечего предложить. Извинения. - person fmw42; 19.08.2018
comment
Не беспокойся! Спасибо, что нашли время написать ответ на мой вопрос! :) - person josch; 19.08.2018
comment
Может быть, это ваш инструмент img2pdf? Вы пробовали другие инструменты? - person fmw42; 19.08.2018
comment
Возможно. Но это было не так. См. Принятый ответ и мой комментарий к нему. - person josch; 20.08.2018
comment
После небольшого исследования выясняется, что действительно виноваты разные варианты декодера. Если я сравниваю с compare -define jpeg:dct-method=islow, тогда изображения сравниваются как равные. Таким образом, imagemagick, похоже, выбирает другой метод dct, чем три движка рендеринга PDF, и это было причиной различий, которые я видел. - person josch; 20.08.2018