Суть сжатия: выразить ту же информацию меньшим объёмом данных
Прежде чем углубляться в различие между сжатием без потерь и сжатием с потерями, нам нужно понять, что именно делает сжатие.
В своей основе сжатие — это выражение той же информации меньшим объёмом данных. Любые данные — будь то текст, изображения, аудио или видео — содержат «избыточность». Избыточность — это части, которые можно удалить без потери смысла информации. Задача алгоритма сжатия — выявить и устранить эту избыточность.
Рассмотрим простой пример. Строка символов AAAAABBBCC занимает 10 байт. Но мы можем представить ту же информацию более компактно, записав «каждый символ и сколько раз он повторяется подряд», получив 5A3B2C — всего 6 байт. Размер данных падает на 40%, но смысл идентичен. Это самая примитивная форма сжатия, известная как Run-Length Encoding (RLE).
С точки зрения теории информации Клод Шеннон ввёл понятие «информационной энтропии»: минимальная средняя длина кодирования потока данных ограничена его энтропией. Ни один алгоритм без потерь не может преодолеть этот теоретический предел. Это означает, что повторное сжатие уже сжатых данных почти не приносит пользы — избыточность уже устранена.
Понимание этой сути выявляет два фундаментально различных технических пути: сжатие без потерь стремится к идеальной точности, тогда как сжатие с потерями намеренно отбрасывает детали, которые человеческий глаз или ухо не может легко воспринять, обменивая их на гораздо более высокий коэффициент сжатия.
Сжатие без потерь: восстановление каждого бита
Главное обещание сжатия без потерь состоит в том, что распакованные данные байт-в-байт идентичны оригиналу — ни один бит не может отличаться. Эти алгоритмы устраняют только «статистическую избыточность» и «структурную избыточность», никогда не затрагивая семантическое содержание информации.
DEFLATE: самый широко используемый алгоритм без потерь
DEFLATE — алгоритм, лежащий в основе ZIP, gzip, zlib и многих других инструментов. Он элегантно объединяет две классические техники:
- LZ77: использует скользящее окно для поиска повторяющихся подстрок в уже обработанных данных, заменяя их указателями «дистанция + длина». Например, слово «сжатие», многократно встречающееся в текстовом файле, можно заменить обратной ссылкой на его первое появление.
- Кодирование Хаффмана: применяет кодирование переменной длины к потоку символов, создаваемому LZ77. Часто встречающиеся символы получают короткие коды; редкие символы получают длинные коды. Это приближает кодирование к энтропийному пределу.
Достоинства DEFLATE — простота, скорость и универсальная совместимость — почти в каждой стандартной библиотеке языков программирования есть его реализация.
LZMA: более высокие коэффициенты через контекстное моделирование
LZMA (Lempel-Ziv-Markov chain Algorithm) строится на LZ77 со значительно большим скользящим окном (до нескольких ГБ), более точной вероятностной моделью и интервальным кодированием. По сравнению с DEFLATE, LZMA обычно достигает более высоких коэффициентов сжатия ценой более медленной скорости сжатия и большего потребления памяти. Формат 7z основан на LZMA.
Ключевое улучшение в LZMA состоит в том, что он не полагается на статическую таблицу вероятностей. Вместо этого он динамически предсказывает вероятность следующего символа на основе контекста. Это «контекстное моделирование» приближает кодирование к теоретическому энтропийному пределу.
Фильтрация PNG: предварительная обработка данных изображения
PNG — формат изображений без потерь, но он не применяет DEFLATE непосредственно к сырым значениям пикселей. Перед сжатием PNG применяет «фильтр» к каждой строке пикселей, чтобы сделать данные более благоприятными для DEFLATE.
Распространённый фильтр хранит разность между каждым пикселем и его соседом слева, сверху или сверху слева. Поскольку естественные изображения имеют локально похожие пиксели, эти разности склонны группироваться вокруг нуля. Такие преобразованные данные имеют более высокую избыточность, что позволяет DEFLATE сжимать их гораздо эффективнее.
Это также объясняет, почему ZIP не может эффективно сжимать изображения JPEG: JPEG уже высоко сжат посредством DCT и энтропийного кодирования, оставляя почти никакой статистической избыточности, которую DEFLATE мог бы использовать. Запуск ZIP над JPEG обычно добавляет несколько байт заголовка без какого-либо уменьшения размера.
Сжатие с потерями: обмен ниже порога восприятия
Центральная идея сжатия с потерями заключается в том, что человеческое восприятие имеет пределы. Если отброшенные детали находятся ниже порога восприятия, визуальная или слуховая разница незначительна — но сокращение данных может быть огромным.
DCT: математическое основание JPEG
Дискретное косинусное преобразование (DCT) — сердце сжатия изображений JPEG. Его роль — преобразовать изображение из «пространственной области» в «частотную область».
В пространственной области изображение представлено значениями яркости пикселей. В частотной области изображение разлагается в сумму компонентов косинусоидальных волн разных частот: низкочастотные компоненты представляют большие гладкие области, тогда как высокочастотные компоненты представляют контуры и мелкие детали.
Сама DCT обратима и не теряет информацию. Фактическая «потеря» происходит на следующем шаге — квантовании.
Квантование: источник потерь
Квантование отображает высокоточные коэффициенты DCT в ограниченный набор дискретных значений. На практике каждый коэффициент делится на значение из таблицы квантования, а затем округляется до целого. Поскольку человеческий глаз менее чувствителен к высокочастотным деталям, таблица квантования применяет большие делители к высокочастотным коэффициентам, заставляя многие из них становиться нулём.
Этот шаг вызывает необратимую потерю информации — как только коэффициент округлён до нуля, его нельзя восстановить. Но он также создаёт огромную возможность сжатия: длинные серии нулей можно кодировать очень эффективно с помощью run-length encoding.
Проектирование таблицы квантования — это искусство: большие делители дают более высокое сжатие, но более заметную потерю качества. Именно это контролирует параметр качества JPEG (например, quality=80) — он масштабирует таблицу квантования вверх или вниз.
Межкадровое предсказание: ключ к сжатию видео
Сжатие видео делает шаг дальше неподвижных изображений. Последовательные кадры в видео часто меняются очень мало (например, статический фон с движущимся человеком), поэтому нет необходимости хранить каждый кадр полностью.
Межкадровое предсказание использует «оценку движения», чтобы найти смещение между текущим кадром и опорным кадром, сохраняя только «векторы движения» и «остатки». Это устранение временной избыточности позволяет коэффициентам сжатия видео достигать сотен или даже тысяч к одному — далеко за пределами того, что может достичь сжатие одиночных кадров.
Без потерь vs с потерями: диаграмма сравнения
Приведённая ниже блок-схема иллюстрирует основные ветви и типичные применения двух семейств сжатия:
Диаграмма принципа DCT
Приведённая ниже диаграмма упрощённо показывает, как DCT преобразует блок пикселей 8x8 из пространственной области в частотную, а затем сохраняет низкие частоты, отбрасывая высокие посредством квантования:
Примеры кода
Сжатие без потерь с помощью zlib
import zlib
# Исходные текстовые данные с сильным повторением
original = b"compression compression compression " * 50
# Сжатие
compressed = zlib.compress(original, level=9)
print(f"Исходный размер: {len(original)} байт")
print(f"Сжатый размер: {len(compressed)} байт")
print(f"Коэффициент: {len(original) / len(compressed):.2f}x")
# Распаковка и проверка, что данные идентичны
decompressed = zlib.decompress(compressed)
assert decompressed == original, "Несовпадение данных!"
print("Проверка пройдена: распакованные данные идентичны оригиналу")
При выполнении этого кода вы обычно увидите коэффициент сжатия выше 10x, а распакованные данные байт-в-байт идентичны оригиналу. В этом и заключается смысл «без потерь».
Сжатие с потерями с помощью PIL
from PIL import Image
import io
# Создание тестового изображения, богатого высокочастотными деталями
img = Image.new("RGB", (512, 512))
pixels = img.load()
for x in range(512):
for y in range(512):
# Генерация узора с высокочастотными деталями
pixels[x, y] = ((x * 7) % 256, (y * 5) % 256, ((x + y) * 3) % 256)
# Сохранение как PNG без потерь
img.save("test_lossless.png")
png_size = len(open("test_lossless.png", "rb").read())
print(f"Размер PNG (без потерь): {png_size} байт")
# Сохранение как JPEG с потерями с качеством 20 для усиления эффекта
buffer = io.BytesIO()
img.save(buffer, format="JPEG", quality=20)
jpeg_size = buffer.tell()
print(f"Размер JPEG (с потерями): {jpeg_size} байт")
print(f"Коэффициент: {png_size / jpeg_size:.2f}x")
# Перезагрузка JPEG и сравнение разницы пикселей
buffer.seek(0)
img_jpeg = Image.open(buffer)
diff_count = sum(
1 for x in range(512) for y in range(512)
if img.getpixel((x, y)) != img_jpeg.getpixel((x, y))
)
print(f"Изменённые пиксели: {diff_count} / {512 * 512}")
print("Вывод: сжатие JPEG необратимо изменяет значения пикселей")
Этот код демонстрирует отличительную черту сжатия с потерями: файл меньшего размера, но со значениями пикселей, необратимо изменёнными.
Сравнительная таблица
| Аспект | Сжатие без потерь | Сжатие с потерями |
|---|---|---|
| Основной принцип | Устраняет статистическую и структурную избыточность | Отбрасывает информацию ниже порога восприятия |
| Точность | 100% обратимо, идентично после распаковки | Необратимо, невосполнимая потеря |
| Типичные алгоритмы | DEFLATE, LZMA, Brotli, Zstandard | DCT+квантование, вейвлет, MDCT |
| Ключевые техники | LZ77, кодирование Хаффмана, интервальное кодирование | Преобразующее кодирование, квантование, предсказание |
| Типичные применения | ZIP, GZIP, 7Z, PNG, FLAC | JPEG, WebP, H.264, MP3, AAC |
| Лучше всего подходит для | Текста, исходного кода, архивов, медицинской визуализации | Фотографий, видео, музыки, потоковой передачи |
| Типичный коэффициент | Обычно от 2x до 5x | Обычно от 10x до 100x и выше |
| Не подходит для | Уже сжатых данных (напр., файлы JPEG) | Данных, требующих точного воспроизведения (напр., юридический текст) |
FAQ
В1: Почему ZIP не может сжать изображение JPEG?
К моменту создания JPEG он уже прошёл через DCT, квантование и энтропийное кодирование. Статистическая избыточность в данных почти полностью устранена. DEFLATE не может найти используемые шаблоны повторения, поэтому запуск ZIP над JPEG не только не уменьшает размер, но и может добавить несколько байт заголовка.
В2: Всегда ли PNG больше JPEG для одного и того же изображения?
Не обязательно. Для изображений с большими областями сплошного цвета или ограниченной палитрой (таких как логотипы, иконки или скриншоты) комбинация фильтр-плюс-DEFLATE формата PNG часто меньше JPEG и сохраняет идеальное качество. Но для цветных естественных фотографий комбинация DCT-плюс-квантование формата JPEG обычно достигает коэффициентов сжатия выше 10x, делая его гораздо меньше PNG.
В3: Можно ли многократно сжимать один и тот же файл алгоритмом без потерь?
Нет. Каждый проход сжатия без потерь приближает данные к их энтропийному пределу. После первого прохода избыточность в значительной степени устранена, и второму проходу почти нечего использовать — он может даже слегка вырасти из-за добавленных метаданных. Именно поэтому «сжимать уже сжатый файл» бесполезно.
Итоги
Сжатие без потерь и сжатие с потерями — это не враждующие лагеря, а оптимальные выборы, сделанные для разных характеристик информации:
- Сжатие без потерь служит данным, где «ни один бит не может быть ошибочным» — текст, код, архивы. Оно использует такие техники, как LZ77 и кодирование Хаффмана, для устранения статистической избыточности, гарантируя идеальную реконструкцию.
- Сжатие с потерями служит деталям, «которые глаз и ухо не могут воспринять» — фотографии, видео, музыка. Оно использует DCT, квантование и межкадровое предсказание для компромиссов ниже порога восприятия, обменивая контролируемую потерю информации на улучшение коэффициента сжатия на порядок.
Понимание фундаментальной разницы между этими двумя путями — краеугольный камень освоения всех технологий сжатия. В последующих статьях мы углубимся в конкретные реализации алгоритмов вдоль каждого пути, постигая элегантность сжатия строка за строкой.
Связанные статьи:
- Полное руководство по сжатию файлов: принципы и методы сжатия PDF/изображений/видео/документов
- Принципы и методы сжатия PDF: как эффективно уменьшить размер PDF
- Руководство по сжатию изображений: сравнение и выбор форматов JPG/PNG/WebP
Нужно сжать файлы? Попробуйте SmartSlim
На базе собственного движка сжатия на Rust поддерживается 10 основных категорий и 40+ форматов, включая PDF/изображения/видео/Office/OFD. Локальная обработка — данные не покидают вашу инфраструктуру.