@vizzly-testing/honeydiff 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +52 -5
- package/index.d.ts +116 -2
- package/package.json +13 -1
- package/platforms/index-aarch64-apple-darwin.node +0 -0
- package/platforms/index-aarch64-unknown-linux-gnu.node +0 -0
- package/platforms/index-x86_64-pc-windows-msvc.node +0 -0
- package/platforms/index-x86_64-unknown-linux-gnu.node +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.7.0] - 2025-12-11
|
|
9
|
+
|
|
10
|
+
## What's Changed
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Image Metadata API** - New functions to extract image dimensions, file size, and format without performing comparison
|
|
14
|
+
- `getImageMetadata(buffer)` / `getImageMetadataSync(buffer)` - Extract metadata from Buffer
|
|
15
|
+
- `getImageMetadataFromFile(path)` / `getImageMetadataFromFileSync(path)` - Extract metadata from file path
|
|
16
|
+
- Returns `ImageMetadata` with `width`, `height`, `fileSizeBytes`, and `format` properties
|
|
17
|
+
- Useful for storage tracking and billing purposes without needing to scan cloud storage buckets
|
|
18
|
+
|
|
19
|
+
**Full Changelog**: https://github.com/vizzly-testing/honeydiff/compare/v0.6.0...v0.7.0
|
|
20
|
+
|
|
21
|
+
## [0.6.0] - 2025-12-10
|
|
22
|
+
|
|
23
|
+
## What's Changed
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- **Noise filtering with `minClusterSize` option** - New option to filter out single-pixel rendering variance while catching real visual changes. Defaults to `2` (filters isolated pixels), can be set to `1` for exact matching or `3+` for more permissive detection. Clustering is automatically enabled when `minClusterSize > 1`.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **`isDifferent` now respects noise filtering** - When `minClusterSize` is set, small clusters below the threshold are filtered out, meaning `isDifferent` may be `false` even when `diffPixels > 0` (those pixels were classified as noise)
|
|
30
|
+
- **`diffPixels` reports raw count** - The raw pixel count is now unaffected by `minClusterSize` filtering, showing all differing pixels including those filtered as noise
|
|
31
|
+
- **Documentation improvements** - Added comprehensive documentation for the `minClusterSize` option in TypeScript types and README, including a behavior table and usage examples
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- Height differences now always count regardless of clustering (structural changes are never filtered as noise)
|
|
35
|
+
|
|
36
|
+
**Full Changelog**: https://github.com/vizzly-testing/honeydiff/compare/v0.5.0...v0.6.0
|
|
37
|
+
|
|
8
38
|
## [0.5.0] - 2025-12-04
|
|
9
39
|
|
|
10
40
|
## What's Changed
|
package/README.md
CHANGED
|
@@ -154,13 +154,14 @@ const result = await compare('baseline.png', 'current.png', {
|
|
|
154
154
|
console.log('Artifacts saved to ./artifacts/');
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
### 5. Spatial Clustering
|
|
157
|
+
### 5. Spatial Clustering & Noise Filtering
|
|
158
158
|
|
|
159
|
-
Group nearby differences into regions
|
|
159
|
+
Group nearby differences into regions and filter out single-pixel noise from rendering variance.
|
|
160
160
|
|
|
161
161
|
```javascript
|
|
162
162
|
const result = await compare('img1.png', 'img2.png', {
|
|
163
|
-
includeClusters: true
|
|
163
|
+
includeClusters: true,
|
|
164
|
+
minClusterSize: 2 // Default: filter single isolated pixels as noise
|
|
164
165
|
});
|
|
165
166
|
|
|
166
167
|
if (result.diffClusters) {
|
|
@@ -180,6 +181,13 @@ if (result.diffClusters) {
|
|
|
180
181
|
// - Average intensity: 127.3
|
|
181
182
|
```
|
|
182
183
|
|
|
184
|
+
**Noise filtering values:**
|
|
185
|
+
| Value | Behavior |
|
|
186
|
+
|-------|----------|
|
|
187
|
+
| 1 | Exact matching - any different pixel counts |
|
|
188
|
+
| 2 | Default - filters single isolated pixels as rendering noise |
|
|
189
|
+
| 3+ | More permissive - only larger clusters detected |
|
|
190
|
+
|
|
183
191
|
### 6. Perceptual Similarity (SSIM)
|
|
184
192
|
|
|
185
193
|
Beyond pixel counting - measure structural similarity from a human perception perspective.
|
|
@@ -255,6 +263,28 @@ let buffer = fs.readFileSync('image.png');
|
|
|
255
263
|
let dims = await getDimensions(buffer);
|
|
256
264
|
```
|
|
257
265
|
|
|
266
|
+
### 10. Image Metadata
|
|
267
|
+
|
|
268
|
+
Get image dimensions, file size, and format detection - useful for storage tracking and billing.
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
const { getImageMetadata, getImageMetadataFromFile } = require('@vizzly-testing/honeydiff');
|
|
272
|
+
|
|
273
|
+
// From buffer
|
|
274
|
+
let buffer = fs.readFileSync('screenshot.png');
|
|
275
|
+
let metadata = await getImageMetadata(buffer);
|
|
276
|
+
console.log(`Image: ${metadata.width}x${metadata.height}`);
|
|
277
|
+
console.log(`Size: ${metadata.fileSizeBytes} bytes`);
|
|
278
|
+
console.log(`Format: ${metadata.format}`);
|
|
279
|
+
// Output: Image: 1920x1080
|
|
280
|
+
// Size: 245760 bytes
|
|
281
|
+
// Format: png
|
|
282
|
+
|
|
283
|
+
// From file (gets accurate file size from disk)
|
|
284
|
+
let metadata = await getImageMetadataFromFile('screenshot.png');
|
|
285
|
+
console.log(`${metadata.width}x${metadata.height}, ${metadata.fileSizeBytes} bytes`);
|
|
286
|
+
```
|
|
287
|
+
|
|
258
288
|
## Accessibility Features
|
|
259
289
|
|
|
260
290
|
Built-in WCAG color contrast analysis and color blindness simulation to catch accessibility violations in screenshots and UI designs.
|
|
@@ -410,6 +440,14 @@ Fast boolean check - returns true if different, false if identical.
|
|
|
410
440
|
|
|
411
441
|
Get image dimensions without loading full image data.
|
|
412
442
|
|
|
443
|
+
**`getImageMetadata(buffer): Promise<ImageMetadata>`**
|
|
444
|
+
|
|
445
|
+
Get image metadata (dimensions, file size, format) from a buffer.
|
|
446
|
+
|
|
447
|
+
**`getImageMetadataFromFile(path): Promise<ImageMetadata>`**
|
|
448
|
+
|
|
449
|
+
Get image metadata from a file path. File size is read from disk for accuracy.
|
|
450
|
+
|
|
413
451
|
### Sync Functions (Blocks Event Loop)
|
|
414
452
|
|
|
415
453
|
**`compareSync(img1, img2, options?): DiffResult`**
|
|
@@ -424,6 +462,14 @@ Synchronous boolean check.
|
|
|
424
462
|
|
|
425
463
|
Synchronous dimension retrieval.
|
|
426
464
|
|
|
465
|
+
**`getImageMetadataSync(buffer): ImageMetadata`**
|
|
466
|
+
|
|
467
|
+
Synchronous metadata retrieval from buffer.
|
|
468
|
+
|
|
469
|
+
**`getImageMetadataFromFileSync(path): ImageMetadata`**
|
|
470
|
+
|
|
471
|
+
Synchronous metadata retrieval from file.
|
|
472
|
+
|
|
427
473
|
### Input Types
|
|
428
474
|
|
|
429
475
|
All functions accept:
|
|
@@ -445,6 +491,7 @@ interface CompareOptions {
|
|
|
445
491
|
includeDiffPixels?: boolean; // List all diff pixels (memory intensive, default: false)
|
|
446
492
|
includeClusters?: boolean; // Spatial clustering (default: false)
|
|
447
493
|
includeSSIM?: boolean; // SSIM perceptual score (slow, default: false)
|
|
494
|
+
minClusterSize?: number; // Filter clusters smaller than this (default: 2)
|
|
448
495
|
|
|
449
496
|
// Accessibility options
|
|
450
497
|
includeAccessibilityData?: boolean; // RGB, luminance, WCAG (default: false)
|
|
@@ -464,10 +511,10 @@ interface CompareOptions {
|
|
|
464
511
|
```typescript
|
|
465
512
|
interface DiffResult {
|
|
466
513
|
// Basic metrics
|
|
467
|
-
isDifferent: boolean; // Are images different?
|
|
514
|
+
isDifferent: boolean; // Are images different? (respects minClusterSize filtering)
|
|
468
515
|
diffPercentage: number; // 0.0-100.0
|
|
469
516
|
totalPixels: number;
|
|
470
|
-
diffPixels: number;
|
|
517
|
+
diffPixels: number; // Raw count (unaffected by minClusterSize filtering)
|
|
471
518
|
|
|
472
519
|
// Anti-aliasing
|
|
473
520
|
aaPixelsIgnored: number;
|
package/index.d.ts
CHANGED
|
@@ -61,13 +61,19 @@ export interface DiffCluster {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export interface DiffResult {
|
|
64
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Whether the images are different based on the comparison threshold
|
|
66
|
+
* Note: This respects minClusterSize filtering - small clusters may be filtered as noise
|
|
67
|
+
*/
|
|
65
68
|
isDifferent: boolean;
|
|
66
69
|
/** Percentage of pixels that differ (0.0 - 100.0) */
|
|
67
70
|
diffPercentage: number;
|
|
68
71
|
/** Total number of pixels compared */
|
|
69
72
|
totalPixels: number;
|
|
70
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Number of pixels that differ (raw count, unaffected by minClusterSize filtering)
|
|
75
|
+
* Note: This may be > 0 even when isDifferent is false if small clusters were filtered as noise
|
|
76
|
+
*/
|
|
71
77
|
diffPixels: number;
|
|
72
78
|
/** Number of pixels ignored due to anti-aliasing detection */
|
|
73
79
|
aaPixelsIgnored: number;
|
|
@@ -139,6 +145,22 @@ export interface CompareOptions {
|
|
|
139
145
|
*/
|
|
140
146
|
includeSSIM?: boolean;
|
|
141
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Minimum cluster size to count as a real difference
|
|
150
|
+
*
|
|
151
|
+
* Clusters smaller than this threshold are filtered out as noise.
|
|
152
|
+
* This helps ignore run-to-run rendering variance (scattered single pixels)
|
|
153
|
+
* while still catching real visual changes (grouped pixel differences).
|
|
154
|
+
*
|
|
155
|
+
* - 1 = Exact matching - any different pixel counts
|
|
156
|
+
* - 2 = Default - filters single isolated pixels as noise
|
|
157
|
+
* - 3+ = More permissive - only larger clusters detected
|
|
158
|
+
*
|
|
159
|
+
* When set to a value > 1, clustering is automatically enabled.
|
|
160
|
+
* @default 2
|
|
161
|
+
*/
|
|
162
|
+
minClusterSize?: number;
|
|
163
|
+
|
|
142
164
|
/**
|
|
143
165
|
* Path to save the diff image (highlighted differences)
|
|
144
166
|
* @default undefined
|
|
@@ -272,6 +294,17 @@ export interface ImageDimensions {
|
|
|
272
294
|
height: number;
|
|
273
295
|
}
|
|
274
296
|
|
|
297
|
+
export interface ImageMetadata {
|
|
298
|
+
/** Image width in pixels */
|
|
299
|
+
width: number;
|
|
300
|
+
/** Image height in pixels */
|
|
301
|
+
height: number;
|
|
302
|
+
/** Size of the image data in bytes */
|
|
303
|
+
fileSizeBytes: number;
|
|
304
|
+
/** Detected image format (e.g., "png", "jpeg", "webp") or null if unknown */
|
|
305
|
+
format: string | null;
|
|
306
|
+
}
|
|
307
|
+
|
|
275
308
|
/**
|
|
276
309
|
* Get image dimensions asynchronously (recommended)
|
|
277
310
|
*
|
|
@@ -308,6 +341,87 @@ export function getDimensions(img: ImageInput): Promise<ImageDimensions>;
|
|
|
308
341
|
*/
|
|
309
342
|
export function getDimensionsSync(img: ImageInput): ImageDimensions;
|
|
310
343
|
|
|
344
|
+
// ============================================================================
|
|
345
|
+
// Image Metadata API
|
|
346
|
+
// ============================================================================
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Get image metadata asynchronously (recommended)
|
|
350
|
+
*
|
|
351
|
+
* Retrieves image dimensions, file size, and format detection.
|
|
352
|
+
* Useful for storage tracking and billing purposes.
|
|
353
|
+
*
|
|
354
|
+
* @param img - Image Buffer
|
|
355
|
+
* @returns Promise resolving to ImageMetadata
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```typescript
|
|
359
|
+
* const buffer = fs.readFileSync('screenshot.png');
|
|
360
|
+
* const metadata = await getImageMetadata(buffer);
|
|
361
|
+
* console.log(`Image: ${metadata.width}x${metadata.height}`);
|
|
362
|
+
* console.log(`Size: ${metadata.fileSizeBytes} bytes`);
|
|
363
|
+
* console.log(`Format: ${metadata.format}`);
|
|
364
|
+
* // Output: Image: 1920x1080
|
|
365
|
+
* // Size: 245760 bytes
|
|
366
|
+
* // Format: png
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
export function getImageMetadata(img: Buffer): Promise<ImageMetadata>;
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Get image metadata synchronously (blocks event loop)
|
|
373
|
+
*
|
|
374
|
+
* Retrieves image dimensions, file size, and format detection.
|
|
375
|
+
* Use this only when you need blocking behavior.
|
|
376
|
+
*
|
|
377
|
+
* @param img - Image Buffer
|
|
378
|
+
* @returns ImageMetadata
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```typescript
|
|
382
|
+
* const buffer = fs.readFileSync('screenshot.png');
|
|
383
|
+
* const metadata = getImageMetadataSync(buffer);
|
|
384
|
+
* console.log(`${metadata.width}x${metadata.height}, ${metadata.fileSizeBytes} bytes`);
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
export function getImageMetadataSync(img: Buffer): ImageMetadata;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get image metadata from file asynchronously (recommended)
|
|
391
|
+
*
|
|
392
|
+
* Retrieves image dimensions, file size (from disk), and format detection.
|
|
393
|
+
* The file size is read from filesystem metadata for accuracy.
|
|
394
|
+
*
|
|
395
|
+
* @param path - Path to the image file
|
|
396
|
+
* @returns Promise resolving to ImageMetadata
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* ```typescript
|
|
400
|
+
* const metadata = await getImageMetadataFromFile('screenshot.png');
|
|
401
|
+
* console.log(`Image: ${metadata.width}x${metadata.height}`);
|
|
402
|
+
* console.log(`Size: ${metadata.fileSizeBytes} bytes`);
|
|
403
|
+
* console.log(`Format: ${metadata.format}`);
|
|
404
|
+
* ```
|
|
405
|
+
*/
|
|
406
|
+
export function getImageMetadataFromFile(path: string): Promise<ImageMetadata>;
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Get image metadata from file synchronously (blocks event loop)
|
|
410
|
+
*
|
|
411
|
+
* Retrieves image dimensions, file size (from disk), and format detection.
|
|
412
|
+
* Use this only when you need blocking behavior.
|
|
413
|
+
*
|
|
414
|
+
* @param path - Path to the image file
|
|
415
|
+
* @returns ImageMetadata
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```typescript
|
|
419
|
+
* const metadata = getImageMetadataFromFileSync('screenshot.png');
|
|
420
|
+
* console.log(`${metadata.width}x${metadata.height}, ${metadata.fileSizeBytes} bytes`);
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
export function getImageMetadataFromFileSync(path: string): ImageMetadata;
|
|
424
|
+
|
|
311
425
|
// ============================================================================
|
|
312
426
|
// WCAG Accessibility API
|
|
313
427
|
// ============================================================================
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizzly-testing/honeydiff",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "High-performance image diffing for Node.js - Native bindings to Honeydiff Rust library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -69,6 +69,18 @@
|
|
|
69
69
|
"load-platform.cjs",
|
|
70
70
|
"platforms/*.node",
|
|
71
71
|
"README.md",
|
|
72
|
+
"CHANGELOG.md",
|
|
73
|
+
"index.js",
|
|
74
|
+
"index.d.ts",
|
|
75
|
+
"load-platform.cjs",
|
|
76
|
+
"platforms/*.node",
|
|
77
|
+
"README.md",
|
|
78
|
+
"CHANGELOG.md",
|
|
79
|
+
"index.js",
|
|
80
|
+
"index.d.ts",
|
|
81
|
+
"load-platform.cjs",
|
|
82
|
+
"platforms/*.node",
|
|
83
|
+
"README.md",
|
|
72
84
|
"CHANGELOG.md"
|
|
73
85
|
],
|
|
74
86
|
"engines": {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|