Есть много способов сделать «патологический» файл JPEG / JFIF необычно большого размера.
На крайнем конце спектра нет ограничений по размеру, поскольку стандарт не ограничивает некоторые типы маркеров, появляющихся более одного раза - например, файл JFIF, заполненный многими ГБ маркеров DRI (определить интервал перезапуска) и затем MCU 8x8 пикселей в конце, технически действителен.
Если мы ограничимся «нормальным» использованием маркера, мы найдем верхний предел следующим образом:
Некоторый фон -
JPEG кодирует пиксели в виде MCU (группы) из блоков пикселей 8x8 (блоков DCT), по одному блоку DCT для каждого компонента (Y, Cb, Cr).
Чтобы получить лучшее сжатие (и наименьший размер), используется схема подвыборки цветности 4: 2: 0, где 75% информации о цветности опущено. Чтобы получить наилучшее качество (и самый большой размер), файл имеет 2/3 цветности, 1/3 яркости.
Символы битового потока Хаффмана используются для кодирования компонентов DCT, из которых до 65 на блок DCT (64 AC + 1 DC).
Символы Хаффмана могут находиться в диапазоне от 1 до 16 бит и выбираются кодером как можно меньшего размера; Однако можно указать длину символа.
Окончательное кодирование битового потока Хаффмана должно быть выполнено так, чтобы маркеры могли быть однозначно идентифицированы. Т.е. любое вхождение байта 0xff на выходе должно быть заменено двумя байтами - 0xff, 0x00.
Используя всю эту информацию, мы можем создать патологический, но действительный файл JPEG, который libjpeg (наиболее распространенная реализация декодера JPEG) с удовольствием декодирует.
Во-первых, нам нужны максимально длинные символы Хаффмана. На первый взгляд, определение символа Хаффмана с максимальной длиной (16 бит) из всех 1 будет занимать большую часть пробела, однако libjpeg отказывается обрабатывать символ Хаффмана, который является всеми 1, это, похоже, не исключается стандартом, так как это по-прежнему уникальный символ, так как размер уже известен как 16 бит в отличие от других символов переменной длины, и действительно некоторые декодеры могут его обрабатывать (JPEGSnoop).
Итак, мы определяем таблицу Хаффмана, которая устанавливает последние два символа следующим образом:
11111111_1111110 -> (0,0) (EOB - end of block value)
11111111_11111110 -> (0,15)
Такая таблица Хаффмана будет отображаться в файле JPEG как:
0xFF, 0xC4 ; DHT - define huffman table
0x00, 35 ; length
0x00 ; DC 0
1,1,1,1,1,1,1,1,1,1, 1, 1, 1, 1, 1, 1 ; histogram
1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,15 ; symbols
Теперь для кодирования блока DCT максимальной длины:
1 x DC of 31 bits ( 11111111 11111110 11111111 1111111 )
64 x AC of 31 bits ( 11111111 11111110 11111111 1111111 )
= 2015 bits
Поскольку MCU будет 3 блоками DCT (по одному для каждого компонента), размер MCU будет
6045 бит.
Большинство этих байтов будут 0xff, которые заменяются на 0xff, 0x00 в выходном потоке в соответствии со стандартом, чтобы отличать поток битов от допустимых маркеров.
Выполните это отображение, и полный DCT будет представлен 8 повторами следующего шаблона байтов:
0xff,0x00,0xfe,0xff,0x00,0xff,0x00
0xff,0x00,0xfd,0xff,0x00,0xff,0x00
0xff,0x00,0xfb,0xff,0x00,0xff,0x00
0xff,0x00,0xf7,0xff,0x00,0xff,0x00
0xff,0x00,0xef,0xff,0x00,0xff,0x00
0xff,0x00,0xdf,0xff,0x00,0xff,0x00
0xff,0x00,0xbf,0xff,0x00,0xff,0x00
0xff,0x00,0x7f,0xff,0x00
, что составляет 8 * 54 = 432 байта
Сложив все это, мы имеем:
3 компонента * (432 байта на компонент)
= 1296 байт на 8x8 пикселей
для сегментов SOI / DHT / DQT / SOS для настройки свойств изображения и таблиц Хаффмана требуется заголовок из 339 байт, для завершения изображения требуется 2-байтовый маркер EOI.
Поскольку изображение размером 200x200 будет размером 25x25 микроконтроллеров, у нас есть окончательный размер:
339 + (25 * 25 * 1296) + 2
= 810341 байт
, который работает чуть более 20,25 байта на пиксель, в 6 раз больше, чем несжатый BMP / TGA.