Глубокие погружения

Рождение PNG: как патентная война создала любимый формат сжатия без потерь

koboshiCo-founder
·13 мин чтения
Рождение PNG: как патентная война создала любимый формат сжатия без потерь
Кратко

PNG родился из патентного кризиса GIF в 1995 году. Построенный волонтёрами за четыре месяца, он заменил GIF для статичных изображений, комбинируя предварительную фильтрацию со сжатием DEFLATE. Это полная техническая история — от иска Unisys до файловой сигнатуры, которую можно прочитать в hex-редакторе.

Откройте файл PNG в hex-редакторе. Первые восемь байтов:

89 50 4E 47 0D 0A 1A 0A

Это файловая сигнатура PNG. Каждый PNG-декодер проверяет её. Первый байт 0x89 намеренно выбран высоким — он не даёт примитивным текстовым редакторам интерпретировать файл как ASCII. 50 4E 47 в ASCII читается как «PNG». 0D 0A — DOS-перевод строки, 1A — DOS-маркер конца файла, а 0A — Unix-перевод строки. Разработчики встроили эти символы перевода строки, чтобы FTP-передача в текстовом режиме немедленно повреждала файл, вынуждая пользователей передавать в бинарном режиме. Это была небольшая паранойя от разработчиков, которые только что наблюдали, как запатентованный формат превращается в юридическое оружие.

Сегодня PNG повсюду. Он лежит в основе скриншотов, UI-ассетов, диаграмм, логотипов и любых изображений, где пиксели должны оставаться точно такими же после многократных сохранений. Он старше Google, старше iPod и до сих пор остаётся выбором по умолчанию, когда важно сжатие без потерь. Но он никогда не задумывался как формат. Он начинался как временная заплатка, а не стандарт.

Иск, который вынудил создать новый формат

В январе 1995 года Unisys объявила, что будет защищать свой патент на компрессию LZW — U.S. Patent 4,558,302 — против разработчиков, использующих формат GIF. Патент покрывал алгоритм Лемпеля — Зива — Велча, метод сжатия в сердце каждого кодировщика и декодера GIF.

В 1995 году веб работал на GIF. Анимированные баннеры, прозрачные логотипы, фоновая плитка — GIF делал всё это. Затем Unisys потребовала роялти. Коммерческие вендоры ПО столкнулись с лицензионными сборами. Опенсорс-проекты оказались под угрозой существования. GNU Image Manipulation Program (GIMP) пострадал напрямую. Веб-сообщество было в ярости.

Что-то должно было заменить GIF для статичных картинок. Требования были чёткими: без патентов, лучшее сжатие, чем у GIF, поддержка true color и полноценный альфа-канал вместо примитивной одноцветной прозрачности GIF. Ещё формат должен был быть достаточно простым, чтобы один разработчик мог написать декодер за выходные.

4 апреля 1995 года Thomas Boutell опубликовал предложение в группе новостей Usenet comp.graphics. Он назвал его PBF — Portable Bitmap Format. Название не прижилось. В следующие месяцы сформировался мейлинг-лист. Среди участников — Tom Lane (лидер Independent JPEG Group), Lee Daniel Crocker, Alexander Lehmann и десятки других. К 1 октября 1996 года спецификация PNG была зафиксирована как RFC 2083. Весь процесс занял примерно восемнадцать месяцев от идеи до стандарта. Для сравнения: на JPEG ушло шесть лет.

Что существовало до PNG

В 1995 году выбор форматов изображений был ограничен, и у каждого были свои проблемы:

ФорматСжатиеГлубина цветаПрозрачностьПатентный рискТипичное применение
GIFLZWМакс. 256 цветов1 бит, 1 цветДа (LZW)Веб-графика, анимация
JPEGDCT + HuffmanTrue color 24 битаНетБазовый истёкФотографии
BMPНет или RLEДо 24 битНетНетОбои Windows
TIFFLZW, PackBits и др.До 48 битДаLZW опциональноПечать, сканирование
PCXRLEДо 24 битНетНетDOS-игры, ранний клипарт

GIF владел вебом, но был юридически токсичен. Его палитра в 256 цветов подходила для иконок и мультфильмов, но бесполезна для фото. Прозрачность была бинарной: пиксель либо полностью непрозрачный, либо полностью прозрачный. Никаких мягких краёв, никаких теней.

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

BMP и PCX были несжатыми или слабосжатыми. BMP 640 × 480 в 1995 году занимал 900 КБ. На модеме 28,8 кбит/с это больше четырёх минут загрузки.

TIFF был мощным и гибким, но его гибкость была проклятием. Файлы TIFF могли использовать дюжину схем сжатия, цветовых пространств и битовых глубин. Написать универсальный декодер TIFF — задача уровня дипломной работы, а не выходного хака.

