Files
ytplayer/tests/helpers/png-diff.js

28 lines
1.7 KiB
JavaScript

// Lossless Chromium screenshots: tolerate a few rasterization pixels while
// keeping strict geometry/style comparisons in the calling UI test.
const { inflateSync } = require('node:zlib');
function decode(buffer) {
let width,height,channels;const chunks=[];
for(let offset=8;offset<buffer.length;){
const length=buffer.readUInt32BE(offset),type=buffer.toString('ascii',offset+4,offset+8),data=buffer.subarray(offset+8,offset+8+length);offset+=length+12;
if(type==='IHDR'){width=data.readUInt32BE(0);height=data.readUInt32BE(4);channels=data[9]===6?4:3;if(data[8]!==8||![2,6].includes(data[9])||data[12])throw new Error('Expected an 8-bit RGB Chromium PNG');}
if(type==='IDAT')chunks.push(data);
}
const raw=inflateSync(Buffer.concat(chunks)),stride=width*channels,pixels=Buffer.alloc(stride*height);let position=0;
const paeth=(a,b,c)=>{const p=a+b-c,da=Math.abs(p-a),db=Math.abs(p-b),dc=Math.abs(p-c);return da<=db&&da<=dc?a:db<=dc?b:c;};
for(let y=0;y<height;y++){
const filter=raw[position++];if(filter>4)throw new Error('Unexpected PNG filter');
for(let x=0;x<stride;x++){
const index=y*stride+x,a=x>=channels?pixels[index-channels]:0,b=y?pixels[index-stride]:0,c=y&&x>=channels?pixels[index-stride-channels]:0;
pixels[index]=(raw[position++]+[0,a,b,Math.floor((a+b)/2),paeth(a,b,c)][filter])&255;
}
}
return {width,height,channels,pixels};
}
function differentPixels(first,second){
const a=decode(first),b=decode(second);if(a.width!==b.width||a.height!==b.height||a.channels!==b.channels)return Infinity;
let count=0;for(let i=0;i<a.pixels.length;i+=a.channels)if(!a.pixels.subarray(i,i+a.channels).equals(b.pixels.subarray(i,i+a.channels)))count++;
return count;
}
module.exports={differentPixels};