Skip to content

Commit

Permalink
Merge pull request #6788 from Papershine/mask-fix
Browse files Browse the repository at this point in the history
Account for pixel density when masking images
  • Loading branch information
davepagurek authored May 3, 2024
2 parents 54dbffd + a11e2bc commit 6b50b5b
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 12 deletions.
20 changes: 11 additions & 9 deletions src/image/p5.Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,8 @@ p5.Image = class {
*
* `img.mask()` uses another <a href="#/p5.Image">p5.Image</a> object's
* alpha channel as the alpha channel for this image. Masks are cumulative
* and can't be removed once applied.
* and can't be removed once applied. If the mask has a different
* pixel density from this image, the mask will be scaled.
*
* @method mask
* @param {p5.Image} srcImage source image.
Expand Down Expand Up @@ -1149,21 +1150,22 @@ p5.Image = class {
}
const currBlend = this.drawingContext.globalCompositeOperation;

let scaleFactor = 1;
let imgScaleFactor = this._pixelDensity;
let maskScaleFactor = 1;
if (p5Image instanceof p5.Renderer) {
scaleFactor = p5Image._pInst._pixelDensity;
maskScaleFactor = p5Image._pInst._pixelDensity;
}

const copyArgs = [
p5Image,
0,
0,
scaleFactor * p5Image.width,
scaleFactor * p5Image.height,
maskScaleFactor * p5Image.width,
maskScaleFactor * p5Image.height,
0,
0,
this.width,
this.height
imgScaleFactor * this.width,
imgScaleFactor * this.height
];

this.drawingContext.globalCompositeOperation = 'destination-in';
Expand All @@ -1178,8 +1180,8 @@ p5.Image = class {
this.gifProperties.frames[i].image = this.drawingContext.getImageData(
0,
0,
this.width,
this.height
imgScaleFactor * this.width,
imgScaleFactor * this.height
);
}
this.drawingContext.putImageData(
Expand Down
62 changes: 59 additions & 3 deletions test/unit/image/p5.Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,44 @@ suite('p5.Image', function() {
});

suite('p5.Image.prototype.mask', function() {
test('it should mask the image', function() {
for (const density of [1, 2]) {
test(`it should mask the image at pixel density ${density}`, function() {
let img = myp5.createImage(10, 10);
img.pixelDensity(density);
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.pixelDensity(density);
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 images of different density', function() {
let img = myp5.createImage(10, 10);
img.pixelDensity(1);
img.loadPixels();
for (let i = 0; i < img.height; i++) {
for (let j = 0; j < img.width; j++) {
Expand All @@ -62,15 +98,16 @@ suite('p5.Image', function() {
}
img.updatePixels();

let mask = myp5.createImage(10, 10);
let mask = myp5.createImage(20, 20);
mask.loadPixels();
for (let i = 0; i < mask.width; i++) {
for (let j = 0; j < mask.height; j++) {
let alpha = j < 5 ? 255 : 0;
let alpha = j < 10 ? 255 : 0;
mask.set(i, j, myp5.color(0, 0, 0, alpha));
}
}
mask.updatePixels();
mask.pixelDensity(2);

img.mask(mask);
img.loadPixels();
Expand All @@ -82,6 +119,25 @@ suite('p5.Image', function() {
}
});

test('it should mask images from createGraphics', function() {
myp5.createCanvas(10,10);
myp5.pixelDensity(2);
let img = myp5.createGraphics(10,10);
img.rect(0,0,10,10);
img.background(0);
let mask = createGraphics(10,10);
mask.rect(0,0,5,5);
let masked = img.get();
masked.mask( mask.get() );

for (let i = 0; i < masked.width; i++) {
for (let j = 0; j < masked.height; j++) {
let alpha = i < 5 && j < 5 ? 255 : 0;
assert.strictEqual(masked.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) {
Expand Down

0 comments on commit 6b50b5b

Please sign in to comment.