Если изображение вращается без потерь, почему изменяется размер файла?

Я искал методы поворота изображения без потерь и наткнулся на этот вопрос, который объясняет это довольно хорошо:

Являются ли повороты «Windows Photo Viewer» без потерь?

Поэтому я создал JPEG 256×256 со случайными пикселями (облачный фильтр Photoshop), а затем повернул его с помощью Windows Picture Viewer. После вращения размер файла действительно увеличился, но только при первом вращении. При каждом последующем вращении размер файла оставался неизменным. Я знаю, что он вращается без потерь, потому что я поворачивал его несколько раз без заметной потери качества, тогда как изображение 257 × 257, повернутое 20 раз, стало с большими потерями.

Насколько увеличился размер файла в ваших тестах?
@JamesSnell Я знал, что должен был включить это. Тот, который я только что сделал, используя фильтр различий cloounds GIMP, изначально имел 14 583 байта, но после поворота он был изменен на 23 638 байт. Разница составляет более 9000 байт, что кажется большим количеством дополнительных данных, если мы говорим только о метаданных.
@JamesSnell Итак, я только что повторил тот же тест с изображением 512x512, и разница в файлах составляет 9 612 байт (было 9 055 с первым). Поскольку увеличенный размер файла не был пропорционален увеличению размеров, я думаю, можно с уверенностью сказать, что это действительно метаданные.
Это похоже на множество дополнительных метаданных. Я бы не торопился считать все эти дополнительные данные метаданными. Мне кажется, что разница в размере из-за метаданных должна быть почти постоянной (с точностью до нескольких байт для учета строкового представления некоторых чисел).
При предоставлении дополнительной информации, относящейся к вопросу, пожалуйста, отредактируйте вопрос, а не комментарии. Комментарии эфемерны и могут время от времени очищаться.
Что произойдет, если вы повернете изображение с помощью другого (лучшего) инструмента для обработки изображений? Черт, я не удивлюсь, если WPV сохранит исходные пиксели :-(
Было бы полезно загрузить исходную версию тестового изображения.
@CodesInChaos - набор файлов «до и после» позволит нам полностью ответить на вопрос. Но они должны быть предоставлены таким образом, чтобы не изменять их, а не обычный маршрут imgur и т. Д.
Не могло ли быть так, что Windows Picture Viewer пересохранил картинку с меньшей степенью сжатия?
Дело в том, что WPV повторно сжимает изображение при первом повороте, но он сжимает его таким образом, что, если размер кратен 8, последующие повороты можно выполнить, просто применяя преобразования байтов к сжатому потоку байтов, мой ответ правильно адресует это, даже если он отрицательный, у него есть полное объяснение (и на самом деле это единственный правильный ответ)
Как @DarioOO, но пытаюсь прояснить. Без потерь не означает равного или идемпотентного. Перекодируя jpg, можно было бы улучшить сжатие (компьютер с лучшим алгоритмом / памятью по сравнению с камерой), и это верно с вращением или без него. Без потерь просто означает, что несжатое изображение будет таким же, ничего об исходном (сжатом) изображении.
@GiacomoCatenazzi Теоретически вы правы, но на практике сжатие JPEG делает это почти невозможным. Поворот JPEG на 90 градусов без потерь выполняется точно без сжатия путем перестановки сжатых данных. Насколько я понимаю ваш комментарий, вы говорите, что всегда есть рекомпрессия, просто неразличимая, в то время как DarioOO говорит, что есть только начальная рекомпрессия в транспонируемый формат, и оттуда она транспонируется. Я считаю, что JPEG, выровненный с MCU, можно транспонировать из коробки. betterjpeg.com/lossless-rotation.htm
Библиотеки сжатия MS бедны и часто дают меньшее сжатие, чем другие движки, использующие «тот же самый» алгоритм.

Ответы (8)

Это, скорее всего, вызвано энтропийным кодированием , которое является последней стадией сжатия JPEG без потерь после квантования данных изображения для уменьшения его размера.

Когда изображение JPEG вращается без потерь, этот последний слой кодирования без потерь должен быть отменен, распакованные коэффициенты DCT перетасованы, а затем перемешанные коэффициенты необходимо снова закодировать энтропийно. Поскольку эффективность уровня энтропийного кодирования зависит от порядка коэффициентов DCT в каждом блоке, который будет меняться при повороте изображения, не следует удивляться тому, что повернутый файл изображения может быть на несколько процентов меньше или больше исходного.

Существует также несколько различных способов выполнения шага энтропийного кодирования, поэтому вполне возможно, что размер файла одного и того же изображения JPEG может различаться в зависимости от программного обеспечения, выполняющего кодирование. Некоторые из потенциальных различий между кодировщиками включают:

  • выбор арифметического кодирования (редкое, но потенциально более эффективное, ранее запатентованное) по сравнению с кодированием Хаффмана (более простое, стандартное);
  • выбор последовательного (каждый блок 8x8 пикселей кодируется по одному) против прогрессивного (низкочастотные компоненты всех блоков кодируются перед более высокочастотными компонентами, обычно немного более компактными) порядка кодирования;
  • выбор использования стандартных таблиц символов Хаффмана (быстрее, проще, может быть более эффективным для очень маленьких изображений) по сравнению с пользовательскими таблицами, оптимизированными для каждого изображения (обычно более эффективными для больших изображений, более медленными и более сложными для кодирования);
  • если используются пользовательские таблицы Хаффмана, разные кодировщики потенциально могут генерировать разные таблицы для одних и тех же данных изображения;
  • различные низкоуровневые детали самого процесса кодирования, такие как необходимость и время включения маркеров перезапуска в поток данных, также могут различаться между кодировщиками.

Кроме того, «файлы JPEG», с которыми обычно работают люди, на самом деле содержат данные изображения, сжатые в формате JPEG, упакованные в контейнер JFIF или Exif , который объединяет данные изображения с одним или несколькими блоками метаданных и вводит свой собственный набор осложнений. Даже если программное обеспечение, которое поворачивает изображение, на самом деле не вносит существенных изменений в метаданные JFIF/Exif, простое изменение порядка данных потенциально может повлиять на размер файла на несколько байтов.

В частности, метаданные JFIF/Exif могут содержать одну или несколько миниатюр полноразмерного изображения, и программное обеспечение, которое поворачивает изображения, действительно должно регенерировать (или также вращать без потерь!) миниатюры, чтобы они соответствовали новой ориентации полноразмерного изображения. размер изображения. Одно это может легко объяснить наблюдаемую разницу в размерах.

Для разницы в 9 КБ (60%), я предполагаю, что это миниатюры.
JPEG может быть слишком простым, чтобы это стоило делать кодировщикам, но видеокодировщики, такие как x264, могут фактически учитывать способность кодировщика ввода кодировать то, что они собираются вывести дальше, при принятии решений о компромиссе между скоростью и искажением. (т.е. решить, сколько битов может стоить каждая альтернатива, и сопоставить это с ошибкой с потерями). Это называется решетчатым квантованием. См. Примечания по реализации решетчатого квантования в H.264 от автора x264 (Лорен Мерритт); он начинает с довольно простого объяснения цели.
В любом случае, кодировщик JPEG мог выбрать коэффициенты DCT так, чтобы они хорошо сжимались с помощью энтропийного кодера, поэтому даже оптимальный компрессор не мог сделать повернутую версию такой маленькой. (Потому что размещение их в другом порядке, вероятно, ухудшит их сжатие.) Это почти наверняка будет небольшим эффектом для JPEG, поскольку каждый блок 8x8 кодируется отдельно (сброс состояния энтропийного кодера, AFAIK). (I-кадры в формате h.264 используют внутреннее предсказание, исходя из других блоков в том же кадре, что делает их меньше, чем JPEG при том же визуальном качестве.)

Я пошел дальше и повторил эксперимент, чтобы посмотреть, смогу ли я понять, что происходит.

Процедура

Я сгенерировал случайное RGB-изображение размером 256 на 256 пикселей, используя фильтр «Сплошной шум» в GIMP (Фильтры > Рендеринг > Облака > Сплошной шум...), используя настройки по умолчанию (показаны ниже):

введите описание изображения здесь

И результат:

введите описание изображения здесь

Затем я сохранил изображение в формате 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 , чтобы увидеть, что именно есть на изображениях.

Поскольку результаты довольно длинные, я связал их как gist . Вот краткое изложение различий:

  • 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 байтов типа «undefined», которые являются нулевыми байтами, за исключением первых шести ( 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. В целом, фактический сегмент сканирования на 28,5% больше в версии WPV.

Резюме

  • Возможно, 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
    
  • ОС (Виндовс):

    введите описание изображения здесь

  • GIMP (Linux): 2.8.14 (из пакета gimp, версия 2.8.14-1+deb8u1)

    введите описание изображения здесь

  • Окно просмотра фотографий (согласно метаданным изображения):

    Microsoft Windows Photo Viewer 10.0.10586.0
    

РЕДАКТИРОВАТЬ : этот ответ был опубликован до того, как я узнал, что размер файлов увеличился примерно на 9 КБ (9055 байт для изображения 256 × 256, 9612 КБ для изображения 512 × 512).

По всей вероятности, когда вы впервые повернули изображение, Windows Picture Viewer сделал одно (или оба) из следующих действий:

  1. Добавлен тег EXIF, которого не было в исходном изображении JPEG (возможно, тег Orientation);
  2. Изменена/добавлена ​​информация к уже существующему тегу (возможно, теги Processing Software или Image Software).

Это увеличило размер файла из-за дополнительного тега EXIF ​​(и/или дополнительных данных к существующим тегам).

Последующие ротации не увеличивали размер файла, потому что все теги и/или данные тегов, которые WPV добавила/изменила, уже были там. Изменилось только значение тега ориентации (и, возможно, также значения тега даты/времени).


РЕДАКТИРОВАТЬ : почти наверняка это объяснение не может учитывать около 9 КиБ дополнительных данных в файле. Кроме того, при отсутствии каких-либо других причин для увеличения размера это объяснение предполагает, что увеличение размера будет более или менее постоянным (по модулю некоторых различий в длине между строковыми представлениями числовых данных, возможно, в несколько байтов). Это явно не то, что здесь происходит, по крайней мере, не полное объяснение.

И тег EXIF ​​​​будет занимать 9 КБ? Что ж, это, по крайней мере, легко проверить - попросите OP удалить EXIF ​​​​или другие теги из повернутого изображения и посмотреть, как изменится размер файла.
@CarlWitthoft, 9 КБ - это новая информация. Редактирование, чтобы упомянуть об этом.

Без реверс-инжиниринга кодировщика/декодера jpeg невозможно сказать наверняка. На самом деле существует несколько стандартов jpeg, и, вопреки распространенному мнению, не все из них можно изменить без перекодирования.

Вполне возможно, что первое сохранение это перезапись с потерями в предпочитаемый формат jpeg, а последующие повороты — это простая настройка метаданных или операция непосредственно в таблице DCT (что возможно для некоторых схем кодирования).

Увеличение размера файла может также включать некоторые дополнительные метаданные, хотя 9k кажется большим, это возможно. Увеличение также может быть связано с добавлением миниатюры, которой могло не быть в выводе GIMP. Возможно, мы сможем получить больше информации непосредственно из файлов (до WPV и после).

В любом случае, пытаться работать с jpeg без потерь — на самом деле глупая затея, так как это полезно только с изображениями определенных размеров, не все декодеры и кодировщики идентичны, и для этого требуется, чтобы эти редакторы работали напрямую с содержимым jpeg, на которое вы не можете полагаться. случае ... То, что это происходит сейчас, не означает, что так будет и в будущем.

Лучше всего работать с форматом без потерь и полностью избежать боли.

Я совсем не уверен, что вращение данных jpeg должно в первую очередь вызывать перекодирование.
Зависит от того, программист ты или нет... Думаю, что нет. Вам нужно специально искать эту оптимизацию, чтобы внести это минимальное изменение, иначе операция сохранения начнется с несжатого растрового изображения.
Из связанного вопроса становится ясно, что Windows Photo Viewer вращает JPEG без потерь.
Но при каких обстоятельствах... Это та часть, которую мы не знаем.
@ Джеймс Я не программист низкого уровня, хотя я играю по телевизору :-). ОП предоставил ссылку на точное описание того, когда будет перекодирование, а когда нет. Из этого обсуждения я сделал вывод, что он вращался всего на $\frac{\pi}{2}$ . Я согласен с тем, что поворот под произвольным углом вызывает перекодирование и, если на то пошло, приведет к потере информации, если только изображение X на Y не встроено в область, по крайней мере, равную гипотенузе.
Дело не в том, что математически возможно. Однако речь идет о том, что на самом деле делает код. OP видит, что итерация 1 вызывает изменение размера файла, а последующие итерации - нет. Для этого есть причины, и я немного отредактирую, чтобы объяснить, что может происходить.
Причина вращения без потерь (это плохой термин; лучше было бы обратимым ) заключается в том, что размеры изображения кратны 8 или 16, что является минимальной сжимаемой единицей . Если JPEG не содержит частичных MCU, то его можно вращать/переворачивать без каких-либо изменений в блоках данных DCT. В этом случае нет никакого перекодирования, просто изменение матрицы индексов для этих блоков.
@scottbb - это относится только к определенным методам кодирования в спецификации jpeg. и он полагается на программное обеспечение, которое ищет эту оптимизацию. Все, что мы знаем, это (а) да, это возможно при определенных обстоятельствах и (б) что мы точно не знаем, что делает это приложение...
Мы почти уверены, что знаем , что WPV обратимо вращается для изображений с размерами, кратными 8/16. См. Комментарий @Tristan к ответу Мэтта Грума на вопрос, связанный с ОП. Тристан работал в команде WPV в Microsoft, и в основном подтверждает.
@scottbb - только для 2-го и последующих. Мы НЕ знаем, что происходит с первым, и это то, что мы пытаемся выяснить здесь.

Вращение JPEG без потерь возможно только без введения граничных артефактов, если размеры изображения кратны размеру блока (обычно[/всегда?] 8). См . справочную страницу jpegtran (извините, у меня нет хорошей канонической ссылки для нее; не стесняйтесь редактировать, если найдете ее) для получения подробной информации о том, что задействовано:

Преобразование транспонирования не имеет ограничений относительно
размеров изображения. Другие преобразования работают довольно странно, если размеры изображения не кратны размеру iMCU (обычно 8 или 16 пикселей), потому что они могут только преобразовывать полные блоки данных коэффициентов DCT желаемым образом.

Поведение jpegtran по умолчанию при преобразовании изображения нечетного размера
предназначено для сохранения точной обратимости и математической
согласованности набора преобразований. Как уже говорилось, транспонирование
может перевернуть всю область изображения. Горизонтальное зеркальное отображение оставляет любой частичный столбец iMCU на правом краю нетронутым, но может перевернуть все строки изображения. Точно так же вертикальное зеркальное отображение оставляет нетронутой любую частичную строку iMCU на нижнем краю, но может перевернуть все столбцы. Другие преобразования могут быть построены как последовательности операций транспонирования и переворачивания; для согласованности их действия с краевыми пикселями определяются как конечные результаты соответствующей последовательности транспонирования и отражения.

Для практического использования вы можете предпочесть отбросить все непреобразуемые
краевые пиксели, а не иметь странную полосу вдоль
правого и/или нижнего края преобразованного изображения. Для этого добавьте ключ -trim:

Я подозреваю, что Windows Photo Viewer избегает этой проблемы, выполняя декомпрессию и повторное сжатие чрезвычайно высокого качества, чтобы имитировать поведение без потерь, когда размеры изображения не кратны 8, а не фактически выполняя вращение без потерь. Хорошая утилита просто делала бы фактически без потерь, с артефактами и всем остальным, или отбрасывала бы несколько пикселей, а не портила бы качество всего изображения (и увеличивала размер файла).

неактуально для изображения 256x256.
Я неправильно прочитал и подумал, что проблема связана с версией 257x257.

У меня нет определенного ответа, но есть несколько возможных теорий, почему это произошло. Некоторые типы файлов работают таким образом, что два разных кода для изображения этого типа файла не обязательно создают разные изображения. Например, тип файла PNG работает таким образом, потому что он допускает прозрачный фон, но изображение с прозрачным фоном и такое же изображение, за исключением того, что тот же фон белый, отображаются точно так же. Файл изображения считается сжатым, если он занимает менее 3 байт памяти на пиксель. Я считаю, что за исключением файлов с прозрачным фоном, никакие два файла PNG не создают одно и то же изображение. Когда вы когда-либо сохраняете изображение в формате PNG, оно преобразует его в код, который генерирует исходное изображение, и, за исключением очень необычных изображений, таких как изображение, где каждый пиксель представляет собой случайный цвет всех 2 ^ 24 цветов, код будет занимать меньше памяти, чем 3 байта на пиксель, поэтому сохранение в формате PNG считается сжатием без потерь. С другой стороны, для экономии памяти код файла изображения JPEG может генерировать только определенные изображения. Вероятно, существует более одного типа файла JPEG, и я не знаю, обладает ли какой-либо из них свойством, согласно которому два разных изображения этого типа файла могут генерировать одно и то же изображение. Я предполагаю, что несколько раз вы просто поворачивали изображение, затем сохраняли его в формате JPEG и давали объяснение того, что произошло, исходя из предположения, что это то, что вы сделали, что я не знаю, верно ли это. Поворот, который вы сделали, не имеет потерь, если есть способ вернуть точно такой же код файла изображения, который у вас был до того, как вы его повернули и сохранили. Возможно, вы ошибаетесь в том, что действительно сделали вращение без потерь. Если бы это действительно было без потерь,

Причин этому несколько

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

Но почему вы поворачиваете jpeg 20 раз?

Если вы прочитали ссылку в исходном вопросе, по крайней мере, для Windows Picture Viewer , если размеры JPEG кратны 8, то повороты JPEGS в WPV являются преобразованиями без потерь. Простой способ проверить это — повернуть 4 раза (что приведет к той же ориентации, что и у оригинала) и выполнить простое попиксельное вычитание изображения.
@scottbb Это не обязательно проблема со средством просмотра изображений Windows. Все, что вращает формат с потерями, должно пересчитывать сжатие. поворот изображения, кратный 8, означает, что все умещается в 8-битных словах и может не сжиматься таким образом, чтобы добавлять артефакты. Это основано на том, как алгоритм работает и реализован в используемой программе.

Из-за того, как работает сжатие изображений . Любой формат, такой как PNG или JPG, в целом не сохраняет размер файла после поворота.

Для компрессора повернутое изображение — это просто другое изображение, из-за того, как работает эвристика сжатия , нет гарантии, что оно будет сжимать повернутое изображение так же .

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

  • Добавлены метаданные : программа по какой-то причине добавила кусок текста
  • Компрессор изменился: программа может просто пересохранить изображение как исходное, если в нем нет изменений, но если вы примените какое-либо изменение (даже 4 поворота на 90 градусов), она может решить повторно сжать изображение снова, используя свой собственный компрессор (программа больше не знает, что это все тот же образ).
  • В общем, один и тот же компрессор (libPNG или libJPG) дает очень разные результаты в разных реализациях, разных версиях одной и той же библиотеки и с разными параметрами сжатия (здесь также иногда имеет значение операционная система и компилятор).

Сжатие изображений работает путем сжатия изображений в фрагменты 4x4 или других размеров. В общем, компрессор видит повернутое изображение как другое изображение, однако, поскольку сжатый фрагмент пикселя представляет собой просто линейную декомпозицию, если фрагменты на изображении одинаковы, можно просто транспонировать/отразить матрицы линейной декомпозиции, эффективно сохраняя то же самое. качественный:

Обратите внимание, что это должно быть реализовано для каждой функции , и это также объясняет начальное увеличение размера => при первом вращении он просто пытается сжать изображение фрагментами, которые можно вращать:

  • Если это не так: качество изображения ухудшается
  • В случае успеха размер увеличивается только один раз, после чего каждое вращение сохраняет одинаковое качество.

  • Эта операция успешна только в том случае, если изображение состоит из равных частей. (размер изображения кратен размеру чанка).

Ответ scottbb неверен, и вы можете выполнить простой тест:

  • Откройте исходное изображение: сделайте скриншот
  • Поверните изображение 4 раза с помощью WPV: сделайте снимок экрана.
  • Сравните 2 скриншота

Вы увидите, что изображение изменилось (оно повторно сжимается при первом повороте). Однако это изменение ограничено по времени, теперь вы можете снова повернуть его без потери качества (если размер изображения кратен 8).

Чтобы напрямую ответить OP:

Я знаю, что он вращается без потерь

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

Речь идет о вращении без потерь, поэтому повторного сжатия избегают.
Я программирую графический редактор, поэтому знаю, что говорю, когда файл сохраняется => он сжимается. По крайней мере, в файл добавляется информация о «вращении».
Я знаю, что говорю, и даже реализовал компрессор изображений. Это возможно, если вы реализуете это только для вращения (это означает, что вы знаете, что вращение - это единственное изменение изображения), в общем случае это невозможно. Кажется, разработчики фоторедактора Windows проделали этот трюк.
ОП спросил не об общем случае, а именно об этом конкретном программном обеспечении и об одном конкретном случае, который это делает. Ваш ответ не является неправильным, он просто отвечает на вопрос, отличный от того, что задал ОП.
Нет отвечает. Прочтите еще раз. Я отредактировал это некоторое время назад.
Первые 3 предложения по-прежнему относятся к другому вопросу: «как работает сжатие изображений» - при вращении без потерь сжатия нет. "Компрессировать повернутое изображение" - опять компрессор не вызывается. "если сжатие без потерь" - сжатие с потерями. Вращение без потерь. Вот как далеко я готов зайти в этом аргументе. Я понимаю вашу точку зрения, я с ней согласен, но здесь она совершенно неуместна. Кстати, я тоже программист, и я в свое время занимался чтением и записью необработанных файлов.
Вы, кажется, принимаете это слишком близко к сердцу. ЭТО НЕ БЕЗ ПОТЕРЬ ВРАЩЕНИЕ: просто прочитайте небольшой эксперимент и сделайте это самостоятельно. Это в основном показывает, что ваш последний комментарий неверен. Uu Вы даже можете быть программистом, но я не верю, что вы когда-либо кодировали компрессор изображений (даже более простой)
Извините, тогда какой эксперимент я могу сделать, чтобы показать это? Потому что в связанном вопросе был проведен эксперимент. Я неправильно интерпретирую результаты?
Я создал изображение в Paint, повернул его 4 раза, и оно идентично, но размер все равно подскочил с 1,6 до 8,1 КБ. Двоичный diff показывает, что данные изображения остались нетронутыми, это просто огромный кусок метаданных в <?xpacketтегах.
Изображение PAint не является хорошим кандидатом. Я только что провел эксперимент с реальной фотографией. Вы использовали другое изображение? Извините, а какая у вас версия Windows?
Сделал скриншот, вставил в пейнт и обрезал до 128х128. Похоже, что один и тот же кусок основных данных повторяется, но в повернутой версии <?xpacketдобавлен огромный кусок почти пустого. У меня нет правильного двоичного diff, поэтому я не могу сказать. После того, как я загрузил оба на verexif.com, они вернулись идентичными друг другу, но не оригиналу. Но, как я уже сказал, я сравниваю их вручную в шестнадцатеричном редакторе, поэтому, вероятно, многое упустил. Windows 8.1
Если размеры JPEG делятся без остатка на 8 (или на 16 с подвыборкой), его можно поворачивать с шагом 90 градусов без потерь . Ключ в том, чтобы не декодировать его полностью в RGB, а работать напрямую с коэффициентами DCT. Это специализированная функция, которая не часто включается в обычный редактор изображений. См., например , en.wikipedia.org/wiki/Libjpeg#jpegtran . Если бы вы провели свой эксперимент со средством просмотра фотографий Windows , как указано в вопросе, вы бы увидели, что это действительно без потерь.