Encoding Files in Node.js
The helpers in hazehash/node read an image file or a buffer, decode it with sharp, and encode the pixels. They are the way to hash images on disk without writing the pixel-reading code yourself.
import { encodeFile, encodeFileToString, encodeFileDetailed } from 'hazehash/node'sharp is an optional peer dependency (0.33 or newer), so install it where you use these helpers:
npm install --save-dev sharpWithout it the helpers throw a PlaceholderError with the code InvalidInput and a message that explains how to install sharp. The core entry points never need it.
The image is converted to sRGB and rotated according to its EXIF orientation before it is encoded, so the hash matches what a browser shows. Every helper takes the same two arguments:
pathOrBuffer
string | Uint8Array
A path to an image file, or the bytes of an encoded image (JPEG, PNG, WebP, AVIF, GIF and the other formats sharp reads).
options
EncodeOptions · optional
The same options as encode(): budget, profile, alpha, analysisSize and weights.
Getting a string
encodeFileToString(pathOrBuffer, options?)
Promise<string>
Resolves to the hash as base64url.
import { encodeFileToString } from 'hazehash/node'
const hash = await encodeFileToString('photo.jpg', { budget: 24 })
// "Ec7UwRWKIv5znmt3XYLUF5zBSYmAo0Wr"Getting the bytes
encodeFile(pathOrBuffer, options?)
Promise<Uint8Array>
Resolves to the raw bytes of the hash, for a binary column.
import { encodeFile } from 'hazehash/node'
const bytes = await encodeFile('photo.jpg')
bytes.length // 28Getting the size as well
encodeFileDetailed(pathOrBuffer, options?)
Promise<EncodedFile>
Resolves to the bytes, the string and the pixel size of the image as displayed, which is its size after the EXIF rotation. It is the function behind the hazehash encode command, and the way to store the real dimensions next to the hash.
import { encodeFileDetailed } from 'hazehash/node'
const { hash, bytes, width, height } = await encodeFileDetailed('photo.jpg')
// hash: "Ed7UwRWKKv5znm6a7sC1tziHDNpMuCikxrYpIg", width: 1280, height: 959The result has this shape:
interface EncodedFile {
bytes: Uint8Array // the hash bytes
hash: string // the hash as base64url
width: number // pixel size as displayed
height: number
}Hashing a folder
The helpers hash one image per call. For a folder, loop over the files; the encoder itself takes a few milliseconds, so the time goes into decoding the image:
import { readdir, writeFile } from 'node:fs/promises'
import { extname, join } from 'node:path'
import { encodeFileToString } from 'hazehash/node'
const dir = './images'
const hashes: Record<string, string> = {}
for (const name of await readdir(dir)) {
if (['.jpg', '.jpeg', '.png', '.webp'].includes(extname(name).toLowerCase())) {
hashes[name] = await encodeFileToString(join(dir, name), { budget: 24 })
}
}
await writeFile('hashes.json', JSON.stringify(hashes, null, 2))For a one-off job the command does the same without code: npx hazehash encode ./images -f json -o hashes.json. In Nuxt, the module generates and caches the hashes during the build.