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 в картинках

Pngintrls.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): Pngtest.png

Анализ этого файла утилитой pngcheck даёт такой результат:

$ pngcheck /tmp/png/example.png

OK: /tmp/png/example.png (320x240, 8-bit colormap, non-interlaced, -5.7%).

Cсылки

  1. http://libpng.org/pub/png/spec/1.2/PNG-Contents.html -- PNG specification
  2. http://www.libpng.org/pub/png/book/toc.html -- PNG Definitive Guide
  3. http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.4 The Simplest PNG
  4. http://www.faqs.org/rfcs/rfc1951.html -- RFC1951 - DEFLATE Compressed Data Format Specification
  5. http://www.faqs.org/rfcs/rfc1950.html -- RFC1950 - ZLIB Compressed Data Format Specification
  6. 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.
  7. www.debian.org: здесь можно найти пакет pngcheck
Личные инструменты
Пространства имён

Варианты
Действия
разработки
технологии
разное
Инструменты