@blazediff/matcher 1.1.1 → 1.2.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/dist/index.d.ts +10 -5
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +6 -6
- package/dist/index.d.mts +0 -211
package/dist/index.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ type ComparisonMethod = "bin" | "core" | "ssim" | "msssim" | "hitchhikers-ssim"
|
|
|
7
7
|
*/
|
|
8
8
|
type SnapshotStatus = "added" | "matched" | "updated" | "failed";
|
|
9
9
|
/**
|
|
10
|
-
* Image input -
|
|
10
|
+
* Image input - file path, raw PNG buffer, or buffer with dimensions
|
|
11
11
|
*/
|
|
12
|
-
type ImageInput = string | {
|
|
12
|
+
type ImageInput = string | Buffer | Uint8Array | {
|
|
13
13
|
data: Uint8Array | Uint8ClampedArray | Buffer;
|
|
14
14
|
width: number;
|
|
15
15
|
height: number;
|
|
@@ -156,6 +156,10 @@ declare function runComparison(received: ImageInput, baseline: ImageInput, metho
|
|
|
156
156
|
* Check if input is a file path
|
|
157
157
|
*/
|
|
158
158
|
declare function isFilePath(input: ImageInput): input is string;
|
|
159
|
+
/**
|
|
160
|
+
* Check if input is a raw PNG buffer (Buffer or Uint8Array without dimensions)
|
|
161
|
+
*/
|
|
162
|
+
declare function isRawPngBuffer(input: ImageInput): input is Buffer | Uint8Array;
|
|
159
163
|
/**
|
|
160
164
|
* Check if input is an image buffer with dimensions
|
|
161
165
|
*/
|
|
@@ -174,8 +178,9 @@ declare function loadPNG(filePath: string): Promise<ImageData>;
|
|
|
174
178
|
declare function savePNG(filePath: string, data: Uint8Array | Uint8ClampedArray | Buffer, width: number, height: number): Promise<void>;
|
|
175
179
|
/**
|
|
176
180
|
* Normalize image input to ImageData
|
|
177
|
-
*
|
|
178
|
-
*
|
|
181
|
+
* - File path: loads the PNG
|
|
182
|
+
* - Raw PNG buffer: decodes to get dimensions
|
|
183
|
+
* - Buffer with dimensions: returns as-is with normalized Uint8Array
|
|
179
184
|
*/
|
|
180
185
|
declare function normalizeImageInput(input: ImageInput): Promise<ImageData>;
|
|
181
186
|
/**
|
|
@@ -208,4 +213,4 @@ declare function getOrCreateSnapshot(received: ImageInput, options: MatcherOptio
|
|
|
208
213
|
*/
|
|
209
214
|
declare function compareImages(received: ImageInput, baseline: ImageInput, options: MatcherOptions): Promise<ComparisonResult>;
|
|
210
215
|
|
|
211
|
-
export { type ComparisonMethod, type ComparisonResult, type FormatOptions, type ImageData, type ImageInput, type MatcherOptions, type TestContext, compareImages, fileExists, formatMessage as formatReport, getOrCreateSnapshot, isFilePath, isImageBuffer, loadPNG, normalizeImageInput, runComparison, savePNG, validateMethodSupportsInput };
|
|
216
|
+
export { type ComparisonMethod, type ComparisonResult, type FormatOptions, type ImageData, type ImageInput, type MatcherOptions, type TestContext, compareImages, fileExists, formatMessage as formatReport, getOrCreateSnapshot, isFilePath, isImageBuffer, isRawPngBuffer, loadPNG, normalizeImageInput, runComparison, savePNG, validateMethodSupportsInput };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var fs=require('fs'),path=require('path'),pngjsTransformer=require('@blazediff/pngjs-transformer'),bin=require('@blazediff/bin'),core=require('@blazediff/core'),gmsd=require('@blazediff/gmsd'),ssim=require('@blazediff/ssim'),hitchhikersSsim=require('@blazediff/ssim/hitchhikers-ssim'),msssim=require('@blazediff/ssim/msssim'),s=require('picocolors');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var s__default=/*#__PURE__*/_interopDefault(s);function c(
|
|
2
|
-
`)}function
|
|
3
|
-
`)}function
|
|
1
|
+
'use strict';var fs=require('fs'),path=require('path'),pngjsTransformer=require('@blazediff/pngjs-transformer'),bin=require('@blazediff/bin'),core=require('@blazediff/core'),gmsd=require('@blazediff/gmsd'),ssim=require('@blazediff/ssim'),hitchhikersSsim=require('@blazediff/ssim/hitchhikers-ssim'),msssim=require('@blazediff/ssim/msssim'),s=require('picocolors');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var s__default=/*#__PURE__*/_interopDefault(s);function c(e){return typeof e=="string"}function $(e){return (Buffer.isBuffer(e)||e instanceof Uint8Array)&&!("width"in e)}function j(e){return typeof e=="object"&&e!==null&&"data"in e&&"width"in e&&"height"in e}async function I(e){if(!fs.existsSync(e))throw new Error(`Image file not found: ${e}`);let t=await pngjsTransformer.pngjsTransformer.read(e);return {data:new Uint8Array(t.data),width:t.width,height:t.height}}async function l(e,t,o,a){let i=path.dirname(e);fs.existsSync(i)||fs.mkdirSync(i,{recursive:true}),await pngjsTransformer.pngjsTransformer.write({data:t,width:o,height:a},e);}async function w(e){if(c(e))return I(e);if($(e)){let t=Buffer.isBuffer(e)?e:Buffer.from(e),o=await pngjsTransformer.pngjsTransformer.read(t);return {data:new Uint8Array(o.data),width:o.width,height:o.height}}return {data:new Uint8Array(e.data),width:e.width,height:e.height}}function E(e){return fs.existsSync(e)}function z(e){fs.existsSync(e)||fs.mkdirSync(e,{recursive:true});}async function U(e,t,o,a){if(!c(e))throw new Error("Method 'bin' only supports file paths, but received a buffer. Use method 'core', 'ssim', or 'gmsd' for buffer inputs.");if(!c(t))throw new Error("Method 'bin' only supports file paths for baseline, but received a buffer. Use method 'core', 'ssim', or 'gmsd' for buffer inputs.");let i=await bin.compare(e,t,o,{threshold:a.threshold,antialiasing:a.antialiasing});if(i.match)return {diffCount:0,diffPercentage:0};if(i.reason==="layout-diff")return {diffCount:Number.MAX_SAFE_INTEGER,diffPercentage:100};if(i.reason==="pixel-diff")return {diffCount:i.diffCount,diffPercentage:i.diffPercentage};if(i.reason==="file-not-exists")throw new Error(`Image file not found: ${i.file}`);return {diffCount:0,diffPercentage:0}}function B(e,t,o,a){let{width:i,height:r}=e,f=i*r;if(e.width!==t.width||e.height!==t.height)return {diffCount:f,diffPercentage:100};let d=o?new Uint8Array(f*4):void 0,n=core.diff(e.data,t.data,d,i,r,{threshold:a.threshold??.1,includeAA:a.includeAA??false});return {diffCount:n,diffPercentage:n/f*100,diffOutput:d}}function k(e,t,o,a){let{width:i,height:r}=e,f=i*r;if(e.width!==t.width||e.height!==t.height)return {score:1};let d=o?new Uint8Array(f*4):void 0;return {score:gmsd.gmsd(e.data,t.data,d,i,r,{downsample:a.downsample}),diffOutput:d}}function F(e,t,o,a,i){let{width:r,height:f}=e,d=r*f;if(e.width!==t.width||e.height!==t.height)return {score:0};let n=a?new Uint8Array(d*4):void 0,u={windowSize:i.windowSize,k1:i.k1,k2:i.k2},p;switch(o){case "ssim":p=ssim.ssim(e.data,t.data,n,r,f,u);break;case "msssim":p=msssim.msssim(e.data,t.data,n,r,f,u);break;case "hitchhikers-ssim":p=hitchhikersSsim.hitchhikersSSIM(e.data,t.data,n,r,f,u);break;default:throw new Error(`Unknown SSIM method: ${o}`)}return {score:p,diffOutput:n}}function x(e){return e==="ssim"||e==="msssim"||e==="hitchhikers-ssim"}function G(e,t){if(e==="bin"&&!c(t))throw new Error("Method 'bin' only supports file paths, but received a buffer. Use method 'core', 'ssim', or 'gmsd' for buffer inputs.")}async function O(e,t,o,a,i){if(G(o,e),G(o,t),o==="bin"){let u=await U(e,t,i,a);return {diffCount:u.diffCount,diffPercentage:u.diffPercentage}}let r=await w(e),f=await w(t),d=i!==void 0;if(x(o)){let u=F(r,f,o,d,a);return {score:u.score,diffOutput:u.diffOutput}}if(o==="gmsd"){let u=k(r,f,d,a);return {score:u.score,diffOutput:u.diffOutput}}let n=B(r,f,d,a);return {diffCount:n.diffCount,diffPercentage:n.diffPercentage,diffOutput:n.diffOutput}}var S={success:s__default.default.isColorSupported?"\u2714":"\u221A",error:s__default.default.isColorSupported?"\u2716":"\xD7",info:s__default.default.isColorSupported?"\u2139":"i",arrow:s__default.default.isColorSupported?"\u2514\u2500":"'-"},J=new Set(["ssim","msssim","hitchhikers-ssim"]);function y(e){return e.snapshotCreated?K(e.baselinePath):e.pass?Q():V(e)}function K(e){return [`${s__default.default.green(S.success)} ${s__default.default.green("New snapshot created")}`,` ${s__default.default.dim(S.arrow)} ${s__default.default.dim(e)}`].join(`
|
|
2
|
+
`)}function Q(){return `${s__default.default.green(S.success)} ${s__default.default.green("Image matches snapshot")}`}function V(e){let{method:t,baselinePath:o,receivedPath:a,diffPath:i,diffCount:r=0,diffPercentage:f,score:d=0,threshold:n,thresholdType:u,updateCommand:p}=e,h=[`${s__default.default.red(S.error)} ${s__default.default.red(s__default.default.bold("Image snapshot mismatch"))}`,""],m=12;if(h.push(` ${s__default.default.dim("Method".padEnd(m))}${t}`),h.push(` ${s__default.default.dim("Baseline".padEnd(m))}${s__default.default.dim(o)}`),h.push(` ${s__default.default.dim("Received".padEnd(m))}${s__default.default.dim(a)}`),h.push(` ${s__default.default.dim("Diff".padEnd(m))}${s__default.default.dim(i)}`),h.push(""),J.has(t)){let b=((1-d)*100).toFixed(2);h.push(` ${s__default.default.dim("SSIM Score".padEnd(m))}${s__default.default.yellow(d.toFixed(4))} ${s__default.default.dim("(1.0 = identical)")}`),h.push(` ${s__default.default.dim("Difference".padEnd(m))}${s__default.default.yellow(`${b}%`)}`);}else if(t==="gmsd")h.push(` ${s__default.default.dim("GMSD Score".padEnd(m))}${s__default.default.yellow(d.toFixed(4))} ${s__default.default.dim("(0.0 = identical)")}`);else {let b=f?.toFixed(2)??"0.00";h.push(` ${s__default.default.dim("Difference".padEnd(m))}${s__default.default.yellow(r.toLocaleString())} pixels ${s__default.default.dim(`(${b}%)`)}`);}let P=u==="percent"?"%":"pixels";return h.push(` ${s__default.default.dim("Threshold".padEnd(m))}${n} ${P}`),h.push(""),h.push(` ${s__default.default.cyan(S.info)} ${s__default.default.cyan(`Run with ${p??"--update"} to update the snapshot`)}`),h.join(`
|
|
3
|
+
`)}function te(e){return e.testName.replace(/[^a-zA-Z0-9-_\s]/g,"").replace(/\s+/g,"-").toLowerCase()||"snapshot"}function re(e,t){let o=path.dirname(e.testPath),a=t.snapshotsDir??"__snapshots__",i=path.isAbsolute(a)?a:path.join(o,a),r=t.snapshotIdentifier??te(e);return {snapshotDir:i,baselinePath:path.join(i,`${r}.png`),receivedPath:path.join(i,`${r}.received.png`),diffPath:path.join(i,`${r}.diff.png`)}}function _(e,t,o){let a=o.failureThreshold??0,i=o.failureThresholdType??"pixel";if(x(e)){let r=t.score??0;return i==="percent"?(1-r)*100<=a:r>=1-a/100}if(e==="gmsd"){let r=t.score??0;return i==="percent"?r*100<=a:r<=a/100}return i==="percent"?(t.diffPercentage??0)<=a:(t.diffCount??0)<=a}async function ae(e,t,o){let a=re(o,t),{snapshotDir:i,baselinePath:r,receivedPath:f,diffPath:d}=a,n=$(e)?await w(e):e;z(i);let u=E(r),p=t.updateSnapshots===true?"all":t.updateSnapshots===false||t.updateSnapshots===void 0?"new":t.updateSnapshots;if(!u&&p!=="none"&&(p==="new"||p==="all")){if(c(n)){let C=await I(n);await l(r,C.data,C.width,C.height);}else await l(r,n.data,n.width,n.height);return {pass:true,message:y({pass:true,method:t.method,snapshotCreated:true,baselinePath:r,receivedPath:f,diffPath:d,diffCount:0,diffPercentage:0,score:0,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),baselinePath:r,snapshotStatus:"added"}}let m=await O(n,r,t.method,t,d),P=_(t.method,m,t);if(P)return fs.existsSync(f)&&fs.unlinkSync(f),fs.existsSync(d)&&fs.unlinkSync(d),{pass:true,message:y({pass:P,method:t.method,snapshotCreated:false,baselinePath:r,receivedPath:f,diffPath:d,diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,baselinePath:r,snapshotStatus:"matched"};if(p==="all"){if(c(n)){let C=await I(n);await l(r,C.data,C.width,C.height);}else await l(r,n.data,n.width,n.height);return fs.existsSync(f)&&fs.unlinkSync(f),fs.existsSync(d)&&fs.unlinkSync(d),{pass:true,message:y({pass:true,method:t.method,snapshotCreated:true,baselinePath:r,receivedPath:f,diffPath:d,diffCount:0,diffPercentage:0,score:0,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),baselinePath:r,snapshotStatus:"updated"}}if(c(n)){let g=await I(n);await l(f,g.data,g.width,g.height);}else await l(f,n.data,n.width,n.height);if(m.diffOutput){let g=await w(n);await l(d,m.diffOutput,g.width,g.height);}return {pass:false,message:y({pass:P,method:t.method,snapshotCreated:false,baselinePath:r,receivedPath:f,diffPath:d,diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,baselinePath:r,receivedPath:f,diffPath:d,snapshotStatus:"failed"}}async function ie(e,t,o){let a=await O(e,t,o.method,o),i=_(o.method,a,o);return {pass:i,message:i?"Images match.":`Images differ: ${a.diffCount??a.score} ${a.diffCount!==void 0?"pixels":"score"}`,diffCount:a.diffCount,diffPercentage:a.diffPercentage,score:a.score}}exports.compareImages=ie;exports.fileExists=E;exports.formatReport=y;exports.getOrCreateSnapshot=ae;exports.isFilePath=c;exports.isImageBuffer=j;exports.isRawPngBuffer=$;exports.loadPNG=I;exports.normalizeImageInput=w;exports.runComparison=O;exports.savePNG=l;exports.validateMethodSupportsInput=G;
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {existsSync,mkdirSync,unlinkSync}from'fs';import {dirname,isAbsolute,join}from'path';import {pngjsTransformer}from'@blazediff/pngjs-transformer';import {compare}from'@blazediff/bin';import {diff}from'@blazediff/core';import {gmsd}from'@blazediff/gmsd';import {ssim}from'@blazediff/ssim';import {hitchhikersSSIM}from'@blazediff/ssim/hitchhikers-ssim';import {msssim}from'@blazediff/ssim/msssim';import s from'picocolors';function c(
|
|
2
|
-
`)}function
|
|
3
|
-
`)}function
|
|
1
|
+
import {existsSync,mkdirSync,unlinkSync}from'fs';import {dirname,isAbsolute,join}from'path';import {pngjsTransformer}from'@blazediff/pngjs-transformer';import {compare}from'@blazediff/bin';import {diff}from'@blazediff/core';import {gmsd}from'@blazediff/gmsd';import {ssim}from'@blazediff/ssim';import {hitchhikersSSIM}from'@blazediff/ssim/hitchhikers-ssim';import {msssim}from'@blazediff/ssim/msssim';import s from'picocolors';function c(e){return typeof e=="string"}function $(e){return (Buffer.isBuffer(e)||e instanceof Uint8Array)&&!("width"in e)}function j(e){return typeof e=="object"&&e!==null&&"data"in e&&"width"in e&&"height"in e}async function I(e){if(!existsSync(e))throw new Error(`Image file not found: ${e}`);let t=await pngjsTransformer.read(e);return {data:new Uint8Array(t.data),width:t.width,height:t.height}}async function l(e,t,o,a){let i=dirname(e);existsSync(i)||mkdirSync(i,{recursive:true}),await pngjsTransformer.write({data:t,width:o,height:a},e);}async function w(e){if(c(e))return I(e);if($(e)){let t=Buffer.isBuffer(e)?e:Buffer.from(e),o=await pngjsTransformer.read(t);return {data:new Uint8Array(o.data),width:o.width,height:o.height}}return {data:new Uint8Array(e.data),width:e.width,height:e.height}}function E(e){return existsSync(e)}function z(e){existsSync(e)||mkdirSync(e,{recursive:true});}async function U(e,t,o,a){if(!c(e))throw new Error("Method 'bin' only supports file paths, but received a buffer. Use method 'core', 'ssim', or 'gmsd' for buffer inputs.");if(!c(t))throw new Error("Method 'bin' only supports file paths for baseline, but received a buffer. Use method 'core', 'ssim', or 'gmsd' for buffer inputs.");let i=await compare(e,t,o,{threshold:a.threshold,antialiasing:a.antialiasing});if(i.match)return {diffCount:0,diffPercentage:0};if(i.reason==="layout-diff")return {diffCount:Number.MAX_SAFE_INTEGER,diffPercentage:100};if(i.reason==="pixel-diff")return {diffCount:i.diffCount,diffPercentage:i.diffPercentage};if(i.reason==="file-not-exists")throw new Error(`Image file not found: ${i.file}`);return {diffCount:0,diffPercentage:0}}function B(e,t,o,a){let{width:i,height:r}=e,f=i*r;if(e.width!==t.width||e.height!==t.height)return {diffCount:f,diffPercentage:100};let d=o?new Uint8Array(f*4):void 0,n=diff(e.data,t.data,d,i,r,{threshold:a.threshold??.1,includeAA:a.includeAA??false});return {diffCount:n,diffPercentage:n/f*100,diffOutput:d}}function k(e,t,o,a){let{width:i,height:r}=e,f=i*r;if(e.width!==t.width||e.height!==t.height)return {score:1};let d=o?new Uint8Array(f*4):void 0;return {score:gmsd(e.data,t.data,d,i,r,{downsample:a.downsample}),diffOutput:d}}function F(e,t,o,a,i){let{width:r,height:f}=e,d=r*f;if(e.width!==t.width||e.height!==t.height)return {score:0};let n=a?new Uint8Array(d*4):void 0,u={windowSize:i.windowSize,k1:i.k1,k2:i.k2},p;switch(o){case "ssim":p=ssim(e.data,t.data,n,r,f,u);break;case "msssim":p=msssim(e.data,t.data,n,r,f,u);break;case "hitchhikers-ssim":p=hitchhikersSSIM(e.data,t.data,n,r,f,u);break;default:throw new Error(`Unknown SSIM method: ${o}`)}return {score:p,diffOutput:n}}function x(e){return e==="ssim"||e==="msssim"||e==="hitchhikers-ssim"}function G(e,t){if(e==="bin"&&!c(t))throw new Error("Method 'bin' only supports file paths, but received a buffer. Use method 'core', 'ssim', or 'gmsd' for buffer inputs.")}async function O(e,t,o,a,i){if(G(o,e),G(o,t),o==="bin"){let u=await U(e,t,i,a);return {diffCount:u.diffCount,diffPercentage:u.diffPercentage}}let r=await w(e),f=await w(t),d=i!==void 0;if(x(o)){let u=F(r,f,o,d,a);return {score:u.score,diffOutput:u.diffOutput}}if(o==="gmsd"){let u=k(r,f,d,a);return {score:u.score,diffOutput:u.diffOutput}}let n=B(r,f,d,a);return {diffCount:n.diffCount,diffPercentage:n.diffPercentage,diffOutput:n.diffOutput}}var S={success:s.isColorSupported?"\u2714":"\u221A",error:s.isColorSupported?"\u2716":"\xD7",info:s.isColorSupported?"\u2139":"i",arrow:s.isColorSupported?"\u2514\u2500":"'-"},J=new Set(["ssim","msssim","hitchhikers-ssim"]);function y(e){return e.snapshotCreated?K(e.baselinePath):e.pass?Q():V(e)}function K(e){return [`${s.green(S.success)} ${s.green("New snapshot created")}`,` ${s.dim(S.arrow)} ${s.dim(e)}`].join(`
|
|
2
|
+
`)}function Q(){return `${s.green(S.success)} ${s.green("Image matches snapshot")}`}function V(e){let{method:t,baselinePath:o,receivedPath:a,diffPath:i,diffCount:r=0,diffPercentage:f,score:d=0,threshold:n,thresholdType:u,updateCommand:p}=e,h=[`${s.red(S.error)} ${s.red(s.bold("Image snapshot mismatch"))}`,""],m=12;if(h.push(` ${s.dim("Method".padEnd(m))}${t}`),h.push(` ${s.dim("Baseline".padEnd(m))}${s.dim(o)}`),h.push(` ${s.dim("Received".padEnd(m))}${s.dim(a)}`),h.push(` ${s.dim("Diff".padEnd(m))}${s.dim(i)}`),h.push(""),J.has(t)){let b=((1-d)*100).toFixed(2);h.push(` ${s.dim("SSIM Score".padEnd(m))}${s.yellow(d.toFixed(4))} ${s.dim("(1.0 = identical)")}`),h.push(` ${s.dim("Difference".padEnd(m))}${s.yellow(`${b}%`)}`);}else if(t==="gmsd")h.push(` ${s.dim("GMSD Score".padEnd(m))}${s.yellow(d.toFixed(4))} ${s.dim("(0.0 = identical)")}`);else {let b=f?.toFixed(2)??"0.00";h.push(` ${s.dim("Difference".padEnd(m))}${s.yellow(r.toLocaleString())} pixels ${s.dim(`(${b}%)`)}`);}let P=u==="percent"?"%":"pixels";return h.push(` ${s.dim("Threshold".padEnd(m))}${n} ${P}`),h.push(""),h.push(` ${s.cyan(S.info)} ${s.cyan(`Run with ${p??"--update"} to update the snapshot`)}`),h.join(`
|
|
3
|
+
`)}function te(e){return e.testName.replace(/[^a-zA-Z0-9-_\s]/g,"").replace(/\s+/g,"-").toLowerCase()||"snapshot"}function re(e,t){let o=dirname(e.testPath),a=t.snapshotsDir??"__snapshots__",i=isAbsolute(a)?a:join(o,a),r=t.snapshotIdentifier??te(e);return {snapshotDir:i,baselinePath:join(i,`${r}.png`),receivedPath:join(i,`${r}.received.png`),diffPath:join(i,`${r}.diff.png`)}}function _(e,t,o){let a=o.failureThreshold??0,i=o.failureThresholdType??"pixel";if(x(e)){let r=t.score??0;return i==="percent"?(1-r)*100<=a:r>=1-a/100}if(e==="gmsd"){let r=t.score??0;return i==="percent"?r*100<=a:r<=a/100}return i==="percent"?(t.diffPercentage??0)<=a:(t.diffCount??0)<=a}async function ae(e,t,o){let a=re(o,t),{snapshotDir:i,baselinePath:r,receivedPath:f,diffPath:d}=a,n=$(e)?await w(e):e;z(i);let u=E(r),p=t.updateSnapshots===true?"all":t.updateSnapshots===false||t.updateSnapshots===void 0?"new":t.updateSnapshots;if(!u&&p!=="none"&&(p==="new"||p==="all")){if(c(n)){let C=await I(n);await l(r,C.data,C.width,C.height);}else await l(r,n.data,n.width,n.height);return {pass:true,message:y({pass:true,method:t.method,snapshotCreated:true,baselinePath:r,receivedPath:f,diffPath:d,diffCount:0,diffPercentage:0,score:0,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),baselinePath:r,snapshotStatus:"added"}}let m=await O(n,r,t.method,t,d),P=_(t.method,m,t);if(P)return existsSync(f)&&unlinkSync(f),existsSync(d)&&unlinkSync(d),{pass:true,message:y({pass:P,method:t.method,snapshotCreated:false,baselinePath:r,receivedPath:f,diffPath:d,diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,baselinePath:r,snapshotStatus:"matched"};if(p==="all"){if(c(n)){let C=await I(n);await l(r,C.data,C.width,C.height);}else await l(r,n.data,n.width,n.height);return existsSync(f)&&unlinkSync(f),existsSync(d)&&unlinkSync(d),{pass:true,message:y({pass:true,method:t.method,snapshotCreated:true,baselinePath:r,receivedPath:f,diffPath:d,diffCount:0,diffPercentage:0,score:0,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),baselinePath:r,snapshotStatus:"updated"}}if(c(n)){let g=await I(n);await l(f,g.data,g.width,g.height);}else await l(f,n.data,n.width,n.height);if(m.diffOutput){let g=await w(n);await l(d,m.diffOutput,g.width,g.height);}return {pass:false,message:y({pass:P,method:t.method,snapshotCreated:false,baselinePath:r,receivedPath:f,diffPath:d,diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,threshold:t.failureThreshold??0,thresholdType:t.failureThresholdType??"pixel",updateCommand:t.updateCommand}),diffCount:m.diffCount,diffPercentage:m.diffPercentage,score:m.score,baselinePath:r,receivedPath:f,diffPath:d,snapshotStatus:"failed"}}async function ie(e,t,o){let a=await O(e,t,o.method,o),i=_(o.method,a,o);return {pass:i,message:i?"Images match.":`Images differ: ${a.diffCount??a.score} ${a.diffCount!==void 0?"pixels":"score"}`,diffCount:a.diffCount,diffPercentage:a.diffPercentage,score:a.score}}export{ie as compareImages,E as fileExists,y as formatReport,ae as getOrCreateSnapshot,c as isFilePath,j as isImageBuffer,$ as isRawPngBuffer,I as loadPNG,w as normalizeImageInput,O as runComparison,l as savePNG,G as validateMethodSupportsInput};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blazediff/matcher",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Core matcher logic for visual regression testing with blazediff",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"picocolors": "^1.1.1",
|
|
36
|
-
"@blazediff/bin": "3.1.
|
|
37
|
-
"@blazediff/core": "1.9.
|
|
38
|
-
"@blazediff/gmsd": "1.7.
|
|
39
|
-
"@blazediff/
|
|
40
|
-
"@blazediff/
|
|
36
|
+
"@blazediff/bin": "3.1.1",
|
|
37
|
+
"@blazediff/core": "1.9.1",
|
|
38
|
+
"@blazediff/gmsd": "1.7.1",
|
|
39
|
+
"@blazediff/pngjs-transformer": "2.1.1",
|
|
40
|
+
"@blazediff/ssim": "1.7.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^24.3.0",
|
package/dist/index.d.mts
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Comparison methods available in blazediff
|
|
3
|
-
*/
|
|
4
|
-
type ComparisonMethod = "bin" | "core" | "ssim" | "msssim" | "hitchhikers-ssim" | "gmsd";
|
|
5
|
-
/**
|
|
6
|
-
* Status of a snapshot operation
|
|
7
|
-
*/
|
|
8
|
-
type SnapshotStatus = "added" | "matched" | "updated" | "failed";
|
|
9
|
-
/**
|
|
10
|
-
* Image input - either a file path or a buffer with dimensions
|
|
11
|
-
*/
|
|
12
|
-
type ImageInput = string | {
|
|
13
|
-
data: Uint8Array | Uint8ClampedArray | Buffer;
|
|
14
|
-
width: number;
|
|
15
|
-
height: number;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Options for the matcher
|
|
19
|
-
*/
|
|
20
|
-
interface MatcherOptions {
|
|
21
|
-
/** Comparison method to use */
|
|
22
|
-
method: ComparisonMethod;
|
|
23
|
-
/**
|
|
24
|
-
* Failure threshold - number of pixels or percentage difference allowed
|
|
25
|
-
* @default 0
|
|
26
|
-
*/
|
|
27
|
-
failureThreshold?: number;
|
|
28
|
-
/**
|
|
29
|
-
* How to interpret failureThreshold
|
|
30
|
-
* @default 'pixel'
|
|
31
|
-
*/
|
|
32
|
-
failureThresholdType?: "pixel" | "percent";
|
|
33
|
-
/**
|
|
34
|
-
* Directory to store snapshots relative to test file
|
|
35
|
-
* @default '__snapshots__'
|
|
36
|
-
*/
|
|
37
|
-
snapshotsDir?: string;
|
|
38
|
-
/**
|
|
39
|
-
* Custom identifier for the snapshot file
|
|
40
|
-
* If not provided, derived from test name
|
|
41
|
-
*/
|
|
42
|
-
snapshotIdentifier?: string;
|
|
43
|
-
/**
|
|
44
|
-
* Snapshot update mode (following Vitest's logic)
|
|
45
|
-
* - 'all': update all snapshots (vitest -u)
|
|
46
|
-
* - 'new': create new snapshots only, don't update existing (default)
|
|
47
|
-
* - 'none': don't create or update any snapshots
|
|
48
|
-
* - true: same as 'all' (backwards compatibility)
|
|
49
|
-
* - false: same as 'new' (backwards compatibility)
|
|
50
|
-
* @default 'new'
|
|
51
|
-
*/
|
|
52
|
-
updateSnapshots?: boolean | "all" | "new" | "none";
|
|
53
|
-
/**
|
|
54
|
-
* Custom update command to display in error messages
|
|
55
|
-
* @default '--update'
|
|
56
|
-
*/
|
|
57
|
-
updateCommand?: string;
|
|
58
|
-
/**
|
|
59
|
-
* Color difference threshold for core/bin methods (0-1)
|
|
60
|
-
* Lower = more strict
|
|
61
|
-
* @default 0.1
|
|
62
|
-
*/
|
|
63
|
-
threshold?: number;
|
|
64
|
-
/**
|
|
65
|
-
* Enable anti-aliasing detection (bin method)
|
|
66
|
-
* @default false
|
|
67
|
-
*/
|
|
68
|
-
antialiasing?: boolean;
|
|
69
|
-
/**
|
|
70
|
-
* Include anti-aliased pixels in diff count (core method)
|
|
71
|
-
* @default false
|
|
72
|
-
*/
|
|
73
|
-
includeAA?: boolean;
|
|
74
|
-
/**
|
|
75
|
-
* Window size for SSIM variants
|
|
76
|
-
* @default 11
|
|
77
|
-
*/
|
|
78
|
-
windowSize?: number;
|
|
79
|
-
/**
|
|
80
|
-
* k1 constant for SSIM
|
|
81
|
-
* @default 0.01
|
|
82
|
-
*/
|
|
83
|
-
k1?: number;
|
|
84
|
-
/**
|
|
85
|
-
* k2 constant for SSIM
|
|
86
|
-
* @default 0.03
|
|
87
|
-
*/
|
|
88
|
-
k2?: number;
|
|
89
|
-
/**
|
|
90
|
-
* Downsample factor for GMSD (0 or 1)
|
|
91
|
-
* @default 0
|
|
92
|
-
*/
|
|
93
|
-
downsample?: 0 | 1;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Result of a comparison operation
|
|
97
|
-
*/
|
|
98
|
-
interface ComparisonResult {
|
|
99
|
-
/** Whether the comparison passed */
|
|
100
|
-
pass: boolean;
|
|
101
|
-
/** Human-readable message describing the result */
|
|
102
|
-
message: string;
|
|
103
|
-
/** Number of different pixels (for pixel-based methods) */
|
|
104
|
-
diffCount?: number;
|
|
105
|
-
/** Percentage of different pixels */
|
|
106
|
-
diffPercentage?: number;
|
|
107
|
-
/** Similarity score (for SSIM/GMSD - 1 = identical for SSIM, 0 = identical for GMSD) */
|
|
108
|
-
score?: number;
|
|
109
|
-
/** Path to baseline snapshot */
|
|
110
|
-
baselinePath?: string;
|
|
111
|
-
/** Path to received image (saved for debugging) */
|
|
112
|
-
receivedPath?: string;
|
|
113
|
-
/** Path to diff visualization */
|
|
114
|
-
diffPath?: string;
|
|
115
|
-
/** Status of the snapshot operation */
|
|
116
|
-
snapshotStatus?: SnapshotStatus;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Context provided by test frameworks
|
|
120
|
-
*/
|
|
121
|
-
interface TestContext {
|
|
122
|
-
/** Absolute path to the test file */
|
|
123
|
-
testPath: string;
|
|
124
|
-
/** Name of the current test */
|
|
125
|
-
testName: string;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Image data with dimensions
|
|
129
|
-
*/
|
|
130
|
-
interface ImageData {
|
|
131
|
-
data: Uint8Array;
|
|
132
|
-
width: number;
|
|
133
|
-
height: number;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
interface RunComparisonResult {
|
|
137
|
-
/** Number of different pixels (for pixel-based methods) */
|
|
138
|
-
diffCount?: number;
|
|
139
|
-
/** Percentage of different pixels */
|
|
140
|
-
diffPercentage?: number;
|
|
141
|
-
/** Score for perceptual methods (SSIM: 1=identical, GMSD: 0=identical) */
|
|
142
|
-
score?: number;
|
|
143
|
-
/** Diff visualization output buffer */
|
|
144
|
-
diffOutput?: Uint8Array;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Validate that the comparison method supports the given input type
|
|
148
|
-
*/
|
|
149
|
-
declare function validateMethodSupportsInput(method: ComparisonMethod, input: ImageInput): void;
|
|
150
|
-
/**
|
|
151
|
-
* Run comparison using the specified method
|
|
152
|
-
*/
|
|
153
|
-
declare function runComparison(received: ImageInput, baseline: ImageInput, method: ComparisonMethod, options: MatcherOptions, diffOutputPath?: string): Promise<RunComparisonResult>;
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Check if input is a file path
|
|
157
|
-
*/
|
|
158
|
-
declare function isFilePath(input: ImageInput): input is string;
|
|
159
|
-
/**
|
|
160
|
-
* Check if input is an image buffer with dimensions
|
|
161
|
-
*/
|
|
162
|
-
declare function isImageBuffer(input: ImageInput): input is {
|
|
163
|
-
data: Uint8Array | Uint8ClampedArray | Buffer;
|
|
164
|
-
width: number;
|
|
165
|
-
height: number;
|
|
166
|
-
};
|
|
167
|
-
/**
|
|
168
|
-
* Load a PNG image from file path
|
|
169
|
-
*/
|
|
170
|
-
declare function loadPNG(filePath: string): Promise<ImageData>;
|
|
171
|
-
/**
|
|
172
|
-
* Save image data to a PNG file
|
|
173
|
-
*/
|
|
174
|
-
declare function savePNG(filePath: string, data: Uint8Array | Uint8ClampedArray | Buffer, width: number, height: number): Promise<void>;
|
|
175
|
-
/**
|
|
176
|
-
* Normalize image input to ImageData
|
|
177
|
-
* If input is a file path, loads the image
|
|
178
|
-
* If input is already a buffer, returns it with normalized Uint8Array
|
|
179
|
-
*/
|
|
180
|
-
declare function normalizeImageInput(input: ImageInput): Promise<ImageData>;
|
|
181
|
-
/**
|
|
182
|
-
* Check if a file exists
|
|
183
|
-
*/
|
|
184
|
-
declare function fileExists(filePath: string): boolean;
|
|
185
|
-
|
|
186
|
-
interface FormatOptions {
|
|
187
|
-
pass: boolean;
|
|
188
|
-
method: ComparisonMethod;
|
|
189
|
-
snapshotCreated: boolean;
|
|
190
|
-
baselinePath: string;
|
|
191
|
-
receivedPath: string;
|
|
192
|
-
diffPath: string;
|
|
193
|
-
diffCount?: number;
|
|
194
|
-
diffPercentage?: number;
|
|
195
|
-
score?: number;
|
|
196
|
-
threshold: number;
|
|
197
|
-
thresholdType: "pixel" | "percent";
|
|
198
|
-
updateCommand?: string;
|
|
199
|
-
}
|
|
200
|
-
declare function formatMessage(opts: FormatOptions): string;
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Main snapshot comparison function
|
|
204
|
-
*/
|
|
205
|
-
declare function getOrCreateSnapshot(received: ImageInput, options: MatcherOptions, testContext: TestContext): Promise<ComparisonResult>;
|
|
206
|
-
/**
|
|
207
|
-
* Compare two images directly without snapshot management
|
|
208
|
-
*/
|
|
209
|
-
declare function compareImages(received: ImageInput, baseline: ImageInput, options: MatcherOptions): Promise<ComparisonResult>;
|
|
210
|
-
|
|
211
|
-
export { type ComparisonMethod, type ComparisonResult, type FormatOptions, type ImageData, type ImageInput, type MatcherOptions, type TestContext, compareImages, fileExists, formatMessage as formatReport, getOrCreateSnapshot, isFilePath, isImageBuffer, loadPNG, normalizeImageInput, runComparison, savePNG, validateMethodSupportsInput };
|