Skip to content

Commit d95db41

Browse files
authored
Better visual tests, test passing, more SVGs (fabricjs#5076)
* improving golddens * more tests * test passing * removed dist * fixed travis * make visual running in browser too * more travis * fixed travis * fixed travis * more coffee
1 parent 4bb1ffb commit d95db41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+570
-62
lines changed

.travis.yml

+10-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ jobs:
3030
fast_finish: true
3131
allow_failures:
3232
- env: LAUNCHER=Node CANFAIL=TRUE
33+
- env: LAUNCHER=Firefox CANFAIL=TRUE
34+
- env: LAUNCHER=Chrome CANFAIL=TRUE
3335
include:
3436
- stage: Linting and Building
3537
env: STEP=LINT
@@ -70,8 +72,15 @@ jobs:
7072
node_js: "4"
7173
- stage: Visual Tests
7274
node_js: "8"
73-
env: LAUNCHER=Node CANFAIL=TRUE
7475
script: npm run test:visual
76+
- stage: Visual Tests
77+
env: LAUNCHER=Chrome CANFAIL=TRUE
78+
79+
script: npm run build:fast && testem ci --port 8080 -f testem-visual.json -l $LAUNCHER
80+
- stage: Visual Tests
81+
env: LAUNCHER=Firefox CANFAIL=TRUE
82+
83+
script: npm run build:fast && testem ci --port 8080 -f testem-visual.json -l $LAUNCHER
7584

7685
script: 'npm run build:fast && testem ci --port 8080 -f testem.json -l $LAUNCHER'
7786

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"export_tests_to_site": "cp test/unit/*.js ../fabricjs.com/test/unit",
5555
"all": "npm run build && npm run test && npm run lint && npm run lint_tests && npm run export_dist_to_site && npm run export_tests_to_site",
5656
"testem": "testem .",
57+
"testem:visual": "testem --file testem-visual.json",
5758
"testem:ci": "testem ci"
5859
},
5960
"optionalDependencies": {

test-visual.js

-28
This file was deleted.

test/lib/pixelmatch.js

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
'use strict';
2+
3+
function pixelmatch(img1, img2, output, width, height, options) {
4+
5+
if (!options) options = {};
6+
7+
var threshold = options.threshold === undefined ? 0.1 : options.threshold;
8+
9+
// maximum acceptable square distance between two colors;
10+
// 35215 is the maximum possible value for the YIQ difference metric
11+
var maxDelta = 35215 * threshold * threshold,
12+
diff = 0;
13+
14+
// compare each pixel of one image against the other one
15+
for (var y = 0; y < height; y++) {
16+
for (var x = 0; x < width; x++) {
17+
18+
var pos = (y * width + x) * 4;
19+
20+
// squared YUV distance between colors at this pixel position
21+
var delta = colorDelta(img1, img2, pos, pos);
22+
23+
// the color difference is above the threshold
24+
if (delta > maxDelta) {
25+
// check it's a real rendering difference or just anti-aliasing
26+
if (!options.includeAA && (antialiased(img1, x, y, width, height, img2) ||
27+
antialiased(img2, x, y, width, height, img1))) {
28+
// one of the pixels is anti-aliasing; draw as yellow and do not count as difference
29+
if (output) drawPixel(output, pos, 255, 255, 0);
30+
31+
} else {
32+
// found substantial difference not caused by anti-aliasing; draw it as red
33+
if (output) drawPixel(output, pos, 255, 0, 0);
34+
diff++;
35+
}
36+
37+
} else if (output) {
38+
// pixels are similar; draw background as grayscale image blended with white
39+
var val = blend(grayPixel(img1, pos), 0.1);
40+
drawPixel(output, pos, val, val, val);
41+
}
42+
}
43+
}
44+
45+
// return the number of different pixels
46+
return diff;
47+
}
48+
49+
// check if a pixel is likely a part of anti-aliasing;
50+
// based on "Anti-aliased Pixel and Intensity Slope Detector" paper by V. Vysniauskas, 2009
51+
52+
function antialiased(img, x1, y1, width, height, img2) {
53+
var x0 = Math.max(x1 - 1, 0),
54+
y0 = Math.max(y1 - 1, 0),
55+
x2 = Math.min(x1 + 1, width - 1),
56+
y2 = Math.min(y1 + 1, height - 1),
57+
pos = (y1 * width + x1) * 4,
58+
zeroes = 0,
59+
positives = 0,
60+
negatives = 0,
61+
min = 0,
62+
max = 0,
63+
minX, minY, maxX, maxY;
64+
65+
// go through 8 adjacent pixels
66+
for (var x = x0; x <= x2; x++) {
67+
for (var y = y0; y <= y2; y++) {
68+
if (x === x1 && y === y1) continue;
69+
70+
// brightness delta between the center pixel and adjacent one
71+
var delta = colorDelta(img, img, pos, (y * width + x) * 4, true);
72+
73+
// count the number of equal, darker and brighter adjacent pixels
74+
if (delta === 0) zeroes++;
75+
else if (delta < 0) negatives++;
76+
else if (delta > 0) positives++;
77+
78+
// if found more than 2 equal siblings, it's definitely not anti-aliasing
79+
if (zeroes > 2) return false;
80+
81+
if (!img2) continue;
82+
83+
// remember the darkest pixel
84+
if (delta < min) {
85+
min = delta;
86+
minX = x;
87+
minY = y;
88+
}
89+
// remember the brightest pixel
90+
if (delta > max) {
91+
max = delta;
92+
maxX = x;
93+
maxY = y;
94+
}
95+
}
96+
}
97+
98+
if (!img2) return true;
99+
100+
// if there are no both darker and brighter pixels among siblings, it's not anti-aliasing
101+
if (negatives === 0 || positives === 0) return false;
102+
103+
// if either the darkest or the brightest pixel has more than 2 equal siblings in both images
104+
// (definitely not anti-aliased), this pixel is anti-aliased
105+
return (!antialiased(img, minX, minY, width, height) && !antialiased(img2, minX, minY, width, height)) ||
106+
(!antialiased(img, maxX, maxY, width, height) && !antialiased(img2, maxX, maxY, width, height));
107+
}
108+
109+
// calculate color difference according to the paper "Measuring perceived color difference
110+
// using YIQ NTSC transmission color space in mobile applications" by Y. Kotsarenko and F. Ramos
111+
112+
function colorDelta(img1, img2, k, m, yOnly) {
113+
var a1 = img1[k + 3] / 255,
114+
a2 = img2[m + 3] / 255,
115+
116+
r1 = blend(img1[k + 0], a1),
117+
g1 = blend(img1[k + 1], a1),
118+
b1 = blend(img1[k + 2], a1),
119+
120+
r2 = blend(img2[m + 0], a2),
121+
g2 = blend(img2[m + 1], a2),
122+
b2 = blend(img2[m + 2], a2),
123+
124+
y = rgb2y(r1, g1, b1) - rgb2y(r2, g2, b2);
125+
126+
if (yOnly) return y; // brightness difference only
127+
128+
var i = rgb2i(r1, g1, b1) - rgb2i(r2, g2, b2),
129+
q = rgb2q(r1, g1, b1) - rgb2q(r2, g2, b2);
130+
131+
return 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;
132+
}
133+
134+
function rgb2y(r, g, b) { return r * 0.29889531 + g * 0.58662247 + b * 0.11448223; }
135+
function rgb2i(r, g, b) { return r * 0.59597799 - g * 0.27417610 - b * 0.32180189; }
136+
function rgb2q(r, g, b) { return r * 0.21147017 - g * 0.52261711 + b * 0.31114694; }
137+
138+
// blend semi-transparent color with white
139+
function blend(c, a) {
140+
return 255 + (c - 255) * a;
141+
}
142+
143+
function drawPixel(output, pos, r, g, b) {
144+
output[pos + 0] = r;
145+
output[pos + 1] = g;
146+
output[pos + 2] = b;
147+
output[pos + 3] = 255;
148+
}
149+
150+
function grayPixel(img, i) {
151+
var a = img[i + 3] / 255,
152+
r = blend(img[i + 0], a),
153+
g = blend(img[i + 1], a),
154+
b = blend(img[i + 2], a);
155+
return rgb2y(r, g, b);
156+
}

test/visual/assets/svg_linear_1.svg

+13
Loading

test/visual/assets/svg_linear_2.svg

+11
Loading

test/visual/assets/svg_linear_3.svg

+11
Loading

test/visual/assets/svg_linear_4.svg

+20
Loading

test/visual/assets/svg_linear_5.svg

+13
Loading

test/visual/assets/svg_linear_6.svg

+13
Loading

test/visual/assets/svg_linear_7.svg

+13
Loading

test/visual/assets/svg_linear_8.svg

+13
Loading

test/visual/assets/svg_radial_1.svg

+11
Loading

test/visual/assets/svg_radial_10.svg

+16
Loading

test/visual/assets/svg_radial_11.svg

+13
Loading

0 commit comments

Comments
 (0)