JPEG-трюк «regressive»: разработчик упаковал видео в один файл-картинку
Прогрессивный JPEG устроен так, что данные изображения разбиты на несколько «сканов» (scans): сначала передаётся низкочастотная информация (грубое приближение картинки), затем всё более детальные уточнения. Каждый скан явно указывает свой спектральный диапазон, то есть какие именно коэффициенты дискретного косинусного преобразования (DCT) он заполняет, от базового DC-коэффициента (общая яркость и цвет блока) до более детальных AC-коэффициентов.
Автор блога заметил: раз каждый скан сам объявляет, какую часть данных он затрагивает, ничто не мешает более позднему скану полностью перезаписать данные, уже отрисованные предыдущим. Экспериментально это подтвердилось: если склеить несколько независимых изображений одинакового разрешения в один файл (вырезав из всех, кроме первого, служебные маркеры начала/конца изображения), браузер при медленной загрузке будет поочерёдно показывать то одну картинку, то другую, файл во время скачивания «переключается» между кадрами.
Проблема в том, что большинство декодеров прекращают отрисовку после ограниченного числа сканов, судя по всему, это защита от атак наподобие zip-бомбы (файла, который при распаковке разрастается до огромных размеров). Это ограничивает трюк примерно девятью кадрами, недостаточно для полноценной анимации.
Чтобы уместить больше кадров, автор попробовал сжать каждый кадр до одного скана, как в обычном базовом (не прогрессивном) JPEG. Но формат прогрессивного JPEG запрещает сканам одновременно нести DC- и AC-данные, а декодер базового формата останавливается после самого первого скана. Поскольку AC-данные по спецификации обязаны идти после DC, минимальный «прогрессивный» скан может содержать только DC-компоненту. Так как дискретное косинусное преобразование работает блоками 16×16 пикселей, изображение из одних DC-сканов получается не сплошным цветом, а уменьшенной в 16 раз копией оригинала, то есть миниатюрой, а не пустым полем.
Используя только DC-сканы (без AC-уточнений), автор добился отображения около 90 кадров в Chrome; другие браузеры, по его наблюдению, оказались терпеливее и справляются с ещё большим числом сканов. Такой подход также избавил от «призрачных» артефактов наложения, которые возникали в первой, наивной версии трюка, они появлялись из-за того, что AC-сканы по замыслу формата должны лишь уточнять уже существующие данные, а не заменять их целиком.
Поскольку файл с одними DC-сканами, полностью стандартный, валидный JPEG, для его создания не нужны никакие сторонние инструменты: достаточно штатной утилиты jpegtran с явно заданным списком сканов. Собранные таким способом «видео-JPEG» автор показал в нескольких формах: обычное видео в HTML на одних лишь тегах
Автор прямо пишет: практического применения у техники нет, разве что нестандартные рикроллы (розыгрыш с внезапной подменой контента ссылкой на известный клип) и прочее шуточное троллинг-использование. Никакого способа задать тайминг кадров формат не предусматривает, скорость смены кадров целиком зависит от скорости сети при загрузке файла.
Ключевые факты
- Прогрессивный JPEG хранит изображение в виде нескольких «сканов»: от грубого низкочастотного приближения до полной детализации, каждый скан явно указывает свой диапазон DCT-коэффициентов
- Автор показал, что склейка нескольких изображений в один файл заставляет декодер при медленной загрузке поочерёдно отрисовывать разные кадры вместо одного уточняющегося изображения
- Большинство декодеров ограничивают число обрабатываемых сканов (защита от zip-бомб), что по умолчанию режет трюк примерно до 9 кадров
- Используя только DC-сканы (без AC-уточнений) через утилиту jpegtran, автору удалось добиться отображения около 90 кадров в Chrome и ещё больше в других браузерах
- Автор прямо признаёт: практического применения у техники нет, кроме нестандартных рикроллов и троллинга, тайминга кадров формат не предусматривает
Почему это важно
Материал, не про новый продукт или угрозу, а про элегантный разбор малоизвестной особенности формата JPEG: возможности переопределять уже отрисованные данные более поздними сканами. Это пример качественного реверс-инжиниринга формата данных, который многие считают «давно изученным вдоль и поперёк», и тем не менее в нём находится неочевидный трюк. Публикация набрала 356 очков и 31 комментарий на Hacker News, то есть вызвала заметный интерес технического сообщества именно как инженерная головоломка.
Кому это важно
В первую очередь, разработчикам, работающим с форматами изображений, авторам браузерных движков и декодеров JPEG, а также всем, кто интересуется низкоуровневым устройством распространённых форматов данных. Материал полезен как учебный пример: как читать спецификацию буквально и находить в ней недокументированные комбинации возможностей.
Как это применить
Автор описывает пошаговый рецепт: склеить несколько JPEG одинакового разрешения, убрав служебные маркеры начала/конца изображения у всех кадров, кроме первого; чтобы обойти ограничение декодеров на число сканов, сжать каждый кадр до одного DC-скана штатной утилитой jpegtran с явно заданным списком сканов (вида «DC only scan: 0,1,2:0-0,0,0»). Автор выложил код (merge.c) и рабочие демонстрации, HTML-видео на одних тегах
Можно ли доверять
Автор, независимый разработчик, ведущий технический блог (maurycyz.com), подробно документирует каждый шаг эксперимента вплоть до байтовой структуры заголовков JPEG-сканов, публикует исходный код инструмента для склейки файлов и живые демонстрации, которые можно проверить самостоятельно. Материал разошёлся на Hacker News и набрал существенное обсуждение, это указывает на то, что техническое сообщество сочло разбор корректным.
Риски и подводные камни
Сам автор честно предупреждает: практического применения у техники нет, единственное реалистичное использование это розыгрыши (нестандартные рикроллы) и троллинг. Формат не даёт управлять таймингом кадров: скорость «анимации» целиком зависит от скорости сети при загрузке, воспроизвести её предсказуемо нельзя. Демонстрация из ~90 кадров работает не во всех декодерах одинаково: разные браузеры по-разному ограничивают число обрабатываемых сканов, а интерактивная веб-страница, по признанию автора, пока работает «немного криво».
«Помимо нестандартных рикроллов и прочего троллинга, практического применения у этого нет»
— автор блога maurycyz.com