PNG проектировался для узкой цели: заменить GIF для статичных изображений, превзойти его сжатие, добавить true color и настоящую прозрачность, и остаться навсегда бесплатным.

Как PNG на самом деле сжимает

Компрессия PNG — это двухступенчатый pipeline. Ни один из этапов сам по себе не является чем-то изощрённым. Вместе они удивительно эффективны.

Этап 1: Фильтрация

Перед любым сжатием PNG пропускает сырые пиксельные данные через фильтр. Фильтр ничего не сжимает. Он перестраивает данные так, чтобы следующий этап сжимал их лучше.

Изображение — это сетка байтов. На фотографии чистого неба соседние пиксели почти идентичны. Но сырой поток байтов всё равно хранит 120, 121, 120, 122, 119 для каждого канала. Разницы крошечные: +1, -1, +2, -3. Если хранить разности вместо абсолютных значений, полученные числа группируются вокруг нуля. Это группирование — то, что обожают алгоритмы сжатия.

PNG определяет пять типов фильтров на строку сканирования:

ФильтрНазваниеЧто делает
0НетХранит сырые байты
1SubХранит разницу от предыдущего пикселя
2UpХранит разницу от пикселя сверху
3AverageХранит разницу от среднего Sub и Up
4PaethХранит разницу от лучшего предиктора (Sub/Up/диагональ)

Кодировщик перебирает все пять фильтров для каждой строки сканирования и выбирает тот, который даёт меньший результат после Этапа 2. Поэтому кодер PNG может быть медленным: он выполняет перебор комбинаций фильтров в лоб. Но декодирование быстрое — тип фильтра хранится в файле, и декодер просто применяет обратную операцию.

Этап 2: DEFLATE

После фильтрации данные сжимаются алгоритмом DEFLATE, тем же, что используют gzip и ZIP. DEFLATE — это комбинация LZ77 (устранение дублирующихся строк в скользящем окне) и кодирования Хаффмана (префиксные коды переменной длины для частых символов).

Результат: типичный скриншот или UI-графика сжимается в 3–5 раз сильнее, чем несжатый BMP. Фотография, сжатая как PNG, обычно в 5–10 раз больше JPEG, но каждый пиксель восстановим. Сжатие без потерь по построению: никакие данные не отбрасываются, удаляются только избыточности.

Для справки: скриншот 1920 × 1080 в сыром RGB весит 6,2 МБ. Тот же скриншот в PNG обычно ужимается до 800 КБ – 1,5 МБ. Та же картинка в JPEG quality 90 — 300–500 КБ, но десять циклов пересохранения внесут заметные артефакты.

Возможности, которые имели значение

PNG был не просто клоном GIF, свободным от патентов. Он добавил функции, которые веб-дизайнеры просили с 1993 года.

True color: PNG поддерживает 24-битный RGB (16,7 миллионов цветов) и 48-битный deep color. Никаких ограничений палитры. Фотография в PNG может отображать каждый цвет, который способен различить человеческий глаз.

Альфа-канал: PNG поддерживает 8-битный альфа — 256 уровней прозрачности на пиксель. Тень может плавно растворяться от непрозрачной к прозрачной. Скруглённая кнопка может сглаживаться на любом фоне. GIF предлагал 1-битную прозрачность: один цвет либо полностью включён, либо полностью выключен. Визуальная разница — как день и ночь.

Adam7 interlacing: PNG может хранить пиксели в 7-проходном чересстрочном порядке. Браузер отрисовывает грубую превью, получив 1/64 файла, а затем постепенно уточняет её. В отличие от построчного чересстрочивания GIF, Adam7 распределяет детали по всему изображению уже с первого прохода. К третьему проходу картинка узнаваема. К седьмому — идеальна.

Гамма-коррекция: PNG хранит значение гаммы в метаданных. Изображение, созданное на Mac (гамма 1.8), отображается корректно на Windows-ПК (гамма 2.2) без ручной цветокоррекции. В 1990-х это была настоящая проблема, когда кросс-платформенная консистентность была редкостью.

CRC-чексуммы: каждый чанк PNG несёт CRC-32 чексумму. Повреждённые загрузки обнаруживаются немедленно вместо того, чтобы порождать наполовину отрисованное изображение.

Определение PNG по файловой сигнатуре

Не доверяйте расширению .png. Прочитайте первые восемь байтов и проверьте сигнатуру.

Точная раскладка байтов:

