Я продолжил и повторил эксперимент, чтобы посмотреть, смогу ли я понять, что происходит.
Процедура
Я сгенерировал случайное RGB-изображение размером 256 на 256 пикселей, используя фильтр «Solid Noise» в GIMP («Фильтры»> «Рендеринг> Облака> Solid Noise ...») с настройками по умолчанию (показано ниже):
И результат:
Затем я сохранил изображение в формате JPEG, используя настройки по умолчанию:
Затем я перенес изображение в Windows и открыл его с помощью средства просмотра фотографий Windows, щелкнув правой кнопкой мыши изображение в проводнике и выбрав в меню « Просмотр» . Затем я повернул изображение с помощью кнопок внизу и сохранил изображение, перейдя к следующему изображению с помощью клавиш со стрелками.
Для каждого из приведенных ниже тестов я начал с копии исходного изображения и повернул (щелкнул по кнопке поворота) соответствующее количество раз перед сохранением. Вот остальные размеры ( ls -l -r
):
size in bytes last-modified date
VVVVV VVVVV
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:24 original.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:30 cw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:30 cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:31 cw-cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:29 ccw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:29 ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:29 ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 ccw-ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 ccw-ccw-ccw-ccw-ccw.jpg
Немедленные наблюдения
- Windows Photo Viewer (WPV) значительно увеличивает размер; величина увеличения в этом тесте примерно в четыре раза!
- Все новые изображения увеличиваются примерно до одинакового размера, но они не идентичны.
- WPV не перекодирует и даже не повторно сохраняет изображение, когда оно поворачивается на 360 градусов. (Отметка времени 11:27 - это время, когда файлы были впервые скопированы.)
Использование cmp -l
файлов, которые должны иметь идентичный контент, позволяет нам увидеть, где файлы отличаются.
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg ccw-ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 60 66
robert@unity ../jpeg-rotate-test % cmp -l cw-cw.jpg ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 62 64
robert@unity ..jpeg-rotate-test % cmp -l ccw.jpg cw-cw-cw.jpg
2223 62 63
2224 71 60
2226 64 60
2227 61 64
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg cw-cw-cw-cw-cw.jpg
2221 60 61
2223 63 61
2224 60 66
2226 60 61
2227 60 61
robert@unity ../jpeg-rotate-test % cmp -l ccw.jpg ccw-ccw-ccw-ccw-ccw.jpg
2223 62 63
2224 71 60
2226 64 65
2227 61 64
Эти файлы отличаются только четырьмя байтами (на самом деле это временная метка), что означает, что WPV каждый раз делает одно и то же; теперь нам нужно только выяснить, что это такое.
Подробные наблюдения
Для этого я использовал JPEGsnoop, чтобы увидеть, что именно было на изображениях.
Поскольку результаты довольно длинные, я привел их в качестве сути . Вот краткое изложение различий:
GIMP использует только APP0
(JFIF) и COM
(комментарий) сегмент для метаданных. WPV оставляет APP0
сегмент нетронутым, но, как ни странно, добавляет к комментарию нулевой байт (так что он завершается нулем).
WPV добавляет два APP1
сегмента, которые являются метаданными Exif и XMP. Эти сегменты составляют 4286 и 12726 байт соответственно. Вместе они составляют почти все увеличение размера файла.
GIMP создает прогрессивный JPEG, а WPV - базовый (не прогрессивный) JPEG. По этой причине изображение GIMP имеет несколько сегментов сканирования, а изображение WPV - только один. По моему опыту, прогрессивное изображение иногда немного меньше.
GIMP использовал 1 × 1 цветовой подвыборки, в то время как WPV использовал 2 × 2 подвыборки. Это наводит меня на мысль, что WPV не использует «истинное» вращение без потерь, если только оно каким-то образом не способно обнаружить это черно-белое изображение.
Чтобы решить эти проблемы, я провел второй тест.
Процедура
Я выполнил шаги, аналогичные первому тесту. Я создал случайное изображение RGB 256 × 256, используя фильтр шума RGB (Фильтры> Нос> Нос RGB ...) со следующими настройками:
Вот результат:
Я экспортировал файл в формате JPEG с использованием следующих настроек:
Прогрессивный режим отключен, но для субсэмплинга по-прежнему установлено значение 4: 4: 4 (другое название для субсэмплинга 1 × 1). Качество увеличено до 98.
Я скопировал изображение и повернул копию по часовой стрелке; затем скопировали повернутую версию и повернули эту копию против часовой стрелки, чтобы мы могли напрямую сравнить качество между оригинальной и обработанной копией WPV.
Полученные результаты
-rwxrwx--- 1 root vboxsf 159774 Nov 8 16:21 original-random.jpg
-rwxrwx--- 1 root vboxsf 222404 Nov 8 16:24 cw-random.jpg
-rwxrwx--- 1 root vboxsf 222467 Nov 8 16:24 cw-ccw-random.jpg
Хотя это увеличение меньше в относительном выражении (около 40%), абсолютное увеличение еще больше - около 62 кБ. Это говорит о том, что WMV использует менее эффективную кодировку.
Я буду использовать ImageMagick для сравнения двух изображений:
robert@unity ../jpeg-rotate-test % compare -verbose -metric AE original-random.jpg cw-ccw-random.jpg null:
original-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 160KB 0.000u 0:00.009
cw-ccw-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 222KB 0.010u 0:00.010
Image: original-random.jpg
Channel distortion: AE
red: 0
green: 0
blue: 0
all: 0
original-random.jpg=> JPEG 256x256 256x256+0+0 8-bit sRGB 0.050u 0:00.020
Есть ноль пикселей разные между оригиналом и копией повернутой. Таким образом, даже если WPV не использует «истинное» вращение без потерь, оно работает достаточно хорошо. Я подозреваю, что знаю, что происходит, и, чтобы объяснить, я немного углублюсь в математику сжатия JPEG.
Алгоритм сжатия JPEG разбивает изображение на блоки 8 × 8 пикселей. Каждый из этих блоков затем подвергается дискретному косинусному преобразованию (DCT) . Результирующие коэффициенты DCT описывают блок как сумму волн различной частоты. Затем алгоритм «выбрасывает» в высокочастотные волны некоторую информацию, соответствующую шуму и очень мелким деталям. Процесс декодирования переворачивает DCT, складывая сохраненные волны вместе, чтобы вернуть блок.
Можно вращать «волны» DCT, фактически не отменяя и не возвращая преобразование (в основном вы превращаете все горизонтальные волны в вертикальные волны и наоборот). Я думаю, что в WPV происходит то, что изображение фактически декодируется, поворачивается, а затем перекодируется. Во время процесса перекодирования, поскольку размер нашего изображения кратен 8 в обоих измерениях, каждый из новых блоков соответствует одному из исходных блоков. Важно отметить, что поскольку каждый блок не имеет высокочастотных компонентов, алгоритм не отбрасывает никакой информации и находит именно те компоненты DCT, которые имел бы «истинный» поворот без потерь.
Наконец, я еще раз посмотрю на компоненты файлов JPEG. Результаты снова связаны между собой . Сравнивая два:
Образ WPV содержит дополнительные 4286 + 2 байта метаданных Exif, 1 дополнительный байт в комментарии и 12 726 + 2 байта метаданных XMP. Это всего 17 017 байтов дополнительных метаданных. Для чего используются все эти данные? Я заглянул в файл с моим верным шестнадцатеричным редактором и копией соответствующих стандартов:
Метаданные Exif структурированы как изображения в формате TIFF, которые содержат несколько тегов (здесь намного сложнее, но я пропущу это сразу). Большинство байтов в сегменте Exif содержатся в двух идентичных тегах с номером тега EA1C
(59 932 десятичных). Этот номер тега нигде не задокументирован. Оба тега содержат 2060 байтов типа «неопределенный», которые являются нулевыми байтами, кроме первых шести ( 1C EA 00 00 00 08
). Я понятия не имею, что это за теги, почему их два, и почему они должны быть размером 2 КБ каждый.
Метаданные XMP на самом деле представляют собой весь встроенный XML-документ с пространством имен и длинными UUID, который просто содержит строку версии WPV (которая уже была в метаданных Exif). Тем не менее, это только около 400 байтов. Остальная часть сегмента - 122 повторения 100 пробелов, сопровождаемых новой строкой . Это более 12 000 байтов полностью потраченного впустую пространства.
Как и в предыдущем тесте, и GIMP, и WPV используют одни и те же таблицы квантования DCT. Это означает, что они должны вычислять точно такие же коэффициенты DCT, поэтому изображения точно такие же. Я не уверен, что WPV просто использует те же таблицы квантования или копирует таблицы из входных данных.
В отличие от предыдущего теста, на этот раз WPV использует субсэмплирование 1 × 1, поэтому он может фактически обнаружить, что это цветное изображение (или, по крайней мере, что более высокие выборки необходимы для перекодирования изображения без потерь).
GIMP и WPV используют разные таблицы Хаффмана (часть этапа энтропийного кодирования). Таблицы для WPV больше на 279 байтов и в одном случае содержат в 7 раз больше кодов.
Глядя на статистику JPEGsnoop, мы видим, что некоторые из этих кодов используются редко. Например, в ID: 1, Class: AC
таблице из 119 определенных 16-битных кодов фактически используются только 23. В целом, фактический сегмент сканирования в версии WPV на 28,5% больше.
Резюме
WPV, возможно, не делает «настоящих» вращений без потерь, но вращения кажутся практически без потерь.
Дополнительный размер частично обусловлен фиксированным количеством добавленных метаданных, а частично - менее эффективным энтропийным кодированием.
Информация о версии:
ОС (Linux) ( uname -a
):
Linux unity 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u1 (2016-09-03) x86_64 GNU/Linux
ОС (Windows):
GIMP (Linux): 2.8.14 (из пакета gimp
, версии 2.8.14-1+deb8u1
)
Окно просмотра фотографий (в соответствии с метаданными изображения):
Microsoft Windows Photo Viewer 10.0.10586.0