I want to write a small utility which will help me load a single 32bit bitmap (with alpha) from a EXE resource:
ImageList1.DrawingStyle := dsTransparent;
ImageList1.Handle := ImageList_LoadImage(MainInstance, 'MyBitmap32', 16, ImageList1.AllocBy,
CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION or LR_LOADTRANSPARENT);
The above works well.
So to generate that bitmap, I'm loading 32 bit transparent icons from my disk (with alpha) into an ImageList
for i := 1 to 10 do ... ImageList2.AddIcon(AIcon)
Now, how do I export the 32 bitmap (which will be transparent and have the alpha channel) from this image list and save it as a file which should looks like this:
Here is my attempt. But the output bitmap does NOT look transparent and does not maintain the alpha channel:
procedure PrepareBitmap(bmp: TBitmap);
var
pscanLine32: pRGBQuadArray;
i, j: Integer;
begin
for i := 0 to bmp.Height - 1 do
begin
pscanLine32 := bmp.Scanline[i];
for j := 0 to bmp.Width - 1 do
begin
pscanLine32[j].rgbReserved := 0;
end;
end;
end;
procedure TForm1.Button4Click(Sender: TObject);
var
bmp: TBitmap;
I: Integer;
IL: TImageList;
begin
IL := Imagelist10;
bmp := TBitmap.Create;
bmp.PixelFormat := pf32Bit;
bmp.Canvas.brush.Color := clNone;
bmp.Width := IL.Width * IL.Count;
bmp.Height := IL.Height;
//SetBkMode(bmp.Canvas.Handle, TRANSPARENT); //TRANSPARENT
PrepareBitmap(bmp);
for I := 0 to IL.Count - 1 do
begin
IL.Draw(bmp.Canvas, (I * 16), 0, I, True);
end;
bmp.SaveToFile('2.bmp');
end;
Note that even if you I manage to use GetImageBitmap
(I did with 24bit imagelist), the output bitmap is vertical and cannot be load via ImageList_LoadImage
:
Even in the code given by Bummi the output bitmap becomes anti-aliased which is no good. here is an example (with 800% zoom - only first 3 icons):
Good bitmap with alpha channel which will load OK with ImageList_LoadImage
:
Bad bitmap with alpha channel (notice the anti-alias with black):
The Only way I could get perfect results was with GDI+ and reading the icons directly from disk files (NOT the ImageList).
This Only works ok on Vista NOT XP (in older versions of GDI+ GdipCreateBitmapFromHICON
and GdipCreateBitmapFromHBITMAP
functions
destroy alpha channel - they write alpha=255 for each pixel).
procedure TForm1.Button3Click(Sender: TObject);
var
i, num_icons: Integer;
ico: TIcon;
icon: HICON;
encoderClsid: TGUID;
g: TGPGraphics;
in_img: TGPBitmap;
out_img: TGPImage;
begin
num_icons := 24;
out_img := TGPBitmap.Create(16 * num_icons , 16, PixelFormat32bppARGB);
for i := 1 to num_icons do
begin
// does not produce correct bitmap:
//ico := TIcon.Create;
//ImageList1.GetIcon(i - 1, ico);
//in_img := TGPBitmap.Create(ico.Handle);
in_img := TGPBitmap.Create('D:\Delphi\Projects\Icons\Icon_' + inttostr(i) + '.ico');
g := TGPGraphics.Create(out_img);
g.DrawImage(in_img, (i - 1) * 16, 0);
g.Free;
in_img.Free;
end;
GetEncoderClsid('image/bmp', encoderClsid);
out_img.Save('output.bmp', encoderClsid);
out_img.Free;
ImageList2.DrawingStyle := dsTransparent;
// Load from file:
ImageList2.Handle := ImageList_LoadImage(0, 'output.bmp', 16, ImageList2.AllocBy,
CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION or LR_LOADTRANSPARENT
or LR_LOADFROMFILE);
end;
All my attempts to load the Icons from the Imagelist directly, failed and resulted anti-aliased bitmaps.
Here is a link to download the icons I'm working with
And here is another picture to illustrate the output bitmap results:
I think I made it work finally. still needs twining but it works for me. the key is to copy the icons bitmaps to the destination scanlines, instead of drawing the icons to the destination canvas.
procedure CopyBitmapChannels(Src, Dst: TBitMap; DstOffset: Integer);
var
pscanLine32Src, pscanLine32Dst: pRGBQuadArray;
nScanLineCount, nPixelCount: Integer;
begin
with Src do
begin
for nScanLineCount := 0 to Height - 1 do
begin
pscanLine32Src := Scanline[nScanLineCount];
pscanLine32Dst := Dst.Scanline[nScanLineCount];
for nPixelCount := 0 to Width - 1 do
with pscanLine32Src[nPixelCount] do
begin
pscanLine32Dst[nPixelCount + DstOffset].rgbReserved := rgbReserved;
pscanLine32Dst[nPixelCount + DstOffset].rgbRed := rgbRed;
pscanLine32Dst[nPixelCount + DstOffset].rgbGreen := rgbGreen;
pscanLine32Dst[nPixelCount + DstOffset].rgbBlue := rgbBlue;
end;
end;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
h_Bitmap, h_Mask: HBITMAP;
bm_out, bm_ico: TBitmap;
hico : HICON;
icoInfo: TIconInfo;
i, icon_size, num_icons: Integer;
in_IL: TImageList;
begin
// in_IL := ImageList1; // imagelist ready with 32 bit icons
in_IL := nil; // from files
icon_size := 16;
num_icons := 24;
bm_out := TBitmap.Create;
bm_out.Width := icon_size * num_icons;
bm_out.Height := icon_size;
SetBitmapAlpha(bm_out, 0, 0, 0, 0); // no need to actually modify ScanLines but anyway
for i := 0 to num_icons - 1 do
begin
if in_IL = nil then
hico := LoadImage(0, PChar('D:\Delphi\Projects\Icons\Icon_' + inttostr(i + 1) + '.ico'), IMAGE_ICON, 0, 0,
LR_LOADFROMFILE or LR_LOADTRANSPARENT or LR_CREATEDIBSECTION)
else
hico := ImageList_GetIcon(in_IL.Handle, i, ILD_TRANSPARENT); // RGB is slightly changed - not 100% perfect but close enough!
// get icon info (hbmColor -> bitmap)
GetIconInfo(hico, icoInfo);
bm_ico := TBitmap.Create;
h_Bitmap := CopyImage(icoInfo.hbmColor, IMAGE_BITMAP, 0, 0, {LR_COPYDELETEORG or} LR_COPYRETURNORG or LR_CREATEDIBSECTION);
bm_ico.Handle := h_Bitmap;
CopyBitmapChannels(bm_ico, bm_out, i * icon_size);
DestroyIcon(hico);
DeleteObject(h_Bitmap);
bm_ico.Free;
end;
bm_out.SaveToFile('output.bmp');
bm_out.Free;
// output.bmp is now ready to load with ImageList_LoadImage
end;
BTW, I could copy GetImageBitmap
handle like this: ImageList_GetImageInfo(ImageList1.Handle, 0, Info); h_Bitmap := CopyImage(Info.hbmImage, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG)
but in any case it is not usable later with ImageList_LoadImage
.
TImageList.GetImageBitmap
can help here. – HehreTBitmap.Handle
, then both the bitmap and the image list think that they own the same bitmap. – FrambesiaBitBlt
. Old school GDI programming. – FrambesiaImageList_Write/ImageList_Read
which is how Delphi streams the imagelist in DFM. and that is an also maybe! :) – Pleading