@ blazediff/ 核心瓦斯
WebAssembly 为浏览器、边缘运行时间和任何主题主机构建了 BlazeDiff Rust 算法 。 相同的双通块算法 @blazediff/core-native编译为 wasm32 与 v128 SIMD (英语:+simd128) (中文(简体) ). -51% 速度超过 像素匹配 在同一 RGBA 缓冲器上( 在 4K 上最多为 ~90% ) ; diff 计数与像素匹配在 ~ 0.05% 内 .
特征 :
- 相同的 Rust 算法为
@blazediff/core-native(YIQ透视三角地+以块为主的冷/热通过) wasm32v128 SIMD: 四行向向量冷热循环; 最高为~16x快于4K上像素匹配- 一样
Image, (中文(简体) ),DiffOptions财务报告和审定财务报表DiffResult作为@blazediff/core。调用器解码图像;没有捆绑的 PNG/JPEG 编码器 - ~32 KB被优化为被子+~10 KB JS胶. 没有本地二进制, 没有邮购, 没有平台包
- 任何地方的运行:浏览器、节点18+、Cloudflare工人、Deno、Bun
安装
npm install @blazediff/core-wasm
正在装入主题模块
选一个适合你运行时间的食谱 四者相等;原相自同.
浏览器( 默认获取)
原子弹 --target web 胶水取出兄弟 .wasm 通过 import.meta.url 自动 :
import { initBlazediff } from '@blazediff/core-wasm';
await initBlazediff();
通用 CDN URL (推荐给节点, 工人, Deno, Bun)
jsDelivr 为已出版的作品服务 .wasm 过HTTPS,所以任何 fetch()- 能够运行的时间可以装上它。 冷起步时一个网络回转, 由之后的运行时间缓存 :
import { initBlazediff } from '@blazediff/core-wasm';
await initBlazediff(
new URL(
'https://cdn.jsdelivr.net/npm/@blazediff/[email protected]/wasm/blazediff_bg.wasm',
),
);
键入版本( P)@7.0.0) (中文(简体) ). 它必须符合安装的软件包,因为JS胶水和 .wasm 一起换衣服. unpkg.com/@blazediff/[email protected]/wasm/blazediff_bg.wasm 一样的工作.
Bundlers (Vite, Webpack 5+, esbuilt, 有插件的滚起)
这个 new URL(asset, import.meta.url) 模式为 bunder-aware : 资产释放到构建输出中, URL 在构建时重写 :
import { initBlazediff } from '@blazediff/core-wasm';
const wasmUrl = new URL(
'@blazediff/core-wasm/wasm/blazediff_bg.wasm',
import.meta.url,
);
await initBlazediff(wasmUrl);
本地文件系统的节点
离线,没有CDN依赖. 读取字节并传入:
// ESM (Node 20.6+):
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { initBlazediff } from '@blazediff/core-wasm';
const wasmPath = fileURLToPath(
import.meta.resolve('@blazediff/core-wasm/wasm/blazediff_bg.wasm'),
);
await initBlazediff(readFileSync(wasmPath));
// CommonJS:
const { readFileSync } = require('node:fs');
const { initBlazediff } = require('@blazediff/core-wasm');
const wasmPath = require.resolve(
'@blazediff/core-wasm/wasm/blazediff_bg.wasm',
);
await initBlazediff(readFileSync(wasmPath));
API 密码
initBlazediff(input?)
初始化 enm 模块 。 安全呼叫多次; 后续呼叫返回已缓存的承诺 。 接受一个 URL, (中文(简体) ), Response, (中文(简体) ), ArrayBuffer, (中文(简体) ), Uint8Array,或编译 WebAssembly.Module没有 input默认值 --target web 胶水取出兄弟 blazediff_bg.wasm 通过 import.meta.url (浏览器中的工作;其他运行时间需要明确输入,见上文).
回返情况: Promise<void>
diff(a, b, options?)
比较两个RGBA图像. 取回与 @blazediff/core是因为 diff,从中导入.
| 参数 | 类型 | 说明 |
|---|---|---|
a, (中文(简体) ), b |
图像 | { data, width, height } 带有 RGBA8 像素(width * height * 4 字节). 浏览器 ImageData 符合现在 |
options |
Diff 选项 | 比较选项( 可选) |
回返情况: Promise<DiffResult>
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
threshold |
编号 | 0.1 数据 | 颜色差阈值 (0-1). 下调更严格 |
antialiasing |
布尔 | 真实 | 检测出反变相像素, 并把它们从数中排除 |
metric |
"yiq" \"oklab" (俄克利亚语) | "对" | 颜色相差度量. oklab 给出与像素匹配 8 相同的计数 |
mask |
Uint8 阵列 | - 说吧 | 每个像素一个字节(宽×高). 非零像素被跳过 |
window |
编号 | - 说吧 | 同时报告最diff像素的 NxN 窗口 |
output |
图像 | - 说吧 | 将 diff 绘制到此图像的位置 。 相同的图像留下未写 |
render |
阿尔法 迪夫克洛尔 迪夫克洛尔 阿尔特 | - 说吧 | 输出造型. background: "transparent" 独自绘制 diff |
type DiffResult =
| {
kind: "compared";
count: number;
percentage: number;
identical: boolean;
/** Top-left corner and count of the busiest window, when `window` is set. */
window?: { x: number; y: number; count: number };
}
| { kind: "dimension-mismatch"; a: Size; b: Size };
以 a 拒绝无效的选项或缓冲 BlazeDiffError 这有一个 code数字 : invalid-image, (中文(简体) ), invalid-output, (中文(简体) ), invalid-mask 或者说 invalid-option。 。 。 .
const result = await diff(a, b, {
output: { data: out, width, height },
render: { diffColorAlt: [0, 128, 255] },
});
区域分析 - 什麽 而不是在——不再参与其中的地方
软件包。 它住在这里
@blazediff/interpret-native, (中文(简体) ),
它是一个节点 N- API 软件包, 并且没有建立主题 .
使用量
浏览器
通过解码图像 createImageBitmap + 键 OffscreenCanvas (或 ImageDecoder API),然后通过 RGBA 缓冲器到 diff()数字 :
import { diff, initBlazediff } from '@blazediff/core-wasm';
await initBlazediff();
async function toRgba(url: string) {
const bitmap = await createImageBitmap(await (await fetch(url)).blob());
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
const ctx = canvas.getContext('2d')!;
ctx.drawImage(bitmap, 0, 0);
return ctx.getImageData(0, 0, bitmap.width, bitmap.height);
}
const a = await toRgba('/baseline.png');
const b = await toRgba('/current.png');
const output = new ImageData(a.width, a.height);
const result = await diff(a, b, { output, threshold: 0.1 });
if (result.kind === 'compared') console.log(`${result.count} pixels differ`);
节点
import { readFileSync } from 'node:fs';
import { diff, initBlazediff } from '@blazediff/core-wasm';
import { PNG } from 'pngjs';
await initBlazediff(
new URL(
'https://cdn.jsdelivr.net/npm/@blazediff/[email protected]/wasm/blazediff_bg.wasm',
),
);
const a = PNG.sync.read(readFileSync('baseline.png'));
const b = PNG.sync.read(readFileSync('current.png'));
const result = await diff(a, b);
业绩
对 pixelmatch 在 M1 Max 上, 图像 I/ O 被排除( 预解码的 RGBA 缓冲) :
| 固定线 | 像素匹配 | 核心主题 | 改进 |
|---|---|---|---|
| 4k/1 (单位:千美元) | 338.53亿 | 34.42毫米口径 | 89.8% |
| 4k/3 (单位:千美元) | 415.01亿 | 45.34米) | 89.1% 妇女 |
| 第2页 | 511.88亿 | 70.89亿 | 86.2% |
| 3号 | 12.08亿 | 5.76亿 | 52.3% |
| 像素比对/ 1个 | 0.57亿 | 0.11亿 | 80.5% (中文(简体) ) |
平均数 -51% 更快地跨出整个固定套(~60%跨出不同的对). 计数在~0.05%范围内(如. 4k/1:69 932 vs 69 912 of 17 9.20万像素).
全部基准 银行。 。 。 .
算法
与双通区块办法相同 @blazediff/core-native,重新编译为:
- 冷传: 使用32位整数比较扫描8x8块的图像,以识别已改变的区域
- 热传: 仅应用 YIQ 感知颜色差异标记的流程块
- 师曰:
v128内在因素(f32x4_*, (中文(简体) ),i32x4_*),用于平行的4行RGBA取出,α相混合,YIQ变出,和阈值比较. 基线 simd128 没有本地的FMA,所以加权金额使用add(mul, c) - 反盗用: Vysniauskas(2009年) 探测AA文物的算法
选择正确的软件包
| 使用大小写 | 软件包 |
|---|---|
| 浏览器、 边工、 站点主机 | @blazediff/core-wasm |
| 带有本地 bin 的节点 CLI / 服务器 | @blazediff/core-native |
| 纯JS/无支持 | @blazediff/core |
参考资料
- YIQ 色彩空间 : 科萨连科和拉莫斯(2009年)
- 反干扰检测: 维斯尼亚卡斯(2009年)
- 网络大会SIMD: 网络大会/图像 (v128 / simd128规格)