Bytes 0–7:   Сигнатура 89 50 4E 47 0D 0A 1A 0A
Bytes 8–11:  Длина чанка (big-endian uint32)
Bytes 12–15: Тип чанка: "IHDR" (заголовок изображения)
Bytes 16–19: Ширина изображения (big-endian uint32)
Bytes 20–23: Высота изображения (big-endian uint32)
Byte 24:     Глубина цвета
Byte 25:     Тип цвета
Byte 26:     Метод сжатия (всегда 0)
Byte 27:     Метод фильтрации (всегда 0)
Byte 28:     Метод чересстрочности (0 или 1)

TypeScript в браузере:

async function isPng(file: File): Promise<boolean> {
  const buffer = await file.slice(0, 8).arrayBuffer()
  const bytes = new Uint8Array(buffer)

  const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]
  return bytes.length === 8 && bytes.every((b, i) => b === signature[i])
}

Python

def is_png(path: str) -> bool:
    with open(path, "rb") as f:
        header = f.read(8)

    return header == b"\x89PNG\r\n\x1a\n"

Высокоуровневый вариант из стандартной библиотеки:

import imghdr

if imghdr.what("image.png") == "png":
    pass

Или с Pillow:

from PIL import Image

try:
    with Image.open("image.png") as img:
        is_png = img.format == "PNG"
except Exception:
    is_png = False

Go

func isPng(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	buf := make([]byte, 8)
	if _, err := f.Read(buf); err != nil {
		return false
	}

	return bytes.Equal(buf, []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a})
}

PHP

function isPng(string $path): bool {
    $header = file_get_contents($path, false, null, 0, 8);
    return $header === "\x89PNG\r\n\x1a\n";
}

С fileinfo:

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file('image.png');
// image/png

ImageMagick CLI

magick identify -verbose image.png | grep "Format:"
# Format: PNG (Portable Network Graphics)

Или просто:

file image.png
# image.png: PNG image data, 1200 x 675, 8-bit/color RGBA, non-interlaced

Ограничения PNG

PNG не идеален. Его архитектурные решения были компромиссами, и некоторые из них до сих пор обходятся нам дорого.

Нет встроенной анимации: Рабочая группа PNG явно отвергла анимацию. Они хотели полностью решить задачу статичных изображений, прежде чем добавлять сложность. Результат: анимированный GIF пережил ещё два десятилетия. APNG был стандартизован лишь в 2004 году, но поддержка в браузерах оставалась фрагментарной до конца 2010-х. Даже сегодня анимированных GIF в разы больше, чем APNG.

Большие размеры для фотографий: Фотография 12 МП в PNG обычно занимает 15–25 МБ. В JPEG quality 90 — 3–5 МБ. Сжатие без потерь PNG не может конкурировать с DCT-психовизуальным отбрасыванием JPEG. Для фотографий PNG — не тот инструмент.

Нет поддержки CMYK: PNG работает только в RGB. Полиграфические workflow, требующие CMYK-сепарации, вынуждены конвертировать PNG в TIFF или JPEG. Это было осознанное решение — разработчики ориентировались на экран, а не на печать — но оно ограничивает применимость PNG в профессиональной издательской деятельности.

Медленнее декодирование, чем JPEG: Декодирование PNG требует обратной фильтрации по строкам сканирования и распаковки DEFLATE. Декодирование JPEG хорошо параллелится и аппаратно ускорено. На мобильных устройствах крупный PNG может рендериться в 2–3 раза дольше, чем JPEG того же разрешения, задерживая Largest Contentful Paint.

Нет прогрессивного качества: В отличие от JPEG 2000 или JPEG XL, PNG не может выдать превью худшего качества из усечённого файла. Либо у вас есть весь файл, либо ничего. Adam7 interlacing помогает с грубой превью, но не уменьшает итоговый размер файла.

Почему PNG так и не заменил JPEG

Это самое распространённое заблуждение о форматах изображений. PNG и JPEG никогда не конкурировали за одну нишу.

JPEG — психовизуальный компрессор с потерями. Он отбрасывает данные, которые глаз вряд ли заметил. Он проектировался для фотографий непрерывного тона — изображений с плавными градиентами, мелкой текстурой и естественным освещением. В этой нише JPEG по-прежнему непобедим на кривой размер-качество спустя тридцать три года.

PNG — компрессор данных без потерь. Он сохраняет каждый бит. Он проектировался для изображений дискретного тона — скриншотов, UI-элементов, диаграмм, логотипов, текстовых оверлеев — где важны чёткие края и точные цвета. В этой нише PNG — стандарт.

Два формата разделили веб на отдельные территории:

