205 lines
6.3 KiB
JavaScript
205 lines
6.3 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";
|
|
import path2D from './tests/path2D';
|
|
import roundRect from './tests/roundRect'
|
|
|
|
const tests = {
|
|
tiger,
|
|
arc,
|
|
arcTo,
|
|
arcTo2,
|
|
arcToScaled,
|
|
emptyArc,
|
|
ellipse,
|
|
ellipse2,
|
|
fillstyle,
|
|
globalAlpha,
|
|
gradient,
|
|
linecap,
|
|
linewidth,
|
|
scaledLine,
|
|
rgba,
|
|
rotate,
|
|
saveandrestore,
|
|
setLineDash,
|
|
text,
|
|
transform,
|
|
pattern,
|
|
path2D,
|
|
roundRect,
|
|
};
|
|
|
|
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);
|
|
})
|
|
}
|
|
})
|