The following code provides a routine for splitting out a source image with an Alpha channel into two images, the first holding the RGB information and the second as a Grayscale mask image.
The routine uses the GDI+ bitmap’s Lockbits method to provide fast access to the image data.
This routine is available in the GDIPExtensions unit which is part of GDI+ Controls.
function SplitAlpha(Source: TGPBitmap; var Bitmap: TGPBitmap; var Mask: TGPBitmap): boolean; procedure SetGrayScale(palette: PColorPalette); var i: integer; begin for i := 0 to Palette.Count - 1 do begin palette.Entries[i] := MakeColor(i, i, i); end; end; var SourcePixelFormat: PixelFormat; w, h: cardinal; x, y: cardinal; sbmd: TBitmapData; bbmd: TBitmapData; mbmd: TBitmapData; r: TGPRect; sImageStart: PByteArray; spixelpos : integer; sPixel: pARGB; bImageStart: PByteArray; bpixelpos: integer; bPixel: PRGBTriple; mImageStart: PByteArray; mpixelpos: integer; mPixel: pByte; Palette: pColorPalette; PaletteSize: cardinal; begin Bitmap := nil; Mask := nil; if not assigned(Source) then raise EImageProcessError.create('No sourceimage assigned'); if (source.GetWidth = 0) or (source.GetHeight = 0) then raise EImageProcessError.create('Height and width of source image must be greater than zero'); SourcePixelFormat := source.GetPixelFormat; if not IsAlphaPixelFormat(SourcePixelFormat) then raise EImageProcessError.create('Source image does not have alpha channel'); w := Source.GetWidth; h := source.GetHeight; Bitmap := TGPBitmap.Create(w, h, PixelFormat32bppRGB); Mask := TGPBitmap.Create(w, h, PixelFormat8bppIndexed); PaletteSize := mask.GetPaletteSize; Palette := AllocMem(PaletteSize); mask.GetPalette(Palette, PaletteSize); SetGrayScale(Palette); mask.SetPalette(Palette); FreeMem(Palette, PaletteSize); r := MakeRect(0, 0, integer(w), integer(h)); source.LockBits(r, ImageLockModeRead, PixelFormat32bppARGB, sbmd); bitmap.LockBits(r, ImageLockModeWrite, PixelFormat32bppRGB, bbmd); mask.LockBits(r, ImageLockModeWrite, PixelFormat8bppIndexed, mbmd); sImageStart := sbmd.Scan0; bImageStart := bbmd.Scan0; mImageStart := mbmd.Scan0; for y := 0 to sbmd.Height - 1 do begin for x := 0 to sbmd.Width - 1 do begin spixelpos := (y * cardinal(sbmd.Stride)) + (x * 4); sPixel := @sImageStart[sPixelPos]; bpixelpos := (y * cardinal(bbmd.Stride)) + (x * 4); bPixel := @bImageStart[bPixelPos]; mpixelpos := (y * cardinal(mbmd.Stride)) + (x); mPixel := @mImageStart[mPixelPos]; bPixel.rgbtRed := (spixel^ and $FF0000) shr 16; bPixel.rgbtGreen := (spixel^ and $00FF00) shr 8; bPixel.rgbtBlue := (spixel^ and $0000FF); mpixel^ := (spixel^ and ALPHA_MASK) shr ALPHA_SHIFT; end; end; source.UnlockBits(sbmd); bitmap.UnlockBits(bbmd); mask.UnlockBits(mbmd); result := true; end;