СценарийПравильный форматПочему
ФотографииJPEG/AVIFСжатие с потерями в 5–10 раз меньше
СкриншотыPNG/WebPБез потерь сохраняет чёткость текста
Логотипы с прозрачностьюPNG/WebPАльфа-канал + края без потерь
UI-иконкиPNG/SVGМалый размер, точное соответствие цвета
Научные визуализации данныхPNGБез артефактов в градиентных легендах
Изображения для печатиTIFF/JPEG XLПоддержка CMYK, высокая битовая глубина

PNG никогда не ставил цель заменить JPEG. Он просто нашёл другое применение.

Где PNG находится сегодня

Web Almanac 2025 оценивает долю PNG примерно в 22% всех изображений, отдаваемых в вебе. Это меньше пиковых значений — WebP и AVIF отъедают долю — но PNG остаётся fallback-форматом, который любой браузер, любой редактор изображений и любая ОС откроет без колебаний.

WebP (Google, 2010) поддерживает как сжатие с потерями, так и без, плюс анимацию и прозрачность. Lossless WebP обычно на 20–30% меньше эквивалентного PNG. Поддержка в браузерах универсальна с 2020 года. Для новых проектов lossless WebP — прагматичная замена PNG в большинстве случаев.

AVIF (AOM, 2019) достигает ещё лучшего сжатия, но его lossless-режим медленнее кодируется и декодируется, чем PNG. AVIF также не полностью поддерживает некоторые продвинутые фичи PNG вроде 16-битных каналов и встроенной гамма-коррекции.

SVG владеет нишей иконок и логотипов для простой векторной графики, но растеризованная сложная графика по-прежнему нуждается в PNG.

Практическая реальность: PNG никуда не денется. Это безопасный дефолт, формат, в который вы экспортируете, когда нужно гарантировать, что получатель откроет файл. Это QWERTY среди форматов изображений — не оптимально, но универсально понятно.

Будущее PNG

PNG — завершённый стандарт. Спецификация не менялась существенно с 2003 года. Эта стабильность — фича, а не баг. PNG, созданный в 1997-м, откроется в любом современном браузере и отрисуется идентично.

Но экосистема вокруг PNG продолжает развиваться:

APNG набирает обороты. Safari поддерживает его с 2014 года. Chrome и Firefox последовали. Discord, Slack и Twitter рендерят APNG нативно. Для коротких UI-анимаций — спиннеров загрузки, реакционных эмодзи, индикаторов статуса — APNG вытесняет анимированный GIF меньшими файлами и лучшей цветопередачей.

Инструменты оптимизации PNG продолжают совершенствоваться. oxipng, pngcrush и zopfli могут срезать ещё 10–30% от размера PNG, перебирая в лучшие комбинации фильтров и параметров DEFLATE. Для высоконагруженных сайтов прогон каждого PNG через oxipng — стандартная практика.

PNG как контейнер: некоторые современные workflow встраивают ICC-профили, EXIF-метаданные и даже XMP-данные внутрь PNG-чанков. PNG стал лёгким архивным форматом — не таким богатым, как TIFF, но гораздо более портабельным.

Долгосрочный прогноз: PNG будет сосуществовать с WebP, AVIF и JPEG XL годами. Он занимает нишу, которую ни один другой формат не покрывает полностью: сжатие без потерь, свобода от патентов, универсальная поддержка, и достаточная простота, чтобы один разработчик мог написать декодер по спецификации за неделю. Такую комбинацию сложно вытеснить.

Итог

PNG появился, потому что разработчикам это надоело. Патентный иск угрожал открытому вебу, и группа разработчиков построила альтернативу в свободное время. Они не ставили цель создать тридцатилетний стандарт. Они ставили цель решить одну проблему: как разместить прозрачный логотип на веб-странице, не платя лицензионные отчисления.

Результат оказался гораздо лучше, чем кто-либо ожидал. PNG подарил вебу графику в true color, плавную прозрачность и устойчивость файлов к повреждениям. Он доказал, что открытые стандарты, созданные волонтёрами, могут превосходить проприетарные форматы при поддержке крупных компаний.

Он не самый компактный формат. Не самый быстрый в декодировании. С анимацией справляется плохо, а для фотографий бесполезен. Но когда вам нужно знать, что каждый сохранённый пиксель — это тот пиксель, который вы получите обратно — PNG по-прежнему остаётся инструментом, к которому вы обращаетесь.

Не каждое изображение с самого начала бывает PNG. Если у вас есть JPG, которым нужна прозрачность или редактирование без потерь, вы можете конвертировать их прямо в браузере — без установки лишних программ, ничего не покидает ваше устройство. JPG в PNG делает это локально. Когда в веб-проекте важен размер файла, JPG в WebP уменьшает вес, не трогая качество. А когда нужны иконки favicon, JPG в ICO превращает фотографии в ICO-файлы разных размеров.

Ещё посты в блоге