Как на самом деле работает сжатие JPEG
Наглядный разбор сжатия JPEG: DCT-преобразование, таблицы квантования и почему одни изображения сжимаются лучше других.

JPEG — это таракан среди форматов файлов. Его стандартизировали в 1992 году, он старше веб-браузера и пережил все попытки его заменить. WebP, AVIF, HEIC — все они сжимают лучше, но JPEG остаётся самым распространённым форматом изображений в интернете. Отчасти это инерция. Но отчасти причина в том, что конвейер сжатия JPEG действительно гениален: это образцовая прикладная обработка сигналов, которую стоит понять, даже если вы никогда не будете писать энкодер.
Большинство разработчиков воспринимают JPEG как чёрный ящик: кладёшь картинку, получаешь файл поменьше, двигаешь ползунок качества, пока результат не покажется приемлемым. Но когда понимаешь, что происходит внутри, по-другому начинаешь смотреть на изображения, сжатие и компромиссы между размером файла и визуальным качеством.
Конвейер в общих чертах
Сжатие JPEG — это конвейер из пяти этапов, и каждый делает что-то умное. Фишка в том, что они работают в связке: каждый этап подготавливает следующий, чтобы тот работал эффективнее.
- Преобразование цветового пространства — из RGB в YCbCr (яркость отделяется от цвета)
- Субдискретизация цветности — уменьшение разрешения цветовых каналов
- Дискретное косинусное преобразование (DCT) — перевод пространственных данных в частотные
- Квантование — отбрасывание высокочастотных деталей (это и есть шаг с потерями)
- Энтропийное кодирование — сжатие квантованных данных без потерь
Первые два шага используют особенности человеческого зрения. Шаги 3 и 4 используют свойства естественных изображений. Пятый шаг — обычное сжатие данных. Каждый шаг по отдельности прост. Вся магия в последовательности.
Шаг 1: преобразование цветового пространства
Камера записывает изображение в RGB — каналы красного, зелёного и синего, по 8 бит на пиксель. Первым делом JPEG переводит это в YCbCr: один канал яркости (Y) и два цветоразностных канала (Cb и Cr). Это ещё не сжатие, данные не теряются. Это просто преобразование координат, как поворот осей.
Зачем это нужно? Глаз человека гораздо чувствительнее к яркости, чем к цвету. Вы легко различаете мельчайшие детали на чёрно-белой фотографии, а разрешающая способность цветового зрения заметно ниже. Отделив яркость от цвета, JPEG может обращаться с ними по-разному: сохранять детализацию яркости и агрессивно уменьшать детализацию цвета.
RGB to YCbCr conversion (simplified):
Y = 0.299R + 0.587G + 0.114B (luminance — brightness)
Cb = -0.169R - 0.331G + 0.500B (blue chrominance)
Cr = 0.500R - 0.419G - 0.081B (red chrominance)
Note: green dominates the luminance calculation because
human eyes have far more green-sensitive cone cells.
This isn't arbitrary — it matches the physiology.
Шаг 2: субдискретизация цветности
Здесь происходит первое по-настоящему существенное уменьшение данных. Поскольку человек не воспринимает цвет в полном пространственном разрешении, JPEG уменьшает разрешение каналов Cb и Cr, обычно вдвое по каждой оси. Это называется субдискретизацией 4:2:0. На каждые четыре пикселя яркости приходится один цветовой отсчёт.
Итог: объём сырых данных сокращается почти вдвое (вместо трёх каналов полного разрешения — один полный и два в четверть), при этом картинка выглядит практически так же, как оригинал. Попробуйте сами: возьмите любую фотографию, уменьшите разрешение цветовых каналов в 4 раза, и разницу будет трудно заметить. Мозг достраивает цветовые детали по информации о яркости.
Работает это не одинаково для всех изображений. Фотографии сжимаются отлично, потому что в естественных сценах плавные цветовые переходы. Но картинки с резкими цветовыми границами, например текст на цветном фоне, красный круг на белом или пиксель-арт, после субдискретизации показывают заметную цветовую кайму. Поэтому JPEG плохо подходит для текста: резкие цветовые края размываются.
Шаг 3: дискретное косинусное преобразование
Вот где JPEG становится по-настоящему интересным. Изображение делится на блоки 8×8 пикселей, и каждый блок переводится из пространственной области (значения яркости пикселей) в частотную (насколько сильно представлена каждая пространственная частота).
Представьте так: блок 8×8 пикселей можно описать как взвешенную сумму 64 базисных паттернов. Первый паттерн — однородный блок (среднее значение). Следующие добавляют горизонтальные и вертикальные градиенты. Паттерны с большими номерами добавляют всё более мелкие детали, то есть частые колебания яркости.
An 8x8 DCT block conceptually:
DC ──► Low frequency ──────────────► High frequency
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ AVG │ → │ → │ → │ → │ → │ → │ → │ Low freq
│ │ │ │ │ │ │ │ │ ↓
│ ↓ │ ↘ │ │ │ │ │ │ │
│ │ │ ↘ │ │ │ │ │ │
│ │ │ │ ↘ │ │ │ │ │
│ │ │ │ │ ↘ │ │ │ │
│ │ │ │ │ │ ↘ │ │ │
│ │ │ │ │ │ │ ↘ │ │
│ │ │ │ │ │ │ │ FINE │ High freq
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
Top-left = low frequency (smooth gradients)
Bottom-right = high frequency (sharp edges, fine detail)
Natural images: most energy concentrated in top-left
Text/line art: significant energy in bottom-right
Само DCT — обратимое преобразование без потерь: по 64 коэффициентам можно точно восстановить исходный блок 8×8. Но ключевое свойство в другом: в естественных изображениях (фотографиях, градиентах, органических текстурах) основная энергия сосредоточена в низкочастотных коэффициентах. Высокочастотные коэффициенты, отвечающие за мелкие детали, как правило, малы. Именно на этом держится следующий шаг.
Почему 8×8? Это компромисс. Блоки побольше (16×16, 32×32) лучше концентрируют энергию, но их дороже считать, а при низком качестве они дают заметные артефакты блочности. Блоки поменьше (4×4) уменьшают блочность, но энергию концентрируют хуже. Размер 8×8 оказался удачным балансом, который держится уже больше 30 лет.
Шаг 4: квантование — где умирают данные
Это шаг с потерями. Каждый коэффициент DCT делится на соответствующее значение из таблицы квантования и округляется до целого. Большие делители (для высокочастотных коэффициентов) превращают мелкие значения в нули. Эти нули исчезают навсегда, именно здесь безвозвратно теряется информация.
Example quantization (quality ~50):
DCT coefficient: 42.7 Quantization divisor: 16 Result: round(42.7/16) = 3
DCT coefficient: 8.3 Quantization divisor: 40 Result: round(8.3/40) = 0
DCT coefficient: -2.1 Quantization divisor: 99 Result: round(-2.1/99) = 0
The quality slider in your image editor controls the quantization table.
Quality 100: divisors close to 1 (almost no rounding, huge file)
Quality 75: moderate divisors (good balance, typical web use)
Quality 50: large divisors (noticeable artifacts, small file)
Quality 10: very large divisors (blocky mess, tiny file)
Таблица квантования — самый важный фактор качества JPEG. Стандарт задаёт таблицу по умолчанию, но энкодер может использовать любую. Современные энкодеры вроде MozJPEG применяют оптимизированные таблицы, которые выжимают больше качества из меньших файлов: делители подобраны под человеческую перцептивную чувствительность, то есть действуют агрессивнее там, где глаз менее чувствителен к частотам.
После квантования типичный блок 8×8 при среднем качестве содержит примерно 6–10 ненулевых коэффициентов из 64. Остальные равны нулю. Это сильное сокращение числа ненулевых значений и делает последний шаг сжатия эффективным.
Шаг 5: энтропийное кодирование
Последний шаг — сжатие квантованных коэффициентов без потерь. JPEG использует комбинацию кодирования длин серий (RLE) и кодирования Хаффмана. Коэффициенты считываются из блока 8×8 зигзагообразно, от DC-коэффициента (верхний левый угол) по возрастанию частот. Так все завершающие нули группируются вместе, и RLE обрабатывает их эффективно: вместо «0, 0, 0, 0, 0, 0, ..., 0» записывается что-то вроде «сорок семь нулей».
Затем кодирование Хаффмана присваивает более частым значениям короткие битовые последовательности, а редким длинные. Поскольку большинство ненулевых коэффициентов — маленькие целые (1, -1, 2, -2), им достаются очень короткие коды. В итоге квантованный блок 8×8, который начинался с 64 значений, обычно сжимается до 20–40 байт в зависимости от содержимого изображения и настройки качества.
Почему одни изображения сжимаются лучше других
Понимание конвейера объясняет поведение при сжатии, которое без него кажется загадочным.
- Фотографии сжимаются хорошо, потому что у них плавные цветовые градиенты (субдискретизация цветности работает отлично) и основная энергия лежит в низкочастотных коэффициентах DCT (квантование обнуляет многие коэффициенты без заметного эффекта).
- Текст и линейные рисунки сжимаются плохо, потому что резкие края дают значительные высокочастотные коэффициенты, которые нельзя обнулить без видимых артефактов. Границы блоков 8×8 становятся заметны в виде «звона» вокруг краёв текста.
- Шум убивает сжатие, потому что шум матрицы сенсора — это высокочастотные случайные данные. Каждый зашумлённый пиксель добавляет ненулевые высокочастотные коэффициенты, которые сопротивляются квантованию. Шумное фото при качестве 80 может быть в 3–5 раз больше чистого снимка той же сцены при том же качестве.
- Градиенты почти бесплатны, потому что плавный градиент на блоке 8×8 описывается всего 2–3 коэффициентами DCT. Остальные равны нулю даже без квантования.
- Повторное сохранение ухудшает качество, потому что при каждом сохранении квантование применяется снова, и ошибки округления накапливаются. Сохранение JPEG 10 раз с качеством 75 заметно хуже, чем однократное сохранение с качеством 75. Поэтому редактировать стоит всегда из исходного файла.
Ползунок качества работает нелинейно
Многие разработчики воспринимают ползунок качества JPEG как линейный компромисс: качество 50 вдвое хуже качества 100 и даёт вдвое меньший файл. Ни то, ни другое не соответствует действительности.
Качество 100 — не «без потерь». Квантование всё равно применяется, просто с маленькими делителями. Файл получается огромным (часто больше PNG), а визуально он неотличим от качества 95. Для фотографий качество 95 неотличимо от 90. Перцептивная разница между 85 и 75 больше, чем между 100 и 85. Ниже 50 артефакты становятся серьёзными, а выигрыш в размере замедляется.
Золотая середина для веб-изображений обычно находится в диапазоне 75–85. Ниже 75 артефакты заметны при обычном размере просмотра. Выше 85 файл заметно растёт, а визуальный выигрыш почти нулевой. Значение по умолчанию 75 у MozJPEG выбрано удачно: оно попадает в точку перегиба кривой «качество — размер» для большинства фотографий.
Современные энкодеры JPEG умнее, чем кажется
Стандарт JPEG описывает формат декодирования, а не энкодер. Поэтому реализации энкодеров могут сильно различаться по эффективности сжатия, оставаясь совместимыми со спецификацией. MozJPEG, разработанный Mozilla, за счёт нескольких приёмов даёт файлы на 5–15% меньше, чем libjpeg, при том же визуальном качестве.
- Trellis-квантование — вместо независимого округления каждого коэффициента DCT trellis-квантование учитывает, как решения об округлении влияют на этап энтропийного кодирования, и принимает глобально более удачные решения.
- Оптимизированные таблицы Хаффмана — стандартные таблицы Хаффмана в JPEG универсальны. MozJPEG строит собственные таблицы, настроенные под реальное распределение коэффициентов в каждом изображении.
- Прогрессивное кодирование — прогрессивные JPEG хранят коэффициенты в нескольких проходах (сначала грубо, затем уточнение). Часто это сжимается лучше последовательного кодирования, потому что грубый проход имеет более предсказуемое распределение коэффициентов.
- Адаптивные таблицы квантования — вместо одной таблицы на всё изображение адаптивные энкодеры подбирают квантование для каждой области: агрессивнее на сложных участках (где артефакты менее заметны) и консервативнее на гладких.
Если вы отдаёте изображения через веб, переход с libjpeg на MozJPEG — один из самых простых способов ускорить сайт. Большинство CDN для изображений и библиотек обработки это поддерживают. Кодирование медленнее (для заранее обработанных статичных картинок это не важно), зато файлы меньше при том же качестве.
JPEG против новых форматов
WebP, AVIF и HEIC используют более современные техники сжатия: блоки преобразования большего размера, внутриконтурные фильтры деблокинга, внутрикадровое предсказание (предсказание текущего блока по соседним). При одинаковом визуальном качестве они сжимают на 20–50% лучше JPEG. AVIF, основанный на видеокодеке AV1, особенно впечатляет по эффективности.
Так почему JPEG до сих пор везде? Универсальная поддержка. Каждый браузер, каждый просмотрщик изображений, каждая операционная система, каждая камера, каждый телефон и каждая программа, работающая с картинками, поддерживают JPEG. WebP почти повсеместно поддерживается в браузерах, но в нативных системах его хуже. Поддержка AVIF пока непоследовательна. HEIC — в основном экосистема Apple. Для формата, который должен работать везде, JPEG остаётся единственным безопасным выбором.
Практический совет: если ваша инфраструктура это поддерживает (большинство CDN умеют через content negotiation), отдавайте AVIF или WebP с JPEG в качестве запасного варианта. Если можно выбрать только один формат, JPEG, закодированный MozJPEG с качеством 80, для фотографий трудно превзойти. Для скриншотов, диаграмм и текстовых изображений по-прежнему лучше PNG — или посмотрите другие креативные подходы к представлению изображений.
Блок 8×8, который покорил мир
Конвейер сжатия JPEG — хрестоматийный пример инженерии, которая работает с человеческим восприятием, а не против него. Каждый этап использует конкретное свойство: нечувствительность к цвету, частотное распределение естественных изображений, перцептивное маскирование шума квантования. Вместе они образуют систему, которая уменьшает файлы в 10–20 раз с минимальным видимым ущербом. Тридцать четыре года спустя те же блоки DCT 8×8, что работали на железе 1992 года, по-прежнему несут на себе большую часть изображений в интернете. Это признак дизайна, в котором с самого начала всё сделали правильно.


