Easy for someone who understands alpha channels and/or masks

Ok…this seems like it ought be really easy…but the solution eludes me for days now. I have some PNG files that have an Alpha Channel – I need to be able to read that PNG file in (sample attached) display it on a canvas…and eventually save the picture without the alpha channel. Any transparent parts of the picture need to be opaque white. I thought I could do this with Christian’s PNGReaderMBS which has an option to strip the alpha channel. It doesn’t seem to matter if I use this option or not… according to runtime properties on my picture HasAlphaChannel = False.
This could be a byproduct of the PictureMBS.CopyPicture process?

My source image does appear to have a valid alpha channel.

Here’s by best but failed effort thus far:

dim f as folderitem = SpecialFolder.Resource("xojo_logo.png")
If f <> Nil Then
  Var Currentin as PictureMBS = nil
  Var pm as new PNGReaderMBS
  if pm.OpenFile(f) then
    'pm.StripAlpha = True
    if pm.ApplyOptions(0) then
      Currentin=new PictureMBS(pm.Width,pm.Height,PictureMBS.ImageFormatRGB)
      Var i,c as Integer
      c=pm.Height-1
      for i=0 to c
        Currentin.RowInFormat(i, PictureMBS.ImageFormatRGBA)=pm.ReadRow
      next
    end if
  end if
  Var p as Picture = Currentin.CopyPicture
  Var p2 as New Picture(p.width,p.height,32)
  Var g as Graphics = p2.Graphics 
  g.DrawPicture(p,0,0,p.Width,p.height)
  Canvas1.Backdrop = p2
end

I was kinda hoping with the various libraries at my disposal this would be fairly easy.
Anybody care to contribute some guidance to a Xojo hobbyist? Much appreciated.

Here’s code to do it in a brute force fashion:

dim fIn as FolderItem = GetFolderItem("").child("xojoLogo.png")
dim p as picture = picture.Open(fIn)

' make a copy of the picture so we can edit it

dim p2 as new Picture(p.width,p.height)
p2.Graphics.DrawPicture(p,0,0)

dim rgb as RGBSurface = p2.RGBSurface
dim w as integer = p2.Width -1
dim h as integer = p2.height -1

for y as integer = 0 to h
  for x as integer = 0 to w
    dim c as color = rgb.Pixel(x,y)
    
    ' set the alpha channel to opaque
    dim c2 as color = color.RGB(c.Red,c.Green,c.Blue,0)
    
    rgb.Pixel(x,y) = c2
    
  next
next

dim fOut as FolderItem =  fIn.parent.child("xojoLogo-noalpha.png")
p2.Save(fOut, picture.Formats.PNG)

This works, but doesn’t do what you want. The problem is that the Xojo Logo image pixels are using black RGB (0,0,0) for the transparent sections, so if you wipe out the alpha channel, you get something that looks like this:

We can work around that by setting all transparent pixels to full white instead:

dim fIn as FolderItem = GetFolderItem("").child("xojoLogo.png")
dim p as picture = picture.Open(fIn)

' make a copy of the picture so we can edit it

dim p2 as new Picture(p.width,p.height)
p2.Graphics.DrawPicture(p,0,0)

dim rgb as RGBSurface = p2.RGBSurface
dim w as integer = p2.Width -1
dim h as integer = p2.height -1

for y as integer = 0 to h
  for x as integer = 0 to w
    dim c as color = rgb.Pixel(x,y)
    
    ' set the alpha channel to opaque, unless alpha was 255 (transparent) in which case set the RGB to full white
    dim c2 as color = color.RGB(c.Red,c.Green,c.Blue,0)
    if c.Alpha = 255 then
      c2 = color.RGB(255,255,255,0)
    end if
    
    ' set the color in the image
    rgb.Pixel(x,y) = c2
    
  next
next

dim fOut as FolderItem =  fIn.parent.child("xojoLogo-noalpha.png")
p2.Save(fOut, picture.Formats.PNG)


which gives a different effect:

This doesn’t look great however, as we lose the fuzzy alpha boundaries.

Notice how the top of the “O” looks jagged:

A much simpler approach is to simply draw the original onto a while background, like this:

dim fIn as FolderItem = GetFolderItem("").child("xojoLogo.png")
dim p as picture = picture.Open(fIn)

' create a new picture, fill with white

dim p2 as new Picture(p.width,p.height)
p2.Graphics.DrawingColor = color.rgb(255,255,255,0)
p2.Graphics.FillRectangle(0,0,p2.Width,p2.Height)

' now draw the transparent picture onto the white one
p2.Graphics.DrawPicture(p,0,0)

'save the result

dim fOut as FolderItem =  fIn.parent.child("xojoLogo-noalpha-v2.png")
p2.Save(fOut, picture.Formats.PNG)


I think this is the result you want?

Notice how the O looks good here:

1 Like

Wow. Thanks Mike! Yes…shows how little (unfortunately) I know about working with graphics in Xojo. I’m going to pour over both these methods until I have a good understanding of both. I see what you did. I had found that my previous method worked on “some” PNG’s with an alpha channel… but did not work on others and I didn’t know why.

So I guess if the transparency property (alpha channel is set to 100% transparent…then the underlying RGB pixel values don’t really matter… but if you strip out the alpha channel…then the underlying RGB pixels become relevant. I’m guessing some people use Black 0,0,0 and some use white 255,255,255 – which is was why I got the desired result “sometimes”.

The idea of drawing the Picture with alpha on top of an opaque white backdrop may also be an option – which does certainly produce a better looking result. Thank you so much for being so helpful. One reason as a hobbyist I like the Xojo platform is the thoughtful and generous responses I receive from Pros when I post an issue on the forum. I always put forth my best effort before I ask the forum – but some times I’m just really stumped. I’ve read previous “Alpha Channel” questions and none of them really seemed to explain what my issue was or how to go about fixing it. Thank you so much.

1 Like

You don’t want to strip the alpha channel as that will break the image.

What you want to do is flatten the source image onto a white background.

so… Load your image with the alpha channel into a picture, create a second picture and fill it white, draw the first picture into the second picture and then dispose of the first picture.

2 Likes

Exactly - that is what my 3rd code example does, see above.