4

How do I take a picture from a TImageList and put it into a TImage (or return it as a TGraphic)?

The important point is that a TImageList can contain 32-bpp alpha blended images. The goal is to get one of these alpha-blended images and place it in a TImage. This means at some point i would likely require a TGraphic. Although, strictly speaking, my question is about placing an image from an ImageList into an Image. If that can be accomplished without an intermedate TGraphic then that is also fine.

What do we want?

We want the guts of a function:

procedure GetImageListImageIntoImage(SourceImageList: TCustomImageList; 
      ImageIndex: Integer; TargetImage: TImage);
begin
   //TODO: Figure this out.
   //Neither SourceImageList.GetIcon nor SourceImageList.GetBitmap preserve the alpha channel
end;

There can also be another useful intermediate helper function:

function ImageListGetGraphic(ImageList: TCustomImageList; ImageIndex: Integer): TGraphic;
var
//  ico: TIcon;
    bmp: TBitmap;
begin
    {Doesn't work; loses alpha channel. 
    Windows Icon format can support 32bpp alpha bitmaps. But it just doesn't work here
    ico := TIcon.Create;
    ImageList.GetIcon(ImageIndex, ico, dsTransparent, itImage);
    Result := ico;
    }

    {Doesn't work; loses alpha channel.
    Windows does support 32bpp alpha bitmaps. But it just doesn't work here
    bmp := TBitmap.Create;
    bmp.PixelFormat := pf32bit;
    Imagelist.GetBitmap(ImageIndex, bmp);
    Result := bmp;
    }
end;

Letting us convert the original procedure to:

procedure GetImageListImageIntoImage(SourceImageList: TCustomImageList; ImageIndex: Integer; TargetImage: TImage);
var
   g: TGraphic;
begin
   g := ImageListGetGraphic(SourceImageList, ImageIndex);
   TargetImage.Picture.Graphic := g; //Assignment of TGraphic does a copy
   g.Free;
end;

I also some random things:

Image1.Picture := TPicture(ImageList1.Components[0]);

but that does not compile.

P.S. I have Delphi 2010

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
Giacomo King Patermo
  • 829
  • 3
  • 13
  • 25
  • "I get a runtime error" means nothing unless you tell us what error, including the exact error message and any memory addresses. – Ken White Jun 10 '12 at 23:51
  • @Ken - I bet it's a compile time error since there's no 'Pictures' property for a TImage, and even if it was 'Picture' that code wouldn't compile (picture <> component). – Sertac Akyuz Jun 10 '12 at 23:59
  • 3
    @Sertac, I agree. It would help, though, if the question contained the info. People seem to forget that we can't see their screens from where we sit. (At least I can't, and psychic debugging should be a last resort. ) – Ken White Jun 11 '12 at 00:14

2 Answers2

2
ImageList1.GetBitmap(0, Image1.Picture.Bitmap);
TLama
  • 75,147
  • 17
  • 214
  • 392
John Easley
  • 1,551
  • 1
  • 13
  • 23
  • @Giacomo - What's the problem, transparency is lost? – Sertac Akyuz Jun 10 '12 at 23:45
  • `TImageList` only supports ICO and BMP formats. Putting a PNG into a `TImageList` converts it to a BMP. If you want to preserve a PNG as a PNG, you have to use another component that supports that, such as a `TPngImageList`. – Remy Lebeau Jun 10 '12 at 23:49
  • Add your PNG to a resource... then load it from the resource... http://stackoverflow.com/questions/1153394/how-do-i-make-a-png-resource – Whiler Jun 11 '12 at 00:18
  • 5
    @GiacomoKingPatermo for 32 bits png images, you can use the `GetIcon` method to extract the image and preserve the transparency , so try `ImageList1.GetIcon(0, Image1.Picture.Icon);` – RRUZ Jun 11 '12 at 00:32
  • 1
    @Giacomo - Nobody knows the problem until you tell it. How does "it doesn't work"? Are you getting an error? – Sertac Akyuz Jun 11 '12 at 17:22
  • Error: List index out of bounds (0) – Giacomo King Patermo Jun 11 '12 at 19:51
  • @Giacomo - It looks like it is raised from somewhere else in your code. You're probably using a list, listbox etc.. and have an error with it. – Sertac Akyuz Jun 11 '12 at 20:48
  • @GiacomoKingPatermo how many images are contained inside ImageList1? – John Easley Jun 12 '12 at 00:37
  • @GiacomoKingPatermo can you add your .png image to your question? – John Easley Jun 12 '12 at 12:57
0

Routine to get a transparent graphic out of an ImageList:

function ImageListGetGraphic(ImageList: TCustomImageList; ImageIndex: Integer): TGraphic;
var
    ico: HICON;
//  png: TPngImage;
//  icon: TIcon;
//  bmp: TBitmap;
    wicbmp: IWICBitmap;
    wi: TWicImage;
begin
{   //Works. Uses our own better Wic library.
    ico := ImageList_GetIcon(ImageList.Handle, ImageIndex, ILD_NORMAL);
    Result := TWicGraphic.FromHICON(ico);
    DestroyIcon(ico);}

    //Works, uses the built-in Delphi TWicImage (careful of VCL bugs)
    ico := ImageList_GetIcon(ImageList.Handle, ImageIndex, ILD_NORMAL);
    wi := TWICImage.Create; //Due to a bug in the VCL, you must construct the TWicImage before trying to access the Wic ImagingFactory
    OleCheck(TWicImage.ImagingFactory.CreateBitmapFromHICON(ico, wicbmp));
    wi.Handle := wicbmp;
    Result := wi;

{   //Doesn't work, loses alpha channel
    icon := TIcon.Create;
    ImageList.GetIcon(ImageIndex, icon, dsTransparent, itImage);
    Result := icon;
    }

{   //Doesn't work, loses alpha channel
    bmp := TBitmap.Create;
    bmp.PixelFormat := pf32bit;
    Imagelist.GetBitmap(ImageIndex, bmp);
    Result := bmp;
    }

{   //Fails: cannot assign a TIcon to a TPngImage
    icon := TIcon.Create;
    ImageList.GetIcon(ImageIndex, icon, ImgList.dsNormal, itImage);
    png := TPngImage.Create;
    png.Assign(icon);
    Result := png;
    icon.Free;
    }

{   //Working failure; doesn't support stretched drawing (e.g. TImage.Stretch = true)
    icon := TIcon.Create;
    ImageList.GetIcon(ImageIndex, icon, ImgList.dsNormal, itImage);
    Result := ico;
    }

end;

Sample usage:

g: TGraphic;

g := ImageListGetGraphic(ImageList1, 7);
Image1.Picture.Graphic := g;
g.Free;

Note: Any code released into public domain. No attribution required.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219