Skip to content

Commit d9bbf8d

Browse files
committed
🔖 v0.9.0
1 parent b542134 commit d9bbf8d

4 files changed

Lines changed: 13 additions & 188 deletions

File tree

CHANGELOG.md

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,6 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [0.10.0] - 2026-02-03
9-
10-
## What's Changed
11-
12-
### Added
13-
- **GMSD (Gradient Magnitude Similarity Deviation)** - New `includeGMSD` option for fast, edge-sensitive perceptual comparison
14-
- Returns `gmsdScore` in results (0.0 = identical, higher = more different)
15-
- Very fast compared to SSIM, ideal for detecting border/outline changes
16-
- Based on Xue et al. 2014 research paper
17-
- **Note:** GMSD requires images with identical dimensions. For variable-height comparisons, `gmsdScore` will be `null`
18-
- **Cluster Merging** - New `clusterMerge` option to consolidate fragmented text regions
19-
- Simple API: `clusterMerge: true` enables with sensible defaults
20-
- Advanced API: Pass an object with `horizontalDistance`, `yBandTolerance`, `maxHeightRatio`, `maxWidthRatio`
21-
- Solves the "59 clusters for one date string" problem by intelligently merging nearby character-level changes into logical text regions
22-
- Uses SWT-inspired heuristics (Epshtein et al. 2010) for horizontal-biased text detection
23-
24-
**Full Changelog**: https://github.com/vizzly-testing/honeydiff/compare/v0.9.0...v0.10.0
25-
26-
## [Unreleased]
27-
28-
### Added
29-
- **GMSD (Gradient Magnitude Similarity Deviation)** - New `includeGMSD` option for fast, edge-sensitive perceptual comparison
30-
- Returns `gmsdScore` in results (0.0 = identical, higher = more different)
31-
- Very fast compared to SSIM, ideal for detecting border/outline changes
32-
- Based on Xue et al. 2014 research paper
33-
- **Cluster Merging** - New `clusterMerge` option to consolidate fragmented text regions
34-
- Simple API: `clusterMerge: true` enables with sensible defaults
35-
- Advanced API: Pass an object with `horizontalDistance`, `yBandTolerance`, `maxHeightRatio`, `maxWidthRatio`
36-
- Solves the "59 clusters for one date string" problem
37-
- Uses SWT-inspired heuristics (Epshtein et al. 2010)
38-
398
## [0.9.0] - 2026-01-26
409

4110
## What's Changed

README.md

