Masks Not Working?

  1. 5 days ago

    Perry F

    Feb 13 Pre-Release Testers
    Edited 5 days ago

    Hey all, I've been hitting my head against this for several hours. I've tried many different methods, and done searches, but just cannot seem to get it to work.

    All I want to do is draw a picture (a square — this will be a piece of a larger picture that the program pulls out) and give it a round rect mask.

    I've put this code in a Canvas Paint event:

    dim magPic as picture
    magPic=TrueWindow.BitmapForCaching(100,100)
    magPic.graphics.foreColor=&c2FACE200
    magPic.graphics.fillRect(0,0,magPic.width,magPic.height)
    
    dim maskPic as picture
    maskPic=TrueWindow.BitmapForCaching(100,100)
    maskPic.graphics.foreColor=&c00000000
    maskPic.graphics.FillRoundRect(0,0,100,100,20,20)
    
    magPic.ApplyMask maskPic
    g.drawPicture magPic,0,0

    What I expect is a blue square with a round rect mask making it a blue round rect. What I get is a blue square with no mask, no matter what I try. I'm sure I'm overlooking something simple, but I'm at a loss. Anyone have any ideas?

    Thank you.

    Make sure you set the background of the mask image to white first.

    dim maskPic as picture
    maskPic=TrueWindow.BitmapForCaching(100,100)
    maskPic.graphics.foreColor=&cFFFFFF
    maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height)
    maskPic.graphics.foreColor=&c00000000
    maskPic.graphics.FillRoundRect(0,0,100,100,20,20)
  2. Anthony C

    Feb 13 Pre-Release Testers, Xojo Pro, XDC Speakers, Third Party Store, Forum Moderators, MVP Answer GraffitiSuite Developer
    Edited 5 days ago

    Make sure you set the background of the mask image to white first.

    dim maskPic as picture
    maskPic=TrueWindow.BitmapForCaching(100,100)
    maskPic.graphics.foreColor=&cFFFFFF
    maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height)
    maskPic.graphics.foreColor=&c00000000
    maskPic.graphics.FillRoundRect(0,0,100,100,20,20)
  3. Derk J

    Feb 13 Pre-Release Testers, Xojo Pro

    Read here:
    https://docs.xojo.com/Window.BitmapForCaching

    Returns a bitmap that is configured correctly for using as a cache for content to be drawn to this Window. This image supports Alpha Channels (not masked images).

    It won't support masked images.
    Use the normal picture constructor for masked pictures

  4. Anthony C

    Feb 13 Pre-Release Testers, Xojo Pro, XDC Speakers, Third Party Store, Forum Moderators, MVP GraffitiSuite Developer

    To follow up on what @Derk J said, this should produce what you're looking for:

    dim magPic as new Picture(100,100)
    magPic.graphics.foreColor=&c2FACE200
    magPic.graphics.fillRect(0,0,magPic.width,magPic.height)
    
    dim maskPic as new picture(100,100)
    maskPic.graphics.foreColor=&cFFFFFF
    maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height)
    maskPic.graphics.foreColor=&c00000000
    maskPic.graphics.FillRoundRect(0,0,100,100,20,20)
    
    magPic.ApplyMask maskPic
    g.drawPicture magPic,0,0
  5. Perry F

    Feb 13 Pre-Release Testers

    @Anthony C Make sure you set the background of the mask image to white first.

    dim maskPic as picture maskPic=TrueWindow.BitmapForCaching(100,100) maskPic.graphics.foreColor=&cFFFFFF maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height) maskPic.graphics.foreColor=&c00000000 maskPic.graphics.FillRoundRect(0,0,100,100,20,20)

    Masks must be black. A white mask inverts the mask.

  6. Anthony C

    Feb 13 Pre-Release Testers, Xojo Pro, XDC Speakers, Third Party Store, Forum Moderators, MVP GraffitiSuite Developer

    @Perry F Masks must be black. A white mask inverts the mask.

    If you look, I'm filling the background of the mask with white to denote the transparent areas, then drawing the RoundRect on top in black.

  7. Perry F

    Feb 13 Pre-Release Testers
    Edited 5 days ago

    @Derk J Read here:
    https://docs.xojo.com/Window.BitmapForCaching

    Returns a bitmap that is configured correctly for using as a cache for content to be drawn to this Window. This image supports Alpha Channels (not masked images).

    It won't support masked images.
    Use the normal picture constructor for masked pictures

    Yes, this works. I had tried that. But I need the images to be retina/HiDPI compatible, so not sure what to do there. Would multiplying the image by screen scale and drawing it at half size work? I had started playing around with that but was running into issues.

  8. Anthony C

    Feb 13 Pre-Release Testers, Xojo Pro, XDC Speakers, Third Party Store, Forum Moderators, MVP GraffitiSuite Developer
    Edited 5 days ago

    @Perry F Yes, this works. I had tried that. But I need the images to be retina/HiDPI compatible, so not sure what to do there. Would multiplying the image by screen scale and drawing it at half size work?

    You can multiply by ScaleFactor of the window/control you're drawing in:

    dim magPic as new Picture(100 * me.TrueWindow.ScaleFactor,100 * me.TrueWindow.ScaleFactor)
    magPic.graphics.foreColor=&c2FACE200
    magPic.graphics.fillRect(0,0,magPic.width,magPic.height)
    
    dim maskPic as new picture(100 * me.TrueWindow.ScaleFactor,100 * me.TrueWindow.ScaleFactor)
    maskPic.graphics.foreColor=&cFFFFFF
    maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height)
    maskPic.graphics.foreColor=&c00000000
    maskPic.graphics.FillRoundRect(0,0,100,100,20,20)
    
    magPic.ApplyMask maskPic
    g.drawPicture magPic,0,0
  9. Derk J

    Feb 13 Pre-Release Testers, Xojo Pro

    @Anthony C To follow up on what @Derk J said, this should produce what you're looking for:
    dim magPic as new Picture(100,100) magPic.graphics.foreColor=&c2FACE200 magPic.graphics.fillRect(0,0,magPic.width,magPic.height) dim maskPic as new picture(100,100) maskPic.graphics.foreColor=&cFFFFFF maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height) maskPic.graphics.foreColor=&c00000000 maskPic.graphics.FillRoundRect(0,0,100,100,20,20) magPic.ApplyMask maskPic g.drawPicture magPic,0,0

    I think you need the "non-alpha-constructor" Pictures created with an alpha channel do not use a mask. The Mask property will be Nil. Use the CopyMask and ApplyMask methods if you need to work with masks.
    https://docs.xojo.com/Picture.Constructor(width_as_Integer,_height_as_Integer )

    you need this constructor:
    https://docs.xojo.com/Picture.Constructor(width_as_Integer,_height_as_Integer,_Depth_as_Integer )

    Something like:

    dim magPic as new Picture(100,100, 32) // <-- specify depth
    magPic.graphics.foreColor=&c2FACE200
    magPic.graphics.fillRect(0,0,magPic.width,magPic.height)
    
    dim maskPic as new picture(100,100)
    maskPic.graphics.foreColor=&cFFFFFF
    maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height)
    maskPic.graphics.foreColor=&c00000000
    maskPic.graphics.FillRoundRect(0,0,100,100,20,20)
    
    magPic.ApplyMask maskPic
    g.drawPicture magPic,0,0
  10. Anthony C

    Feb 13 Pre-Release Testers, Xojo Pro, XDC Speakers, Third Party Store, Forum Moderators, MVP GraffitiSuite Developer
    Edited 5 days ago

    @Derk J I think you need the "non-alpha-constructor"

    Nope. Use it all the time, and just tested it again when checking his issue in the IDE. ApplyMask takes care of that.

  11. Ed P

    Feb 13 Pre-Release Testers Tampa, FL, USA

    @Derk J It won't support masked images.
    Use the normal picture constructor for masked pictures

    Doc page for ApplyMask:

    When used on a Picture with an alpha channel, this overwrites the Picture’s alpha channel with the mask data.

  12. Derk J

    Feb 13 Pre-Release Testers, Xojo Pro

    @Anthony C Nope. Use it all the time, and just tested it again when checking his issue in the IDE. ApplyMask takes care of that.

    Alpha and masks don't combine so then the picture is NON-ALPHA by using the ALPHA constructor ?

  13. Perry F

    Feb 13 Pre-Release Testers

    Interesting. I read in the documentation that when used with a picture with an alpha channel, it should still work and override the picture's alpha channel. Why isn't that working?

  14. Perry F

    Feb 13 Pre-Release Testers

    @Anthony C You can multiply by ScaleFactor of the window/control you're drawing in:
    dim magPic as new Picture(100 * me.TrueWindow.ScaleFactor,100 * me.TrueWindow.ScaleFactor) magPic.graphics.foreColor=&c2FACE200 magPic.graphics.fillRect(0,0,magPic.width,magPic.height) dim maskPic as new picture(100 * me.TrueWindow.ScaleFactor,100 * me.TrueWindow.ScaleFactor) maskPic.graphics.foreColor=&cFFFFFF maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height) maskPic.graphics.foreColor=&c00000000 maskPic.graphics.FillRoundRect(0,0,100,100,20,20) magPic.ApplyMask maskPic g.drawPicture magPic,0,0

    It looks like that works. Now I just need to change all of my drawing code to use the Picture constructor rather than BitmapForCaching. Thank you.

  15. Anthony C

    Feb 13 Pre-Release Testers, Xojo Pro, XDC Speakers, Third Party Store, Forum Moderators, MVP GraffitiSuite Developer

    @Perry F Interesting. I read in the documentation that when used with a picture with an alpha channel, it should still work and override the picture's alpha channel. Why isn't that working?

    Try my code above. It is working as I wrote it. You weren't filling the context with white (&cFFFFFF) first.

  16. Derk J

    Feb 13 Pre-Release Testers, Xojo Pro

    @Perry F Interesting. I read in the documentation that when used with a picture with an alpha channel, it should still work and override the picture's alpha channel. Why isn't that working?

    Well it's probably locked in the picture returned from BitmapForCaching

  17. Derk J

    Feb 13 Pre-Release Testers, Xojo Pro

    Try this one:

    Function BitmapForCaching(Extends g as Graphics, Width as Integer,  Height as Integer) As Picture
      Dim p as New Picture(Width * g.ScaleX, Height * g.ScaleY)
      // Set the appropriate resolution
      p.HorizontalResolution = 72 * g.ScaleX
      p.VerticalResolution = 72 * g.ScaleY
    
      // Set the scale factor so drawing to it will be correct
      p.Graphics.ScaleX = g.ScaleX
      p.Graphics.ScaleY = g.ScaleY
    
      // Very important to remember the mask!
      p.Mask.Graphics.ScaleX = g.ScaleX
      p.Mask.Graphics.ScaleY = g.ScaleY
    
      // Return the new picture
      Return p
    End Function
  18. Perry F

    Feb 13 Pre-Release Testers
    Edited 5 days ago

    @Anthony C Try my code above. It is working as I wrote it. You weren't filling the context with white (&cFFFFFF) first.

    THANK YOU! You are correct, I was missing the white part inside the round rect. It looks like it is working with BitmapForCaching as I expected. I knew I was missing something simple.

    Here is the full code, working as intended. Very clean and simple. Thank you Anthony!

    dim magPic as picture
    magPic=TrueWindow.BitmapForCaching(100,100)
    magPic.graphics.foreColor=&c2FACE200
    magPic.graphics.fillRect(0,0,magPic.width,magPic.height)

    dim maskPic as picture
    maskPic=TrueWindow.BitmapForCaching(100,100)
    maskPic.graphics.foreColor=&cFFFFFF
    maskPic.graphics.FillRect(0,0,maskPic.Width, maskPic.Height)
    maskPic.graphics.foreColor=&c00000000
    maskPic.graphics.FillRoundRect(0,0,100,100,20,20)
    magPic.ApplyMask maskPic
    g.drawPicture magPic,0,0

  19. Anthony C

    Feb 13 Pre-Release Testers, Xojo Pro, XDC Speakers, Third Party Store, Forum Moderators, MVP GraffitiSuite Developer

    Happy to help!

  20. Perry F

    Feb 13 Pre-Release Testers

    Thank you to everyone, I appreciate all of your help. It is possible to use a mask with BitmapForCaching, which lets you avoid handling all of the scale factor math. This is what I was going for.

  21. Newer ›

or Sign Up to reply!