PNG - это тоже просто
Материал из b4wiki
Содержание |
Введение
Однажды пользователи попросили добавить в прибор возможность получения скриншотов с экрана Беркут-ET. Поскольку к тому моменту доступ по HTTP-протоколу к прибору уже был реализован, сразу же родилась идея генерировать картинку с копией экрана по запросу какой-нибудь страницы. Но тут же возник вопрос -- в каком формате? JPEG -- кажется, что сложный; GIF -- документирован вроде, коммерческий; PNG -- открытый и хорошо документирован.
Так или иначе, выбран был PNG ;). Он очень хорошо документирован и, как впоследствии оказалось, очень прост. Ведь генерация образа экрана должна делаться на процессоре с тактовой частотой 8 МГц и 40 килобайтами оперативной памяти! Под память программ у этого процессора имеется всего 256 КБайт и из них уже двести заняты.
Речь в статье пойдет об устройстве PNG и алгоритмах, которые обеспечивают упаковку изображения в контейнеры. Рассмотрение будет делаться на примере примитивного PNG, содержащего образ экрана 320х240 точек с глубиной цвета 3 бита.
Подробную информацию о PNG можно найти в [1]
Структура файла PNG
Файл PNG состоит из блоков данных, называющихся chunk'ами. chunk в общем случае имеет переменную длину. Чтобы отличить один от другого, в каждом chunk'е есть поле типа.
Минимальный PNG-файл должен содержать как минимум сигнатуру и три chunk'a [3]:
- IHDR -- заголовок файла
- IDAT -- данные, собственно картинка
- IEND -- конец файла
Chunk состоит из четырёх полей:
- Length -- длина поля данных chunk'а (4 байта)
- Type -- поле типа (4 байта)
- Data -- поле данных. может быть нулевой длины
- CRC -- поле с проверочным кодом для полей Type, Data
PNG File signature
Она содержит всегда 8 байт:
* (decimal) 137 80 78 71 13 10 26 10 * (hexadecimal) 89 50 4e 47 0d 0a 1a 0a * (ASCII C notation) \211 P N G \r \n \032 \n
Сигнатура не является стандартным chunk'ом.
IHDR chunk
Этот chunk содержит основную информацию о картинке: ширина и высоту в пикселях, количество битов на сэмпл (не на пиксель) или количество бит, определяющее размер палитры и т.п. Более подробно этот chunk рассмотрен в [1].
Для нашей картинки параметры следующие:
- ширина = 320
- высота = 240
- размер палитры минимальный - 16, поэтому количество бит = 4
- color type = 3, то есть используем палитру и каждый пиксель описывается индексом из этой палитры
- метод компрессии = 0. означает, что используется deflate/inflate алгоритм [4]
IEND chunk
Тут по названию всё ясно. Это chunk сигнализирует о конце PNG-файла [1,2].
IDAT chunk
Этот chunk содержит данные с графической информацией. Эти данные запакованы в zlib формат [5]. Данные, запакованные в zlib формат, запакованы в формат DEFLATE, который в общем случае предусматривает сжатие информации. Но один из вариантов DEFLATE позволяет хранить данные в контейнерах DEFLATE без сжатия [4, 3.2.4]. А это - то, что надо для нашей задачи, поскольку при размере 320х240 пикселей и 3х битах на цвет размер файла не принципиален.
Графическая информация, хранящаяся в IDAT chunk'ах представляет собой набор строк (scanlines, [2]). В формате PNG для более эффективного сжатия предусмотрена фильтрация строк. Для указания используемого фильтра перед данными строки должен следовать один байт. Содержимое означает, какой фильтр использовуется. В самой простой реализации фильтр можно не использовать (ведь и сжатия никакого не планируется). В этом случае этот байт должен быть равен 0.
Как вариант, одна строка графической информации может упаковываться в один IDAT chunk. Так, например, сделано в Беркут-ЕТ: файл содержит 240 IDAT chunk'ов.
Алгоритмы упаковки данных без сжатия в zlib и deflate форматы очень просты для реализации во встраиваемых системах, поскольку они сводятся к простому формированию заголовков и подсчёту контрольной суммы adler32 [6].
Структура PNG в картинках
На рисунке изображена последовательность chunk'ов, образующих файл PNG. Как уже говорилось, в chunk'и IDAT "укладываются" 240 строк. Перед каждой строкой следует байт, указывающий тип фильтра (значение 0).
На рисунке используются следующие обозначения:
- CH -- chunk header, содержит длину поля данных и тип chunk'а IDAT
- ZH -- zlib header,
- DH -- DEFLATE header, содержит 5 байт, см. ниже
- CC -- контрольная сумма crc32 для chunk'a
- ZA -- контрольная сумма adler32 для данных, упакованных DEFLATE алгоритмом. [6]
Важно, что CC считается для каждого chunk'a, а ZA считается для всего вектора данных, упакованного алгоритмом DEFLATE.
zlib header
Он содержит 2 байта: 0x78, 0x01 [5, ch 2.2]
0х78 означает, что для компрессии данных используется DEFLATE с окном до 32 КБайт.
0х01 содержит проверочный бит для первого байта и определяет уровень сжатия "без сжатия" ;)
DEFLATE header
DEFLATE header содержит 5 байт. Первый байт содержит информацию о типе компрессии и о последнем блоке. Если используется тип компрессии "no compression" [4], то первый и последующие блоки должны иметь первый байт равным 0x00, а последний блок -- 0x01.
Ещё четыре байта используются для указания длины блока (первые 2 байта) и проверочного поля для длины блока (вторые 2 байта). Другими cловами -- LEN и NLEN, где NLEN = 0xffff - LEN [4, ch. 3.2.4].
png check
PNG check -- это утилита, упрощающая жизнь программисту при отладке кода, создающего PNG. Она проверяет правильность формирования PNG и сообщает, если что-то не так. Например, утилита может отследить, что не сходится контрольная сумма или отсутствует какой-нибудь chunk, и т.п.
исходный код
Поэкспериметировать над созданием PNG-картинок можно, используя следующий исходный код:
- tinyz -- примитивная замена zlib, алгоритмы DEFLATE & zlib
- checksum -- реализация алгоритмов crc32, adler32
- png -- функции для создания chunk'ов PNG. тестовая программа, создающая чёрную картинку с вертикальной красной чертой
Программы находятся в http://metrotek.spb.ru/files/sources/png
Результат выполнения тестовой программы (png/pngtest.c):
Анализ этого файла утилитой pngcheck даёт такой результат:
$ pngcheck /tmp/png/example.png
OK: /tmp/png/example.png (320x240, 8-bit colormap, non-interlaced, -5.7%).
Cсылки
- http://libpng.org/pub/png/spec/1.2/PNG-Contents.html -- PNG specification
- http://www.libpng.org/pub/png/book/toc.html -- PNG Definitive Guide
- http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.4 The Simplest PNG
- http://www.faqs.org/rfcs/rfc1951.html -- RFC1951 - DEFLATE Compressed Data Format Specification
- http://www.faqs.org/rfcs/rfc1950.html -- RFC1950 - ZLIB Compressed Data Format Specification
- ITU-T Recommendation X.224, Annex D, "Checksum Algorithms," November, 1993, pp. 144, 145. (Available from gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073.
- www.debian.org: здесь можно найти пакет pngcheck

