Skip to content

Commit

Permalink
Fix multiple applications of blend image filter with transparent imag…
Browse files Browse the repository at this point in the history
…es (#5121)

* Fix multiple applications of blend image filter with transparent images

* Add blend image filter visual test
  • Loading branch information
brandondong authored and asturur committed Jul 29, 2018
1 parent 6353b09 commit acb0b14
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/filters/blendimage_filter.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
canvas1, context, image = this.image, blendData;

if (!resources.blendImage) {
resources.blendImage = document.createElement('canvas');
resources.blendImage = fabric.util.createCanvasElement();
}
canvas1 = resources.blendImage;
if (canvas1.width !== width || canvas1.height !== height) {
Expand All @@ -159,6 +159,7 @@
context.setTransform(image.scaleX, 0, 0, image.scaleY, image.left, image.top);
context.drawImage(image._element, 0, 0, width, height);
blendData = context.getImageData(0, 0, width, height).data;
context.clearRect(0, 0, width, height);
for (var i = 0; i < iLen; i += 4) {

r = data[i];
Expand Down
Binary file added test/fixtures/greyfloral_partial_transparent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
94 changes: 94 additions & 0 deletions test/visual/blendimage_filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
(function() {
fabric.enableGLFiltering = false;
var _pixelMatch = pixelmatch;
if (fabric.isLikelyNode) {
var fs = global.fs;
_pixelMatch = global.pixelmatch;
}
var fabricCanvas = this.canvas = new fabric.Canvas(null, {enableRetinaScaling: false, renderOnAddRemove: false});
var pixelmatchOptions = {
includeAA: false,
threshold: 0.01
};
fabric.Object.prototype.objectCaching = false;

function getAbsolutePath(path) {
var isAbsolute = /^https?:/.test(path);
if (isAbsolute) { return path; };
var imgEl = fabric.document.createElement('img');
imgEl.src = path;
var src = imgEl.src;
imgEl = null;
return src;
}

function getFixtureName(filename) {
var finalName = '/../fixtures/' + filename;
return fabric.isLikelyNode ? (__dirname + finalName) : getAbsolutePath('test/fixtures/' + filename);
}

function getImage(filename, original, callback) {
if (fabric.isLikelyNode && original) {
try {
fs.statSync(filename);
}
catch (err) {
var dataUrl = original.toDataURL().split(',')[1];
console.log('creating original for ', filename);
fs.writeFileSync(filename, dataUrl, { encoding: 'base64' });
}
}
var img = fabric.document.createElement('img');
img.onload = function() {
callback(img);
};
img.onerror = function(err) {
console.log('Image loading errored', err);
};
img.src = filename;
}

QUnit.module('Blend image filter test', {
afterEach: function() {
fabricCanvas.clear();
fabricCanvas.renderAll();
}
});

var testName = 'Multiple applications of filter';
QUnit.test(testName, function(assert) {
var done = assert.async();
getImage(getFixtureName('greyfloral.png'), false, function(img) {
getImage(getFixtureName('greyfloral_partial_transparent.png'), false, function(backdrop) {
var image = new fabric.Image(img);
var backdropImage = new fabric.Image(backdrop);
image.filters.push(new fabric.Image.filters.BlendImage({image: backdropImage}));
image.applyFilters();

fabricCanvas.add(image);
fabricCanvas.renderAll();

var renderedCanvas = fabricCanvas.lowerCanvasEl;

var width = renderedCanvas.width;
var height = renderedCanvas.height;
var totalPixels = width * height;
var imageDataCanvas = renderedCanvas.getContext('2d').getImageData(0, 0, width, height).data;

image.applyFilters();
fabricCanvas.renderAll();
var imageDataCanvas2 = renderedCanvas.getContext('2d').getImageData(0, 0, width, height).data;

var differentPixels = _pixelMatch(imageDataCanvas, imageDataCanvas2, null, width, height, pixelmatchOptions);
var percDiff = differentPixels / totalPixels * 100;
var okDiff = totalPixels * 0.01;
assert.ok(
differentPixels < okDiff,
testName + ' has too many different pixels ' + differentPixels + '(' + okDiff + ') representing ' + percDiff + '%'
);
console.log('Different pixels:', differentPixels, '/', totalPixels, ' diff:', percDiff.toFixed(3), '%');
done();
});
});
});
})();

0 comments on commit acb0b14

Please sign in to comment.