Skip to main content
Deno 2 is finally here 🎉️
Learn more

dhash

A dhash implementation for Deno.

A fast algorithm that allows checking if two images are “kind of” the same (the same source image, slightly modified). Examples:

  • A resized, compressed, slightly cropped, or color-altered image compared with the original
  • A watermarked image versus it’s source
  • Meme images (mostly the same template, different text)

It does this by computing a perceptual hash of each image and then using it to compare similarity.

Perceptual hashing is the use of a fingerprinting algorithm that produces a 
snippet or fingerprint of various forms of multimedia.

Based on the “Kind of Like That” article by Dr. Neal Krawetz.

Usage

You can compare dhash values by simply computing the Hamming distance between them:

  • A distance of 0 represents an identical, or very similar image
  • A distance greater than 10 means that you’re most likely dealing with a different image
  • A distance between 1 and 10 may indicate that you’re dealing with variations of the same base image
const [hash1, hash2] = await Promise.all([
  dhash("./tests/dalle.png"),
  dhash("./tests/dalle-copyright.png"),
]);

console.log(compare(hash1, hash2));

Bit convention: this implementation sets bit 1 when the pixel intensity increases left-to-right (left < right). Use dhash(src, { invert: true }) if you need the opposite convention to match another implementation.

API

In addition to dhash() and compare():

toAscii(hash: string, chars?: [string, string]): string
raw(hash: string): Promise<Uint8Array> // PNG bytes for the 8x8 fingerprint
save(hash: string, filePath: string): Promise<void> // writes `${filePath}.png`

toAscii() always renders an 8x8 matrix (64 bits); leading zero bits are preserved.

Development

  • Run tests: deno task test (requires --allow-read --allow-ffi --allow-env because sharp uses native bindings and reads fixtures).

License

MIT Š Claudiu Ceia