Copying and assigning a Mask results in an odd color shift in the new image

Hi Folks,

I have an image that displays properly when it is displayed - and the mask is correct (it’s a PNG with Alpha). For a listbox where I want to place a count bug onto the image, I use the following code:

    Dim bigP As New Picture(TapeImage26x26.Width, TapeImage26x26.Height, 32)
    Dim bigM As New Picture(TapeImage26x26.Width, TapeImage26x26.Height, 32)
    Dim bigMG As Graphics = bigM.Graphics
    bigP.Graphics.DrawPicture TapeImage26x26, 0, 0
    bigMG.DrawPicture(TapeImage26x26, 0, 0)
    bigP.Mask = bigM
    Dim slen As Double = bigP.Graphics.StringWidth(Str(MyTapeSetRecords(x).trVolumeCount))
    Dim p As New Picture(sLen + 2, 14, 32)
    Dim pG As Graphics = p.Graphics
    pG.TextFont = "Helvetica"
    pG.TextSize = 10
    pg.Bold = True
    pG.ForeColor = &c6278E300
    pG.FillRoundRect(0,0,sLen + 2, 14, 7, 7)
    pG.ForeColor = &cFFFFFF00
    pG.DrawString(Str(MyTapeSetRecords(x).trVolumeCount), 1, 9)
    bigP.Graphics.DrawPicture(p, TapeImage26x26.Width - (slen + 2), TapeImage26x26.Height - 14)

Unfortunately, the result of applying the mask to the new bigP picture looks as if the mask wasn’t fully black (the lighter versions here):

Do any of you see what I’m doing incorrectly in the code to cause that?

Should this :

bigMG.DrawPicture(TapeImage26x26, 0, 0)

Be

bigMG.DrawPicture(TapeImage26x26.Mask, 0, 0)

Oh, and this:

bigP.Graphics.DrawPicture TapeImage26x26, 0, 0

Should probably be this:

bigP.Graphics.DrawPicture TapeImage26x26.CopyColorChannels, 0, 0

[quote=366268:@Greg O’Lone]

bigP.Graphics.DrawPicture TapeImage26x26.CopyColorChannels, 0, 0

UnsupportedOperationException

[quote=366266:@Greg O’Lone]

bigMG.DrawPicture(TapeImage26x26.Mask, 0, 0)

The picture is now invisible.

I don’t exactly understand why you’re mucking with masks if you’re drawing a badge on something?

I can’t draw the badge onto the original because I reuse the original many times. If I just create the new picture and draw the badge, the mask is discarded and the image is antialiased white around the picture.

I still don’t think you should need to be mucking with masks. Can I ask if this is happening in a Listbox CellBackgroundPaint event? Or is this a neat way to cache the image to avoid that much drawing? I would take the tape image and draw the badge on top in a new image (which you shouldn’t need to mask).

Color me intrigued, this could be a fun little project to solve.
Feel free to shoot me an email or PM if you want to send a lot of details.

Brb opening Xojo on vacation :stuck_out_tongue:

Yes - as the image above shows, I’m using the image as a RowPicture in a listbox.

Hmm, I had to look up this term - vacation. I’m not familiar with its use in the world of computer software development :stuck_out_tongue:

this is the method I use for all my “badged” controls
I think somewhere on this forum I posted a link to a custom “iOS like” tabbar for Xojo (desktop) which does this

Without the masking, I get this:

Interesting discovery - 2013r3.3 displays the image properly in the ListBox without the need for the mask.

So, it’s a bug in the ListBox that crept in sometime between 2013r3.3 and 2017r3.

Here’s my little test project for a badging routine that doesn’t need to mess around with masks:
https://www.dropbox.com/s/hkcy0fvs954lhin/badges.zip?dl=1

It returns a Picture so you can shove it into RowPicture if you want. It’s likely not HiDPI friendly and might require some tweaking. The positioning of the digit in the badge background isn’t absolutely perfect, but again can be tweaked to suit :slight_smile:

Oh man - I LOVE that tape icon. Too bad most of our users are IT geeks with no sense of humor!

Very odd that the artifacting doesn’t appear. I’m changing it to use an ImageSet and we’ll see…

Okay - Thanks, @Tim Parnell, That sorted it out. Replaced your tape with the real thing and:

Because I know I clean out my Dropbox frequently here’s the badge method code for future reference:

[code]Public Function MakeBadge(sLabel as String) as Picture
dim pTemp as new Picture(picTape.Width, picTape.Height)
dim g as Graphics = pTemp.Graphics

g.DrawPicture(picTape, 0, 0)

g.TextFont = “Helvetica”

g.Bold = True
g.TextSize = 24

const kPadding = 5

dim iBadgeTextLength as Integer = g.StringWidth(sLabel)
dim iBadgeTextHeight as Integer = g.StringHeight(sLabel, 9001)

dim iBadgePosX as Integer = pTemp.Width - (kPadding * 3) - iBadgeTextLength
dim iBadgePosY as Integer = pTemp.Height - (kPadding * 3) - iBadgeTextHeight

g.ForeColor = &c6278E3
g.FillRoundRect(iBadgePosX, iBadgePosY, iBadgeTextLength + kPadding, iBadgeTextHeight + kPadding, 7, 7)

g.ForeColor = &cFFFFFF
g.DrawString(sLabel, iBadgePosX + (kPadding / 2), iBadgePosY + iBadgeTextHeight)

return pTemp
End Function
[/code]

And here’s my alternate signature version that accepts a passed in picture.

Function MakeBadge(pic As picture, sLabel as String) As Picture
  Dim pTemp As New Picture(pic.Width, pic.Height)
  dim g as Graphics = pTemp.Graphics

  g.DrawPicture(pic, 0, 0)

  g.TextFont = "Helvetica"

  g.Bold = True
  g.TextSize = 11

  Const kPadding = 2

  dim iBadgeTextLength as Integer = g.StringWidth(sLabel)
  dim iBadgeTextHeight as Integer = g.StringHeight(sLabel, 9001)

  dim iBadgePosX as Integer = pTemp.Width - (kPadding * 3) - iBadgeTextLength
  dim iBadgePosY as Integer = pTemp.Height - (kPadding * 3) - iBadgeTextHeight

  g.ForeColor = &c6278E3
  g.FillRoundRect(iBadgePosX, iBadgePosY, iBadgeTextLength + kPadding, iBadgeTextHeight + kPadding, 2, 2)

  g.ForeColor = &cFFFFFF
  g.DrawString(sLabel, iBadgePosX + (kPadding / 2), iBadgePosY + iBadgeTextHeight)

  return pTemp
End Function