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 и командаhazehashhazehash-vue— компонентPlaceholderImageи composableusePlaceholder()для Vue 3hazehash-nuxt— модуль Nuxt, который регистрирует компонент и генерирует хеши при сборке