@argos-ci/mask-fingerprint
v0.1.3
Published
Fast, deterministic visual diff fingerprinting for PNG images, exposed as a Node.js native module via N-API.
Downloads
798
Maintainers
Readme
mask-fingerprint
Fast, deterministic visual diff fingerprinting for PNG images, exposed as a Node.js native module via N-API.
This library takes a PNG diff image (for example red-pixel visual diffs) and produces a stable equality fingerprint.
Two diffs that are visually very close will produce the same fingerprint, enabling:
fingerprintA === fingerprintB- database indexing
- grouping and deduplication
- joins without custom comparison logic
The core algorithm is written in Rust for performance and exposed to Node.js.
What problem this solves
Classic perceptual hashes require distance comparisons, which do not work well with SQL indexes or strict equality.
This project instead:
- normalizes the diff mask
- quantizes spatial density
- hashes a coarse representation
The result is tolerant equality, not approximate similarity.
How it works
- Decode PNG into RGBA
- Extract a binary mask of red pixels
- Optional dilation to absorb small pixel noise
- Crop to the bounding box
- Optional square padding
- Split into a small grid (8×8, 16×16, or 32×32)
- Compute per-cell red density
- Quantize densities into bins
- Pack bits and hash with FNV-1a 64-bit
- Return a deterministic string key
Small local differences usually do not change the final fingerprint.
Installation
Requirements
- Node.js 24 or newer
- Rust stable
- Cargo
Install dependencies
pnpm installor
npm installThis builds the native module.
Usage
import fs from 'node:fs'
import { fingerprintDiff } from 'mask-fingerprint'
const png = fs.readFileSync('diff.png')
const fingerprint = await fingerprintDiff(png, {
gridSize: 16,
dilateRadius: 1,
padToSquare: true,
densityThresholds: [0.002, 0.02, 0.08],
redThreshold: {
rMin: 200,
gMax: 90,
bMax: 90,
aMin: 16,
},
})
console.log(fingerprint)
// v1:g16:d1:t0.002,0.02,0.08:3fa1c2e9a4b8d210The returned value is designed to be stored in a database, indexed, and compared using strict equality.
API
fingerprintDiff(buffer, options?)
Returns a Promise<string>.
Parameters
buffer
- Node.js
Buffer - Raw PNG file contents
options (optional)
{
gridSize?: 8 | 16 | 32 // default: 16
dilateRadius?: 0 | 1 // default: 1
padToSquare?: boolean // default: true
densityThresholds?: number[] // default: [0.002, 0.02, 0.08]
// sorted, values between 0 and 1
redThreshold?: {
rMin?: number // default: 200
gMax?: number // default: 90
bMax?: number // default: 90
aMin?: number // default: 16
}
}Returns
stringA deterministic fingerprint string suitable for equality comparison and indexing.
Supported PNG formats
- RGBA
- RGB
- Grayscale
- Grayscale with alpha
- Indexed or palette PNGs
Palette and low bit-depth images are automatically expanded.
Performance characteristics
- Linear time in number of pixels
- No heavy floating-point operations
- Minimal allocations in hot paths
- Suitable for batch processing
Typical workloads handle thousands of diffs per second.
When to use this
Good fit:
- Visual regression testing
- Screenshot diff deduplication
- CI artifact clustering
- Database-backed visual change tracking
Not a good fit:
- General image similarity search
- Large geometric transformations
- Rotation or strong scale invariance
This library is intentionally optimized for diff masks, not arbitrary images.
Development
cargo check
cargo testRebuild the native module:
pnpm buildLicense
MIT
