<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Алгоритмы сжатия</title>
    <description>Алгоритмы сжатия — это методы обработки данных, направленные на уменьшение их объема без значительных потерь качества. Они используются для оптимизации хранения файлов, ускорения передачи данных и снижения нагрузки на системы.

Существует два основных типа сжатия: с потерями (lossy) и без потерь (lossless). Среди популярных алгоритмов сжатия — ZIP, JPEG, MP3, Huffman Coding и LZ77. Эти технологии находят применение в мультимедийных файлах, архивировании, передаче данных и облачных сервисах.</description>
    <link>https://tproger.ru/tag/algoritmy-szhatia</link>
    <atom:link href="https://tproger.ru/tag/algoritmy-szhatia/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Thu, 24 Sep 2026 00:04:54 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Алгоритмы сжатия</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Оптимизация изображений для веба: где теряются мегабайты</title>
      <link>https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v</link>
      <comments>https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v</guid>
      <description><![CDATA[<p>Оптимизация изображений для веба: размер в пикселях, формат под тип картинки, AVIF против WebP и сжатие в браузере. Проверьте свои картинки по чеклисту.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/optimizaciya-kartinok-dlya-veba-gde-teryayutsya-megabajty-i-kak-ih-v">Оптимизация изображений для веба: где теряются мегабайты</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Алгоритмы сжатия]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Sep 2026 09:00:41 GMT</pubDate>
      <content:encoded><![CDATA[<p>Картинки обычно оказываются самой тяжёлой частью страницы, и почти всегда они тяжелее, чем нужно. Скриншот интерфейса на 2,1 МБ ужимается до 102 КБ без заметной глазу разницы, а фотография на 4,7 МБ теряет три четверти веса ещё до того, как вы дотронетесь до качества сжатия.</p><p>Разница между четырёхсекундной загрузкой и загрузкой меньше секунды обычно лежит именно здесь, а не в бандле скриптов. Ниже пошаговая оптимизация изображений: что делать первым, какой формат выбирать под какой тип картинки и почему кодировать современные форматы нужно на сборке, а не на лету.</p><p>Первым делом уменьшайте размер в пикселях, а не качество: фотография 6000×4000 в карточке шириной 1200 пикселей это чистые потери. Один этот шаг убрал 77% веса тестового снимка.</p><p>Формат выбирается под тип картинки: фотографиям WebP или AVIF, скриншотам и интерфейсам сжатие без потерь, логотипам SVG, анимациям анимированный WebP вместо GIF.</p><p>AVIF при равном качестве весит вдвое меньше JPEG, но кодируется примерно в пятнадцать раз дольше, поэтому генерировать его нужно на этапе сборки.</p><p>Метаданные съёмки занимают от 10 до 30 КБ на файл и в вебе не нужны ни для чего.</p><p>Сжатие с потерями на тексте и резких границах даёт видимые артефакты: скриншоты и логотипы жмутся только без потерь, зато на 20–60%.</p><h2>Шаг, который экономит больше всех остальных</h2><p>Прежде чем подбирать кодек и качество, посмотрите на фактические размеры. Фотография 6000×4000 в карточке шириной 1200 CSS-пикселей отдаёт браузеру в двадцать пять раз больше пикселей, чем нужно обычному экрану, и вшестеро больше, чем нужно экрану с двойной плотностью.</p><p>В замерах автора чеклиста <a href="https://dev.to/_544bf5cbd223c35a49756/image-optimization-the-complete-2026-checklist-for-faster-websites-3pi5">одно только уменьшение до реально отображаемого размера ужало тестовое изображение с 4,7 МБ до 1,1 МБ</a>. Это минус 77% при нулевой потере качества: пиксели, которых не видно, просто перестали передаваться.</p><p><b>Как определить нужный размер:</b><br />Отправная точка это ширина контейнера в CSS-пикселях. На обычном экране она же и есть нужная ширина в физических пикселях, на плотных экранах нужно кратно больше: у части ноутбуков это двойка, у большинства современных смартфонов тройка. Поэтому правильный инструмент здесь не фиксированный множитель, а атрибут srcset с несколькими вариантами файла: браузер сам возьмёт тот, что соответствует плотности экрана посетителя.</p><h2>Формат под тип изображения, а не один на всё</h2><p>Самая частая ошибка — выбрать один формат и применять его ко всему подряд. Между фотографией с плавными градиентами и скриншотом с текстом и резкими границами разница принципиальная, и сжимаются они противоположными способами.</p><ul><li>Фотографии — WebP (на 30–50% меньше JPEG) или AVIF (ещё примерно на 30% меньше WebP).</li><li>Скриншоты и элементы интерфейса — PNG или WebP без потерь.</li><li>Логотипы и иконки — SVG: вектор весит копейки и масштабируется без предела.</li><li>Анимации — анимированный WebP вместо GIF, это экономит 60–80% веса.</li></ul><p>Отдельно про текст. Сжатие с потерями на буквах и резких границах создаёт заметные ореолы вокруг символов, поэтому скриншоты и логотипы обрабатываются только алгоритмами без потерь. Инструменты вроде oxipng ужимают такие файлы на 20–60%, не меняя при этом ни одного пикселя.</p><h3>Конвертация и сжатие — это два разных действия</h3><p>Перевод PNG в JPEG экономит место. Сжатие получившегося JPEG экономит ещё столько же, и про этот второй проход регулярно забывают. Для фотографий рабочий диапазон качества это 75–82%: от стопроцентного такая картинка визуально неотличима, а весит заметно меньше.</p><h3>Метаданные, которые вы отдаёте бесплатно</h3><p>В файле с камеры или из редактора лежат EXIF, координаты GPS, модель камеры и метки программы обработки. Для показа в браузере это бесполезный груз весом от 10 до 30 КБ на файл, за одним исключением: тег ориентации. Часть снимков с телефона хранит пиксели неповёрнутыми и полагается на него, поэтому поворот нужно применить к самим пикселям до того, как метаданные срежутся, иначе фотографии лягут набок. На каталоге из тысячи товарных снимков набегает до 30 МБ трафика ни за что, а координаты съёмки вдобавок могут оказаться данными, которые вы не собирались публиковать.</p><h2>AVIF: что это и почему его нельзя кодировать на лету</h2><p>AVIF (AV1 Image File Format) выпущен Alliance for Open Media в 2019 году и построен на внутрикадровом кодировании видеокодека AV1. По сути это инструменты сжатия одного кадра AV1, упакованные в самостоятельный контейнер для картинок.</p><p>Перед WebP у него два практических преимущества: выше степень сжатия при равном качестве и глубина цвета до 12 бит с поддержкой расширенного динамического диапазона, тогда как WebP ограничен восемью битами и обычным диапазоном. Достигается это за счёт заметно более богатого набора инструментов предсказания, унаследованного от видеокодека.</p><h3>Сколько это в килобайтах</h3><p>В сравнительном тесте <a href="https://dev.to/uglypeardata/avif-format-guide-the-next-generation-image-compression-std-4oa5">брали пейзажный кадр 1920×1080 с градиентами неба, текстурой листвы и границами зданий, исходник в BMP весил 5,93 МБ</a>. Целевое качество задавали по метрике структурного сходства: она сравнивает сжатую картинку с исходной, где единица означает полное совпадение, а 0,92 примерно соответствует порогу, за которым разницу перестают замечать глазом. Результаты:</p><p>На листве и градиентах неба разница видна и глазом: JPEG на низком битрейте показывает цветовые блоки, у AVIF артефактов практически нет. Отвечают за это многоуровневые фильтры внутри цикла кодирования, которые заглаживают границы блоков и восстанавливают детали текстур.</p><p>Плата за это — время. Кодирование AVIF примерно в пятнадцать раз дольше JPEG и вчетверо дольше WebP, потому что выбор разбиения и типа преобразования требует перебора с оптимизацией. Зато декодирование медленнее JPEG всего вдвое, и на просмотр это почти не влияет. Практический вывод прямой: генерируйте AVIF заранее, на этапе сборки. Сервисы доставки изображений кодируют его и по запросу, но только с кешированием результата, чтобы платить за кодирование один раз на вариант, а не на каждого посетителя. Чего делать нельзя, так это кодировать заново при каждом обращении.</p><h3>Как отдавать современный формат и не потерять старые браузеры</h3><p>Поддержка AVIF в браузерах составляет примерно 96%, но подстраховка всё равно нужна. Делается она тегом &lt;picture&gt;: браузер берёт первый формат, который понимает, и до остальных не доходит.</p><p>Атрибуты width и height здесь не декоративные: без них браузер не знает пропорций до загрузки файла и подвёрстывает страницу заново, когда картинка приходит. Это тот самый прыжок содержимого, который портит метрику визуальной стабильности. Атрибут loading=lazy убирает изображения за пределами первого экрана из очереди, конкурирующей за отрисовку главного элемента.</p><p>Именно за пределами: на картинку первого экрана его ставить нельзя. Отложенная загрузка задержит ровно тот элемент, скорость появления которого и меряет метрика отрисовки основного содержимого. Там уместен противоположный по смыслу fetchpriority=high.</p><h2>Сжатие в браузере: почему это вообще возможно</h2><p>Браузер умеет декодировать, преобразовывать и кодировать изображение прямо на устройстве, не отправляя файл никуда. Для товарных снимков, клиентских материалов и прочего чувствительного это снимает целый шаг из конвейера вместе с вопросом, где полежит копия.</p><p>Речь здесь уже не про ассеты вашего сайта, которые готовятся на сборке. Речь про картинки, которые в браузер приносит сам пользователь: форма загрузки в личном кабинете, объявление на маркетплейсе, вложение в заявку. Сжать их до отправки на сервер можно прямо во вкладке, и это снимает и трафик, и вопрос о том, где полежит оригинал.</p><p>Автор одного из таких инструментов <a href="https://dev.to/_544bf5cbd223c35a49756/how-i-built-a-browser-image-compressor-that-handles-30-images-at-once-56k4">разобрал устройство своего конвейера</a>, и его опыт пригодится всем, кто выносит тяжёлые вычисления во фронтенд.</p><h3>Вся тяжёлая работа уходит из главного потока</h3><p>Перекодирование снимка 4000×4000 нагружает процессор настолько, что в главном потоке интерфейс замирает, а браузер показывает предупреждение о зависшей странице. Поэтому весь конвейер живёт в Web Worker: главный поток отвечает за выбор файлов, превью и состояние, а рабочий поток декодирует через createImageBitmap, применяет преобразования и кодирует через OffscreenCanvas. Именно через него, а не через canvas.toBlob: последний это метод DOM-элемента, а DOM в рабочем потоке отсутствует, и нужный метод там называется convertToBlob.</p><p>Важная деталь производительности: передавать данные между потоками нужно как ArrayBuffer через механизм передачи владения, а не структурным клонированием. На пачке из тридцати изображений это разница между мгновенным откликом и лишними полусекундами нагрузки на сборщик мусора для каждого файла.</p><h3>Три ошибки, которые ищутся дольше всего</h3><p><b>Рабочий поток не имеет доступа к window.</b> Причём не только напрямую: достаточно подключить библиотеку, которая трогает window на верхнем уровне модуля. В консоли разработчика появляется ошибка обращения к неопределённому объекту, а вот в интерфейсе не появляется ничего: если сбой рабочего потока никак не показан пользователю, тот видит вечный спиннер. Лечится ревизией всех импортов рабочего потока: библиотеки, завязанные на браузерное окружение, остаются в главном потоке и передают в рабочий поток уже готовые данные.</p><p><b>Округление сломало масштабирование.</b> Быстрый путь изменения размера использовал округлённый шаг по пикселям. На больших изображениях округление уводило исходную координату за пределы строки, и картинка выходила разрезанной по горизонтали с чёрной мозаикой внизу. Помогли точные дробные коэффициенты и ограничение по границам в каждом ручном проходе по пикселям.</p><p><b>Асинхронный обработчик сообщений перепутал порядок.</b> Обработчик стал ждать преобразование уже после кодирования, а асинхронные обработчики порядок не сохраняют: состояние поворота разъехалось с готовым изображением. Полностью синхронным такой обработчик не сделать, декодирование и кодирование асинхронны по своей природе. Работает другое: обрабатывать сообщения строго по одному, не начиная следующее до завершения предыдущего, и хранить состояние вроде угла поворота рядом с данными конкретного сообщения, а не в общей переменной.</p><p><b>Заголовки безопасности ломают рабочие потоки молча:</b><br />Блокирует загрузку скрипта заголовок Cross-Origin-Embedder-Policy: он требует, чтобы каждый сторонний ресурс отдавал разрешающий заголовок, иначе браузер молча его отбрасывает. Cross-Origin-Opener-Policy на это не влияет, но включают их обычно парой, поэтому и ломается всё в одном релизе. Любое изменение заголовков безопасности проверяйте на настоящем развёрнутом стенде, а не только на машине разработчика.</p><h2>Что это даёт в цифрах</h2><p>Скриншот 1920×1080 проходит такой путь: исходный PNG весит 2,1 МБ, после уменьшения и перевода в WebP с качеством 75% — 186 КБ, то есть минус 91%. Тот же кадр в AVIF занимает 102 КБ, минус 95% от исходного.</p><p>Именно эти проценты и отделяют страницу, которая грузится четыре секунды, от страницы, которая укладывается в одну.</p><h2>Что забрать с собой</h2><p>Порядок действий важнее набора инструментов. Сначала пиксели, потом формат под тип изображения, потом второй проход сжатия, и только затем разговор про кодеки нового поколения. Обратный порядок даёт красивую строчку в отчёте и почти никакого эффекта на реальной странице.</p><p>Материалы разбора: <a href="https://dev.to/_544bf5cbd223c35a49756/image-optimization-the-complete-2026-checklist-for-faster-websites-3pi5">чеклист оптимизации с замерами</a>, <a href="https://dev.to/uglypeardata/avif-format-guide-the-next-generation-image-compression-std-4oa5">техническое устройство AVIF и сравнительный тест форматов</a> и <a href="https://dev.to/_544bf5cbd223c35a49756/how-i-built-a-browser-image-compressor-that-handles-30-images-at-once-56k4">разбор браузерного конвейера сжатия</a>.</p><p>Откройте свою главную страницу с открытой панелью сети и отсортируйте запросы по размеру. Первые три строки почти наверняка окажутся картинками, и это ваша ближайшая оптимизация изображений: уменьшить их вдвое реально за один вечер.</p>]]></content:encoded>
    </item>
    <item>
      <title>Аппаратное сжатие текстур: AFRC, PVRIC4 и Metal</title>
      <link>https://tproger.ru/translations/apparatnoe-szhatie-tekstur--afrc--pvric4-i-metal</link>
      <comments>https://tproger.ru/translations/apparatnoe-szhatie-tekstur--afrc--pvric4-i-metal?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/apparatnoe-szhatie-tekstur--afrc--pvric4-i-metal</guid>
      <description><![CDATA[<p>Сравнение трёх форматов аппаратного сжатия текстур — ARM AFRC, ImgTec PVRIC4 и Apple Metal Lossy. Точные данные RMSE, производительность в МПикс/сек, Vulkan BPC.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/apparatnoe-szhatie-tekstur--afrc--pvric4-i-metal">Аппаратное сжатие текстур: AFRC, PVRIC4 и Metal</a>»</p>]]></description>
      <category><![CDATA[Низкоуровневое программирование]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Hardware]]></category>
      <category><![CDATA[Компьютерная графика]]></category>
      <category><![CDATA[ARM]]></category>
      <category><![CDATA[Алгоритмы сжатия]]></category>
      <category><![CDATA[GPU]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 30 Mar 2026 15:22:10 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перевод статьи <a href="https://www.ludicon.com/castano/blog/2026/03/hardware-image-compression/">Hardware Image Compression</a> Игнасио Кастаньо (Ignacio Castaño). Оригинал опубликован в марте 2026 года.</p><p>Одним из поводов для разочарования в области аппаратных форматов изображений всегда было медленное развитие. Разработчики обычно не решались поставлять текстуры в новом формате, пока он не становился повсеместно доступным — поддерживался большинством целевого железа и всеми вендорами без исключения. Сегодня три вендора предлагают собственные форматы аппаратного сжатия текстур на лету: ARM AFRC, ImgTec PVRIC4 и Apple Metal Lossy. Игнасио Кастаньо исследовал все три и сравнил их с программным сжатием реального времени Spark от NVIDIA.</p><p>— ARM AFRC (Pixel 8, Mali-G715) — явный победитель: по метрике RMSE значительно обходит Spark и других конкурентов во всех форматах.</p><p>— Apple Metal Lossy (A15/M2+) — коэффициент сжатия 1:2, API минималистичен: один флаг в дескрипторе текстуры.</p><p>— ImgTec PVRIC4 (Pixel 10) разочаровал: драйвер игнорирует запрошенный bitrate, качество хуже Spark для R и RG форматов.</p><p>— Vulkan-расширение VK_EXT_image_compression_control унифицирует доступ к аппаратному сжатию через параметр BPC (bits per component).</p><p>— Аппаратное сжатие — перспективная альтернатива программному, но пока ограничено современными топовыми устройствами.</p><h2>Контекст: почему это важно</h2><p>Разработчики обычно не решались поставлять текстуры в новом формате, пока он не становился широко доступным — то есть поддерживался большинством целевого железа и всеми вендорами. Например, хотя ATI представила форматы 3Dc в 2004 году вместе с Radeon X800 (R420) и открыла их через расширения D3D9, их использование не стало распространённым, когда Direct3D 10 стандартизировал их как BC4 и BC5 в 2007 году. Массовое применение началось лишь тогда, когда Direct3D 10 стал минимальным требованием к железу.</p><p><a href="https://www.crytek.com/games/crysis">Crysis</a> стала первой крупной игрой, поставляемой с BC5-текстурами, но большинство игр ещё долгие годы не решались устанавливать такое жёсткое требование к железу. Чтобы избежать задержек с принятием, форматы BC6 и BC7 разрабатывались совместно ATI и NVIDIA для Direct3D 11.</p><p>Именно поэтому сжатие текстур в реальном времени так интересно: когда кодировщик работает в реальном времени, внедрять новые аппаратные форматы значительно проще — не нужно ждать, пока будет подготовлен контент, целенаправленно созданный под них. Аппаратное сжатие устраняет эту проблему принятия: детали форматов не документируются, их использование абсолютно прозрачно — приложению не нужно явно указывать эти форматы, драйвер сжимает текстуры динамически в процессе рендеринга и загрузки изображений.</p><h2>Apple Metal: Lossy-сжатие</h2><p>Apple представила сжатие текстур с потерями в чипах A15 и M2 (оба используют одно поколение GPU). Оно обеспечивает коэффициент сжатия 1:2. Включить его на удивление просто — API минималистичен. Свойство compressionType дескриптора MTLTextureDescriptor принимает значение из перечисления MTLTextureCompressionType, и установка MTLTextureCompressionTypeLossy зачастую является единственным необходимым изменением:</p><p>Согласно таблицам возможностей Metal Feature Set Tables, все обычные пиксельные форматы поддерживают сжатие с потерями — включая 10-битные и форматы с плавающей точкой. Тестирование это подтвердило, однако основное внимание сосредоточено на форматах R8, RG8 и RGBA8.</p><p>Внутренний алгоритм Apple не задокументирован. По результатам реверс-инжиниринга lossy-форматов используется размер блока 8×4 пикселя — и они напоминают некоторые особенности форматов ETC и EAC. Несмотря на заявленное сжатие 1:2, на практике для каждого блока выделяется один байт метаданных, так что реальное потребление памяти чуть выше заявленного.</p><h3>Качество на M4 Pro</h3><p>Для форматов R и RG Metal Lossy показывает результаты лучше кодеков Spark EAC, но хуже BC4 и BC5. Результаты RMSE (Root Mean Square Error — среднеквадратичная ошибка; меньше = лучше):</p><p><b>Формат R:</b><br /><br /></p>МетрикаMetal Lossy (1:2)BC4 Medium (1:2)BC4 High (1:2)EAC_RG Low (1:2)EAC_RG Medium (1:2)EAC_RG High (1:2)RMSE1,85791,84691,71492,33992,29221,8636<p></p><p><b>Формат RG:</b><br /><br /></p>МетрикаMetal Lossy (1:2)BC5 Medium (1:2)BC5 High (1:2)EAC_RG Low (1:2)EAC_RG Medium (1:2)EAC_RG High (1:2)RMSE3,17573,30993,04424,22614,15923,3601<p></p><p>Прямое сравнение lossy RGBA8 с форматами Spark некорректно из-за разных коэффициентов сжатия: Metal Lossy поддерживает только 1:2, тогда как форматы Spark RGB(A) — 1:4. Тем не менее, для полноты картины:</p><p><b>Формат RGBA:</b><br /><br /></p>МетрикаMetal Lossy (1:2)ASTC 4×4 Low (1:4)ASTC 4×4 Medium (1:4)ASTC 4×4 High (1:4)BC7 Low (1:4)BC7 Medium (1:4)BC7 High (1:4)RMSE1,49476,29945,96865,36375,72135,35854,2136<p></p><h3>Производительность на M4 Pro</h3><p>С точки зрения производительности lossy-форматы показывают себя отлично и при достаточно большом размере текстуры упираются в пропускную способность памяти. Результаты на M4 Pro (16 ядер GPU) в МПикс/сек:</p><p></p>Метод409620481024512256Uncompressed (blit)41 61826 68043 74970 11144 939Metal Lossy (blit)41 80740 84743 10069 87348 729BC7 High (GPU)35 56342 23037 08234 22410 985<p></p><p>Обратите внимание, что пропускная способность стандартных блитов остаётся достаточно стабильной вне зависимости от размера текстуры. Кодеки Spark, напротив, имеют фиксированные накладные расходы, которые становятся заметнее при уменьшении размеров текстур. Интересен скачок скорости блитов при 512×512 — у него пока нет объяснения. Также стоит учесть, что кодеки Spark требуют дополнительного копирования из буфера вывода кодека в финальную сжатую текстуру — это дополнительные накладные расходы, которых можно было бы избежать, если бы Metal поддерживал запись в блочно-сжатые текстуры, как это делает Vulkan.</p><h2>Vulkan: расширение VK_EXT_image_compression_control</h2><p>В Vulkan расширение VK_EXT_image_compression_control даёт приложениям возможность запрашивать сжатие изображений с фиксированной скоростью. Расширение уже доступно на флагманских устройствах от ARM и Imagination. Включение потерявого сжатия в Vulkan несколько многословнее, чем в Metal, но на практике ненамного сложнее: нужно лишь расширить структуру VkImageCreateInfo, добавив в цепочку VkImageCompressionControlEXT.</p><p>Можно использовать флаг VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT, чтобы позволить реализации самой выбрать параметры сжатия:</p><p>Альтернативно можно явно указать флаги фиксированной скорости для управления допустимыми коэффициентами сжатия:</p><p>BPC (bits per component — бит на компонент) — несколько нестандартная единица, но она позволяет задавать коэффициент сжатия единообразно вне зависимости от количества каналов. Для справки, BPC существующих форматов блочного сжатия GPU:</p><p></p>ФорматКаналыРазмер на пиксельРазмер на каналBC1RGB4 bpp~1,33 bpcBC4R4 bpp4 bpcBC5RG8 bpp4 bpcBC7RGBA8 bpp2 bpcASTC 4×4RGBA8 bpp2 bpcASTC 6×6RGBA~3,55 bpp~1,18 bpc<p></p><p>Расширение VK_EXT_image_compression_control также присутствует в некоторых драйверах AMD и Qualcomm, однако, насколько известно, ни один из этих вендоров не поддерживает аппаратное сжатие изображений с фиксированной скоростью. В случае AMD расширение присутствует в драйвере RADV, чтобы Proton мог отключать потерявое сжатие фреймбуфера в некоторых играх, где оно вызывало проблемы с корректностью — через флаг VK_IMAGE_COMPRESSION_DISABLED_EXT.</p><h2>ARM AFRC: лучший результат среди всех</h2><p>ARM Fixed Rate Compression (AFRC) было анонсировано в 2021 году и впервые появилось в Mali-G510 в 2022-м, однако широкого распространения этот дизайн не получил. По-настоящему массовым AFRC стало с выпуском Mali-G715 и Mali-G615 в том же году. Тестирование проводилось на Pixel 8 с GPU Mali-G715.</p><p>Устройство сообщило поддержку следующих форматов сжатия с фиксированной скоростью (возможности значительно шире Metal Lossy):</p><p></p>Формат2 bpc3 bpc4 bpc5 bpcR82 bpp3 bpp4 bpp—RG84 bpp6 bpp8 bpp—RGB86 bpp—12 bpp15 bppRGBA88 bpp12 bpp16 bpp—<p></p><p>В отличие от Metal Lossy, AFRC не использует дополнительных байт метаданных — все управляющие биты находятся внутри самого блока. Изображение делится на блоки 8×8 пикселей, в ряде случаев разбиваемые на подблоки меньшего размера. Размер каждого блока 8×8 в байтах:</p><p></p>Формат2 bpc3 bpc4 bpc5 bpcR8162432—RG8324864—RGB864—96128RGBA86496128—<p></p><p>По результатам реверс-инжиниринга удалось установить: AFRC представляет цвета с использованием преобразования YCoCg, а представление пикселей напоминает вейвлет Хаара. Для каждого подблока 4×4 используется 16 коэффициентов, квантование которых зависит от режима. Форматы RGB и RGBA принципиально одинаковы — флаг в заголовке просто указывает, присутствует ли альфа-канал или блок полностью непрозрачен.</p><h3>Качество AFRC</h3><p>Качество AFRC впечатляет. В отличие от Metal, здесь можно сделать прямое сравнение с ASTC в реальном времени, поскольку Mali поддерживает сжатие 1:4:</p><p><b>Формат R:</b><br /><br /></p>МетрикаAFRC (1:2)EAC_R Low (1:2)EAC_R Medium (1:2)EAC_R High (1:2)RMSE<b>1,4937</b>2,33992,29221,8636<p></p><p><b>Формат RG:</b><br /><br /></p>МетрикаAFRC (1:2)EAC_RG Low (1:2)EAC_RG Medium (1:2)EAC_RG High (1:2)RMSE<b>2,2079</b>4,22614,15923,3601<p></p><p><b>Формат RGBA:</b><br /><br /></p>МетрикаAFRC (1:2)AFRC (1:4)ASTC 4×4 Low (1:4)ASTC 4×4 Medium (1:4)ASTC 4×4 High (1:4)RMSE<b>0,6679</b><b>3,4184</b>6,29945,96865,3637<p></p><p>Во всех случаях RMSE значительно ниже, то есть AFRC превосходит Spark ASTC при нацеливании на ASTC с кодировщиком реального времени. Тем не менее есть несколько случаев, когда Spark даёт более высокое качество: на очень гладких изображениях сжатие AFRC приводит к заметным паттернам дизеринга, раскрывающим границы блоков. Это особенно заметно при использовании AFRC в качестве текстуры с увеличением, тогда как для сжатия фреймбуфера — основного сценария применения — такие паттерны практически незаметны.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-30/7b1601e9-42b2-4416-a0d0-dfda1bf1cafa.webp" alt="Сравнение AFRC с дизерингом и без: AFRC сохраняет детали значительно лучше конкурентов при том же bitrate" /><figcaption>Сравнение AFRC с дизерингом и без: AFRC сохраняет детали значительно лучше конкурентов при том же bitrate</figcaption></figure><h3>Производительность AFRC (Pixel 8)</h3><p>Включение AFRC не вызывает значительных накладных расходов по сравнению с несжатыми загрузками текстур, за исключением некоторых размеров. Результаты на Pixel 8 в МПикс/сек:</p><p></p>Метод409620481024512256Uncompressed4 9613 9513 0632 2902 337AFRC 4 bpc5 5083 7921 7712 3412 318AFRC 2 bpc5 0414 4332 5562 2672 332Spark ASTC Q04 8104 2072 5033 6622 259Spark ASTC Q24 4813 7152 3192 9501 903<p></p><p>Пропускная способность здесь масштабируется с размером текстуры, а не остаётся стабильной. Накладные расходы одинаково влияют на блиты и compute-шейдеры Spark. В отличие от секции Metal, где lossy-блиты явно доминировали над Spark на малых размерах, здесь картина смешанная: Spark вплотную приближается к AFRC или превосходит его. Это показывает, что кодирование текстур в реальном времени вполне конкурентоспособно с аппаратным сжатием. Абсолютные числа здесь значительно ниже, чем на M4 Pro, — это принципиально разные классы устройств.</p><h2>ImgTec PVRIC4: разочарование от Pixel 10</h2><p>ImgTec впервые анонсировала поддержку PVRIC4 ещё в 2018 году для GPU серии Series 6, однако протестировать её удалось только с выходом Pixel 10 на чипе Series D. Первоначальное объявление намекало на то, что, как и Metal Lossy, PVRIC4 поддерживает только 50%-е сжатие, но расширение декларирует более широкий спектр опций:</p><p></p>Формат1 bpc2 bpc3 bpc4 bpcR81 bpp2 bpp3 bpp4 bppRG82 bpp4 bpp6 bpp8 bppRGBA84 bpp8 bpp12 bpp16 bpp<p></p><p>К большому удивлению, качество вывода оказалось одинаковым вне зависимости от BPC. Дальнейшее расследование показало: <b>драйвер игнорирует запрошенный BPC и всегда использует 4 bpc (сжатие 1:2)</b>. Формат блоков PVRIC4 — наиболее сложный из всех трёх вендоров: размер блоков составляет 16×16 пикселей, и, как в Metal Lossy, присутствует один байт метаданных на блок. Сделать реверс-инжиниринг практически не удалось.</p><h3>Качество PVRIC4</h3><p>Качество оказалось разочаровывающим. Для форматов R и RG Spark фактически превосходит PVRIC4 при нацеливании на стандартные форматы блочного сжатия, поддерживаемые этим железом:</p><p><b>Формат R:</b><br /><br /></p>МетрикаPVRIC4 (1:2)BC4 Medium (1:2)BC4 High (1:2)EAC_R Low (1:2)EAC_R Medium (1:2)EAC_R High (1:2)RMSE3,43461,84691,71492,33992,29221,8636<p></p><p><b>Формат RG:</b><br /><br /></p>МетрикаPVRIC4 (1:2)BC5 Medium (1:2)BC5 High (1:2)EAC_RG Low (1:2)EAC_RG Medium (1:2)EAC_RG High (1:2)RMSE5,43923,30993,04424,22614,15923,3601<p></p><p>Для RGBA прямое сравнение невозможно из-за разных коэффициентов сжатия, но качество также значительно хуже других вендоров:</p><p><b>Формат RGBA:</b><br /><br /></p>МетрикаPVRIC4 (1:2)ASTC 4×4 Low (1:4)ASTC 4×4 Medium (1:4)ASTC 4×4 High (1:4)RMSE2,31606,29945,96865,3637<p></p><h3>Производительность PVRIC4 (Pixel 10)</h3><p></p>Метод409620481024512256Uncompressed2 2992 6292 6431 9091 178PVRIC4 4 bpc2 5822 9723 8512 8771 102Spark ASTC Q03 3273 5093 0972 051911Spark ASTC Q23 0022 7592 4981 485634<p></p><p>Кривая пропускной способности на этом устройстве существенно отличается от Pixel 8: пик приходится на размеры 1024–2048, а не монотонно возрастает с размером. На больших размерах пропускная способность Spark фактически выше, чем у несжатых загрузок текстур. Это характерно для устройств, ограниченных пропускной способностью памяти: обычный блит должен прочитать всё входное изображение и записать обратно тот же объём данных, тогда как Spark записывает лишь 1/4 входных данных. Экономия на записи зачастую перекрывает вычислительные затраты кодирования.</p><p><b>Комментарий PowerVR Dev (ImgTec)</b><br />PVRIC4 поддерживает только сжатие 1:2. TFBC (доступен исключительно в чипах Rogue XE) поддерживал соотношения 1:2, 1:4 и 1:3. Дизайн расширения был спорным — многим не нравилась многословность выбора BPC, поэтому было решено экспонировать все BPC в рамках поддерживаемых соотношений и повышать их до поддерживаемого ratio. Это считалось допустимым, поскольку качество не деградирует относительно запроса приложения, а приложение всё равно обязано запрашивать реальный размер изображения, который не гарантирует уменьшения.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-03-30/34deaeec-ec94-4d39-9a82-dd707dcf71a6.webp" alt="Сравнение Spark ASTC с дизерингом и без. Программный Spark показывает хорошие результаты, но AFRC его превосходит" /><figcaption>Сравнение Spark ASTC с дизерингом и без. Программный Spark показывает хорошие результаты, но AFRC его превосходит</figcaption></figure><h2>Spark: программная точка отсчёта</h2><p><a href="https://github.com/NVIDIA/Spark">Spark</a> — библиотека NVIDIA для программного сжатия текстур в реальном времени. Работает на GPU как compute shader, поддерживает форматы BC1–BC7 и ASTC. В тесте выступает базовой точкой сравнения как лучшее доступное программное сжатие без специализированного железа.</p><p>Spark показывает стабильные результаты по форматам, но требует явного вызова compute-прохода — это дополнительный этап в пайплайне. Аппаратное сжатие, напротив, встроено в рендеринг и не требует дополнительного кода. Отдельный плюс Spark — предсказуемое и согласованное поведение на всех устройствах, что важно, если унифицированный вывод критичен для вашего сценария. Ни один из форматов аппаратного сжатия пока не доступен через WebGPU — если это изменится, расширить spark.js для их поддержки будет несложно.</p><h2>Итоги: кто победил</h2><p>ARM AFRC — явный победитель. Это не только превосходит программные реализации вроде Spark, но и обходит все остальные форматы по всем метрикам. Итоговая таблица RMSE по всем протестированным форматам:</p><p></p>ФорматRMSE 1:2RMSE 1:4R8 Metal Lossy1,8579—<b>R8 AFRC</b><b>1,4937</b>—R8 PVRIC43,4346—Spark BC41,7149—RG8 Metal Lossy3,1757—<b>RG8 AFRC</b><b>2,2079</b>—RG8 PVRIC45,4392—Spark BC53,0442—RGBA8 Metal Lossy1,4947—<b>RGBA8 AFRC</b><b>0,6679</b><b>3,4184</b>RGBA8 PVRIC42,3160—Spark BC7—4,2136<p></p><p>Стоит оговориться: результаты PVRIC4 могут не отражать полного потенциала железа — драйвер игнорирует запрошенный коэффициент сжатия и всегда использует 1:2. Возможно, эти результаты удастся пересмотреть после исправления проблемы.</p><p>Аппаратное сжатие — убедительная альтернатива программному. Главная оговорка — оно сейчас ограничено современными топовыми устройствами, которые как раз и располагают наибольшим объёмом памяти и пропускной способностью.</p><p>Даже когда нативное аппаратное сжатие доступно, есть веские причины продолжать использовать Spark. Вывод аппаратного сжатия различается у разных вендоров, и в некоторых случаях — как мы видели с PVRIC4 — качество уступает кодировщику реального времени. Если для вашего сценария критичен единообразный и предсказуемый вывод на всех вендорах, Spark остаётся правильным выбором.</p>]]></content:encoded>
    </item>
    <item>
      <title>ТОП-15 алгоритмов, которые реально нужны на бэкенде</title>
      <link>https://tproger.ru/articles/top-10-algoritmov--kotorye-realno-nuzhny-na-bekende</link>
      <comments>https://tproger.ru/articles/top-10-algoritmov--kotorye-realno-nuzhny-na-bekende?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Ксения Андреева]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/top-10-algoritmov--kotorye-realno-nuzhny-na-bekende</guid>
      <description><![CDATA[<p>Узнайте о 10 ключевых алгоритмах, которые реально используются в бэкенд-разработке: от хеширования до алгоритма Дейкстры и балансировки нагрузки и поиска. Простые объяснения и практические примеры.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/top-10-algoritmov--kotorye-realno-nuzhny-na-bekende">ТОП-15 алгоритмов, которые реально нужны на бэкенде</a>»</p>]]></description>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[Графы]]></category>
      <category><![CDATA[Алгоритмы сжатия]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 21 Feb 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Алгоритмы — не просто абстрактная теория из учебников, а основа работы любого бэкенда. От поиска данных до оптимизации загрузки — правильный выбор алгоритмов делает систему быстрой, надёжной и масштабируемой. В этой статье — десятка действительно полезных алгоритмов, без которых не обходится ни один серьёзный сервер.</p><h2>Алгоритмы поиска</h2><h3>Бинарный поиск: быстрое нахождение элемента в отсортированном массиве</h3><p>Бинарный поиск — один из самых быстрых способов файндинга элемента массива в backend разработке. Если в линейном поиске все проверяется поэтапно, то в бинарном количество проверок уменьшается за счёт «располовинивания» массива на каждом этапе поиска.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/3aacbddb-c0a2-4145-8a1b-2c267c38b325.png" alt="" /></figure><p>Как работает бинарный поиск:</p><ol><li>Устанавливаются индексы начала и конца массива;</li><li>Находится индекс среднего элемента;</li><li>Если средний элемент равен значению, поиск завершается;</li><li>Если элемент меньше среднего, поиск продолжается в левой половине массива, а если больше — в правой;</li><li>И так до тех пор, пока не будет найден элемент.</li></ol><p>Бинарный поиск имеет сложность O(log n). Это означает, что сложность растёт логарифмически.</p><h3>Поиск подстроки: алгоритмы KMP и Rabin-Karp</h3><p>Поиск текста внутри текста нужен, например, в обработке данных логов.</p><p>Алгоритм Кнута-Морриса-Пратта (KMP) был создан для поиска подстрок с предварительной обработкой шаблона.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/1c794604-0117-41dd-b8e7-cc8d3727d78d.png" alt="" /></figure><ul><li>Сначала создаётся таблица префиксов, которая выявляет сдвиги шаблона при несовпадении;</li><li>А затем эта же таблица используется для увеличения количества позиций сдвига во время поиска подстроки в тексте.</li></ul><p>Алгоритм KMP имеет сложность O(n + m), где n — длина текста, m — длина шаблона. А значит, сложность растёт линейно, в зависимости от длины текста и длины шаблона.</p><p>Алгоритм Рабина-Карпа создан для поиска подстроки через хеширование.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/c28458e9-aac2-42f9-91da-baa1b2ea73c9.png" alt="" /></figure><ul><li>Сначала определяются хеш-коды для шаблона и для каждой подстроки текста той же длины;</li><li>Далее хеши сравниваются. При их совпадении проводится дополнительное сравнение символов;</li><li>В конечном итоге хеш-код обновляется при переходе к следующей позиции текста.</li></ul><p>Рабин-Карп нужен, если у вас есть много шаблонов для поиска одновременно — здесь работает параллельное вычисление.</p><h2>Алгоритмы сортировки</h2><p>Алгоритмы сортировки помогают в оптимизации данных в backendе. Они снижают время обработки массивов данных. А это особенно важно при высоких нагрузках и больших объёмах информации.</p><h3>Quicksort и Merge Sort: эффективная сортировка больших массивов</h3><p>Quicksort разделяет массив на подмассивы с помощью опорного элемента.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/5665f84f-ad46-4e01-8d20-53c68aa3f062.png" alt="" /></figure><p>Алгоритм имеет среднюю сложность O(n log n). Время выполнения алгоритма растёт быстрее, чем линейно, но медленнее, чем квадратично:</p><ol><li>Сначала выбирается элемент массива: средний, случайный, первый или последний;</li><li>Все элементы меньше опорного перемещаются влево от него, а больше — вправо;</li><li>И всё то же самое повторяется с подмассивами.</li></ol><p>Quicksort подходит для работы в оперативной памяти, но нужно правильно определять опорный элемент. Для этого используются случайный подбор опорного элемента или метод медианы из трёх значений (сумма трёх значений за вычетом минимального и максимального).</p><p>Медиана — значение, которое будет совпадать с серединой данных, а если нужно определить ее из чётных чисел, то считается среднее из двух.</p><p><b>Merge Sort </b>имеет среднюю сложность O(n log n) во всех случаях.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/5e41a64e-10d1-49a9-ac4d-008deac1697e.png" alt="" /></figure><p>Он объединяет отсортированные подмассивы в один полностью отсортированный массив:</p><ol><li>Массив делится пополам каждый раз, пока не останутся отдельные элементы;</li><li>И в конце концов подмассивы «собираются» снова, но уже в отсортированном виде.</li></ol><p>Merge Sort весит больше, чем Quicksort. Зато он более стабилен и подойдёт для обработки больших файлов или для поток данных.</p><h3>Heap Sort: сортировка для работы с приоритетами</h3><p><b>Heap Sort</b> — алгоритм сортировки двоичной кучи (структуры данных), где каждый раз минимальное значение находится и помещается в начало списка. Процедура повторяется каждый раз, пока структура не будет полностью отсортирована.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/8d9cc5b8-e423-4823-a5db-d7c5392caa28.png" alt="" /></figure><p>Хорош этот алгоритм тем, что подойдёт для сортировки данных по приоритету для создания частичных выборок:</p><ol><li>Сначала массив преобразуется в двоичную кучу;</li><li>Затем для max-heap выделяется максимальный элемент и заменяется следующим, более «низким»;</li><li>Далее создаётся правильный порядок с помощью функции maxHeapify() или heapify();</li><li>Процесс повторяется до тех пор, пока не будет сформирован правильный порядок для всех элементов.</li></ol><p>Heap Sort имеет сложность O(n log n) — она растёт быстрее, чем линейно, но медленнее, чем квадратично. Для метода не нужна дополнительная память для хранения промежуточных результатов.</p><h2>Работа с графами</h2><p>Мы когда-то упоминали в <a href="https://tproger.ru/articles/chto-takoe-grafy-i-kak-ih-primenjat-v-analitike">этой статье</a>, графы используются для аналитики данных в backend-разработке. С помощью них определяется связь элементов друг с другом. Графы состоят из вершин, рёбер и весов, связей между рёбрами и вершинами.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/f419e12f-07b7-4183-873c-c1223189abca.png" alt="" /></figure><h3>Алгоритм Дейкстры: нахождение кратчайшего пути</h3><p><b>Алгоритм Дейкстры</b> используется для нахождения самого короткого пути от одной вершины ко всем остальным. Этот алгоритм работает в системах навигации и приложениях, где нужно подобрать самый оптимальный маршрут между двумя элементами. А ещё алгоритм Дейкстры используется, например, для определения поведения NPS в играх или чтобы понять, как будет двигаться робот в определённой местности.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/1e8b563a-782d-4be5-80f4-2769b58e19a6.png" alt="" /></figure><ol><li>Сначала определяется главная вершина. Расстояние до неё, при этом, равно нулю, а до всех остальных вершин задаётся вручную (ну или определяется автоматически).</li><li>И далее алгоритм идёт от соседней (относительно начальной) вершины до следующей. И так, пока цель не будет достигнута.</li></ol><p>Алгоритм Дейкстры имеет сложность O(V²), то есть, растёт квадратично. Сложность может уменьшиться до O(E log V) при работе с очередями приоритетности.</p><h3>Алгоритм Флойда-Уоршелла: нахождение всех кратчайших путей</h3><p>Если смысл Дейкстры в том, чтобы искать наиболее короткий путь от начальной вершины к остальным, то смысл алгоритма Флойда-Уоршелла в том, чтобы находить самый короткий путь между всеми вершинами.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/b220f7fc-57a1-4a6f-8c56-6bad1142cd42.png" alt="" /></figure><ol><li>Сначала создаётся матрица расстояний, где каждая ячейка [i][j] содержит вес ребра (i,j) или бесконечность, если ребра нет;</li><li>Для каждого узла проверяется возможности оптимизации пути между двумя другими узлами;</li><li>Далее матрица расстояний обновляется и ранжируется по самым коротким путям.</li></ol><p><b>Алгоритм Флойда-Уоршелла</b> имеет сложность O(V³), то есть, растёт кубически, и подходит для анализа связей между вершинами.</p><h3>Алгоритмы хеширования</h3><p><b>Хеш-функция</b> — алгоритм, который принимает обычный текст и преобразовывает его в хешированный размером в 128 бит. Хеширование используется в backend разработке, например, при создании ключей шифрования исходя из пароля.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/d53e40d8-b81b-4b68-afc9-482e34aea450.png" alt="" /></figure><p>К плюсам хеширования можно отнести то, что один текст имеет строго один хешированный «вариант», а оригинальный текст не получится восстановить только с помощью хеша.</p><p><b>MD5 </b>(алгоритм дайджеста сообщений 5) — самая популярная хеш-функция. Она используется для проверки целостности данных.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/65004206-f236-474c-a508-534635ab9b35.png" alt="" /></figure><p>Раньше считалось, что два разных фрагмента не могут дать один и тот же MD5 хеш. Но система была взломана: <a href="https://www.mscs.dal.ca/~selinger/md5collision/">в 2005 году</a> китайские криптологи опубликовали статью с описанием алгоритма, который помогает найти 2 разные последовательности, но с одним MD5 хешем.</p><p><b>SHA</b> — сразу несколько версий алгоритма (SHA-1, SHA-256, SHA-512). Сейчас распространены SHA-256 и SHA-512 с выходом дайджеста сообщений в 256 и 512 бит соответственно.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/2ca23ec2-d9df-49d6-af17-9a14650f10a1.png" alt="" /></figure><p>SHA используется для создания цифровых подписей и сертификатов безопасности — всё благодаря устойчивости алгоритма к «коллизиям» (иными словами, взломам) и постоянным обновлениям.</p><p><b>CRC32</b> (циклический избыточный код)<b> </b>— ещё одна хеш-функция для проверки целостности данных. CRC нельзя использовать для защиты данных от атак, поскольку ее основная задача — быстро обнаружить изменения данных при передаче или хранении.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/dd0259dc-85f5-43cc-9a3d-9b8cc21d1466.png" alt="" /></figure><p>CRC32 подходит для работы с сетевыми протоколами и для базового обеспечения целостности данных.</p><h2>Работа с деревьями</h2><p>Работа с <a href="https://tproger.ru/translations/binary-search-tree-for-beginners">деревьями</a> — основа backend разработки. С помощью нее можно эффективно и правильно организовывать и хранить данные.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/d61be107-536a-4443-ba93-df3406e7eacf.png" alt="" /></figure><h3>Алгоритм обхода деревьев (DFS, BFS)</h3><p>Обход деревьев, если коротко, нужен для того, чтобы обработать каждый узел в своём порядке. Есть 2 главных способа обхода: поиск в глубину (Depth-First Search, DFS) и поиск в ширину (Breadth-First Search, BFS).</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/0b71e14e-cdef-4b83-b721-29e613213929.png" alt="" /></figure><p><b>Принцип поиска в глубину (DFS)</b> — сначала анализируются все «вторичные» (ну или дочерние) узлы одного поддерева, а потом следующее поддерево. DFS полезен для того, чтобы сначала проанализировать все узлы, а потом уже искать элементы с определённым условием.</p><p><b>Принцип поиска в ширину (BFS)</b> — здесь анализируются все узлы на текущем уровне дерева, а уже потом осуществляется переход к следующему уровню. BFS подходит для нахождения кратчайшего маршрута в неглубоких структурах.</p><h3>Балансировка деревьев (AVL, красно-чёрное дерево)</h3><p>Без балансировки вставка и поиск могут занимать ну очень много времени из-за огромной глубины дерева данных.</p><p><b>AVL-деревья</b> — двоичное дерево поиска с быстрым доступом к данным. При каждом добавлении или удалении элемента дерево автоматически балансируется. А это означает, что сложность операций всегда будет равна O(log n).</p><p><b>Красно-чёрные деревья </b>менее сбалансированы по сравнению с AVL, зато операции вставки и удаления проводятся быстрее (за счёт меньшего количества вращений дерева).</p><p>Глобально: разница между двумя этими подходами в том, что: путь от корня (основания) дерева AVL — не более ~1,44 lg(n+2), а путь от корная красно-чёрного дерева — не более ~2 lg(n+1). AVL-деревья быстрее ищут данные, но требуют больше времени на вставку и удаление. А красно-чёрные деревья более простые и стабильные в реализации из-за меньших требований к балансировке.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/83fbcc2d-94e4-4faa-b815-535ec3f58c14.png" alt="" /></figure><h2>Алгоритмы сжатия данных</h2><p>Алгоритмы сжатия данных нужны для обработки и передачи больших объёмов информации в backend разработке. А потому и нужна оптимизация.</p><h3>Huffman Coding: оптимизация хранения и передачи данных</h3><p><b>Алгоритм Хаффмана</b> (Huffman Coding) — один из видов алгоритмов префиксного кодирования. С помощью него можно уменьшить размер данных, при этом, «выигрывая» как в скорости, так и в объёме.</p><p>Символы, которые появляются чаще всего, кодируются более короткими последовательностями, а символы, встречающиеся реже, имеют более длинную последовательность.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/80109697-d66e-445e-be21-d2105067bd4f.png" alt="" /></figure><p>Код Хаффмана — основа форматов сжатия по типу JPEG и MP3.</p><h3>LZ77/LZ78: алгоритмы для компрессии больших объёмов данных</h3><p>Алгоритмы семейства Lempel-Ziv — база современных методов сжатия без потерь качества и производительности. С помощью них большие по объёму данные сжимаются за счёт поиска повторяющихся последовательностей внутри массива.</p><p><b>Принцип работы LZ77</b> — второе и последующее совпадение данных ссылается на самое первое совпадение.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/2136cb98-6fc3-41b1-bb43-c5c643259680.png" alt="" /></figure><p><b>Принцип работы LZ78</b> — создание динамического словаря «фраз» по мере обработки данных. В процессе добавляются новые комбинации символов («фразы») по мере их обнаружения.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/eece1565-5093-4af1-9c0b-3a0450799eda.jpg" alt="" /></figure><p>На этих алгоритмах строится форматы архивирования файлов по типу ZIP и GZIP.</p><h2>Жадные алгоритмы</h2><p>Жадные алгоритмы — класс алгоритмов, внутри которых данные принимаются локально. «Жадными» они названы потому, что требуется найти самый оптимальный способ решения с минимальными затратами в backend-разработке.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/5104f87d-5821-4740-9e67-91babfa35e56.png" alt="" /></figure><h3>Алгоритмы «наиболее подходящего выбора»: оптимизация решений</h3><p>Фишка жадных алгоритмов в том, что каждый шаг локально выбирается лучшим. При этом финальный результат не может быть самым оптимальным. Поэтому важно внимательно анализировать условия задачи.</p><p><b>Задача о рюкзаке</b> — здесь вам нужно выбрать максимальное количество предметов (рёбер) по большей стоимости (ценности) без превышения вместимости (веса) рюкзака (контейнера). В жадном подходе все предметы сортируются по стоимости за единицу веса и добавляются в рюкзак в порядке убывания.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/1487ddf3-b5e0-4801-8c1d-c201ecac1636.jpg" alt="" /></figure><p><b>Минимальное остовное дерево через алгоритм Прима.</b> Здесь поэтапно выбирается ребро с минимальным весом, которое соединяет уже включенные вершины с остальными.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/a97b0cd2-2501-438a-9fe4-a853a1fb8ee6.png" alt="" /></figure><p><b>Алгоритм Дейкстры</b> мы уже разбирали выше. Если коротко: он используется для поиска кратчайшего пути от одной вершины графа до всех остальных. Основывается на выборе наименьшей стоимости пути из всех доступных на каждом шаге.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/a4c2a039-9918-4f46-be07-9fba63f9cfd5.jpg" alt="" /></figure><h2>Динамическое программирование</h2><p>С помощью динамического программирования решаются задачи оптимизации в backend-разработке. Происходит разбивка одной большой задачи на более простые. При этом, используется информация об уже проведённых вычислениях, чтобы не было повторов.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/e6f71da7-916b-4065-8116-155021cb9319.png" alt="" /></figure><h3>Алгоритм поиска подстроки (Longest Common Subsequence): анализ строк</h3><p>Грубо говоря, этот алгоритм помогает найти определённый повторяющийся сценарий в тексте. Если строка содержит этот паттерн, то вы получаете ответ «да» или прямую ссылку, где этот паттерн впервые был представлен. Это в целом основной принцип криптографии, архивирования и компиляции.</p><p>Алгоритм имеет сложность O(n*m), где n и m — длины сравниваемых между собой строк. При этом, таблица с выводами заполняется последовательно, по мере нахождения паттернов.</p><h2>Алгоритмы для работы с потоками данных</h2><p>Для обработки данных в backend в режиме реального времени используются специальные алгоритмы: <b>Sliding Window и Bloom Filter</b> — с максимальной итоговой производительностью.</p><h3>Sliding Window: обработка данных в реальном времени</h3><p><b>Алгоритм скользящего окна</b> используется для обработки непрерывного потока данных. Данные здесь разбиваются на небольшие окна определённой длины. Даже при самых высоких нагрузках и минимальном времени, весь поток хранить не нужно — и всё это благодаря скользящему окну.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/bc15a23a-2f50-43cd-a77e-3a71079f06fb.png" alt="" /></figure><p>Со скользящим окном можно работать при мониторинге трафика или отслеживании активности пользователей. При этом, всю историю наблюдений загружать не нужно — анализируются данные только конкретного окна.</p><h3>Bloom Filter: проверка существования элемента в наборе</h3><p><b>Фильтр Блума</b> — структура данных, которая используется для того, чтобы проверить, принадлежит ли конкретный элемент конкретному массиву данных.</p><figure><img src="https://media.tproger.ru/user-uploads/106063/2025-02-03/85d63420-3fb5-4204-9524-6af32af967e7.jpg" alt="" /></figure><p>Фильтр Блума занимает гораздо меньше места в сравнении с обычными структурами данных. С помощью него можно быстро проверить существование элемента через использование нескольких хеш-функций. По такому же принципу работает спам-фильтр в почтовом клиенте.</p><p>Все перечисленные и описанные выше алгоритмы критически важны для реализации практически любых задач backend’а. Как правило, их не нужно реализовывать с нуля, но нужно понимать принцип работы каждого. Потому что именно от сложности зависит время, которое тратится на решение конкретной задачи.</p>]]></content:encoded>
    </item>
    <item>
      <title>Методы сжатия данных: алгоритмы и инструменты</title>
      <link>https://tproger.ru/articles/metody-szhatiya-dannyh--algoritmy-i-instrumenty-251908</link>
      <comments>https://tproger.ru/articles/metody-szhatiya-dannyh--algoritmy-i-instrumenty-251908?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Владислав Устинов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/metody-szhatiya-dannyh--algoritmy-i-instrumenty-251908</guid>
      <description><![CDATA[<p>Методы сжатия данных. Показываем, какие есть алгоритмы и инструменты. Рассматриваем реальные примеры и кейсы ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/metody-szhatiya-dannyh--algoritmy-i-instrumenty-251908">Методы сжатия данных: алгоритмы и инструменты</a>»</p>]]></description>
      <category><![CDATA[Алгоритмы сжатия]]></category>
      <category><![CDATA[Алгоритмы и структуры данных]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 18 Sep 2024 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Классификация методов сжатия данных</h2><p>Наверняка вы сталкивались с zip–архивами, сохраняли фото в jpeg или смотрели видео в 144p — всё это примеры сжатых данных. Когда мы говорим о сжатии (компрессии), то имеем в виду уменьшение исходного размера без потери содержимого. Так можно хранить больше информации, быстрее её передавать и считывать.</p><p>Методы сжатия данных принято делить на 2 категории: с потерей и без потери. Рассмотрим их подробнее.</p><h3>Сжатие с потерями (lossy)</h3><p>При сжатии данных с потерями мы безвозвратно удаляем часть информации. Но делаем это так, чтобы не потерять общую суть.</p><p>Например, надо сжать картинку для сайта, чтобы он быстрее прогружался. Ниже два варианта одного изображения. Один исходник, второй сжатый. Как думаете — какой где?</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/3b566655-b869-40b1-9e31-bc07cb391d37.png" alt="Методы сжатия данных" /><figcaption>Вариант 1</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/2c77669c-fc49-4448-877e-5afcfa0fdc02.png" alt="Алгоритмы и инструменты сжатия" /><figcaption>Вариант 2</figcaption></figure><p>По идее исходник должен уступать оригиналу в визуальном плане, однако разницы между этими изображениями практически не видно.</p><p>Оригинал — первое изображение в формате png. Второе — сжатый вариант в формате jpeg.</p><p>Казалось бы, вариант 2 должен был потерять качество, и это произошло. При компрессии были удалены некоторые похожие оттенки цветов и лишние детали, а размер файла уменьшился с 2.38МБ до 145 КБ. При этом визуально он все еще выглядит неплохо.</p><p>То же самое происходит и при работе с аудио и видео. В файле могут содержаться звуки, которые не воспринимает человеческое ухо, статичные элементы, которые не изменяются от кадра к кадру. Всё это излишки, которые можно отбросить без потери смысла.</p><h3>Сжатие данных без потерь (lossless)</h3><p>При методах сжатия без потерь мы не удаляем лишние данные, а стараемся упаковать их более компактно.</p><p>Допустим, нам нужно составить список покупок. Мы можем записать его так:</p><p>Однако некоторые продукты повторяются здесь несколько раз, поэтому эту запись можно сделать более компактной вот так:</p><h2>Популярные алгоритмы сжатия данных без потерь</h2><p>Давайте рассмотрим три наиболее распространенных метода сжатия без потерь.</p><h3>Huffman coding</h3><p>Метод Хаффмана позволяет нам компактно закодировать данные при помощи манипуляций с частотой объектов и выстраивания дерева. А еще его включают в себя многие другие алгоритмы и форматы сжатия.</p><p>Рассмотрим пошагово кодирование Хаффмана на примере сжатия слова: «compression».</p><h4>Шаг 1 — строим таблицу частотности</h4><p>Определяем, сколько раз тот или иной символ встречался в тексте. Записываем символы в таблицу в порядке убывания. Под ними указываем частоту.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/4261ae8b-a6f4-4c6f-a9a0-3f8228e014fd.png" alt="Методы сжатия данных" /><figcaption>Частота символов в тексте</figcaption></figure><h4>Шаг 2 — строим дерево</h4><p>Записываем символы как листья дерева. Их частотность будет весом.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/5556973a-367f-4c99-b652-757fbdd757e4.png" alt="Алгоритмы и инструменты сжатия" /><figcaption>Символы как листья</figcaption></figure><p>Находим два крайних правых листа и строим над ними новый. Записываем в него символы и сумму их частот.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/373a9ffe-c82f-4793-98f3-e158070ed1f0.png" alt="Методы сжатия данных" /><figcaption>Формирование нового листа «in»</figcaption></figure><p>Мы создали лист «in» с весом 2. Формируем листы дальше.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/5336b2d9-e436-4eec-8121-c184db207d57.png" alt="Алгоритмы и инструменты сжатия" /><figcaption>Формирование нового листа «ein»</figcaption></figure><p>Теперь мы построили лист «ein» с весом 3 из «in» и «e». Продолжаем до тех пор, пока не создадим последний лист.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/de080d1d-22fd-461b-b746-a5e5bbe9c491.png" alt="Методы сжатия данных" /><figcaption>Итоговое дерево</figcaption></figure><h4>Шаг 3 — кодируем текст</h4><p>Мы закончили строить дерево. Теперь можно приступить к кодированию знаков.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/0fff8763-d67c-4e02-ba9f-4f022d68a716.png" alt="Алгоритмы и инструменты сжатия" /><figcaption>Коды дерева</figcaption></figure><p>Вершина «oscmprein» является корнем нашего дерева, так как обладает наибольшим весом — 11.</p><p>Каждая линия означает один бит. Для линий справа это единица, слева — ноль. Теперь при помощи битов линий мы кодируем каждый символ. Для этого необходимо представить путь от корня до нужного знака. Сочетание битов линий на пути будет нашим кодом.</p><p>Например, между «o» и корнем «oscmprein» есть только одно ребро, которое равно нулю. Следовательно, «o» это 0. От корня до «s» ведут две линии: один и ноль. Значит, код будет 10. И так до узла «n», код которого 11111111.</p><p>В итоге получим следующую кодировку символов:</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/8f0870f6-319e-4fd3-949d-f8aab4ecf1d9.png" alt="Методы сжатия данных" /><figcaption>Итоговый код Хаффмана</figcaption></figure><p>В изначальном варианте «compression» весит 88 бит, но благодаря методу Хаффмана мы сжали его до 48 бит.</p><h3>Lempel-Ziv-Welch (LZW)</h3><p>Метод Лемпеля создает словарь, где кодирует символы, слова и сочетания слов. Давайте рассмотрим принцип работы данного алгоритма на примере текста: «The big big big cat sat on the mat mat mat. The big big cat ate the fat fat rat. The cat cat cat sat sat sat.»</p><h4>Шаг 1 — создаем словарь</h4><p>Начнем с создания словаря, содержащего все возможные одиночные символы и их коды. В нашем случае мы будем использовать ASCII-коды для простоты:</p><h4>Шаг 2 — сжимаем текст и расширяем словарь</h4><p>Теперь будем читать каждый символ из фразы. Если он уже есть в словаре, то считаем комбинацию символов:</p><ul><li>Читаем «T». Проверяем его в словаре. Записываем код (84).</li><li>Проверяем его сочетание со следующим символом. «Th» нет в словаре.</li><li>Присваиваем для «Th» код 256.</li><li>Читаем «h». Есть в словаре, пишем код (104).</li><li>Проверяем «he». Этого сочетания нет в словаре.</li><li>Присваиваем код 257.</li></ul><p>Продолжаем этот процесс для всей фразы. Как только данный метод наткнется на комбинацию знаков, которая уже есть в словаре, он заменит её кодом. Не каждый знак по отдельности, а всё сочетание.</p><p>Например, слово «big» повторяется пять раз. Первое повторение мы закодируем по коду символов «b», «i», «g»: 98 105 103.</p><p>Так как в словаре нет сочетаний «bi» и «ig», присвоим им новые коды и добавим в словарь:</p><p>При следующем повторении мы закодируем «big» как 260 261, а не 98 105 103.</p><p>В итоге получим вот такой код:</p><p>Исходная фраза весила 73 байта, но мы сжали её до 53 байт.</p><h3>Deflate</h3><p>На самом деле с этим алгоритмом мы уже сталкивались. Ну, почти. Он основан на двух методах сжатия без потерь: LZ77 и коде Хаффмана. LZ77 — более старая версия LZW. Они отличаются только тем, что LZ77 не создает словарь с кодами — вместо этого он использует ссылки. Для примера возьмем текст: «The big big big cat sat on the mat mat mat».</p><h4>Шаг 1 — определяем повторяющиеся подстроки</h4><p>Это будут:</p><ul><li>big;</li><li>cat;</li><li>mat.</li></ul><h4>Шаг 2 — создаем ссылки</h4><p>Ссылки записываем в следующем формате:</p><p>Например, буква «b» в слове «big» является пятым по порядку символом, если смотреть относительно всего текста. При счете с нуля её индекс — 4. Слово состоит из трех букв. Поэтому наша ссылка выглядит так:</p><p>Аналогично с cat (16,3) и mat (31,3).</p><h4>Шаг 3 — сжимаем текст</h4><p>Последовательно записываем наш текст, заменяя повторения ссылками:</p><h4>Шаг 4 — применяем метод Хаффмана</h4><p>Далее в дело вступает сжатие данных методом Хаффмана. По вышеописанному принципу мы разбиваем этот код на отдельные знаки, ранжируем их по частотности, строим дерево и кодируем каждый символ.</p><h2>Алгоритмы сжатия с потерями</h2><h3>JPEG (для изображений)</h3><p>Сжатие данных исходного изображения в jpeg происходит в четыре этапа.</p><h4>Этап 1 — переводим в цветовое пространство YCbCr</h4><p>YCbCr — цветовой профиль, который условно можно представить как три маски.</p><p>Y — чёрно-белая картинка, которая демонстрирует уровень яркости.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/89736c5c-70c3-4a11-96c0-646d185f0ea8.png" alt="Методы сжатия данных" /><figcaption>Y-канал</figcaption></figure><p>Cb — синий канал.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/08b8722d-bc22-436a-92b4-f52c5254229b.png" alt="Алгоритмы и инструменты сжатия" /><figcaption>Cb-канал</figcaption></figure><p>Cr — красный канал.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/2afcbe1b-917a-4868-8064-599a24954fc4.png" alt="Методы сжатия данных" /><figcaption>Cr-канал</figcaption></figure><p>Так мы сможем отделить цвета от яркости.</p><p>Если что, отсутствие синих и красных оттенков нормально, потому что каналы Cb и Cr не представляют напрямую синий и красный цвета. Они показывают отклонения от нейтрального серого в сторону сине-желтого (Cb) и красно-зеленого (Cr) спектров.</p><h4>Этап 2 — Дискретное косинусное преобразование (DCT)</h4><p>На этом этапе нужно понять, как много деталей содержится в разных частях изображения. Для этого делим картинку на блоки 8 на 8 пикселей. Далее раскладываем каждый блок на паттерны при помощи дискретного косинусного преобразования. Паттерны  — это пространственные волны, которые мы можем представить в виде 64 картинок.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/3f7995d8-3602-402f-b4cd-0a3051a8a2bd.png" alt="Алгоритмы и инструменты сжатия" /><figcaption>64 паттерна</figcaption></figure><p>Комбинируя их, можно повторить любое изображение 8x8 пикселей.</p><p>У каждого паттерна есть свой вес, который можно менять — его называют коэффициентом. DCT определяет, на какие паттерны с какими коэффициентами можно разложить блок.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/b6754156-1a82-48c7-ad65-4b40b95c182c.jpg" alt="Методы сжатия данных" /><figcaption>Пример коэффициентов блока</figcaption></figure><h4>Этап 3 — Квантование</h4><p>Есть объекты, которые человеческий глаз не видит, либо почти не видит, поэтому некоторые детали на фото не нужны. Найти их помогает таблица квантования. В ней прописаны значения коэффициентов, по которым становится понятно, важны детали на блоке или нет. При помощи этих значений мы округляем коэффициенты паттернов до целых чисел. Если они близки или равны нулю, то содержат минимум важных деталей. Последовательности нулей удаляем, и вместо них записываем в скобках один ноль и число его повторений.</p><h4>Этап 4 — сжатие Хаффмана</h4><p>Да-да. Здесь опять вступает в игру метод сжатия Хаффмана, который сжимает нашу последовательность еще сильнее.</p><h3>MP3 и ACC (для аудио)</h3><p>MP3 и ACC — это два формата компрессии аудио с потерями. Сжатие в них работает аналогично сжатию в jpeg.</p><h4>Этап 1 — раскладываем звук на волны</h4><p>Мы раскладываем звук на несколько кусочков — фреймов. Эти фреймы разделяем на волны.</p><h4>Этап 2 — находим у волн лишние частоты</h4><p>У каждой волны есть своя частота. Некоторые частоты человек не воспринимает, поэтому MP3 использует психоакустическую модель. Она удаляет такие частоты, а еще заменяет похожие волны одной.</p><p>ACC использует более свежую и, потому, совершенную версию психоакустической модели, благодаря чему точнее определяет излишние частоты.</p><h4>Этап 3 — округляем коэффициенты частот</h4><p>Далее начинается квантование. Мы округляем коэффициенты частот. Те, что слышим хуже, получают меньше битов, и наоборот.</p><p>Если последовательность частот равна нулю, то удаляем нули и заменяем их записью по типу:</p><p>(0, количество повторений). Точно как с jpeg.</p><h4>Этап 4 — пропускаем через алгоритм Хаффмана</h4><p>В конце получаем последовательность битов, которые означают коэффициенты частот. Проводим сжатие данных алгоритмом Хаффмана.</p><h3>H.264 и HEVC (для видео)</h3><p>H.264 и HEVC — это стандарты видео сжатия. Еще их называют кодеки. Вот основные этапы сжатия видео:</p><h4>Этап 1 — разбиение на кадры и блоки</h4><p>Разбиваем видео на кадры. Каждый кадр раскладываем на блоки:</p><ul><li>16x16 пикселей в H264.</li><li>64x64 в HEVC (H.265).</li></ul><p>Благодаря этим небольшим блокам мы можем отслеживать изменения в кадрах.</p><h4>Этап 2 — формируем I,P,B-кадры</h4><p>Далее мы сравниваем последовательности блоков кадров между собой. Если видим смещения, то создаем векторы, в которые записываем информацию о направлении смещений и их длине в пикселях.</p><p>Этим методом формируем три категории кадров:</p><ol><li>I-кадры (intra-coded frames) — это опорные кадры, которые кодируются без учета других кадров. Они содержат полную информацию о текущем изображении и служат отправной точкой для декодирования других кадров. Такие кадры наиболее «тяжелые» по объему, но необходимы для восстановления видео.</li><li>P-кадры (predictive frames) основываются на предыдущих I- или P-кадрах. В них кодируется только информация о различиях между текущим кадром и предыдущим, что значительно сокращает объем данных.<br /></li><li>B-кадры (bi-predictive frames) используют как предыдущие, так и последующие кадры для предсказания текущего кадра. Это делает их наиболее эффективно сжимаемыми, поскольку они могут использовать информацию из двух направлений — как вперед, так и назад. Однако их обработка требует больше вычислительных ресурсов.<br /></li></ol><p>P и B кадры — это не статичные изображения, а всего лишь информация о том, какая часть кадра изменилась, в каком направлении и как.</p><p>Представим последовательность кадров:</p><p>В I-кадре статичная картинка. В первом P-кадре мы повторяем предыдущий I-кадр и благодаря информации о смещении дорисовываем его часть. То же самое проделываем со вторым P-кадром относительно первого P-кадра.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-09-16/b2d0db25-ba46-4d6c-a544-f19cea7b0842.jpg" alt="Алгоритмы и инструменты сжатия" /><figcaption>Условный пример работы I,P-кадров</figcaption></figure><p>Таким образом, мы как бы изучаем все кадры, создаем болванку и дублируем её в следующих кадрах, дорисовывая некоторые фрагменты.</p><h4>Этап 3 — выводим коэффициенты</h4><p>Далее работаем с кадрами так же, как с jpeg. Прогоняем через дискретное косинусное преобразование и выводим коэффициенты деталей.</p><h4>Этап 4 — округляем, убираем излишки и кодируем по Хаффману</h4><p>Округляем их при помощи квантования, сокращаем коэффициенты близкие или равные нулю и используем метод сжатия Хаффмана.</p><h2>Инструменты для сжатия данных</h2><h3>ZIP и GZIP</h3><p>ZIP и GZIP — это утилиты для архивирования файлов. Они уменьшают размер данных без потери информации.</p><ul><li><b>ZIP</b> использует алгоритмы из метода  Deflate, который мы рассматривали выше. Преимущества ZIP в том, что он поддерживается практически на всех операционных системах и способен сжимать несколько файлов.</li><li><b>GZIP</b> используется на серверах для уменьшения объёма данных, передаваемых по сети. GZIP также основан на алгоритме Deflate, но в нем нет реализации методов сжатия многокомпонентных архивов. Это значит, что он не умеет сжимать несколько файлов.</li></ul><h3>FFmpeg</h3><p>FFmpeg — фреймворк, который применяется для сжатия, конвертации и обработки медиафайлов.</p><p>FFmpeg поддерживает широкий набор кодеков и форматов, включая H.264, H.265 для видео и AAC, MP3 для аудио.</p><p>Но его возможности не ограничиваются только сжатием. По сути, это движок с инструментами  для редактирования медиафайлов. Здесь мы можем сделать нарезку, применить фильтры, конвертировать в другие форматы и много чего еще.</p><h3>7-Zip</h3><p>7-Zip — бесплатная утилита для сжатия данных, которая поддерживает формат 7z, а еще там есть ZIP, RAR, и TAR.</p><p>Основное преимущество 7-Zip в его высоком уровне сжатия. Здесь применяется метод сжатия LZMA. Это модифицированная версия LZ77.</p><p>LZMA, так же как и LZ77, ищет повторяющиеся последовательности и заменяет их ссылками. Но еще он использует метод Маркова для предсказания вероятности появления символов.</p><p>7-Zip также поддерживает создание защищённых паролем архивов с шифрованием и работает на большинстве платформ, включая Windows и Linux.</p><h2>Преимущества и недостатки различных методов сжатия</h2><h3>Баланс между эффективностью сжатия, скоростью и качеством данных</h3><h4>Сжатие без потерь</h4><p>Лучше всего подходит для текстов, программного кода, баз данных и других типов данных, где принципиально важно сохранить всю информацию. При этом приходится мириться с ограниченным уровнем сжатия, особенно если мы используем данные, где мало повторяющихся элементов. Это может быть критично при работе с медиафайлами.</p><p>Поэтому методы сжатия данных без потерь лучше применять, когда сохранение качества данных важнее эффективности сжатия и скорости.</p><h4>Сжатие с потерями</h4><p>Позволяет достичь значительно большего уменьшения размера файлов за счёт удаления излишков данных, таких как мелкие детали изображения или неслышимые частоты в аудио.</p><p>Подходит только для данных, где не критично потерять часть информации. При этом стоит иметь в виду, что алгоритмы сжатия с потерями могут сильно убить качество, если использовать высокую степень сжатия.</p><p>Методы сжатия с потерями уместны когда для нас важнее скорость и компактность, чем изначальное качество.</p><h3>Как выбрать метод сжатия данных</h3><p>Выбор способа сжатия данных зависит от задачи.</p><h4>Для хранения архивов</h4><p>Zip, 7-zip или RAR-архивы станут отличными инструментами, если нам нужно просто сохранить набор файлов на компьютере.</p><p>Они умеют компрессировать сразу несколько файлов при помощи методов сжатия без потери данных.</p><h4>Для сжатия веб-сайтов</h4><p>Для оптимизации сайта подойдет формат gzip. Он умеет сжимать html и css без потерь, благодаря чему веб-страницы быстрее прогружаются.</p><h4>Для изображений</h4><p>Когда мы делаем снимки на смартфон для соцсетей, JPEG формат будет оптимальным выбором, поскольку сохраняет баланс между качеством и размером файла.</p><p>Но если мы увлекаемся профессиональной фотографией, то стоит выбрать RAW формат — он содержит максимум данных, которые нужны для обработки.</p><h4>Для видео</h4><p>Для любительской съемки и просмотра видео подойдет Кодек H264. Но если мы занимаемся видеопроизводством профессионально, то для редактирования нам подойдут форматы вроде ProRes. А финальную версию можно сохранить в H.265 (HEVC).</p><h4>Для аудио</h4><p>Чтобы послушать музыку на смартфоне или в машине, нам хватит MP3 или ACC формата. Но для аудиофилов и тех, кто занимается музыкой профессионально, подойдет формат без потери данных FLAC.</p><p><i>А с какими методами сжатия работаете вы? Расскажите в комментариях</i>👇</p>]]></content:encoded>
    </item>
    <item>
      <title>FLIF — новый формат сжатия изображений</title>
      <link>https://tproger.ru/news/free-lossless-image-format</link>
      <comments>https://tproger.ru/news/free-lossless-image-format?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Пётр Соковых]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/free-lossless-image-format</guid>
      <description><![CDATA[<p>Файлы FLIF медианно на 12% компактнее лучшего конкурента и на 19% в среднем с учётом 16-битных изображений, которые не поддерживают WebP и BPG.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/free-lossless-image-format">FLIF — новый формат сжатия изображений</a>»</p>]]></description>
      <category><![CDATA[Алгоритмы сжатия]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 08 Mar 2016 16:55:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Согласно <a href="https://docs.google.com/spreadsheets/d/1LxY78fbm47VmrYGTXkBXXitGjhGl32NsuHPH2QXufgA/edit#gid=751305882">результатам</a> исследований файлы FLIF в среднем занимают места меньше</p><ul><li>Чем <a href="https://developers.google.com/speed/webp/">WebP</a>: на 14%</li><li>Чем <a href="http://bellard.org/bpg/">BPG</a>: на 22%</li><li>Чем PNG с брутфорсом через ZopfliPNG: на 33%</li><li>Чем обычный PNG: на 43%</li><li>Чем PNG, оптимизированный через Adam7: 46%</li><li>Чем JPEG2000 без потерь: на 53%</li><li>Чем JPEG XR без потерь: на 74%</li></ul><p>Даже если из конкурентов FLIF выбирать наиболее подходящий для конкретной фотографии, он всё равно медианно эффективнее на 12 % (в среднем — на 19%, учитывая 16 битные изображения, которые не поддерживают WebP и BPG).</p><h2>Преимущества FLIF</h2><h3>Лучшее сжатие</h3><p>На графике ниже предоставлены результаты тестирования, аналогичного <a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results">тестированию WebP</a>. Вы можете видеть, что FLIF однозначно побеждает все другие инструменты, даже учитывая, что это ранняя версия — сейчас FLIF ещё эффективнее.</p><figure><img src="https://media.tproger.ru/uploads/2016/03/comparison-1024x1024.png" alt="" /></figure><h3>Работает с любыми типами изображений</h3><p>С FLIF вам не нужно будет больше думать о том, какой формат для изображения подойдёт лучше, потому что лучше гарантированно подойдёт FLIF ?</p><p>Графики говорят сами за себя:</p><figure><img src="https://media.tproger.ru/uploads/2016/03/photo.png" alt="На фотографиях отлично себя показывают JPEG, BPG и WebP, а вот PNG выглядит бледно" /><figcaption>На фотографиях отлично себя показывают JPEG, BPG и WebP, а вот PNG выглядит бледно</figcaption></figure><figure><img src="https://media.tproger.ru/uploads/2016/03/medical.png" alt="На медицинских снимках себя хорошо проявляют только BPG и JPG" /><figcaption>На медицинских снимках себя хорошо проявляют только BPG и JPG</figcaption></figure><figure><img src="https://media.tproger.ru/uploads/2016/03/maps-300x300.png" alt="" /></figure><p>Но в любом из трёх типов изображений FLIF на голову опережает конкурентов.</p><h3>Прогрессивная загрузка</h3><p>У формата FLIF отсутствуют потери и, как у других форматов без потерь, поддерживается прогрессивная загрузка. Поддерживается она, разумеется, лучше чем у остальных, убедитесь сами:</p><h3>FLIF — свободный формат</h3><p>FLIF распространяется под свободной лицензией LGPL. Это означает, что программа может распространяться асболютно свободно, а <a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BF%D0%B8%D0%BB%D0%B5%D1%84%D1%82">копилефт</a> распространяется только на саму программу, но не на её производные, т.е. этот формат можно будет использовать и в коммерческих продуктах.</p><p>Подробнее можете прочитать на <a href="http://flif.info">официальном сайте FLIF</a>.</p>]]></content:encoded>
    </item>
  </channel>
</rss>