You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Using mask() to mask an image leads to mask() can only be used with an image that's the same size. though both images are created with same size. Worked until 4.4.2.
Hey @hkiel Thank you for reporting this, this is a result of us switching to the pixelDensity = displayDensity by default.
You can revert back to previous behaviour by calling pixelDensity(1) in your setup.
As for what happened here, turns out that createImage does not create an image based on the current pixel density and createGraphics does, leading two different buffers with different sizes. I'll look into it later to see if either would need to be adjusted.
I don't really get why pixel densities matter here. I'm working on two images of exactly the same size in pixels. Why would the density matter?
It would help if there was a createGraphics(img) method that clones the image properties (width, height, density, etc.?)
One thing to know is that pixelDensity controls how many physical pixels are used for each logical pixel in your sketch.
For example, at a pixel density of 2, what looks like a single pixel in your sketch is actually made up of 4 smaller pixels (2x2) behind the scenes. This helps sketches look sharper on high-resolution displays.
The issue comes from the fact that createGraphics() automatically adjusts for the pixel density of the sketch, but createImage() does not. That’s why even if the width and height match in your code, the underlying pixel arrays can end up being different sizes. Since mask() directly compares the pixel data, this mismatch becomes a problem.
This discrepancy wasn't as apparent when pixelDensity(1) was the default, but now that we use the screen’s density by default (starting with Processing 4.4.3), this issue shows up for high-DPI screens.
Here's a sketch that demonstrates this:
voidsetup() {
size(100, 100);
pixelDensity(1); // comment this line out (or set to 2) to see the differencePImage img =createImage(50, 50, RGB);
PGraphics pg =createGraphics(50, 50);
pg.beginDraw();
pg.endDraw();
println("img pixels:", img.pixels.length);
println("pg pixels:", pg.pixels.length);
}
To create an appropriate mask while avoiding the pixelDensity mismatch, you can use createGraphics() for both your drawing and mask buffers, then call .get() to extract a PImage since that is what the mask() function expects.
Here’s a code example:
PImage drawImage;
PImage maskImage;
PGraphics drawBuffer;
PGraphics maskBuffer;
voidsetup() {
size(200, 200);
// Create two PGraphics of the same dimensions
drawBuffer =createGraphics(100, 100);
maskBuffer =createGraphics(100, 100);
}
voiddraw() {
background(200);
drawBuffer.beginDraw();
drawBuffer.background(255, 0, 0); // Red
drawBuffer.circle(mouseX, mouseY, 20);
drawBuffer.endDraw();
// Get the draw image
drawImage = drawBuffer.get();
// Note: if you don't need to animate the mask // it will be more efficient to do this in setup() (including the .get call)
maskBuffer.beginDraw();
maskBuffer.background(0);
maskBuffer.fill(255);
maskBuffer.circle(50, 50, map(sin(frameCount*0.01),-1,1,40,80));
maskBuffer.endDraw();
// Get the mask image
maskImage = maskBuffer.get();
drawImage.mask(maskImage);
image(drawImage, 0, 0);
}
So, finally only the error message of mask() is misleading, since .width and .height attributes of image and mask are the same, but pixelDensity is different for the two objects, resulting it buffers of different size, which is the problem. Maybe you can add an assertion for the densities in mask().
@Stefterv I would not have had a clue how to fix the problem, if I had been warned about different densities, but at least I could have seen that the problem is not the size.
@SableRaf We should not replace the existing error in mask(pixelArray), as in that spot it only has the array length to check, we should add a new error in the mask(PImage) function.
I would suggest to not repeat the values. You never know which one is really wrong. image and mask must have the same dimensions, image is 320x240, mask is 300x200. image and mask must have the same pixel density, image is pixelDensity(1) and mask is pixelDensity(2).
I would suggest to not repeat the values. You never know which one is really wrong. image and mask must have the same dimensions, image is 320x240, mask is 300x200.image and mask must have the same pixel density, image is pixelDensity(1) and mask is pixelDensity(2).
ok but this is a partial answer. How to have same pixelDensity on mask and picture? return to 1 ?
Hi! I saw that this issue has not been assigned to anyone. I'm new to Processing and would like to take this on! The solution that everyone discussed is to add an error message if underlying sizes don't match because of the pixel densities right? I assume if the pixel densities are different but if the underlying sizes match then it should be fine? Or do we want strictly that both pixel density and size of the picture and mask must be the same?
Hi @pnngocdoan Thank you for your interest in contributing! Yes if the sizes still match despite different pixel densities I think it is fine to let it go through.
Activity
Stefterv commentedon Apr 28, 2025
Hey @hkiel Thank you for reporting this, this is a result of us switching to the
pixelDensity = displayDensityby default.You can revert back to previous behaviour by calling
pixelDensity(1)in your setup.As for what happened here, turns out that
createImagedoes not create an image based on the current pixel density andcreateGraphicsdoes, leading two different buffers with different sizes. I'll look into it later to see if either would need to be adjusted.Stefterv commentedon Apr 28, 2025
I think a great start is to add an error here if the pixelDensities of the images do not match
processing4/core/src/processing/core/PImage.java
Lines 841 to 844 in c83f44c
Would you have been able to resolve the error if you would have been warned that the pixeldensity between
imgandmaskImagedid not match @hkiel ?hkiel commentedon Apr 29, 2025
I don't really get why pixel densities matter here. I'm working on two images of exactly the same size in pixels. Why would the density matter?
It would help if there was a
createGraphics(img)method that clones the image properties (width, height, density, etc.?)SableRaf commentedon Apr 29, 2025
Hi @hkiel,
One thing to know is that
pixelDensitycontrols how many physical pixels are used for each logical pixel in your sketch.For example, at a pixel density of 2, what looks like a single pixel in your sketch is actually made up of 4 smaller pixels (2x2) behind the scenes. This helps sketches look sharper on high-resolution displays.
The issue comes from the fact that
createGraphics()automatically adjusts for the pixel density of the sketch, butcreateImage()does not. That’s why even if thewidthandheightmatch in your code, the underlying pixel arrays can end up being different sizes. Sincemask()directly compares the pixel data, this mismatch becomes a problem.This discrepancy wasn't as apparent when
pixelDensity(1)was the default, but now that we use the screen’s density by default (starting with Processing 4.4.3), this issue shows up for high-DPI screens.Here's a sketch that demonstrates this:
Output for
pixelDensity(1)Output for
pixelDensity(2)hkiel commentedon Apr 29, 2025
What is the 'correct' way of creating an apropriate mask in my example? I would let
pixelDensitybe at default value.SableRaf commentedon Apr 29, 2025
To create an appropriate mask while avoiding the
pixelDensitymismatch, you can usecreateGraphics()for both your drawing and mask buffers, then call.get()to extract aPImagesince that is what themask()function expects.Here’s a code example:
hkiel commentedon Apr 29, 2025
So, finally only the error message of
mask()is misleading, since.widthand.heightattributes of image and mask are the same, butpixelDensityis different for the two objects, resulting it buffers of different size, which is the problem. Maybe you can add an assertion for the densities inmask().@Stefterv I would not have had a clue how to fix the problem, if I had been warned about different densities, but at least I could have seen that the problem is not the size.
SableRaf commentedon Apr 29, 2025
@Stefterv @hkiel: What would you think of replacing the existing error with this?
mask() error: image and mask must have the same dimensions and pixel density.Stefterv commentedon Apr 29, 2025
@SableRaf We should not replace the existing error in
mask(pixelArray), as in that spot it only has the array length to check, we should add a new error in themask(PImage)function.SableRaf commentedon Apr 29, 2025
@Stefterv Even better! What do you think would be a good error message?
Stefterv commentedon Apr 29, 2025
@SableRaf What you wrote seems correct, maybe it can be a bit more specific
image and mask must have the same dimensions (320px by 240px) vs (300 by 200px), mask should be 320px by 240pxand in case of different pixel densities
image and mask must have the same pixel density, image is pixelDensity(1) and mask is pixelDensity(2). mask should also be pixelDensity(1)Dynamically based on the current situation
hkiel commentedon Apr 30, 2025
I would suggest to not repeat the values. You never know which one is really wrong.
image and mask must have the same dimensions, image is 320x240, mask is 300x200.image and mask must have the same pixel density, image is pixelDensity(1) and mask is pixelDensity(2).mrbbp commentedon Apr 30, 2025
ok but this is a partial answer. How to have same pixelDensity on mask and picture? return to 1 ?
pnngocdoan commentedon May 12, 2025
Hi! I saw that this issue has not been assigned to anyone. I'm new to Processing and would like to take this on! The solution that everyone discussed is to add an error message if underlying sizes don't match because of the pixel densities right? I assume if the pixel densities are different but if the underlying sizes match then it should be fine? Or do we want strictly that both pixel density and size of the picture and mask must be the same?
Stefterv commentedon May 12, 2025
Hi @pnngocdoan Thank you for your interest in contributing! Yes if the sizes still match despite different pixel densities I think it is fine to let it go through.
pnngocdoan commentedon May 17, 2025
Hi @Stefterv I have submitted my first PR! Thank you so much for your help. Please let me know if I need to fix anything!