diff --git a/src/image/p5.Image.js b/src/image/p5.Image.js index c78fa7959c..6bbb9fdf11 100644 --- a/src/image/p5.Image.js +++ b/src/image/p5.Image.js @@ -629,10 +629,6 @@ p5.Image.prototype.copy = function(...args) { * http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ */ // TODO: - Accept an array of alpha values. -// - Use other channels of an image. p5 uses the -// blue channel (which feels kind of arbitrary). Note: at the -// moment this method does not match native processing's original -// functionality exactly. p5.Image.prototype.mask = function(p5Image) { if (p5Image === undefined) { p5Image = this; @@ -657,7 +653,29 @@ p5.Image.prototype.mask = function(p5Image) { ]; this.drawingContext.globalCompositeOperation = 'destination-in'; - p5.Image.prototype.copy.apply(this, copyArgs); + if (this.gifProperties) { + for (let i = 0; i < this.gifProperties.frames.length; i++) { + this.drawingContext.putImageData( + this.gifProperties.frames[i].image, + 0, + 0 + ); + p5.Image.prototype.copy.apply(this, copyArgs); + this.gifProperties.frames[i].image = this.drawingContext.getImageData( + 0, + 0, + this.width, + this.height + ); + } + this.drawingContext.putImageData( + this.gifProperties.frames[this.gifProperties.displayIndex].image, + 0, + 0 + ); + } else { + p5.Image.prototype.copy.apply(this, copyArgs); + } this.drawingContext.globalCompositeOperation = currBlend; this.setModified(true); }; diff --git a/test/unit/image/p5.Image.js b/test/unit/image/p5.Image.js index eb83102d85..2600be63ff 100644 --- a/test/unit/image/p5.Image.js +++ b/test/unit/image/p5.Image.js @@ -49,4 +49,77 @@ suite('p5.Image', function() { assert.strictEqual(img.height, 30); }); }); + + suite('p5.Image.prototype.mask', function() { + test('it should mask the image', function() { + let img = myp5.createImage(10, 10); + img.loadPixels(); + for (let i = 0; i < img.height; i++) { + for (let j = 0; j < img.width; j++) { + let alpha = i < 5 ? 255 : 0; + img.set(i, j, myp5.color(0, 0, 0, alpha)); + } + } + img.updatePixels(); + + let mask = myp5.createImage(10, 10); + mask.loadPixels(); + for (let i = 0; i < mask.width; i++) { + for (let j = 0; j < mask.height; j++) { + let alpha = j < 5 ? 255 : 0; + mask.set(i, j, myp5.color(0, 0, 0, alpha)); + } + } + mask.updatePixels(); + + img.mask(mask); + img.loadPixels(); + for (let i = 0; i < img.width; i++) { + for (let j = 0; j < img.height; j++) { + let alpha = i < 5 && j < 5 ? 255 : 0; + assert.strictEqual(img.get(i, j)[3], alpha); + } + } + }); + + test('it should mask the animated gif image', function() { + const imagePath = 'unit/assets/nyan_cat.gif'; + return new Promise(function(resolve, reject) { + myp5.loadImage(imagePath, resolve, reject); + }).then(function(img) { + let mask = myp5.createImage(img.width, img.height); + mask.loadPixels(); + for (let i = 0; i < mask.width; i++) { + for (let j = 0; j < mask.height; j++) { + const alpha = j < img.height / 2 ? 255 : 0; + mask.set(i, j, myp5.color(0, 0, 0, alpha)); + } + } + mask.updatePixels(); + + img.mask(mask); + img.loadPixels(); + for (let i = 0; i < img.width; i++) { + for (let j = 0; j < img.height; j++) { + const alpha = j < img.height / 2 ? 255 : 0; + assert.strictEqual(img.get(i, j)[3], alpha); + } + } + for ( + frameIndex = 0; + frameIndex < img.gifProperties.numFrames; + frameIndex++ + ) { + const frameData = img.gifProperties.frames[frameIndex].image.data; + for (let i = 0; i < img.width; i++) { + for (let j = 0; j < img.height; j++) { + const index = 4 * (i + j * img.width) + 3; + const alpha = j < img.height / 2 ? 255 : 0; + assert.strictEqual(frameData[index], alpha); + } + } + } + }); + }); + }); });