svgcanvas/test/rendering.test.js
Chris Waters 67d5dfd52e
Merge pull request #4 from aha-app/issue-scale-lineWidth
Apply to scale to lineWidth.
2022-07-17 20:14:35 -07:00

201 lines
6.2 KiB
JavaScript

import { Element } from '../index'
import { expect } from 'chai'
import arc from './tests/arc'
import arcTo from './tests/arcTo'
import arcTo2 from './tests/arcTo2'
import arcToScaled from './tests/arcToScaled'
import emptyArc from './tests/emptyArc'
import ellipse from './tests/ellipse'
import ellipse2 from './tests/ellipse2'
import fillstyle from './tests/fillstyle'
import globalAlpha from './tests/globalalpha'
import gradient from './tests/gradient'
import linecap from './tests/linecap'
import linewidth from './tests/linewidth'
import scaledLine from './tests/scaledLine'
import rgba from './tests/rgba'
import rotate from './tests/rotate'
import saveandrestore from './tests/saveandrestore'
import setLineDash from './tests/setLineDash'
import text from './tests/text'
import tiger from './tests/tiger'
import transform from './tests/transform'
import pattern from "./tests/pattern";
const tests = {
tiger,
arc,
arcTo,
arcTo2,
arcToScaled,
emptyArc,
ellipse,
ellipse2,
fillstyle,
globalAlpha,
gradient,
linecap,
linewidth,
scaledLine,
rgba,
rotate,
saveandrestore,
setLineDash,
text,
transform,
pattern
};
const config = {
pixelDensity: 3 // for 200% and 150%
}
class RenderingTester {
constructor(name, fn) {
this.name = name;
this.fn = fn;
this.width = 600;
this.height = 600;
}
async test() {
const canvas = document.createElement('canvas');
const svgcanvas = new Element();
[canvas, svgcanvas].forEach((canvas) => {
canvas.width = this.width
canvas.height = this.height
const ctx = canvas.getContext('2d')
this.fn(ctx)
})
// Pixels
const svg = svgcanvas.toDataURL("image/svg+xml");
const svgImage = await new Promise((resolve) => {
var svgImage = new Image();
svgImage.onload = function () {
resolve(svgImage)
}
svgImage.src = svg;
})
const svgPixels = this.getPixels(svgImage);
const canvasPixels = this.getPixels(canvas);
const diffPixels = this.diffPixels(svgPixels, canvasPixels);
const removeThinLinesPixels = this.removeThinLines(this.removeThinLines(diffPixels));
const svgPixelsCount = this.countPixels(svgPixels);
const canvasPixelsCount = this.countPixels(canvasPixels)
const count = Math.max(svgPixelsCount, canvasPixelsCount);
const diffPixelsCount = this.countPixels(removeThinLinesPixels);
console.log({ fn: this.name, count, diffCount: diffPixelsCount, svgPixelsCount, canvasPixelsCount })
if (count === 0 && diffPixelsCount === 0) {
return 0
}
const diffRate = diffPixelsCount / count;
return diffRate;
}
getPixels(image) {
const canvas = document.createElement('canvas');
const width = this.width;
const height = this.height;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0, width, height);
return ctx.getImageData(0, 0, width, height);
}
// count non transparent pixels
countPixels(imgData) {
var count = 0;
for (var i = 3; i < imgData.data.length; i += 4) {
if (imgData.data[i] > 0) {
count++;
}
}
return count;
};
diffPixels(imgData1, imgData2) {
const canvas = document.createElement('canvas');
const width = this.width;
const height = this.height;
const diffImgData = canvas.getContext('2d').getImageData(0, 0, width, height);
for (var i = 0; i < imgData1.data.length; i += 4) {
var indexes = [i, i + 1, i + 2, i + 3];
indexes.forEach(function (i) {
diffImgData.data[i] = 0;
});
if (indexes.some(function (i) {
return Math.abs(imgData1.data[i] - imgData2.data[i]) > 0;
})) {
diffImgData.data[i + 3] = 255; // set black
}
}
return diffImgData;
}
removeThinLines(imageData) {
const canvas = document.createElement('canvas');
const width = this.width;
const height = this.height;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.putImageData(imageData, 0, 0);
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var imgDataCopy = ctx.getImageData(0, 0, canvas.width, canvas.height);
var getPixelIndex = function (x, y) {
return (y * width + x) * 4 + 3;
};
var getPixel = function (x, y) {
var alphaIndex = getPixelIndex(x, y);
return imgDataCopy.data[alphaIndex];
};
var setPixel = function (x, y, value) {
imgData.data[getPixelIndex(x, y)] = value;
};
for (var x = 1; x < width - 1; x++) {
for (var y = 1; y < height - 1; y++) {
if (getPixel(x, y) == 0) {
continue; // ignore transparents
}
var links = [
{ x: x - 1, y: y - 1 },
{ x: x, y: y - 1 },
{ x: x + 1, y: y - 1 },
{ x: x - 1, y: y },
{ x: x + 1, y: y },
{ x: x - 1, y: y + 1 },
{ x: x, y: y + 1 },
{ x: x + 1, y: y + 1 }
].map(function (p) {
return getPixel(p.x, p.y);
}).filter(function (val) {
return val > 0; // not transparent?
}).length;
if (links < 5) { // is a thin line
setPixel(x, y, 0); // make it transparent
}
}
}
return imgData;
}
}
describe('RenderTest', () => {
for (let fn of Object.keys(tests)) {
it(`should render same results for ${fn}`, async () => {
const tester = new RenderingTester(fn, tests[fn]);
const diffRate = await tester.test();
expect(diffRate).to.lessThan(0.05);
})
}
})