Хранение хешей
Хеш создан для того, чтобы жить рядом с данными, которые он описывает: в колонке базы данных, поле CMS, JSON-ответе или манифесте сборки. Посчитайте его один раз при добавлении картинки, и каждый читатель получает плейсхолдер, не скачивая и не декодируя изображение.
Текст или байты
У хеша две взаимозаменяемые формы: сырые байты и строка base64url. Они преобразуются друг в друга без потерь, и любая функция, читающая хеш, принимает обе.
- Текст —
VARCHAR(40)вмещает любой хеш с бюджетом по умолчанию (38 символов), а для хешей до 48 байт нуженVARCHAR(64). Его легко читать, логировать, класть в JSON и передавать в HTML-атрибуте. - Байты —
BYTEAилиBLOBна 28 байт примерно на 25% меньше текстовой формы. Берите их, когда колонка большая или хеш идёт по бинарному протоколу.
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() возвращает оба значения за один вызов:
const { hash, width, height } = await encodeFileDetailed(path)
await db.images.insert({ path, hash, width, height })Стабильность
- Детерминированность. Одни и те же пиксели и опции всегда дают одни и те же байты, поэтому повторный расчёт хеша даёт строку, которая у вас уже есть, а хеш можно использовать как ключ кэша или сравнивать.
- Неизменное декодирование. Декодирование версии 1 не меняется между релизами: сохранённый хеш декодируется в те же пиксели в любой версии. В формате есть место для новых версий, а декодер отклоняет незнакомую версию с
UnsupportedVersion; см. Формат хеша. - Обрезка. Обрезанный хеш остаётся допустимым и декодируется с меньшей детализацией, потому что наименее важные коэффициенты лежат в конце. Не рассчитывайте на это ради экономии места (для этого есть меньший бюджет), но это значит, что обрезанное значение в старой колонке деградирует плавно, а не падает.
Смена бюджета позже
Хеш, созданный с одним бюджетом, остаётся допустимым после смены значения по умолчанию: старые и новые хеши декодируются одной и той же функцией. Чтобы дать старым картинкам качество побольше, закодируйте их заново из исходных изображений: скриптом или командой hazehash encode.