mirror of
https://github.com/pissang/claygl.git
synced 2026-01-25 16:46:30 +00:00
149 lines
5.1 KiB
JavaScript
149 lines
5.1 KiB
JavaScript
const fs = require('fs');
|
|
const nativeImage = require('electron').nativeImage;
|
|
const assert = require('assert');
|
|
|
|
const testErrors = [];
|
|
|
|
module.exports = {
|
|
getTestErrors() {
|
|
return testErrors;
|
|
},
|
|
|
|
/**
|
|
* Get image content of the canvas
|
|
* @param {Canvas} canvas
|
|
* @returns {Buffer} image
|
|
*/
|
|
getGlImage(canvas) {
|
|
const gl = canvas.gl,
|
|
width = canvas.width,
|
|
height = canvas.height;
|
|
if (!gl) {
|
|
return null;
|
|
}
|
|
const pixels = new Uint8Array(4 * width * height);
|
|
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
|
|
const clamped = new Uint8ClampedArray(pixels),
|
|
imageData = new ImageData(clamped, width, height);
|
|
const glImg = document.createElement('canvas');
|
|
glImg.width = width;
|
|
glImg.height = height;
|
|
const ctx = glImg.getContext('2d');
|
|
ctx.putImageData(imageData, 0, 0);
|
|
const data = glImg.toDataURL('image/png');
|
|
const buf = nativeImage.createFromDataURL(data).toPng();
|
|
return buf;
|
|
},
|
|
|
|
/**
|
|
* Write canvas as png image to file at given path
|
|
* @param {Canvas} canvas canvas
|
|
* @param {String} path file path
|
|
* @param {Function} cb callback when finishing or error occuring
|
|
*/
|
|
writeGLImage(canvas, path, cb) {
|
|
const buf = this.getGlImage(canvas);
|
|
fs.writeFile(path, buf, cb);
|
|
},
|
|
|
|
assertWith(canvas, options, cb) {
|
|
const fixturePath = options.fixture;
|
|
if (process.env.GENERATE_FIXTURE) {
|
|
this.writeGLImage(canvas, fixturePath, function () {
|
|
cb();
|
|
});
|
|
} else {
|
|
const fixture = fs.readFileSync(fixturePath);
|
|
const actual = this.getGlImage(canvas);
|
|
this._loadImage(fixture, actual, (fixture, actual) => {
|
|
const diff = this.compareImagePixel(fixture, actual, options.diffOptions);
|
|
let err;
|
|
if (diff !== 0) {
|
|
if (diff > 0) {
|
|
err = {
|
|
'error' : `Image is different from fixture with delta ${diff}`
|
|
};
|
|
} else {
|
|
err = {
|
|
'error' : 'Image is blank'
|
|
};
|
|
}
|
|
err.fixture = fixture;
|
|
err.actual = actual;
|
|
testErrors.push(err);
|
|
}
|
|
cb(err);
|
|
});
|
|
}
|
|
},
|
|
|
|
_loadImage(fixture, actual, cb) {
|
|
const img1 = nativeImage.createFromBuffer(fixture);
|
|
const img2 = nativeImage.createFromBuffer(actual);
|
|
|
|
const webImg1 = new Image();
|
|
const webImg2 = new Image();
|
|
webImg1.onload = onload;
|
|
webImg2.onload = onload;
|
|
function onload() {
|
|
this.finished = true;
|
|
if (webImg1.finished && webImg2.finished) {
|
|
cb(webImg1, webImg2);
|
|
}
|
|
}
|
|
webImg1.src = img1.toDataURL();
|
|
webImg2.src = img2.toDataURL();
|
|
},
|
|
|
|
/**
|
|
* Compare image pixel difference
|
|
* @param {Buffer} fixture
|
|
* @param {Buffer} actual
|
|
* @param {Number} colorDelta Max. distance colors in the 4 dimensional color-space without triggering a difference. (default: 20)
|
|
* @return {Number} -1 : blank image, 0: same, > 0 : color delta
|
|
*/
|
|
compareImagePixel(fixture, actual, options = {}) {
|
|
if (fixture.width !== actual.width || fixture.height !== actual.height) {
|
|
return fixture.width * fixture.height;
|
|
}
|
|
const rgbaDelta = options.rgbaDelta || 6; // default rgba delta is 5
|
|
const diffRatio = options.diffRatio || 0.01; //default diff ratio is 1%
|
|
const w = fixture.width, h = fixture.height;
|
|
const canvas1 = document.createElement('canvas');
|
|
const canvas2 = document.createElement('canvas');
|
|
canvas1.width = canvas2.width = w;
|
|
canvas1.height = canvas2.height = h;
|
|
const ctx1 = canvas1.getContext('2d');
|
|
const ctx2 = canvas2.getContext('2d');
|
|
|
|
ctx1.drawImage(fixture, 0, 0);
|
|
ctx2.drawImage(actual, 0, 0);
|
|
|
|
const data1 = ctx1.getImageData(0, 0, w, h).data;
|
|
const data2 = ctx2.getImageData(0, 0, w, h).data;
|
|
|
|
let blank = -1; //blank in default
|
|
let diffCount = 0;
|
|
for (let i = 0, l = data1.length; i < l; i += 4) {
|
|
if (blank === -1 && data2[i + 3] > 0) {
|
|
blank = 0; //met 1st drawn pixel
|
|
}
|
|
for (let ii = 0; ii < 4; ii++) {
|
|
const d = Math.abs(data1[i + ii] - data2[i + ii]);
|
|
if (d > rgbaDelta) {
|
|
// console.log(Math.floor(i / 4), data1.slice(i, i + 4).join(' '), data2.slice(i, i + 4).join(' '));
|
|
diffCount += d;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (diffCount / (w * h) > diffRatio) {
|
|
// console.log('diff count', diffCount);
|
|
return diffCount;
|
|
}
|
|
return blank;
|
|
}
|
|
|
|
};
|