Lines changed: 12 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -188,39 +188,10 @@ if (result.diffClusters) {
188188
| 2 | Default - filters single isolated pixels as rendering noise |
189189
| 3+ | More permissive - only larger clusters detected |
190190

191-
**Cluster Merging for Text Regions:**
192-
193-
Text changes often fragment into many small clusters (one per character). Enable cluster merging to consolidate them into logical regions:
194-
195-
```javascript
196-
// Simple: enable with sensible defaults
197-
const result = await compare('img1.png', 'img2.png', {
198-
includeClusters: true,
199-
clusterMerge: true // Merge nearby clusters (great for text)
200-
});
201-
202-
// Advanced: tune the merging behavior
203-
const result = await compare('img1.png', 'img2.png', {
204-
includeClusters: true,
205-
clusterMerge: {
206-
horizontalDistance: 15, // Max gap between clusters to merge (pixels)
207-
yBandTolerance: 5, // Vertical tolerance for "same line"
208-
maxHeightRatio: 2.0, // Prevent merging very different sized clusters
209-
maxWidthRatio: 3.0
210-
}
211-
});
212-
213-
// Before: "2024-01-01" detected as 59 clusters (one per character/gap)
214-
// After: "2024-01-01" detected as 1-2 logical regions
215-
```
216-
217-
Uses SWT-inspired heuristics from text detection research (Epshtein et al. 2010).
218-
219-
### 6. Perceptual Similarity (SSIM & GMSD)
191+
### 6. Perceptual Similarity (SSIM)
220192

221193
Beyond pixel counting - measure structural similarity from a human perception perspective.
222194

223-
**SSIM (Structural Similarity Index)** - Overall perceptual similarity:
224195
```javascript
225196
const result = await compare('img1.png', 'img2.png', {
226197
includeSSIM: true // Note: Can be slow on large images
@@ -229,33 +200,13 @@ const result = await compare('img1.png', 'img2.png', {
229200
if (result.perceptualScore !== null) {
230201
console.log(`SSIM: ${result.perceptualScore.toFixed(3)}`);
231202
// Output: SSIM: 0.923 (0.0 = different, 1.0 = identical)
232-
}
233-
```
234-
235-
**GMSD (Gradient Magnitude Similarity Deviation)** - Fast edge-sensitive metric:
236-
```javascript
237-
const result = await compare('img1.png', 'img2.png', {
238-
includeGMSD: true // Very fast, great for detecting structural changes
239-
});
240-
241-
if (result.gmsdScore !== null) {
242-
console.log(`GMSD: ${result.gmsdScore.toFixed(4)}`);
243-
// Output: GMSD: 0.0234 (0.0 = identical, higher = more different)
244203

245-
if (result.gmsdScore < 0.05) {
246-
console.log('Edges are very similar');
204+
if (result.perceptualScore > 0.95) {
205+
console.log('Images are perceptually very similar');
247206
}
248207
}
249208
```
250209

251-
GMSD is ideal for catching:
252-
- Border thickness changes
253-
- Font weight shifts
254-
- Icon updates
255-
- Any edge/outline regressions
256-
257-
**Reference:** Xue et al. 2014 - "Gradient Magnitude Similarity Deviation: A Highly Efficient Perceptual Image Quality Index"
258-
259210
### 7. Tolerance & Color Spaces
260211

261212
**RGB Mode (default)** - Exact matching with pixel tolerance:
@@ -607,22 +558,22 @@ All functions accept:
607558
```typescript
608559
interface CompareOptions {
609560
// Basic options
610-
threshold?: number; // CIEDE2000 Delta E threshold (default: 2.0)
561+
pixelTolerance?: number; // 0-255, ignore diffs below threshold (default: 0)
562+
colorThreshold?: number; // 0.0-1.0, YIQ mode threshold (default: 0.0 = RGB)
611563
antialiasing?: boolean; // Ignore AA artifacts (default: true)
564+
ignoreColors?: boolean; // Brightness only (default: false)
612565
maxDiffs?: number; // Stop after N diffs (default: unlimited)
613566

614567
// Analysis options
615568
includeDiffPixels?: boolean; // List all diff pixels (memory intensive, default: false)
616569
includeClusters?: boolean; // Spatial clustering (default: false)
617570
includeSSIM?: boolean; // SSIM perceptual score (slow, default: false)
618-
includeGMSD?: boolean; // GMSD edge similarity (fast, default: false)
619571
minClusterSize?: number; // Filter clusters smaller than this (default: 2)
620-
clusterMerge?: boolean | { // Merge nearby clusters (default: false)
621-
horizontalDistance?: number; // Max horizontal gap to merge (default: 15)
622-
yBandTolerance?: number; // Vertical "same line" tolerance (default: 5)
623-
maxHeightRatio?: number; // Max height ratio to merge (default: 2.0)
624-
maxWidthRatio?: number; // Max width ratio to merge (default: 3.0)
625-
};
572+
573+
// Accessibility options
574+
includeAccessibilityData?: boolean; // RGB, luminance, WCAG (default: false)
575+
checkColorBlindness?: boolean; // Color blindness simulation (default: false)
576+
colorBlindnessThreshold?: number; // Visibility threshold 0-255 (default: 30.0)
626577

627578
// Output options
628579
diffPath?: string; // Save diff image path
@@ -655,8 +606,7 @@ interface DiffResult {
655606
diffPixelsList: DiffPixel[] | null; // Null unless includeDiffPixels enabled
656607
diffClusters: DiffCluster[] | null; // Null unless includeClusters enabled
657608
intensityStats: IntensityStats | null; // Null unless includeDiffPixels enabled
658-
perceptualScore: number | null; // SSIM 0.0-1.0, null unless includeSSIM enabled
659-
gmsdScore: number | null; // GMSD 0.0+, null unless includeGMSD enabled
609+
perceptualScore: number | null; // 0.0-1.0, null unless includeSSIM enabled
660610
}
661611
```
662612

index.d.ts

Lines changed: 0 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -91,67 +91,12 @@ export interface DiffResult {
9191
intensityStats: IntensityStats | null;
9292
/** SSIM (Structural Similarity Index) perceptual score 0.0-1.0 (null unless includeSSIM is enabled) */
9393
perceptualScore: number | null;
94-
/**
95-
* GMSD (Gradient Magnitude Similarity Deviation) score (null unless includeGMSD is enabled)
96-
* Lower values (closer to 0.0) indicate more similar images
97-
* Typical range: 0.0 to ~0.3 for natural images
98-
*/
99-
gmsdScore: number | null;
10094
}
10195

10296
// ============================================================================
10397
// Options
10498
// ============================================================================
10599

106-
/**
107-
* Options for merging nearby clusters
108-
*
109-
* These heuristics are designed to merge fragmented text regions (like individual
110-
* characters in a date string) into logical regions while avoiding merging
111-
* unrelated visual changes.
112-
*
113-
* Inspired by the Stroke Width Transform (SWT) text detection algorithm:
114-
* Epshtein, B., Ofek, E., & Wexler, Y. (2010). "Detecting Text in Natural Scenes
115-
* with Stroke Width Transform." CVPR 2010.
116-
*/
117-
export interface ClusterMergeOptions {
118-
/**
119-
* Maximum horizontal distance to merge clusters in same Y-band (pixels)
120-
*
121-
* Clusters within this horizontal distance and overlapping Y-ranges
122-
* will be merged. Suitable for merging characters in text.
123-
* @default 15
124-
*/
125-
horizontalDistance?: number;
126-
127-
/**
128-
* Maximum vertical tolerance for "same Y-band" (pixels)
129-
*
130-
* Clusters with Y-ranges within this tolerance of each other are
131-
* considered to be on the same line.
132-
* @default 5
133-
*/
134-
yBandTolerance?: number;
135-
136-
/**
137-
* Maximum height ratio between clusters to allow merging
138-
*
139-
* Prevents merging clusters of very different sizes (e.g., a word
140-
* with a large image). Based on SWT heuristic.
141-
* @default 2.0
142-
*/
143-
maxHeightRatio?: number;
144-
145-
/**
146-
* Maximum width ratio between clusters to allow merging
147-
*
148-
* Additional SWT-inspired heuristic to prevent merging dissimilar
149-
* regions.
150-
* @default 3.0
151-
*/
152-
maxWidthRatio?: number;
153-
}
154-
155100
export interface CompareOptions {
156101
/**
157102
* Perceptual color difference threshold using CIEDE2000 (Delta E units)
@@ -200,23 +145,6 @@ export interface CompareOptions {
200145
*/
201146
includeSSIM?: boolean;
202147

203-
/**
204-
* Calculate GMSD (Gradient Magnitude Similarity Deviation) score
205-
*
206-
* GMSD is very fast and highly sensitive to edge/structural changes.
207-
* Useful for detecting border thickness changes, font weight shifts,
208-
* and icon updates.
209-
*
210-
* **Note:** GMSD requires images with identical dimensions. For variable-height
211-
* comparisons, `gmsdScore` will be `null`. Use SSIM for variable-height images.
212-
*
213-
* Reference: Xue et al. 2014 - "Gradient Magnitude Similarity Deviation:
214-
* A Highly Efficient Perceptual Image Quality Index"
215-
*
216-
* @default false
217-
*/
218-
includeGMSD?: boolean;
219-
220148
/**
221149
* Minimum cluster size to count as a real difference
222150
*
@@ -233,28 +161,6 @@ export interface CompareOptions {
233161
*/
234162
minClusterSize?: number;
235163

236-
/**
237-
* Merge nearby clusters into logical regions
238-
*
239-
* When enabled, nearby clusters are merged using horizontal-biased heuristics
240-
* that work well for text regions. This helps consolidate fragmented text
241-
* changes (e.g., "2024-01-01" showing as 59 clusters) into logical regions.
242-
*
243-
* Automatically enables clustering when set.
244-
*
245-
* @default undefined (no merging)
246-
*
247-
* @example
248-
* ```typescript
249-
* // Simple: enable merging with sensible defaults
250-
* { clusterMerge: true }
251-
*
252-
* // Advanced: tune the merging behavior
253-
* { clusterMerge: { horizontalDistance: 20, yBandTolerance: 10 } }
254-
* ```
255-
*/
256-
clusterMerge?: boolean | ClusterMergeOptions;
257-
258164
/**
259165
* Path to save the diff image (highlighted differences)
260166
* @default undefined

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vizzly-testing/honeydiff",
3-
"version": "0.10.0",
3+
"version": "0.9.0",
44
"description": "High-performance image diffing for Node.js - Native bindings to Honeydiff Rust library",
55
"type": "module",
66
"main": "index.js",

0 commit comments

Comments
 (0)