Skip to content

Хранение хешей ​

Хеш создан для того, чтобы жить рядом с данными, которые он описывает: в колонке базы данных, поле CMS, JSON-ответе или манифесте сборки. Посчитайте его один раз при добавлении картинки, и каждый читатель получает плейсхолдер, не скачивая и не декодируя изображение.

Текст или байты ​

У хеша две взаимозаменяемые формы: сырые байты и строка base64url. Они преобразуются друг в друга без потерь, и любая функция, читающая хеш, принимает обе.

  • Текст — VARCHAR(40) вмещает любой хеш с бюджетом по умолчанию (38 символов), а для хешей до 48 байт нужен VARCHAR(64). Его легко читать, логировать, класть в JSON и передавать в HTML-атрибуте.
  • Байты — BYTEA или BLOB на 28 байт примерно на 25% меньше текстовой формы. Берите их, когда колонка большая или хеш идёт по бинарному протоколу.
ts
import { encode, toBase64Url } from 'hazehash/encode'
import { toBytes } from 'hazehash'

const bytes = encode(image) // Uint8Array, храните в бинарной колонке
const text = toBase64Url(bytes) // или держите текстовую форму
const back = toBytes(text) // снова те же байты

В Node.js Buffer.from(bytes).toString('base64url') даёт ту же строку, что и toBase64Url().

Размер хеша не фиксирован ​

Бюджет это потолок. Плоскому или плавно закрашенному изображению нужно меньше байт, чем детальному, а изображение с прозрачностью добавляет два байта к заголовку, поэтому у разных картинок хеши разной длины даже при одинаковых опциях. Рассчитывайте колонку на самый большой допустимый хеш (бюджет), а не на длину одного примера.

Размер рядом с хешем ​

Соотношение сторон внутри хеша хранится с разрешением около 9%: этого хватает, чтобы нарисовать плейсхолдер, но не чтобы сверстать страницу. Храните настоящие ширину и высоту изображения рядом с хешем и используйте их как width и height рамки. encodeFileDetailed() возвращает оба значения за один вызов:

ts
const { hash, width, height } = await encodeFileDetailed(path)
await db.images.insert({ path, hash, width, height })

Стабильность ​

  • Детерминированность. Одни и те же пиксели и опции всегда дают одни и те же байты, поэтому повторный расчёт хеша даёт строку, которая у вас уже есть, а хеш можно использовать как ключ кэша или сравнивать.
  • Неизменное декодирование. Декодирование версии 1 не меняется между релизами: сохранённый хеш декодируется в те же пиксели в любой версии. В формате есть место для новых версий, а декодер отклоняет незнакомую версию с UnsupportedVersion; см. Формат хеша.
  • Обрезка. Обрезанный хеш остаётся допустимым и декодируется с меньшей детализацией, потому что наименее важные коэффициенты лежат в конце. Не рассчитывайте на это ради экономии места (для этого есть меньший бюджет), но это значит, что обрезанное значение в старой колонке деградирует плавно, а не падает.

Смена бюджета позже ​

Хеш, созданный с одним бюджетом, остаётся допустимым после смены значения по умолчанию: старые и новые хеши декодируются одной и той же функцией. Чтобы дать старым картинкам качество побольше, закодируйте их заново из исходных изображений: скриптом или командой hazehash encode.