@vizzly-testing/honeydiff 0.15.0 → 0.17.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 +35 -0
- package/LICENSE +21 -0
- package/README.md +80 -119
- package/examples/basic.js +19 -79
- package/examples/buffers.js +6 -37
- package/examples/typescript.ts +25 -78
- package/index.d.ts +173 -1183
- package/index.js +91 -7
- package/package.json +4 -3
- 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/index.js
CHANGED
|
@@ -37,12 +37,14 @@ if (existsSync(platformLoaderPath)) {
|
|
|
37
37
|
|
|
38
38
|
// Core comparison API
|
|
39
39
|
export const compare = addon.compare;
|
|
40
|
-
export const quickCompare = addon.quickCompare;
|
|
41
40
|
export const compareSync = addon.compareSync;
|
|
42
|
-
export const
|
|
41
|
+
export const imagesDiffer = addon.imagesDiffer;
|
|
42
|
+
export const imagesDifferSync = addon.imagesDifferSync;
|
|
43
|
+
export const analyze = addon.analyze;
|
|
44
|
+
export const analyzeSync = addon.analyzeSync;
|
|
45
|
+
export const configureThreads = addon.configureThreads;
|
|
43
46
|
export const getDimensions = addon.getDimensions;
|
|
44
47
|
export const getDimensionsSync = addon.getDimensionsSync;
|
|
45
|
-
export const maskSemanticsVersion = addon.maskSemanticsVersion;
|
|
46
48
|
export const version = packageMetadata.version;
|
|
47
49
|
|
|
48
50
|
// Image Metadata API
|
|
@@ -70,7 +72,89 @@ export const analyzeWcagAllCvd = addon.analyzeWcagAllCvd;
|
|
|
70
72
|
export const analyzeWcagAllCvdSync = addon.analyzeWcagAllCvdSync;
|
|
71
73
|
export const getColorBlindnessTypes = addon.getColorBlindnessTypes;
|
|
72
74
|
|
|
73
|
-
// Diff
|
|
74
|
-
export
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
// Diff fingerprints are pure derivatives of the returned analysis.
|
|
76
|
+
export function computeFingerprintSync(analysis) {
|
|
77
|
+
let regions = analysis.difference.regions;
|
|
78
|
+
if (regions.length === 0) return null;
|
|
79
|
+
|
|
80
|
+
let width = analysis.images.canvas.width;
|
|
81
|
+
let height = analysis.images.canvas.height;
|
|
82
|
+
let canvasArea = width * height;
|
|
83
|
+
let regionPositions = regions.map(({ spatial }) => [
|
|
84
|
+
spatial.centroid.x / width,
|
|
85
|
+
spatial.centroid.y / height,
|
|
86
|
+
]);
|
|
87
|
+
let regionSizes = regions.map(
|
|
88
|
+
({ spatial }) => (spatial.bounds.width * spatial.bounds.height) / canvasArea
|
|
89
|
+
);
|
|
90
|
+
let averageDensity =
|
|
91
|
+
regions.reduce((total, region) => total + region.spatial.density, 0) / regions.length;
|
|
92
|
+
let zoneMask = regions.reduce((mask, region) => {
|
|
93
|
+
let zoneX = Math.min(3, Math.floor((region.spatial.centroid.x / width) * 4));
|
|
94
|
+
let zoneY = Math.min(3, Math.floor((region.spatial.centroid.y / height) * 4));
|
|
95
|
+
return mask | (1 << (zoneY * 4 + zoneX));
|
|
96
|
+
}, 0);
|
|
97
|
+
let fraction = analysis.difference.fraction;
|
|
98
|
+
let diffMagnitude =
|
|
99
|
+
fraction < 0.001
|
|
100
|
+
? 'tiny'
|
|
101
|
+
: fraction < 0.01
|
|
102
|
+
? 'small'
|
|
103
|
+
: fraction < 0.05
|
|
104
|
+
? 'medium'
|
|
105
|
+
: fraction < 0.2
|
|
106
|
+
? 'large'
|
|
107
|
+
: 'massive';
|
|
108
|
+
let fingerprint = {
|
|
109
|
+
regionCount: regions.length,
|
|
110
|
+
regionPositions,
|
|
111
|
+
regionSizes,
|
|
112
|
+
meanDeltaE: analysis.difference.appearance?.mean ?? null,
|
|
113
|
+
averageDensity,
|
|
114
|
+
zoneMask,
|
|
115
|
+
diffMagnitude,
|
|
116
|
+
hash: '',
|
|
117
|
+
};
|
|
118
|
+
fingerprint.hash = fingerprintHashSync(fingerprint);
|
|
119
|
+
return fingerprint;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function fingerprintSimilaritySync(left, right) {
|
|
123
|
+
let intersection = left.zoneMask & right.zoneMask;
|
|
124
|
+
let union = left.zoneMask | right.zoneMask;
|
|
125
|
+
let bitCount = (value) => {
|
|
126
|
+
let count = 0;
|
|
127
|
+
for (let remaining = value; remaining !== 0; remaining >>>= 1) count += remaining & 1;
|
|
128
|
+
return count;
|
|
129
|
+
};
|
|
130
|
+
let weighted = (bitCount(intersection) / Math.max(1, bitCount(union))) * 40;
|
|
131
|
+
let weights = 40;
|
|
132
|
+
weighted += (1 / (1 + Math.abs(left.regionCount - right.regionCount) * 0.5)) * 20;
|
|
133
|
+
weights += 20;
|
|
134
|
+
weighted += (left.diffMagnitude === right.diffMagnitude ? 1 : 0) * 15;
|
|
135
|
+
weights += 15;
|
|
136
|
+
weighted += (1 / (1 + Math.abs(left.averageDensity - right.averageDensity) * 5)) * 15;
|
|
137
|
+
weights += 15;
|
|
138
|
+
if (left.meanDeltaE !== null && right.meanDeltaE !== null) {
|
|
139
|
+
weighted += (1 / (1 + Math.abs(left.meanDeltaE - right.meanDeltaE) / 10)) * 10;
|
|
140
|
+
weights += 10;
|
|
141
|
+
}
|
|
142
|
+
return weighted / weights;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function fingerprintHashSync(fingerprint) {
|
|
146
|
+
let magnitude = ['tiny', 'small', 'medium', 'large', 'massive'].indexOf(
|
|
147
|
+
fingerprint.diffMagnitude
|
|
148
|
+
);
|
|
149
|
+
if (magnitude === -1) throw new TypeError('Invalid diffMagnitude');
|
|
150
|
+
let countBucket =
|
|
151
|
+
fingerprint.regionCount === 1
|
|
152
|
+
? 0
|
|
153
|
+
: fingerprint.regionCount <= 3
|
|
154
|
+
? 1
|
|
155
|
+
: fingerprint.regionCount <= 10
|
|
156
|
+
? 2
|
|
157
|
+
: 3;
|
|
158
|
+
let value = fingerprint.zoneMask * 32 + magnitude * 4 + countBucket;
|
|
159
|
+
return value.toString(16).padStart(16, '0');
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizzly-testing/honeydiff",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"build-debug": "cargo build",
|
|
19
19
|
"test": "node --test --experimental-strip-types tests/*.test.ts",
|
|
20
20
|
"test:types": "tsc --noEmit",
|
|
21
|
-
"test:examples": "node examples/basic.js",
|
|
21
|
+
"test:examples": "node examples/basic.js ../../tests/fixtures/screenshots/vizzly-baseline.png ../../tests/fixtures/screenshots/vizzly-with-diff.png",
|
|
22
22
|
"check": "biome check .",
|
|
23
23
|
"check:fix": "biome check --write .",
|
|
24
24
|
"lint": "biome lint .",
|
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"assets/",
|
|
52
52
|
"examples/",
|
|
53
53
|
"README.md",
|
|
54
|
-
"CHANGELOG.md"
|
|
54
|
+
"CHANGELOG.md",
|
|
55
|
+
"LICENSE"
|
|
55
56
|
],
|
|
56
57
|
"engines": {
|
|
57
58
|
"node": ">=22.0.0"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|