RGBSurface.pixel to Graphics.FillRect transparency issue

For test purpose I created a very small program that takes a 32x32 transparent picture and copies each pixel into another transparent picture Graphics through the FillRect method.

dim factor as integer = 16 dim pic as picture = user_bart dim p as new picture(pic.width,pic.height) p = pic dim c as Color dim px as new picture(pic.width*factor,pic.height*factor,32) px.Transparent = 1 dim surf as RGBSurface = p.RGBSurface for x as integer = 0 to p.width for y as integer = 0 to p.height px.graphics.ForeColor = surf.Pixel(x,y) px.graphics.FillRect(x*factor,y*factor,factor,factor) next next self.backdrop = px self.width = px.width self.height = px.height

It works well and fast for the transparent background and for solid colors, but shadows end up black. I checked the result of RGBSurface.pixel and it does report the alpha channel correctly.

What did I miss ?

It’s always the question if you just put the color there or apply the color to the color which is there already.
That makes a difference.

[quote=123923:@Christian Schmitz]It’s always the question if you just put the color there or apply the color to the color which is there already.
That makes a difference.[/quote]

I do not understand. Do you have an example ?

Tried to fill the picture with black, with white, with nothing, that does not make any difference…

Just some unformulated thoughts – I have been digging into NSColor lately rather than the built-in methods, so I am not sure if this applies to your project at all. Anyway I find it easier to prepare apps for UI changes then by picking the predefined UI NSColors. Black and white colors there usually use different color spaces than RGB. Have you checked if the black color comes as RGB too or did you try to convert it into RGB color space?

What I get from RGBSurface.pixel, or from Graphics.pixel I tried as well, is a color with Alpha channel information appended such as &cECCDFF00. The black component is only the result of the sum of colors.

I think you might be confusing how alpha colors and masked pictures work together. If user_bart is a masked picture then surf.Pixel has no alpha. If user_bart is an alpha channel picture you still have the problem that you’re drawing to a masked picture, that doesn’t change it’s mask.

How you do this depends on whether your source and destination pictures are alphaed or masked. Here’s some of the differences between the two…

---- Masked pictures are created these ways (as best I can tell)
dim p As new Picture(w, h, 32)
dim p As Picture = projectImage
dim p As Picture = Picture.Open(f, …)

dim c As color = p.RGBSurface.Pixel(x, y) //c has no Alpha value
dim a As integer = p.Mask.RGBSurface.Pixel(x, y).Red //the “alpha” is in Mask

When you draw on a masked picture with a transparent color the Mask layer is not modified. You need to separately draw into the Mask to have transparent areas. A new masked Picture starts out opaque.

---- Alpha Channel pictures are only made this way
dim p As new Picture(w, h)

dim c As color = p.RGBSurface.Pixel(x, y) //c has Alpha value

dim m As Picture = p.Mask //m is nil, alpha channel pictures have no Mask

//use CopyMask to generate a mask image from an alpha channel picture
dim m As Picture = p.CopyMask

---- The Picture.Transparency property is something else. Don’t use it with a masked or alpha channel picture because they’re doing the transparency.

This code creates user_bart as a masked picture (first creating an alpha channel picture for blended drawing then copies that to user_bart). After that is your routine modified to also draw the Mask portion to px.

I think the transparency you were getting before was from the px.Transparent property and not the actual mask which was solid opaque the whole time.

[code]Sub Action()

dim user_bart As Picture //masked or alpha channel?

//========================
dim pp As new Picture(32, 32) //alpha channel picture
pp.Graphics.ForeColor = &c0000FF
pp.Graphics.FillOval(3, 3, 26, 26)
pp.Graphics.ForeColor = &c00000080
pp.Graphics.DrawRect(0, 0, 32, 32)

user_bart = new Picture(32, 32, 32) //masked picture
user_bart.Graphics.ForeColor = &c000000 //(fill black to fix premultiplied alpha)
user_bart.Graphics.FillRect(0, 0, 32, 32)
user_bart.Graphics.DrawPicture pp, 0, 0 //draw color portion
user_bart.Mask.Graphics.DrawPicture(pp.CopyMask, 0, 0) //draw mask portion
//========================

dim factor as integer = 16
dim p as picture = user_bart

dim px as new picture(p.widthfactor,p.heightfactor,32) //masked picture
dim pxMask As Picture = px.Mask

dim surf as RGBSurface = p.RGBSurface
dim surfMask As RGBSurface = p.CopyMask.RGBSurface

dim grey as integer
for x as integer = 0 to p.width - 1 // -1
for y as integer = 0 to p.height - 1

  px.graphics.ForeColor = surf.Pixel(x, y)
  px.graphics.FillRect(x*factor,y*factor,factor,factor)
  
  grey = surfMask.Pixel(x, y).Red
  pxMask.Graphics.ForeColor = RGB(grey, grey, grey)
  pxMask.Graphics.FillRect(x*factor,y*factor,factor,factor)
  
next

next

self.backdrop = px
self.width = px.width
self.height = px.height

End Sub[/code]

[quote=123975:@Will Shank]
I think you might be confusing how alpha colors and masked pictures work together. If user_bart is a masked picture then surf.Pixel has no alpha. If user_bart is an alpha channel picture you still have the problem that you’re drawing to a masked picture, that doesn’t change it’s mask.

How you do this depends on whether your source and destination pictures are alphaed or masked. Here’s some of the differences between the two…[/quote]

I appreciate your insight, and you code. Now I understand what was going on. Thank you, Will.