Pull to refresh

PNG — not GIF!

Reading time 4 min
Views 80K
Доброго времени суток!
Вам когда-нибудь хотелось узнать как устроены файлы PNG? Нет? А я все равно расскажу.
Формат PNG(Portable Network Graphics) был изобретен в 1995 году, чтобы стать заменой GIF, а уже в 1996, с выходом версии 1.0, он был рекомендован W3C, в качестве полноправного сетевого формата. На сегодняшний день PNG является одним из основных форматов веб-графики.

Под катом вы найдете общее описание строения PNG-файла, некоторое количество картинок-схем, препарирование в hex-редакторе, и, конечно, ссылку на спецификацию.

Общее строение


Структура PNG в самом общем виде представлена на следующем рисунке.

То есть файл состоит из подписи и некоторого количества блоков(чанков, chunks), каждый из которых несет в себе некоторую информацию (спасибо КО!). Но почему подпись нельзя считать одним из чанков? Давайте разберемся поподробнее.

Подпись файла

Подпись PNG-файла всегда одинакова, состоит из 8 байт, и представляет собой (в hex-записи)
89 50 4E 47 0D 0A 1A 0A

Что же это означает?
  • 89 — non-ASCII символ. Препятствует распознаванию PNG, как текстового файла, и наоборот.
  • 50 4E 47 — PNG в ASCII записи.
  • 0D 0A — CRLF (Carriage-return, Line-feed), DOS-style перевод строки.
  • 1A — останавливает вывод файла в DOS режиме (end-of-file), чтобы вам не вываливалось многокилобайтное изображение в текстовом виде.
  • 0A — LF, Unix-style перевод строки.


Chunks

Чанки — это блоки данных, из которых состоит файл. Каждый чанк состоит из 4 секций.

Разберем эти секции по порядку.

Длина

Ну, с длиной вроде все ясно. Просто числовое значение длины блока данных.

Тип (имя)

С типом немного поинтересней. Тип представляет собой 4 чувствительных к регистру ASCII-символа. Регистры символов (пятый бит в числовой записи символа) в имени чанка различаются неспроста — это флаги, которые сообщают декодеру некоторую дополнительную информацию.
  • Регистр первого символа определяет является ли данный чанк критическим(верхний регистр) или вспомогательным(нижний регистр). Критические чанки должны распознаваться каждым декодером. Если декодер встречает критический чанк, тип которого не может распознать, он обязан завершить выполнение с ошибкой.
  • Регистр второго символа задает «публичность»(верхний регистр) или «приватность»(нижний регистр) чанка. «Публичные» чанки — официальные, задокументированные, распознаваемые большинством декодеров. Но если вдруг вам для каких-то своих нужд понадобится кодировать специфическую информацию, то просто в имени чанка сделайте второй символ маленьким.
  • Регистр третьего символа оставлен для будущих свершений. Предполагается, что он будет использоваться для дифференциации различных версий стандарта. Для версий 1.0 и 1.1 третий символ должен быть большим. Если он (внезапно!) оказался маленьким, все нынешние декодеры должны поступать с чанком, так же как и с любым другим не распознанным (то есть выходить с ошибкой если чанк критический, или пропускать в противном случае).
  • Регистр же четвертого символа означает возможность копирования данного чанка редакторами, которые не могут его распознать. Если регистр нижний, чанк может быть скопирован, вне зависимости от степени модификации файла, иначе (верхний регистр) он копируется только в случае, когда при модификации не были затронуты никакие критические чанки.

Для лучшего понимания, давайте разберем флаги на примере чанка, содержащего текст.


Ниже приведен список типов чанков с краткими пояснениями.
Критические чанки
  • IHDR — заголовок файла, содержит основную информацию о изображении. Обязан быть первым чанком.
  • PLTE — палитра, список цветов.
  • IDAT — содержит, собственно, изображение. Рисунок можно разбить на несколько IDAT чанков, для потоковой передачи. В каждом файле должен быть хотя бы один IDAT чанк.
  • IEND — завершающий чанк, обязан быть последним в файле.


Вспомогательные чанки
  • bKGD — этот чанк задает основной фоновый цвет.
  • cHRM используется для задания CIE 1931 цветового пространства.
  • gAMA — определяет гамму.
  • hIST — в этом чанке может храниться гистограмма или общее содержание каждого цвета в изображении.
  • iCCP — цветовой профиль ICC
  • iTXt — содержит текст в UTF-8, возможно сжатый, с необязательной языковой меткой. iTXt чанк с ключевым словом 'XML:com.adobe.xmp' может содержать Extensible Metadata Platform (XMP).
  • pHYs — содержит предполагаемый размер пикселя и/или отношение сторон изображения.
  • sBIT (significant bits) — определяет «цветовую точность» (color-accuracy) изображения (черно-белое, полный цвет, черно-белое с прозрачностью и т.д.), для более простого декодирования.
  • sPLT — предлагает палитру для использования, если полный спектр цветов недоступен.
  • sRGB — свидетельствует о использовании стандартной sRGB схемы.
  • sTER — индикатор стереоскопических изображений.
  • tEXt — может содержать текст в ISO/IEC 8859-1 формате, с одной name=value парой для каждого чанка.
  • tIME — хранит дату последнего изменения изображения.
  • tRNS — содержит информацию о прозрачности.
  • zTXt — сжатый текст, с теми же ограничениям, что и tEXt.

Более подробную информацию можно найти в спецификации.

CRC

Контрольная сумма CRC-32. Кстати на днях был топик о ее подсчете в Windows.

Минимальный PNG


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


IHDR

Блок данных в IHDR содержит следующие поля:
  • Ширина, 4 байта
  • Высота, 4 байта
  • Битовая глубина (bit depth), определяет количество бит на каждый сэмпл(не пиксель), 1 байт
  • Тип цвета, состоит из 3 флагов 1 (используется палитра), 2 (используется цвет, не монохромное изображение), and 4 (присутствует альфа-канал), 1 байт
  • Метод сжатия. На данный момент доступно только значение 0 — сжатие по алгоритму deflate. Если значение отлично от 0, чанк считается нераспознанным, и декодер рапортует об ошибке. 1 байт
  • Метод фильтрации. Так же, как и в случае сжатия, на данный момент может быть только нулем. 1 байт
  • Interlace(переплетение) метод. Определяет порядок передачи данных. На данный момент доступно 2 значения: 0 (no interlace) и 1 (Adam7 interlace). 1 байт

Adam7 interlacing прекрасно демонстрирует картинка из википедии (да-да, GIF в статье про PNG):
image

IEND

Сигнализирует о конце файла, блок данных этого чанка не содержит ничего.

IDAT

Содержит данные, закодированные, в соответствии с полем метода сжатия в заголовке. Алгоритм декодирования выходит за рамки данной статьи (однако если будут желающие, может появиться в следующей), но в довольно хорошо (и по-русски) описан здесь.

Таким образом, простейший PNG-файл (на примере ) выглядит следующим образом.


Заключение


При написании данной статьи я ставил своей задачей дать читателю общие знания о строении PNG-файла, для более глубокого понимания рекомендуется читать спецификации.

Топик на хабре про строение JPEG: habrahabr.ru/blogs/algorithm/102521
Топик на хабре про строение GIF: habrahabr.ru/blogs/algorithm/127083

Спасибо за внимание, буду рад любой критике!
Tags:
Hubs:
+183
Comments 78
Comments Comments 78

Articles