Skip to content

HazeHash ​

Компактные плейсхолдеры изображений: картинка превращается в строку из 16–48 байт (по умолчанию 28, это 38 символов base64url), из которой за доли миллисекунды восстанавливается размытое превью. В строке также лежат соотношение сторон и, когда нужно, альфа-канал. Ядро работает в браузерах, Node.js и edge-окружениях, а поверх него есть компонент для Vue 3, модуль Nuxt и командная строка.

Возможности ​

  • Выше точность при том же размере — при 28 байтах средняя ошибка на 49% ниже, чем у BlurHash, и на 20% ниже, чем у ThumbHash; измерено на 513 фото, скриншотов и графических изображений, см. Бенчмарк
  • Бюджет в байтах вместо размера сетки — budget это максимальный размер хеша в байтах (16 для самого компактного, 28 по умолчанию, 36 и больше для детализации), и энкодер тратит его там, где картинке это нужно; простые изображения получаются меньше бюджета
  • Соотношение сторон и прозрачность внутри строки — заголовок хранит пропорции, так что рамку можно рассчитать до загрузки картинки, а блок альфа-канала добавляется только если у изображения есть прозрачные пиксели
  • Более удачная цветовая модель — цвет в OKLab, ортогональный базис DCT, отдельные сетки для яркости и цвета, квантование с оптимизацией «скорость–искажение» и кодирование Голомба–Райса; см. Формат хеша
  • Без зависимостей — ядро не трогает DOM, window и Buffer, поэтому работает в браузерах, Node.js 20+, Cloudflare Workers и других средах; для чтения файлов в Node.js нужна необязательная peer-зависимость sharp
  • Детерминированность и стабильность — один и тот же ввод и опции всегда дают одни и те же байты, а декодирование версии 1 не меняется между релизами, так что сохранённый хеш всегда декодируется одинаково
  • Точки входа, которые хорошо режутся при сборке — декодер весит около 2,6 КБ gzip, энкодер около 6,3 КБ, хелпер для canvas добавляет около 0,05 КБ, так что браузер скачивает только то, что импортирует
  • Устойчивость к обрезке — обрезанный хеш остаётся допустимым и декодируется с меньшей детализацией, а повреждённый никогда не вешает и не роняет декодер: он либо декодируется, либо бросает PlaceholderError
  • Компонент для Vue 3 и модуль Nuxt — <PlaceholderImage> на сервере рендерит только средний цвет и соотношение сторон, поэтому расхождений при гидрации не бывает, а модуль Nuxt генерирует хеши ваших картинок при сборке
  • Командная строка — hazehash encode, decode и info хешируют файлы, папки и glob-шаблоны, рисуют превью в терминале и объясняют, что лежит в строке

Как это работает ​

При кодировании изображение усредняется по площади в линейном свете до небольшой сетки для анализа и переводится в OKLab. Яркость и два цветовых канала получают собственные сетки коэффициентов DCT, подобранные под соотношение сторон картинки, а коэффициенты квантуются поиском «скорость–искажение», который укладывает результат в бюджет. Итог записывается как заголовок в 7 байт и коэффициенты, закодированные по Голомбу–Райсу, и выводится в base64url.

При декодировании коэффициенты восстанавливаются из строки, превращаются обратно в пиксели нужного размера, переводятся из OKLab в sRGB с отображением в гамму и размываются детерминированным дизерингом, чтобы градиенты не давали полос.

Пакеты ​

HazeHash публикуется как три npm-пакета из одного репозитория:

  • hazehash — энкодер, декодер, хелперы для canvas и Node.js и команда hazehash
  • hazehash-vue — компонент PlaceholderImage и composable usePlaceholder() для Vue 3
  • hazehash-nuxt — модуль Nuxt, который регистрирует компонент и генерирует хеши при сборке