@blazediff/bin 1.7.0 → 2.0.1
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/README.md +166 -81
- package/bin/blazediff.exe +0 -0
- package/binaries/blazediff-linux-arm64 +0 -0
- package/binaries/blazediff-linux-x64 +0 -0
- package/binaries/blazediff-macos-arm64 +0 -0
- package/binaries/blazediff-macos-x64 +0 -0
- package/binaries/blazediff-windows-arm64.exe +0 -0
- package/binaries/blazediff-windows-x64.exe +0 -0
- package/dist/index.d.mts +44 -67
- package/dist/index.d.ts +44 -67
- package/dist/index.js +108 -1
- package/dist/index.mjs +79 -0
- package/package.json +23 -21
- package/post_install.js +40 -0
- package/dist/cli.js +0 -979
- package/dist/commands/diff.js +0 -255
- package/dist/commands/gmsd.js +0 -201
- package/dist/commands/hitchhikers-ssim.js +0 -217
- package/dist/commands/msssim.js +0 -163
- package/dist/commands/ssim.js +0 -163
package/README.md
CHANGED
|
@@ -7,118 +7,203 @@
|
|
|
7
7
|
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
The fastest single-threaded image diff in the world. Native Rust implementation with SIMD optimization, **3-4x faster** and **3x smaller** than [odiff](https://github.com/dmtrKovalenko/odiff).
|
|
11
|
+
|
|
12
|
+
**Features:**
|
|
13
|
+
- SIMD-accelerated (NEON on ARM, SSE4.1 on x86)
|
|
14
|
+
- Block-based two-pass optimization
|
|
15
|
+
- YIQ perceptual color difference
|
|
16
|
+
- Anti-aliasing detection
|
|
17
|
+
- Cross-platform pre-built binaries (~700KB-900KB, no compilation required)
|
|
11
18
|
|
|
12
19
|
## Installation
|
|
13
20
|
|
|
14
21
|
```bash
|
|
15
|
-
npm install
|
|
22
|
+
npm install @blazediff/bin
|
|
16
23
|
```
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
Pre-built [binaries](https://github.com/teimurjan/blazediff/tree/main/packages/bin/binaries) are included for:
|
|
26
|
+
- macOS ARM64 (Apple Silicon)
|
|
27
|
+
- macOS x64 (Intel)
|
|
28
|
+
- Linux ARM64
|
|
29
|
+
- Linux x64
|
|
30
|
+
- Windows ARM64
|
|
31
|
+
- Windows x64
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### compare(basePath, comparePath, diffOutput, options?)
|
|
36
|
+
|
|
37
|
+
Compare two PNG images and generate a diff image.
|
|
38
|
+
|
|
39
|
+
<table>
|
|
40
|
+
<tr>
|
|
41
|
+
<th width="500">Parameter</th>
|
|
42
|
+
<th width="500">Type</th>
|
|
43
|
+
<th width="500">Description</th>
|
|
44
|
+
</tr>
|
|
45
|
+
<tr>
|
|
46
|
+
<td><code>basePath</code></td>
|
|
47
|
+
<td>string</td>
|
|
48
|
+
<td>Path to the base/expected image</td>
|
|
49
|
+
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td><code>comparePath</code></td>
|
|
52
|
+
<td>string</td>
|
|
53
|
+
<td>Path to the comparison/actual image</td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<td><code>diffOutput</code></td>
|
|
57
|
+
<td>string</td>
|
|
58
|
+
<td>Path where the diff image will be saved</td>
|
|
59
|
+
</tr>
|
|
60
|
+
<tr>
|
|
61
|
+
<td><code>options</code></td>
|
|
62
|
+
<td>BlazeDiffOptions</td>
|
|
63
|
+
<td>Comparison options (optional)</td>
|
|
64
|
+
</tr>
|
|
65
|
+
</table>
|
|
66
|
+
|
|
67
|
+
<strong>Returns:</strong> `Promise<BlazeDiffResult>`
|
|
68
|
+
|
|
69
|
+
<table>
|
|
70
|
+
<tr>
|
|
71
|
+
<th width="500">Option</th>
|
|
72
|
+
<th width="500">Type</th>
|
|
73
|
+
<th width="500">Default</th>
|
|
74
|
+
<th width="500">Description</th>
|
|
75
|
+
</tr>
|
|
76
|
+
<tr>
|
|
77
|
+
<td><code>threshold</code></td>
|
|
78
|
+
<td>number</td>
|
|
79
|
+
<td>0.1</td>
|
|
80
|
+
<td>Color difference threshold (0.0-1.0). Lower = more strict</td>
|
|
81
|
+
</tr>
|
|
82
|
+
<tr>
|
|
83
|
+
<td><code>antialiasing</code></td>
|
|
84
|
+
<td>boolean</td>
|
|
85
|
+
<td>false</td>
|
|
86
|
+
<td>Enable anti-aliasing detection to exclude AA pixels from diff count</td>
|
|
87
|
+
</tr>
|
|
88
|
+
<tr>
|
|
89
|
+
<td><code>diffMask</code></td>
|
|
90
|
+
<td>boolean</td>
|
|
91
|
+
<td>false</td>
|
|
92
|
+
<td>Output only differences with transparent background</td>
|
|
93
|
+
</tr>
|
|
94
|
+
<tr>
|
|
95
|
+
<td><code>failOnLayoutDiff</code></td>
|
|
96
|
+
<td>boolean</td>
|
|
97
|
+
<td>false</td>
|
|
98
|
+
<td>Fail immediately if images have different dimensions</td>
|
|
99
|
+
</tr>
|
|
100
|
+
</table>
|
|
101
|
+
|
|
102
|
+
### Result Types
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
type BlazeDiffResult =
|
|
106
|
+
| { match: true }
|
|
107
|
+
| { match: false; reason: "layout-diff" }
|
|
108
|
+
| { match: false; reason: "pixel-diff"; diffCount: number; diffPercentage: number }
|
|
109
|
+
| { match: false; reason: "file-not-exists"; file: string };
|
|
22
110
|
```
|
|
23
111
|
|
|
24
|
-
##
|
|
112
|
+
## Usage
|
|
25
113
|
|
|
26
|
-
|
|
114
|
+
### Programmatic API
|
|
27
115
|
|
|
28
|
-
|
|
29
|
-
|
|
116
|
+
```typescript
|
|
117
|
+
import { compare } from '@blazediff/bin';
|
|
30
118
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
119
|
+
const result = await compare('expected.png', 'actual.png', 'diff.png', {
|
|
120
|
+
threshold: 0.1,
|
|
121
|
+
antialiasing: true,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (result.match) {
|
|
125
|
+
console.log('Images are identical!');
|
|
126
|
+
} else if (result.reason === 'pixel-diff') {
|
|
127
|
+
console.log(`${result.diffCount} pixels differ (${result.diffPercentage.toFixed(2)}%)`);
|
|
128
|
+
} else if (result.reason === 'layout-diff') {
|
|
129
|
+
console.log('Images have different dimensions');
|
|
130
|
+
}
|
|
35
131
|
```
|
|
36
132
|
|
|
37
|
-
|
|
38
|
-
- `-o, --output <path>` - Output path for the diff image
|
|
39
|
-
- `-t, --threshold <num>` - Matching threshold (0 to 1, default: 0.1)
|
|
40
|
-
- `-a, --alpha <num>` - Opacity of original image in diff (default: 0.1)
|
|
41
|
-
- `--aa-color <r,g,b>` - Color for anti-aliased pixels (default: 255,255,0)
|
|
42
|
-
- `--diff-color <r,g,b>` - Color for different pixels (default: 255,0,0)
|
|
43
|
-
- `--diff-color-alt <r,g,b>` - Alternative color for dark differences
|
|
44
|
-
- `--include-aa` - Include anti-aliasing detection
|
|
45
|
-
- `--diff-mask` - Draw diff over transparent background
|
|
46
|
-
- `--color-space <name>` - Specify color space to use (yiq, ycbcr)
|
|
47
|
-
- `--transformer <name>` - Specify transformer to use (pngjs, sharp)
|
|
48
|
-
- `-h, --help` - Show help message
|
|
49
|
-
|
|
50
|
-
### `gmsd` - Gradient Magnitude Similarity Deviation
|
|
51
|
-
Perceptual quality metric based on gradient similarity.
|
|
133
|
+
### CLI Usage
|
|
52
134
|
|
|
53
135
|
```bash
|
|
54
|
-
|
|
55
|
-
|
|
136
|
+
# Compare two images
|
|
137
|
+
npx blazediff expected.png actual.png diff.png
|
|
56
138
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- `--downsample <0|1>` - Downsample factor (0=full-res, 1=2x, default: 0)
|
|
60
|
-
- `--gmsd-c <num>` - Stability constant (default: 170)
|
|
61
|
-
- `--transformer <name>` - Specify transformer to use (pngjs, sharp)
|
|
62
|
-
- `-h, --help` - Show help message
|
|
139
|
+
# With options
|
|
140
|
+
npx blazediff expected.png actual.png diff.png --threshold 0.05 --antialiasing
|
|
63
141
|
|
|
64
|
-
|
|
65
|
-
|
|
142
|
+
# With higher compression (smaller output file, slower)
|
|
143
|
+
npx blazediff expected.png actual.png diff.png -c 6
|
|
66
144
|
|
|
67
|
-
|
|
68
|
-
blazediff
|
|
145
|
+
# Output as JSON
|
|
146
|
+
npx blazediff expected.png actual.png diff.png --output-format json
|
|
69
147
|
```
|
|
70
148
|
|
|
71
|
-
|
|
72
|
-
- `-o, --output <path>` - Output path for SSIM map visualization
|
|
73
|
-
- `--transformer <name>` - Specify transformer to use (pngjs, sharp)
|
|
74
|
-
- `-h, --help` - Show help message
|
|
75
|
-
|
|
76
|
-
### `msssim` - Multi-Scale Structural Similarity Index
|
|
77
|
-
Enhanced SSIM that operates at multiple image scales.
|
|
149
|
+
### CLI Options
|
|
78
150
|
|
|
79
|
-
```
|
|
80
|
-
blazediff
|
|
151
|
+
```
|
|
152
|
+
Usage: blazediff [OPTIONS] <IMAGE1> <IMAGE2> <OUTPUT>
|
|
153
|
+
|
|
154
|
+
Arguments:
|
|
155
|
+
<IMAGE1> First image path
|
|
156
|
+
<IMAGE2> Second image path
|
|
157
|
+
<OUTPUT> Output diff image path
|
|
158
|
+
|
|
159
|
+
Options:
|
|
160
|
+
-t, --threshold <THRESHOLD> Color difference threshold (0.0-1.0) [default: 0.1]
|
|
161
|
+
-a, --antialiasing Enable anti-aliasing detection
|
|
162
|
+
--diff-mask Output only differences (transparent background)
|
|
163
|
+
--fail-on-layout Fail on layout (size) difference
|
|
164
|
+
-c, --compression <LEVEL> PNG compression level (0-9, 0=fastest/largest, 9=slowest/smallest) [default: 0]
|
|
165
|
+
--output-format <FORMAT> Output format (json or text) [default: json]
|
|
166
|
+
-h, --help Print help
|
|
167
|
+
-V, --version Print version
|
|
81
168
|
```
|
|
82
169
|
|
|
83
|
-
|
|
84
|
-
- `-o, --output <path>` - Output path for MS-SSIM map visualization
|
|
85
|
-
- `--transformer <name>` - Specify transformer to use (pngjs, sharp)
|
|
86
|
-
- `-h, --help` - Show help message
|
|
170
|
+
### Exit Codes
|
|
87
171
|
|
|
88
|
-
|
|
172
|
+
- `0` - Images are identical
|
|
173
|
+
- `1` - Images differ (or layout mismatch with `--fail-on-layout`)
|
|
174
|
+
- `2` - Error (file not found, invalid format, etc.)
|
|
89
175
|
|
|
90
|
-
|
|
91
|
-
# Pixel-by-pixel diff (default)
|
|
92
|
-
blazediff image1.png image2.png
|
|
93
|
-
blazediff diff image1.png image2.png -o diff.png -t 0.05
|
|
176
|
+
## Performance
|
|
94
177
|
|
|
95
|
-
|
|
96
|
-
blazediff gmsd image1.png image2.png
|
|
97
|
-
blazediff gmsd image1.png image2.png -o gms-map.png
|
|
178
|
+
Benchmarked on Apple M1 Pro with 5600x3200 4K images:
|
|
98
179
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
blazediff
|
|
180
|
+
| Tool | Benchmark Time | vs blazediff |
|
|
181
|
+
|------|------|--------------|
|
|
182
|
+
| **blazediff** | ~327ms | - |
|
|
183
|
+
| odiff | ~1215ms | 3.4x slower |
|
|
102
184
|
|
|
103
|
-
|
|
104
|
-
blazediff msssim image1.png image2.png
|
|
105
|
-
blazediff msssim image1.png image2.png -o msssim-map.png
|
|
185
|
+
Binary sizes (stripped, LTO optimized) - **~3x smaller than odiff**:
|
|
106
186
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
187
|
+
| Platform | blazediff | odiff |
|
|
188
|
+
|----------|-----------|-------|
|
|
189
|
+
| macOS ARM64 | 702 KB | 2.2 MB |
|
|
190
|
+
| macOS x64 | 773 KB | 2.6 MB |
|
|
191
|
+
| Linux ARM64 | 753 KB | 2.3 MB |
|
|
192
|
+
| Linux x64 | 869 KB | 2.9 MB |
|
|
193
|
+
| Windows ARM64 | 580 KB | 2.4 MB |
|
|
194
|
+
| Windows x64 | 915 KB | 3.0 MB |
|
|
110
195
|
|
|
111
|
-
##
|
|
196
|
+
## Algorithm
|
|
112
197
|
|
|
113
|
-
|
|
114
|
-
- **sharp** - Native bindings, significantly faster. Supports PNG and JPEG.
|
|
198
|
+
BlazeDiff uses a two-pass block-based approach with SIMD acceleration:
|
|
115
199
|
|
|
116
|
-
|
|
200
|
+
1. **Cold Pass**: Scans image in 8x8 blocks using 32-bit integer comparison to identify changed regions
|
|
201
|
+
2. **Hot Pass**: Only processes blocks marked as changed, applying YIQ perceptual color difference
|
|
202
|
+
3. **SIMD**: Uses NEON (ARM) or SSE4.1 (x86) for parallel pixel processing
|
|
203
|
+
4. **Anti-aliasing**: Implements Vysniauskas (2009) algorithm to detect AA artifacts
|
|
117
204
|
|
|
118
|
-
|
|
119
|
-
- `0` - Images are identical
|
|
120
|
-
- `1` - Images have differences or error occurred
|
|
205
|
+
## References
|
|
121
206
|
|
|
122
|
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
207
|
+
- **YIQ Color Space**: [Kotsarenko & Ramos (2009)](https://doaj.org/article/b2e3b5088ba943eebd9af2927fef08ad) - "Measuring perceived color difference using YIQ NTSC transmission color space"
|
|
208
|
+
- **Anti-Aliasing Detection**: [Vysniauskas (2009)](https://www.researchgate.net/publication/234073157_Anti-aliased_Pixel_and_Intensity_Slope_Detector) - "Anti-aliased Pixel and Intensity Slope Detector"
|
|
209
|
+
- **Inspiration**: [odiff](https://github.com/dmtrKovalenko/odiff) - Fast image comparison tool written in Zig
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/index.d.mts
CHANGED
|
@@ -1,69 +1,46 @@
|
|
|
1
|
-
interface
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
options?: Record<string, unknown>;
|
|
22
|
-
}
|
|
23
|
-
interface SsimModeOptions {
|
|
24
|
-
outputPath?: string;
|
|
25
|
-
transformer: Transformer;
|
|
26
|
-
mode: "ssim";
|
|
27
|
-
options?: Record<string, unknown>;
|
|
28
|
-
}
|
|
29
|
-
interface MsssimModeOptions {
|
|
30
|
-
outputPath?: string;
|
|
31
|
-
transformer: Transformer;
|
|
32
|
-
mode: "msssim";
|
|
33
|
-
options?: Record<string, unknown>;
|
|
34
|
-
}
|
|
35
|
-
interface DiffModeResult {
|
|
36
|
-
mode: "diff";
|
|
1
|
+
interface BlazeDiffOptions {
|
|
2
|
+
/** Color difference threshold (0.0-1.0). Lower = more strict. Default: 0.1 */
|
|
3
|
+
threshold?: number;
|
|
4
|
+
/** Enable anti-aliasing detection to exclude AA pixels from diff count */
|
|
5
|
+
antialiasing?: boolean;
|
|
6
|
+
/** Output only differences with transparent background */
|
|
7
|
+
diffMask?: boolean;
|
|
8
|
+
/** Fail immediately if images have different dimensions */
|
|
9
|
+
failOnLayoutDiff?: boolean;
|
|
10
|
+
/** PNG compression level (0-9, 0=fastest/largest, 9=slowest/smallest) */
|
|
11
|
+
compression?: number;
|
|
12
|
+
}
|
|
13
|
+
type BlazeDiffResult = {
|
|
14
|
+
match: true;
|
|
15
|
+
} | {
|
|
16
|
+
match: false;
|
|
17
|
+
reason: "layout-diff";
|
|
18
|
+
} | {
|
|
19
|
+
match: false;
|
|
20
|
+
reason: "pixel-diff";
|
|
37
21
|
diffCount: number;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
score: number;
|
|
62
|
-
width: number;
|
|
63
|
-
height: number;
|
|
64
|
-
outputData?: Uint8Array;
|
|
65
|
-
duration: number;
|
|
66
|
-
}
|
|
67
|
-
type BlazeDiffBinResult = DiffModeResult | GmsdModeResult | SsimModeResult | MsssimModeResult;
|
|
22
|
+
diffPercentage: number;
|
|
23
|
+
} | {
|
|
24
|
+
match: false;
|
|
25
|
+
reason: "file-not-exists";
|
|
26
|
+
file: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Compare two PNG images and generate a diff image.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const result = await compare('expected.png', 'actual.png', 'diff.png');
|
|
34
|
+
*
|
|
35
|
+
* if (result.match) {
|
|
36
|
+
* console.log('Images identical');
|
|
37
|
+
* } else if (result.reason === 'pixel-diff') {
|
|
38
|
+
* console.log(`${result.diffCount} pixels differ`);
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare function compare(basePath: string, comparePath: string, diffOutput: string, options?: BlazeDiffOptions): Promise<BlazeDiffResult>;
|
|
43
|
+
/** Get the path to the blazediff binary for direct CLI usage. */
|
|
44
|
+
declare function getBinaryPath(): string;
|
|
68
45
|
|
|
69
|
-
export
|
|
46
|
+
export { type BlazeDiffOptions, type BlazeDiffResult, compare, getBinaryPath };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,69 +1,46 @@
|
|
|
1
|
-
interface
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
options?: Record<string, unknown>;
|
|
22
|
-
}
|
|
23
|
-
interface SsimModeOptions {
|
|
24
|
-
outputPath?: string;
|
|
25
|
-
transformer: Transformer;
|
|
26
|
-
mode: "ssim";
|
|
27
|
-
options?: Record<string, unknown>;
|
|
28
|
-
}
|
|
29
|
-
interface MsssimModeOptions {
|
|
30
|
-
outputPath?: string;
|
|
31
|
-
transformer: Transformer;
|
|
32
|
-
mode: "msssim";
|
|
33
|
-
options?: Record<string, unknown>;
|
|
34
|
-
}
|
|
35
|
-
interface DiffModeResult {
|
|
36
|
-
mode: "diff";
|
|
1
|
+
interface BlazeDiffOptions {
|
|
2
|
+
/** Color difference threshold (0.0-1.0). Lower = more strict. Default: 0.1 */
|
|
3
|
+
threshold?: number;
|
|
4
|
+
/** Enable anti-aliasing detection to exclude AA pixels from diff count */
|
|
5
|
+
antialiasing?: boolean;
|
|
6
|
+
/** Output only differences with transparent background */
|
|
7
|
+
diffMask?: boolean;
|
|
8
|
+
/** Fail immediately if images have different dimensions */
|
|
9
|
+
failOnLayoutDiff?: boolean;
|
|
10
|
+
/** PNG compression level (0-9, 0=fastest/largest, 9=slowest/smallest) */
|
|
11
|
+
compression?: number;
|
|
12
|
+
}
|
|
13
|
+
type BlazeDiffResult = {
|
|
14
|
+
match: true;
|
|
15
|
+
} | {
|
|
16
|
+
match: false;
|
|
17
|
+
reason: "layout-diff";
|
|
18
|
+
} | {
|
|
19
|
+
match: false;
|
|
20
|
+
reason: "pixel-diff";
|
|
37
21
|
diffCount: number;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
score: number;
|
|
62
|
-
width: number;
|
|
63
|
-
height: number;
|
|
64
|
-
outputData?: Uint8Array;
|
|
65
|
-
duration: number;
|
|
66
|
-
}
|
|
67
|
-
type BlazeDiffBinResult = DiffModeResult | GmsdModeResult | SsimModeResult | MsssimModeResult;
|
|
22
|
+
diffPercentage: number;
|
|
23
|
+
} | {
|
|
24
|
+
match: false;
|
|
25
|
+
reason: "file-not-exists";
|
|
26
|
+
file: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Compare two PNG images and generate a diff image.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const result = await compare('expected.png', 'actual.png', 'diff.png');
|
|
34
|
+
*
|
|
35
|
+
* if (result.match) {
|
|
36
|
+
* console.log('Images identical');
|
|
37
|
+
* } else if (result.reason === 'pixel-diff') {
|
|
38
|
+
* console.log(`${result.diffCount} pixels differ`);
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare function compare(basePath: string, comparePath: string, diffOutput: string, options?: BlazeDiffOptions): Promise<BlazeDiffResult>;
|
|
43
|
+
/** Get the path to the blazediff binary for direct CLI usage. */
|
|
44
|
+
declare function getBinaryPath(): string;
|
|
68
45
|
|
|
69
|
-
export
|
|
46
|
+
export { type BlazeDiffOptions, type BlazeDiffResult, compare, getBinaryPath };
|
package/dist/index.js
CHANGED
|
@@ -1 +1,108 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
compare: () => compare,
|
|
34
|
+
getBinaryPath: () => getBinaryPath
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
var import_node_child_process = require("child_process");
|
|
38
|
+
var import_node_path = __toESM(require("path"));
|
|
39
|
+
var import_node_util = require("util");
|
|
40
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
41
|
+
var BINARY_PATH = import_node_path.default.join(__dirname, "..", "bin", "blazediff.exe");
|
|
42
|
+
function buildArgs(diffOutput, options) {
|
|
43
|
+
const args = [diffOutput, "--output-format=json"];
|
|
44
|
+
if (!options) return args;
|
|
45
|
+
if (options.threshold !== void 0) args.push(`--threshold=${options.threshold}`);
|
|
46
|
+
if (options.antialiasing) args.push("--antialiasing");
|
|
47
|
+
if (options.diffMask) args.push("--diff-mask");
|
|
48
|
+
if (options.failOnLayoutDiff) args.push("--fail-on-layout");
|
|
49
|
+
if (options.compression !== void 0) args.push(`--compression=${options.compression}`);
|
|
50
|
+
return args;
|
|
51
|
+
}
|
|
52
|
+
function parseJsonOutput(text) {
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(text);
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function detectMissingFile(error, basePath, comparePath) {
|
|
60
|
+
if (!/Failed to load images:.*(?:No such file|not found)/i.test(error)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (error.includes(basePath)) return basePath;
|
|
64
|
+
if (error.includes(comparePath)) return comparePath;
|
|
65
|
+
return basePath;
|
|
66
|
+
}
|
|
67
|
+
async function compare(basePath, comparePath, diffOutput, options) {
|
|
68
|
+
const args = [basePath, comparePath, ...buildArgs(diffOutput, options)];
|
|
69
|
+
try {
|
|
70
|
+
await execFileAsync(BINARY_PATH, args);
|
|
71
|
+
return { match: true };
|
|
72
|
+
} catch (err) {
|
|
73
|
+
const { code, stdout, stderr } = err;
|
|
74
|
+
const output = stdout || stderr || "";
|
|
75
|
+
if (code === 1) {
|
|
76
|
+
const json = parseJsonOutput(output);
|
|
77
|
+
if (json?.error?.includes("Layout differs")) {
|
|
78
|
+
return { match: false, reason: "layout-diff" };
|
|
79
|
+
}
|
|
80
|
+
if (json) {
|
|
81
|
+
return {
|
|
82
|
+
match: false,
|
|
83
|
+
reason: "pixel-diff",
|
|
84
|
+
diffCount: json.diffCount,
|
|
85
|
+
diffPercentage: json.diffPercentage
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (output.includes("Layout differs")) {
|
|
89
|
+
return { match: false, reason: "layout-diff" };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (code === 2) {
|
|
93
|
+
const missingFile = detectMissingFile(output, basePath, comparePath);
|
|
94
|
+
if (missingFile) {
|
|
95
|
+
return { match: false, reason: "file-not-exists", file: missingFile };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
throw new Error(output || `blazediff exited with code ${code}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function getBinaryPath() {
|
|
102
|
+
return BINARY_PATH;
|
|
103
|
+
}
|
|
104
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
105
|
+
0 && (module.exports = {
|
|
106
|
+
compare,
|
|
107
|
+
getBinaryPath
|
|
108
|
+
});
|