p5.js icon indicating copy to clipboard operation
p5.js copied to clipboard

Graphics object used as mask results in image that is half the size of the original graphics object

Open taliacotton opened this issue 1 year ago • 9 comments
trafficstars

Most appropriate sub-area of p5.js?

  • [ ] Accessibility
  • [ ] Color
  • [X] Core/Environment/Rendering
  • [ ] Data
  • [ ] DOM
  • [ ] Events
  • [X] Image
  • [ ] IO
  • [ ] Math
  • [ ] Typography
  • [ ] Utilities
  • [ ] WebGL
  • [ ] Build process
  • [X] Unit testing
  • [ ] Internationalization
  • [ ] Friendly errors
  • [X] Other (specify if possible)

p5.js version

1.9.0

Web browser and version

Chrome 121.0.6167.139

Operating system

MacOSX

Steps to reproduce this

Steps:

  1. Create a p5.Graphics object the same size as canvas—I've called mine "maskGraphics"
  2. Draw something to the main canvas—in my case it's an image
  3. Use get() to save a the canvas as an image, then clear the canvas.
  4. Draw something to the new Graphics object that will be the mask—in my case it's an ellipse
  5. Use mask() to mask the main image using the newly drawn mask to the mask graphics object.
  6. When you draw both the display image and the mask graphics image, the masked image is half the size as the mask graphics object when they're both drawn at the same size. Screenshot 2024-02-04 at 2 07 13 PM

My gut is that it might have something to do with the device pixel ratio or the pixel density, but I have no reason to believe that and haven't been able to prove that.

Snippet:


let sketch = function(p) {
  let img, maskGraphics, cnv;


  p.preload = function() {
     img = p.loadImage("https://hips.hearstapps.com/hmg-prod/images/dog-puppy-on-garden-royalty-free-image-1586966191.jpg?crop=1xw:0.74975xh;center,top&resize=1200:*");
  };
  
  p.setup = () => {
      cnv = p.createCanvas(p.windowWidth, p.windowHeight);
      maskGraphics = p.createGraphics(p.windowWidth, p.windowHeight);
  }

  p.draw = () => {
    
        // draw an image to the main canvas
        p.image(img, 0,0,p.width, p.height);

        // save the canvas as an image, then clear the canvas
        let displayImage = p.get();
        p.clear();

        maskGraphics.clear();
        maskGraphics.fill(0);
        // Draw an ellipse to the mask graphics element in the center of the canvas
        maskGraphics.ellipse(p.width/2,p.height/2,300,300)

        // Apply the mask to displayImage
        // Without this, the image will be full size without the circle mask
        displayImage.mask(maskGraphics);

        // Draw the masked image
        // Without this, there will not be the masked image 
        p.image(displayImage, 0, 0, p.width, p.height);

        // Draw the mask circle  as an image to the main cnv to test its position on the canvas
        p.image(maskGraphics, 0, 0, p.width, p.height);
  };
}

new p5(sketch, 'container');

taliacotton avatar Feb 04 '24 22:02 taliacotton

Thanks for filing this issue! I think this bug may be the same as https://github.com/processing/p5.js/issues/6770 -- @Papershine, maybe you can test this example on your PR to see if it fixes it too?

davepagurek avatar Feb 05 '24 01:02 davepagurek

Thank you! Yes, I had actually tested adding pixelDensity(1) prior to contributing the issue, but then the quality of the sketch goes down significantly. If I add pixelDensity(2) it also fixes the issue, but on devices where the device pixel ratio is something else the sketch lags significantly because it's drawing at 2x the size. I tried pixelDensity(window.devicePixelRatio) but that didn't fix the issue.

Is there a solution that solves the misalignment without losing the quality of the sketch?

taliacotton avatar Feb 05 '24 01:02 taliacotton

If it helps to debug, I just switched to version 1.4.1 per #6770, and that worked. However, not ideal for a long-term solution since I'd like to use the most recent version. Let's see if @Papershine's pull request solves it?

taliacotton avatar Feb 05 '24 02:02 taliacotton

Yep I've tried it with the code in the PR and this is how it looks - this should be what it looks like right?

Screenshot 2024-02-04 at 6 55 38 PM

Papershine avatar Feb 05 '24 02:02 Papershine

whee yes! <3

taliacotton avatar Feb 05 '24 02:02 taliacotton

Hey awesome P5 team, do you have any tips for what I should do in the meantime regarding this bug while the pull request is being approved? Clients eager to see things right.

taliacotton avatar Feb 08 '24 21:02 taliacotton

Hi! One option to use a shader to do the masking. Not sure if you can use webGL or not, but if you can it's a pretty short shader. Here's a quick example: https://editor.p5js.org/aferriss/sketches/qYWb4P49d

aferriss avatar Feb 08 '24 23:02 aferriss

Another option, if your mask is shapes that you draw, is to use beginClip/endClip: https://p5js.org/reference/#/p5/beginClip

davepagurek avatar Feb 09 '24 14:02 davepagurek

Awesome, thanks so much Dave. Will look into both of these.

taliacotton avatar Feb 09 '24 14:02 taliacotton