@blazediff/core-native 4.0.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/LICENSE.md +21 -0
- package/README.md +238 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +293 -0
- package/dist/index.mjs +250 -0
- package/package.json +60 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Teimur Gasanov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# @blazediff/core-native
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@blazediff/core-native)
|
|
6
|
+
[](https://www.npmjs.com/package/@blazediff/core-native)
|
|
7
|
+
[](https://crates.io/crates/blazediff)
|
|
8
|
+
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
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).
|
|
12
|
+
|
|
13
|
+
**Features:**
|
|
14
|
+
- **PNG, JPEG & QOI support** - auto-detected by file extension
|
|
15
|
+
- SIMD-accelerated (NEON on ARM, SSE4.1 on x86)
|
|
16
|
+
- Block-based two-pass optimization
|
|
17
|
+
- YIQ perceptual color difference
|
|
18
|
+
- Anti-aliasing detection
|
|
19
|
+
- Cross-platform pre-built binaries (~700KB-900KB, no compilation required)
|
|
20
|
+
|
|
21
|
+
**Vendored Libraries:**
|
|
22
|
+
- [libspng](https://libspng.org/) - Fast PNG decoding/encoding with SIMD
|
|
23
|
+
- [libjpeg-turbo](https://libjpeg-turbo.org/) - High-performance JPEG codec with SIMD
|
|
24
|
+
- [qoi](https://github.com/aldanor/qoi-rust) - QOI (Quite OK Image) format for fast lossless compression
|
|
25
|
+
|
|
26
|
+
> **Note:** This package was previously published as [`@blazediff/bin`](https://www.npmjs.com/package/@blazediff/bin), which is now deprecated. Please use `@blazediff/core-native` instead.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @blazediff/core-native
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Also available as a Rust crate: [`cargo install blazediff`](https://crates.io/crates/blazediff)
|
|
35
|
+
|
|
36
|
+
Pre-built binaries are included via platform-specific packages:
|
|
37
|
+
- [`@blazediff/core-native-darwin-arm64`](https://github.com/teimurjan/blazediff/tree/main/packages/core-native-darwin-arm64) - macOS ARM64 (Apple Silicon)
|
|
38
|
+
- [`@blazediff/core-native-darwin-x64`](https://github.com/teimurjan/blazediff/tree/main/packages/core-native-darwin-x64) - macOS x64 (Intel)
|
|
39
|
+
- [`@blazediff/core-native-linux-arm64`](https://github.com/teimurjan/blazediff/tree/main/packages/core-native-linux-arm64) - Linux ARM64
|
|
40
|
+
- [`@blazediff/core-native-linux-x64`](https://github.com/teimurjan/blazediff/tree/main/packages/core-native-linux-x64) - Linux x64
|
|
41
|
+
- [`@blazediff/core-native-win32-arm64`](https://github.com/teimurjan/blazediff/tree/main/packages/core-native-win32-arm64) - Windows ARM64
|
|
42
|
+
- [`@blazediff/core-native-win32-x64`](https://github.com/teimurjan/blazediff/tree/main/packages/core-native-win32-x64) - Windows x64
|
|
43
|
+
|
|
44
|
+
## API
|
|
45
|
+
|
|
46
|
+
### compare(basePath, comparePath, diffOutput, options?)
|
|
47
|
+
|
|
48
|
+
Compare two images (PNG or JPEG) and generate a diff image. Format is auto-detected from file extension.
|
|
49
|
+
|
|
50
|
+
<table>
|
|
51
|
+
<tr>
|
|
52
|
+
<th width="500">Parameter</th>
|
|
53
|
+
<th width="500">Type</th>
|
|
54
|
+
<th width="500">Description</th>
|
|
55
|
+
</tr>
|
|
56
|
+
<tr>
|
|
57
|
+
<td><code>basePath</code></td>
|
|
58
|
+
<td>string</td>
|
|
59
|
+
<td>Path to the base/expected image</td>
|
|
60
|
+
</tr>
|
|
61
|
+
<tr>
|
|
62
|
+
<td><code>comparePath</code></td>
|
|
63
|
+
<td>string</td>
|
|
64
|
+
<td>Path to the comparison/actual image</td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td><code>diffOutput</code></td>
|
|
68
|
+
<td>string</td>
|
|
69
|
+
<td>Path where the diff image will be saved</td>
|
|
70
|
+
</tr>
|
|
71
|
+
<tr>
|
|
72
|
+
<td><code>options</code></td>
|
|
73
|
+
<td>BlazeDiffOptions</td>
|
|
74
|
+
<td>Comparison options (optional)</td>
|
|
75
|
+
</tr>
|
|
76
|
+
</table>
|
|
77
|
+
|
|
78
|
+
<strong>Returns:</strong> `Promise<BlazeDiffResult>`
|
|
79
|
+
|
|
80
|
+
<table>
|
|
81
|
+
<tr>
|
|
82
|
+
<th width="500">Option</th>
|
|
83
|
+
<th width="500">Type</th>
|
|
84
|
+
<th width="500">Default</th>
|
|
85
|
+
<th width="500">Description</th>
|
|
86
|
+
</tr>
|
|
87
|
+
<tr>
|
|
88
|
+
<td><code>threshold</code></td>
|
|
89
|
+
<td>number</td>
|
|
90
|
+
<td>0.1</td>
|
|
91
|
+
<td>Color difference threshold (0.0-1.0). Lower = more strict</td>
|
|
92
|
+
</tr>
|
|
93
|
+
<tr>
|
|
94
|
+
<td><code>antialiasing</code></td>
|
|
95
|
+
<td>boolean</td>
|
|
96
|
+
<td>false</td>
|
|
97
|
+
<td>Enable anti-aliasing detection to exclude AA pixels from diff count</td>
|
|
98
|
+
</tr>
|
|
99
|
+
<tr>
|
|
100
|
+
<td><code>diffMask</code></td>
|
|
101
|
+
<td>boolean</td>
|
|
102
|
+
<td>false</td>
|
|
103
|
+
<td>Output only differences with transparent background</td>
|
|
104
|
+
</tr>
|
|
105
|
+
</table>
|
|
106
|
+
|
|
107
|
+
### Result Types
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
type BlazeDiffResult =
|
|
111
|
+
| { match: true }
|
|
112
|
+
| { match: false; reason: "layout-diff" }
|
|
113
|
+
| { match: false; reason: "pixel-diff"; diffCount: number; diffPercentage: number }
|
|
114
|
+
| { match: false; reason: "file-not-exists"; file: string };
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Usage
|
|
118
|
+
|
|
119
|
+
### Programmatic API
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { compare } from '@blazediff/core-native';
|
|
123
|
+
|
|
124
|
+
const result = await compare('expected.png', 'actual.png', 'diff.png', {
|
|
125
|
+
threshold: 0.1,
|
|
126
|
+
antialiasing: true,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (result.match) {
|
|
130
|
+
console.log('Images are identical!');
|
|
131
|
+
} else if (result.reason === 'pixel-diff') {
|
|
132
|
+
console.log(`${result.diffCount} pixels differ (${result.diffPercentage.toFixed(2)}%)`);
|
|
133
|
+
} else if (result.reason === 'layout-diff') {
|
|
134
|
+
console.log('Images have different dimensions');
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### CLI Usage
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Compare two PNG images
|
|
142
|
+
npx blazediff expected.png actual.png diff.png
|
|
143
|
+
|
|
144
|
+
# Compare two JPEG images
|
|
145
|
+
npx blazediff expected.jpg actual.jpg diff.jpg
|
|
146
|
+
|
|
147
|
+
# Compare two QOI images
|
|
148
|
+
npx blazediff expected.qoi actual.qoi diff.qoi
|
|
149
|
+
|
|
150
|
+
# Mixed formats (PNG input, QOI output - recommended for smallest diff files)
|
|
151
|
+
npx blazediff expected.png actual.png diff.qoi
|
|
152
|
+
|
|
153
|
+
# With options
|
|
154
|
+
npx blazediff expected.png actual.png diff.png --threshold 0.05 --antialiasing
|
|
155
|
+
|
|
156
|
+
# With higher PNG compression (smaller output file, slower)
|
|
157
|
+
npx blazediff expected.png actual.png diff.png -c 6
|
|
158
|
+
|
|
159
|
+
# With JPEG quality setting
|
|
160
|
+
npx blazediff expected.jpg actual.jpg diff.jpg -q 85
|
|
161
|
+
|
|
162
|
+
# Output as JSON
|
|
163
|
+
npx blazediff expected.png actual.png diff.png --output-format json
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### CLI Options
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
Usage: blazediff [OPTIONS] <IMAGE1> <IMAGE2> [OUTPUT]
|
|
170
|
+
|
|
171
|
+
Arguments:
|
|
172
|
+
<IMAGE1> First image path (PNG, JPEG, or QOI)
|
|
173
|
+
<IMAGE2> Second image path (PNG, JPEG, or QOI)
|
|
174
|
+
[OUTPUT] Output diff image path (optional, format detected from extension)
|
|
175
|
+
|
|
176
|
+
Options:
|
|
177
|
+
-t, --threshold <THRESHOLD> Color difference threshold (0.0-1.0) [default: 0.1]
|
|
178
|
+
-a, --antialiasing Enable anti-aliasing detection
|
|
179
|
+
--diff-mask Output only differences (transparent background)
|
|
180
|
+
-c, --compression <LEVEL> PNG compression level (0-9, 0=fastest, 9=smallest) [default: 0]
|
|
181
|
+
-q, --quality <QUALITY> JPEG quality (1-100) [default: 90]
|
|
182
|
+
--output-format <FORMAT> Output format (json or text) [default: json]
|
|
183
|
+
-h, --help Print help
|
|
184
|
+
-V, --version Print version
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Supported Formats
|
|
188
|
+
|
|
189
|
+
| Format | Extensions | Notes |
|
|
190
|
+
|--------|------------|-------|
|
|
191
|
+
| PNG | `.png` | Lossless, supports transparency |
|
|
192
|
+
| JPEG | `.jpg`, `.jpeg` | Lossy, smaller file sizes |
|
|
193
|
+
| QOI | `.qoi` | Fast lossless, ideal for diff outputs (12x smaller than uncompressed PNG) |
|
|
194
|
+
|
|
195
|
+
Input images can be mixed formats (e.g., compare PNG to JPEG). Output format is determined by the output file extension.
|
|
196
|
+
|
|
197
|
+
**QOI for diff outputs:** QOI excels at encoding diff images with large uniform areas, producing files 12x smaller than PNG (level 0) while being faster to encode.
|
|
198
|
+
|
|
199
|
+
### Exit Codes
|
|
200
|
+
|
|
201
|
+
- `0` - Images are identical
|
|
202
|
+
- `1` - Images differ (includes layout/size mismatch)
|
|
203
|
+
- `2` - Error (file not found, invalid format, etc.)
|
|
204
|
+
|
|
205
|
+
## Performance
|
|
206
|
+
|
|
207
|
+
Benchmarked on Apple M1 Pro with 5600x3200 4K PNG images:
|
|
208
|
+
|
|
209
|
+
| Tool | Benchmark Time | vs blazediff |
|
|
210
|
+
|------|------|--------------|
|
|
211
|
+
| **blazediff** | ~327ms | - |
|
|
212
|
+
| odiff | ~1215ms | 3.4x slower |
|
|
213
|
+
|
|
214
|
+
Binary sizes (stripped, LTO optimized) - **~3x smaller than odiff**:
|
|
215
|
+
|
|
216
|
+
| Platform | blazediff | odiff |
|
|
217
|
+
|----------|-----------|-------|
|
|
218
|
+
| macOS ARM64 | 702 KB | 2.2 MB |
|
|
219
|
+
| macOS x64 | 773 KB | 2.6 MB |
|
|
220
|
+
| Linux ARM64 | 753 KB | 2.3 MB |
|
|
221
|
+
| Linux x64 | 869 KB | 2.9 MB |
|
|
222
|
+
| Windows ARM64 | 580 KB | 2.4 MB |
|
|
223
|
+
| Windows x64 | 915 KB | 3.0 MB |
|
|
224
|
+
|
|
225
|
+
## Algorithm
|
|
226
|
+
|
|
227
|
+
BlazeDiff uses a two-pass block-based approach with SIMD acceleration:
|
|
228
|
+
|
|
229
|
+
1. **Cold Pass**: Scans image in 8x8 blocks using 32-bit integer comparison to identify changed regions
|
|
230
|
+
2. **Hot Pass**: Only processes blocks marked as changed, applying YIQ perceptual color difference
|
|
231
|
+
3. **SIMD**: Uses NEON (ARM) or SSE4.1 (x86) for parallel pixel processing
|
|
232
|
+
4. **Anti-aliasing**: Implements Vysniauskas (2009) algorithm to detect AA artifacts
|
|
233
|
+
|
|
234
|
+
## References
|
|
235
|
+
|
|
236
|
+
- **YIQ Color Space**: [Kotsarenko & Ramos (2009)](https://doaj.org/article/b2e3b5088ba943eebd9af2927fef08ad) - "Measuring perceived color difference using YIQ NTSC transmission color space"
|
|
237
|
+
- **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"
|
|
238
|
+
- **Inspiration**: [odiff](https://github.com/dmtrKovalenko/odiff) - Fast image comparison tool written in Zig
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
/** PNG compression level (0-9, 0=fastest/largest, 9=slowest/smallest) */
|
|
9
|
+
compression?: number;
|
|
10
|
+
/** JPEG quality (1-100). Default: 90 */
|
|
11
|
+
quality?: number;
|
|
12
|
+
}
|
|
13
|
+
type BlazeDiffResult = {
|
|
14
|
+
match: true;
|
|
15
|
+
} | {
|
|
16
|
+
match: false;
|
|
17
|
+
reason: "layout-diff";
|
|
18
|
+
} | {
|
|
19
|
+
match: false;
|
|
20
|
+
reason: "pixel-diff";
|
|
21
|
+
diffCount: number;
|
|
22
|
+
diffPercentage: number;
|
|
23
|
+
} | {
|
|
24
|
+
match: false;
|
|
25
|
+
reason: "file-not-exists";
|
|
26
|
+
file: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Compare two images (PNG or JPEG) and optionally generate a diff image.
|
|
30
|
+
*
|
|
31
|
+
* Uses native N-API bindings when available for ~10-100x better performance
|
|
32
|
+
* on small images (no process spawn overhead). Falls back to execFile if
|
|
33
|
+
* native bindings are unavailable.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // With diff output
|
|
38
|
+
* const result = await compare('expected.png', 'actual.png', 'diff.png');
|
|
39
|
+
*
|
|
40
|
+
* // Without diff output (faster, just returns comparison result)
|
|
41
|
+
* const result = await compare('expected.png', 'actual.png');
|
|
42
|
+
*
|
|
43
|
+
* if (result.match) {
|
|
44
|
+
* console.log('Images identical');
|
|
45
|
+
* } else if (result.reason === 'pixel-diff') {
|
|
46
|
+
* console.log(`${result.diffCount} pixels differ`);
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function compare(basePath: string, comparePath: string, diffOutput?: string, options?: BlazeDiffOptions): Promise<BlazeDiffResult>;
|
|
51
|
+
/** Get the path to the blazediff binary for direct CLI usage. */
|
|
52
|
+
declare function getBinaryPath(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Check if native N-API bindings are available.
|
|
55
|
+
* Returns true if the native module loaded successfully.
|
|
56
|
+
*/
|
|
57
|
+
declare function hasNativeBinding(): boolean;
|
|
58
|
+
|
|
59
|
+
export { type BlazeDiffOptions, type BlazeDiffResult, compare, getBinaryPath, hasNativeBinding };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
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
|
+
hasNativeBinding: () => hasNativeBinding
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.0_postcss@8.5.6_tsx@4.20.6_typescript@5.9.2_yaml@2.8.1/node_modules/tsup/assets/cjs_shims.js
|
|
40
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
|
|
41
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
42
|
+
|
|
43
|
+
// src/index.ts
|
|
44
|
+
var import_node_child_process = require("child_process");
|
|
45
|
+
var import_node_fs = require("fs");
|
|
46
|
+
var import_node_module = require("module");
|
|
47
|
+
var import_node_os = __toESM(require("os"));
|
|
48
|
+
var import_node_path = __toESM(require("path"));
|
|
49
|
+
var import_node_url = require("url");
|
|
50
|
+
var import_node_util = require("util");
|
|
51
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
52
|
+
var PLATFORM_PACKAGES = {
|
|
53
|
+
"darwin-arm64": {
|
|
54
|
+
packageName: "@blazediff/core-native-darwin-arm64",
|
|
55
|
+
packageDir: "core-native-darwin-arm64"
|
|
56
|
+
},
|
|
57
|
+
"darwin-x64": {
|
|
58
|
+
packageName: "@blazediff/core-native-darwin-x64",
|
|
59
|
+
packageDir: "core-native-darwin-x64"
|
|
60
|
+
},
|
|
61
|
+
"linux-arm64": {
|
|
62
|
+
packageName: "@blazediff/core-native-linux-arm64",
|
|
63
|
+
packageDir: "core-native-linux-arm64"
|
|
64
|
+
},
|
|
65
|
+
"linux-x64": {
|
|
66
|
+
packageName: "@blazediff/core-native-linux-x64",
|
|
67
|
+
packageDir: "core-native-linux-x64"
|
|
68
|
+
},
|
|
69
|
+
"win32-arm64": {
|
|
70
|
+
packageName: "@blazediff/core-native-win32-arm64",
|
|
71
|
+
packageDir: "core-native-win32-arm64"
|
|
72
|
+
},
|
|
73
|
+
"win32-x64": {
|
|
74
|
+
packageName: "@blazediff/core-native-win32-x64",
|
|
75
|
+
packageDir: "core-native-win32-x64"
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var nativeBinding = null;
|
|
79
|
+
var nativeBindingAttempted = false;
|
|
80
|
+
function tryLoadNativeBinding() {
|
|
81
|
+
if (nativeBindingAttempted) {
|
|
82
|
+
return nativeBinding;
|
|
83
|
+
}
|
|
84
|
+
nativeBindingAttempted = true;
|
|
85
|
+
const platform = import_node_os.default.platform();
|
|
86
|
+
const arch = import_node_os.default.arch();
|
|
87
|
+
const key = `${platform}-${arch}`;
|
|
88
|
+
const platformInfo = PLATFORM_PACKAGES[key];
|
|
89
|
+
if (!platformInfo) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const require2 = (0, import_node_module.createRequire)(importMetaUrl);
|
|
94
|
+
const binding = require2(platformInfo.packageName);
|
|
95
|
+
if (typeof binding?.compare === "function") {
|
|
96
|
+
nativeBinding = binding;
|
|
97
|
+
return binding;
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const currentDir = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
103
|
+
const packagesDir = import_node_path.default.resolve(currentDir, "..", "..");
|
|
104
|
+
const nodePath = import_node_path.default.join(
|
|
105
|
+
packagesDir,
|
|
106
|
+
platformInfo.packageDir,
|
|
107
|
+
"blazediff.node"
|
|
108
|
+
);
|
|
109
|
+
if ((0, import_node_fs.existsSync)(nodePath)) {
|
|
110
|
+
const require2 = (0, import_node_module.createRequire)(importMetaUrl);
|
|
111
|
+
const binding = require2(nodePath);
|
|
112
|
+
if (typeof binding?.compare === "function") {
|
|
113
|
+
nativeBinding = binding;
|
|
114
|
+
return binding;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
function convertNapiResult(result) {
|
|
122
|
+
if (result.matchResult) {
|
|
123
|
+
return { match: true };
|
|
124
|
+
}
|
|
125
|
+
if (result.reason === "layout-diff") {
|
|
126
|
+
return { match: false, reason: "layout-diff" };
|
|
127
|
+
}
|
|
128
|
+
if (result.reason === "pixel-diff") {
|
|
129
|
+
return {
|
|
130
|
+
match: false,
|
|
131
|
+
reason: "pixel-diff",
|
|
132
|
+
diffCount: result.diffCount ?? 0,
|
|
133
|
+
diffPercentage: result.diffPercentage ?? 0
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
match: false,
|
|
138
|
+
reason: "pixel-diff",
|
|
139
|
+
diffCount: result.diffCount ?? 0,
|
|
140
|
+
diffPercentage: result.diffPercentage ?? 0
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function convertToNapiOptions(options) {
|
|
144
|
+
return {
|
|
145
|
+
threshold: options?.threshold,
|
|
146
|
+
antialiasing: options?.antialiasing,
|
|
147
|
+
diffMask: options?.diffMask,
|
|
148
|
+
compression: options?.compression,
|
|
149
|
+
quality: options?.quality
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function resolveBinaryPath() {
|
|
153
|
+
const platform = import_node_os.default.platform();
|
|
154
|
+
const arch = import_node_os.default.arch();
|
|
155
|
+
const key = `${platform}-${arch}`;
|
|
156
|
+
const platformInfo = PLATFORM_PACKAGES[key];
|
|
157
|
+
if (!platformInfo) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Unsupported platform: ${key}. Supported: ${Object.keys(PLATFORM_PACKAGES).join(", ")}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const binaryName = platform === "win32" ? "blazediff.exe" : "blazediff";
|
|
163
|
+
try {
|
|
164
|
+
const require2 = (0, import_node_module.createRequire)(importMetaUrl);
|
|
165
|
+
const packagePath = require2.resolve(
|
|
166
|
+
`${platformInfo.packageName}/package.json`
|
|
167
|
+
);
|
|
168
|
+
const packageDir = import_node_path.default.dirname(packagePath);
|
|
169
|
+
const binaryPath = import_node_path.default.join(packageDir, binaryName);
|
|
170
|
+
if ((0, import_node_fs.existsSync)(binaryPath)) {
|
|
171
|
+
return binaryPath;
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
const currentDir = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
176
|
+
const packagesDir = import_node_path.default.resolve(currentDir, "..", "..");
|
|
177
|
+
const siblingPath = import_node_path.default.join(
|
|
178
|
+
packagesDir,
|
|
179
|
+
platformInfo.packageDir,
|
|
180
|
+
binaryName
|
|
181
|
+
);
|
|
182
|
+
if ((0, import_node_fs.existsSync)(siblingPath)) {
|
|
183
|
+
return siblingPath;
|
|
184
|
+
}
|
|
185
|
+
throw new Error(
|
|
186
|
+
`Platform package ${platformInfo.packageName} is not installed. This usually means the optional dependency wasn't installed for your platform. Try reinstalling with: npm install @blazediff/core-native`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
var cachedBinaryPath = null;
|
|
190
|
+
function getBinaryPathInternal() {
|
|
191
|
+
if (!cachedBinaryPath) {
|
|
192
|
+
cachedBinaryPath = resolveBinaryPath();
|
|
193
|
+
}
|
|
194
|
+
return cachedBinaryPath;
|
|
195
|
+
}
|
|
196
|
+
function buildArgs(diffOutput, options) {
|
|
197
|
+
const args = [];
|
|
198
|
+
if (diffOutput) args.push(diffOutput);
|
|
199
|
+
args.push("--output-format=json");
|
|
200
|
+
if (!options) return args;
|
|
201
|
+
if (options.threshold !== void 0)
|
|
202
|
+
args.push(`--threshold=${options.threshold}`);
|
|
203
|
+
if (options.antialiasing) args.push("--antialiasing");
|
|
204
|
+
if (options.diffMask) args.push("--diff-mask");
|
|
205
|
+
if (options.compression !== void 0)
|
|
206
|
+
args.push(`--compression=${options.compression}`);
|
|
207
|
+
if (options.quality !== void 0) args.push(`--quality=${options.quality}`);
|
|
208
|
+
return args;
|
|
209
|
+
}
|
|
210
|
+
function parseJsonOutput(text) {
|
|
211
|
+
try {
|
|
212
|
+
return JSON.parse(text);
|
|
213
|
+
} catch {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function detectMissingFile(error, basePath, comparePath) {
|
|
218
|
+
if (!/Failed to load images:.*(?:No such file|not found)/i.test(error)) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
if (error.includes(basePath)) return basePath;
|
|
222
|
+
if (error.includes(comparePath)) return comparePath;
|
|
223
|
+
return basePath;
|
|
224
|
+
}
|
|
225
|
+
async function execFileCompare(basePath, comparePath, diffOutput, options) {
|
|
226
|
+
const binaryPath = getBinaryPathInternal();
|
|
227
|
+
const args = [basePath, comparePath, ...buildArgs(diffOutput, options)];
|
|
228
|
+
try {
|
|
229
|
+
await execFileAsync(binaryPath, args);
|
|
230
|
+
return { match: true };
|
|
231
|
+
} catch (err) {
|
|
232
|
+
const { code, stdout, stderr } = err;
|
|
233
|
+
const output = stdout || stderr || "";
|
|
234
|
+
if (code === 1) {
|
|
235
|
+
const json = parseJsonOutput(output);
|
|
236
|
+
if (json?.error?.includes("Layout differs")) {
|
|
237
|
+
return { match: false, reason: "layout-diff" };
|
|
238
|
+
}
|
|
239
|
+
if (json) {
|
|
240
|
+
return {
|
|
241
|
+
match: false,
|
|
242
|
+
reason: "pixel-diff",
|
|
243
|
+
diffCount: json.diffCount,
|
|
244
|
+
diffPercentage: json.diffPercentage
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (output.includes("Layout differs")) {
|
|
248
|
+
return { match: false, reason: "layout-diff" };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (code === 2) {
|
|
252
|
+
const missingFile = detectMissingFile(output, basePath, comparePath);
|
|
253
|
+
if (missingFile) {
|
|
254
|
+
return { match: false, reason: "file-not-exists", file: missingFile };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
throw new Error(output || `blazediff exited with code ${code}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async function compare(basePath, comparePath, diffOutput, options) {
|
|
261
|
+
const binding = tryLoadNativeBinding();
|
|
262
|
+
if (binding) {
|
|
263
|
+
try {
|
|
264
|
+
const result = binding.compare(
|
|
265
|
+
basePath,
|
|
266
|
+
comparePath,
|
|
267
|
+
diffOutput ?? null,
|
|
268
|
+
convertToNapiOptions(options)
|
|
269
|
+
);
|
|
270
|
+
return convertNapiResult(result);
|
|
271
|
+
} catch (err) {
|
|
272
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
273
|
+
const missingFile = detectMissingFile(message, basePath, comparePath);
|
|
274
|
+
if (missingFile) {
|
|
275
|
+
return { match: false, reason: "file-not-exists", file: missingFile };
|
|
276
|
+
}
|
|
277
|
+
throw err;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return execFileCompare(basePath, comparePath, diffOutput, options);
|
|
281
|
+
}
|
|
282
|
+
function getBinaryPath() {
|
|
283
|
+
return getBinaryPathInternal();
|
|
284
|
+
}
|
|
285
|
+
function hasNativeBinding() {
|
|
286
|
+
return tryLoadNativeBinding() !== null;
|
|
287
|
+
}
|
|
288
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
289
|
+
0 && (module.exports = {
|
|
290
|
+
compare,
|
|
291
|
+
getBinaryPath,
|
|
292
|
+
hasNativeBinding
|
|
293
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { execFile } from "child_process";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { promisify } from "util";
|
|
9
|
+
var execFileAsync = promisify(execFile);
|
|
10
|
+
var PLATFORM_PACKAGES = {
|
|
11
|
+
"darwin-arm64": {
|
|
12
|
+
packageName: "@blazediff/core-native-darwin-arm64",
|
|
13
|
+
packageDir: "core-native-darwin-arm64"
|
|
14
|
+
},
|
|
15
|
+
"darwin-x64": {
|
|
16
|
+
packageName: "@blazediff/core-native-darwin-x64",
|
|
17
|
+
packageDir: "core-native-darwin-x64"
|
|
18
|
+
},
|
|
19
|
+
"linux-arm64": {
|
|
20
|
+
packageName: "@blazediff/core-native-linux-arm64",
|
|
21
|
+
packageDir: "core-native-linux-arm64"
|
|
22
|
+
},
|
|
23
|
+
"linux-x64": {
|
|
24
|
+
packageName: "@blazediff/core-native-linux-x64",
|
|
25
|
+
packageDir: "core-native-linux-x64"
|
|
26
|
+
},
|
|
27
|
+
"win32-arm64": {
|
|
28
|
+
packageName: "@blazediff/core-native-win32-arm64",
|
|
29
|
+
packageDir: "core-native-win32-arm64"
|
|
30
|
+
},
|
|
31
|
+
"win32-x64": {
|
|
32
|
+
packageName: "@blazediff/core-native-win32-x64",
|
|
33
|
+
packageDir: "core-native-win32-x64"
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var nativeBinding = null;
|
|
37
|
+
var nativeBindingAttempted = false;
|
|
38
|
+
function tryLoadNativeBinding() {
|
|
39
|
+
if (nativeBindingAttempted) {
|
|
40
|
+
return nativeBinding;
|
|
41
|
+
}
|
|
42
|
+
nativeBindingAttempted = true;
|
|
43
|
+
const platform = os.platform();
|
|
44
|
+
const arch = os.arch();
|
|
45
|
+
const key = `${platform}-${arch}`;
|
|
46
|
+
const platformInfo = PLATFORM_PACKAGES[key];
|
|
47
|
+
if (!platformInfo) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const require2 = createRequire(import.meta.url);
|
|
52
|
+
const binding = require2(platformInfo.packageName);
|
|
53
|
+
if (typeof binding?.compare === "function") {
|
|
54
|
+
nativeBinding = binding;
|
|
55
|
+
return binding;
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
61
|
+
const packagesDir = path.resolve(currentDir, "..", "..");
|
|
62
|
+
const nodePath = path.join(
|
|
63
|
+
packagesDir,
|
|
64
|
+
platformInfo.packageDir,
|
|
65
|
+
"blazediff.node"
|
|
66
|
+
);
|
|
67
|
+
if (existsSync(nodePath)) {
|
|
68
|
+
const require2 = createRequire(import.meta.url);
|
|
69
|
+
const binding = require2(nodePath);
|
|
70
|
+
if (typeof binding?.compare === "function") {
|
|
71
|
+
nativeBinding = binding;
|
|
72
|
+
return binding;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
function convertNapiResult(result) {
|
|
80
|
+
if (result.matchResult) {
|
|
81
|
+
return { match: true };
|
|
82
|
+
}
|
|
83
|
+
if (result.reason === "layout-diff") {
|
|
84
|
+
return { match: false, reason: "layout-diff" };
|
|
85
|
+
}
|
|
86
|
+
if (result.reason === "pixel-diff") {
|
|
87
|
+
return {
|
|
88
|
+
match: false,
|
|
89
|
+
reason: "pixel-diff",
|
|
90
|
+
diffCount: result.diffCount ?? 0,
|
|
91
|
+
diffPercentage: result.diffPercentage ?? 0
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
match: false,
|
|
96
|
+
reason: "pixel-diff",
|
|
97
|
+
diffCount: result.diffCount ?? 0,
|
|
98
|
+
diffPercentage: result.diffPercentage ?? 0
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function convertToNapiOptions(options) {
|
|
102
|
+
return {
|
|
103
|
+
threshold: options?.threshold,
|
|
104
|
+
antialiasing: options?.antialiasing,
|
|
105
|
+
diffMask: options?.diffMask,
|
|
106
|
+
compression: options?.compression,
|
|
107
|
+
quality: options?.quality
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function resolveBinaryPath() {
|
|
111
|
+
const platform = os.platform();
|
|
112
|
+
const arch = os.arch();
|
|
113
|
+
const key = `${platform}-${arch}`;
|
|
114
|
+
const platformInfo = PLATFORM_PACKAGES[key];
|
|
115
|
+
if (!platformInfo) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Unsupported platform: ${key}. Supported: ${Object.keys(PLATFORM_PACKAGES).join(", ")}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
const binaryName = platform === "win32" ? "blazediff.exe" : "blazediff";
|
|
121
|
+
try {
|
|
122
|
+
const require2 = createRequire(import.meta.url);
|
|
123
|
+
const packagePath = require2.resolve(
|
|
124
|
+
`${platformInfo.packageName}/package.json`
|
|
125
|
+
);
|
|
126
|
+
const packageDir = path.dirname(packagePath);
|
|
127
|
+
const binaryPath = path.join(packageDir, binaryName);
|
|
128
|
+
if (existsSync(binaryPath)) {
|
|
129
|
+
return binaryPath;
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
134
|
+
const packagesDir = path.resolve(currentDir, "..", "..");
|
|
135
|
+
const siblingPath = path.join(
|
|
136
|
+
packagesDir,
|
|
137
|
+
platformInfo.packageDir,
|
|
138
|
+
binaryName
|
|
139
|
+
);
|
|
140
|
+
if (existsSync(siblingPath)) {
|
|
141
|
+
return siblingPath;
|
|
142
|
+
}
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Platform package ${platformInfo.packageName} is not installed. This usually means the optional dependency wasn't installed for your platform. Try reinstalling with: npm install @blazediff/core-native`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
var cachedBinaryPath = null;
|
|
148
|
+
function getBinaryPathInternal() {
|
|
149
|
+
if (!cachedBinaryPath) {
|
|
150
|
+
cachedBinaryPath = resolveBinaryPath();
|
|
151
|
+
}
|
|
152
|
+
return cachedBinaryPath;
|
|
153
|
+
}
|
|
154
|
+
function buildArgs(diffOutput, options) {
|
|
155
|
+
const args = [];
|
|
156
|
+
if (diffOutput) args.push(diffOutput);
|
|
157
|
+
args.push("--output-format=json");
|
|
158
|
+
if (!options) return args;
|
|
159
|
+
if (options.threshold !== void 0)
|
|
160
|
+
args.push(`--threshold=${options.threshold}`);
|
|
161
|
+
if (options.antialiasing) args.push("--antialiasing");
|
|
162
|
+
if (options.diffMask) args.push("--diff-mask");
|
|
163
|
+
if (options.compression !== void 0)
|
|
164
|
+
args.push(`--compression=${options.compression}`);
|
|
165
|
+
if (options.quality !== void 0) args.push(`--quality=${options.quality}`);
|
|
166
|
+
return args;
|
|
167
|
+
}
|
|
168
|
+
function parseJsonOutput(text) {
|
|
169
|
+
try {
|
|
170
|
+
return JSON.parse(text);
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function detectMissingFile(error, basePath, comparePath) {
|
|
176
|
+
if (!/Failed to load images:.*(?:No such file|not found)/i.test(error)) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
if (error.includes(basePath)) return basePath;
|
|
180
|
+
if (error.includes(comparePath)) return comparePath;
|
|
181
|
+
return basePath;
|
|
182
|
+
}
|
|
183
|
+
async function execFileCompare(basePath, comparePath, diffOutput, options) {
|
|
184
|
+
const binaryPath = getBinaryPathInternal();
|
|
185
|
+
const args = [basePath, comparePath, ...buildArgs(diffOutput, options)];
|
|
186
|
+
try {
|
|
187
|
+
await execFileAsync(binaryPath, args);
|
|
188
|
+
return { match: true };
|
|
189
|
+
} catch (err) {
|
|
190
|
+
const { code, stdout, stderr } = err;
|
|
191
|
+
const output = stdout || stderr || "";
|
|
192
|
+
if (code === 1) {
|
|
193
|
+
const json = parseJsonOutput(output);
|
|
194
|
+
if (json?.error?.includes("Layout differs")) {
|
|
195
|
+
return { match: false, reason: "layout-diff" };
|
|
196
|
+
}
|
|
197
|
+
if (json) {
|
|
198
|
+
return {
|
|
199
|
+
match: false,
|
|
200
|
+
reason: "pixel-diff",
|
|
201
|
+
diffCount: json.diffCount,
|
|
202
|
+
diffPercentage: json.diffPercentage
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (output.includes("Layout differs")) {
|
|
206
|
+
return { match: false, reason: "layout-diff" };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (code === 2) {
|
|
210
|
+
const missingFile = detectMissingFile(output, basePath, comparePath);
|
|
211
|
+
if (missingFile) {
|
|
212
|
+
return { match: false, reason: "file-not-exists", file: missingFile };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
throw new Error(output || `blazediff exited with code ${code}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function compare(basePath, comparePath, diffOutput, options) {
|
|
219
|
+
const binding = tryLoadNativeBinding();
|
|
220
|
+
if (binding) {
|
|
221
|
+
try {
|
|
222
|
+
const result = binding.compare(
|
|
223
|
+
basePath,
|
|
224
|
+
comparePath,
|
|
225
|
+
diffOutput ?? null,
|
|
226
|
+
convertToNapiOptions(options)
|
|
227
|
+
);
|
|
228
|
+
return convertNapiResult(result);
|
|
229
|
+
} catch (err) {
|
|
230
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
231
|
+
const missingFile = detectMissingFile(message, basePath, comparePath);
|
|
232
|
+
if (missingFile) {
|
|
233
|
+
return { match: false, reason: "file-not-exists", file: missingFile };
|
|
234
|
+
}
|
|
235
|
+
throw err;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return execFileCompare(basePath, comparePath, diffOutput, options);
|
|
239
|
+
}
|
|
240
|
+
function getBinaryPath() {
|
|
241
|
+
return getBinaryPathInternal();
|
|
242
|
+
}
|
|
243
|
+
function hasNativeBinding() {
|
|
244
|
+
return tryLoadNativeBinding() !== null;
|
|
245
|
+
}
|
|
246
|
+
export {
|
|
247
|
+
compare,
|
|
248
|
+
getBinaryPath,
|
|
249
|
+
hasNativeBinding
|
|
250
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blazediff/core-native",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Native Rust binaries for blazediff - the fastest image diff in the world",
|
|
5
|
+
"private": false,
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"module": "dist/index.mjs",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.mjs",
|
|
16
|
+
"require": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"optionalDependencies": {
|
|
23
|
+
"@blazediff/core-native-darwin-arm64": "4.0.0",
|
|
24
|
+
"@blazediff/core-native-darwin-x64": "4.0.0",
|
|
25
|
+
"@blazediff/core-native-linux-arm64": "4.0.0",
|
|
26
|
+
"@blazediff/core-native-linux-x64": "4.0.0",
|
|
27
|
+
"@blazediff/core-native-win32-arm64": "4.0.0",
|
|
28
|
+
"@blazediff/core-native-win32-x64": "4.0.0"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"image",
|
|
32
|
+
"comparison",
|
|
33
|
+
"diff",
|
|
34
|
+
"pixel",
|
|
35
|
+
"visual-testing",
|
|
36
|
+
"visual-regression",
|
|
37
|
+
"screenshot",
|
|
38
|
+
"native",
|
|
39
|
+
"rust",
|
|
40
|
+
"simd",
|
|
41
|
+
"fast"
|
|
42
|
+
],
|
|
43
|
+
"author": "Teimur Gasanov <me@teimurjan.dev> (https://github.com/teimurjan)",
|
|
44
|
+
"repository": "https://github.com/teimurjan/blazediff",
|
|
45
|
+
"homepage": "https://blazediff.dev",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^24.3.0",
|
|
49
|
+
"tsup": "8.5.0",
|
|
50
|
+
"typescript": "5.9.2",
|
|
51
|
+
"vitest": "^3.2.4"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"build": "tsup",
|
|
56
|
+
"clean": "rm -rf dist",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:watch": "vitest"
|
|
59
|
+
}
|
|
60
|
+
}
|