Convert full RGBA to grayscale

Before I reinvent the wheel yet again, does anyone have a function to convert a standard RGBA PNG image to a grayscale image? MBS or Einhugur are quite acceptable.

I would be very surprised if MBS doesnt have a function to do it.

How do you want to convert it to grayscale?

Luminosity, average, brightness or maximum, minimum, value (HSV), or a custom implementation where you can fiddle with the RGB channels?

function  grayScale(c as color) as color
return rgb(( * 0.299),( * 0.587) , (c.Blue *0.114),c.alpha)
end function

scan the RGBSurface and apply this equation to each color

you can also use a MAP and TRANSFORM, but I’d have to look up the exact code I used for that… the Transform method is very fast

You could use the MBS method Picture.GrayScaleMBS(mode as Integer). Mode 3 e.g. replicates the function Dave uses in his example. GrayScaleMBS is, however, much faster than doing it yourself via iterating through every color in a RGBSurface.

I have routines that use the transform method that will do an entire image at very high speed. They work for 256, 16 and 4 level grayscale as well as Sepia. I will try and find them in the morning and post them here

Einhugur plugin has the picture effects classes which allow you to chain together filters to convert to grayscale. You covert the picture to a raw data class, run all your effects and then get your finial image. It runs nice an fast and apparently can use up to 8 cores.

Whatever you have in Xojo, the plugins will be easily several times faster.

You can read the PNG directly with GraphicsFormats and use PictureEffectsRaw to do the Grayscale conversion, with option of several variations of grayscale methods. You can do this all synchronous or asynchronous. TypeLibs RawBitmapConverter if at any point in the process you need it in Xojo Picture Object.

The good news is that I’m dealing with 16x16, 22x22, 26x26, 32x32, and 48x48 PNG files so all of these are fast.

Thanks to everyone and I look forward to seeing Dave’s transform code!

my bad. My Paint program scans an RGBSurface to do grayscale, sepia and color reduction … it uses the RGBSurface.Transform function for altering Brightness, Contrast and Exposure

For @Christian Schmitz - the GrayScaleMBS(3) is giving the best result for these images. But …

When I set it to the RowPicture, the mask or alpha are being ignored.

I’ve tried using both CopyPictureWithMask and CopyPictureWithAlpha when creating the Picture, but the result always has a black background when I set the RowPicture (using GrayScaleMBS(3) doesn’t matter either way):

The code looks like this when using the IconMBS picture (leaf is a folderitem):

Me.RowPicture(Me.LastIndex) = leaf.IconMBS(20).GrayScaleMBS(3)

And like this when using the NSImageMBS:

Dim i As NSImageMBS = NSWorkspaceMBS.iconForFileType("fcpxml") lbBackupFileSystem.RowPicture(lbBackupFileSystem.LastIndex) = i.CopyPictureWithMask.ScaleMBS(20, 20, True).GrayScaleMBS(3)

Any ideas?

the scale function only works on the main picture, not it’s mask.
you may need to assign the original mask to the new picture.

I can understand that when I’m building the picture from the NSImageMBS, but what about the IconMBS call where I’m not scaling the picture returned?

well, you got picture form IconMBS and maybe you should put it in variable.
Than check for nil and call GrayScaleMBS on it.
Than move the mask from the old picture to the new picture.

Hmm, I can get this sorted on the Mac side, but for Linux, LinuxIconMBS.FileIcon(f, 32) is returning a picture without a mask, so trying to get the mask from the icon fails with an UnsupportedFormatException with a message stating that you can’t copy a mask from an image with an alpha channel, but the Picture returned doesn’t have an alpha channel.

Calling the Linux code like this:

iconPic = LinuxIconMBS.FileIcon(leaf, 32)

That is strange.

The screenshot looks like the pictures got some alpha channel here!?

The Alpha is there on mine as well if I accept the 48x48 image. It’s the scaling that’s causing the issue and loss of the alpha.

It’s something in the way the Xojo paints the picture into the RowPicture of a Listbox when you manage the CellBackgroundPaint instead of using defaults.

Dim surf As RGBSurface = picture.RGBSurface
Dim c As Color
Dim w As Integer = picture.Width - 1
Dim h As Integer = picture.Height - 1
Dim cg As Integer // color grey
rem farbe in graustufen wandeln
For y As Integer = 0 To h
For x As Integer = 0 To w
c = surf.Pixel(x, y)
cg=( + c. blue )/3
surf.Pixel(x, y) = RGB(cg,cg,cg)