123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- import { Helper } from "../commons/helper";
- import { AbstractViewer } from "babylonjs-viewer";
- export class PixelPixieUtils {
- public static threshold = 3;
- public static errorRatio = 1;
- public static loadReferenceImage(name: string, callback: (success) => void) {
- const img = Helper.getReferenceImg();
- const timeout = setTimeout(() => {
- img.onload = null;
- if (callback) {
- callback(false);
- }
- }, 1000);
- img.onload = () => {
- clearTimeout(timeout);
- const resultCanvas = Helper.getReferenceCanvas();
- const resultContext = resultCanvas.getContext("2d");
- resultCanvas.width = img.width;
- resultCanvas.height = img.height;
- resultContext.drawImage(img, 0, 0);
- if (callback) {
- callback(true);
- }
- };
- img.src = "base/assets/referenceImages/" + name + ".png";
- }
- public static compare(canvas: HTMLCanvasElement, renderData: Uint8Array, stats: { maxDelta: number, differencesCount: number }): boolean {
- const referenceCanvas = canvas;
- const width = referenceCanvas.width;
- const height = referenceCanvas.height;
- const size = width * height * 4;
- const referenceContext = referenceCanvas.getContext("2d");
- const referenceData = referenceContext.getImageData(0, 0, width, height);
- let maxDelta = 0;
- let differencesCount = 0;
- for (let index = 0; index < size; index += 4) {
- const [r, g, b] = [index, index + 1, index + 2];
- const maxComponentDelta = Math.max(
- Math.abs(renderData[r] - referenceData.data[r]),
- Math.abs(renderData[g] - referenceData.data[g]),
- Math.abs(renderData[b] - referenceData.data[b])
- );
- maxDelta = Math.max(maxDelta, maxComponentDelta);
- if (maxComponentDelta < this.threshold) {
- continue;
- }
- referenceData.data[r] = 255;
- referenceData.data[g] *= 0.5;
- referenceData.data[b] *= 0.5;
- differencesCount++;
- }
- referenceContext.putImageData(referenceData, 0, 0);
- stats.maxDelta = maxDelta;
- stats.differencesCount = differencesCount;
- return (differencesCount * 100) / (width * height) > this.errorRatio;
- }
- public static getRenderData(renderEngine: AbstractViewer): Uint8Array {
- const width = renderEngine.canvas.width;
- const height = renderEngine.canvas.height;
- const renderData = renderEngine.engine.readPixels(0, 0, width, height);
- const numberOfChannelsByLine = width * 4;
- const halfHeight = height / 2;
- for (let i = 0; i < halfHeight; i++) {
- for (let j = 0; j < numberOfChannelsByLine; j++) {
- const currentCell = j + i * numberOfChannelsByLine;
- const targetLine = height - i - 1;
- const targetCell = j + targetLine * numberOfChannelsByLine;
- const temp = renderData[currentCell];
- renderData[currentCell] = renderData[targetCell];
- renderData[targetCell] = temp;
- }
- }
- return renderData;
- }
- public static evaluate(testName, renderEngine: AbstractViewer, callback: (result: boolean, picture: string, maxDelta: number, differencesCount: number) => void): void {
- renderEngine.scene.executeWhenReady(() => {
- // Extra render shouldn't be necessary, this is due to a bug in IE
- //TODO - this should be the viewer's render loop
- renderEngine.forceRender();
- const renderData = this.getRenderData(renderEngine);
- Helper.getRenderImg().src = renderEngine.canvas.toDataURL();
- renderEngine.runRenderLoop = false;
- this.loadReferenceImage(testName, (success) => {
- const referenceCanvas = Helper.getReferenceCanvas();
- if (success) {
- const stats = { maxDelta: 0, differencesCount: 0 };
- const different = this.compare(referenceCanvas, renderData, stats);
- const resultPicture = referenceCanvas.toDataURL();
- Helper.getReferenceImg().onload = null;
- Helper.getReferenceImg().src = resultPicture;
- callback(!different, resultPicture, stats.maxDelta, stats.differencesCount);
- }
- else {
- callback(false, "Reference image not loaded.", 0, 0);
- }
- });
- });
- }
- }
|