1
votes

I recently came across a situation where I needed to write a counter to an image used for a navbar, where the image was coming from an imagelist component.

After racking my brain for a few hours looking at other articles such as:

How to load a transparent Image from ImageList?

*.bmp loses transparent background if using v6 ImageList Control

http://codeverge.com/embarcadero.delphi.graphics/timage-is-not-transparent-after-a/1080826

http://www.efg2.com/Lab/Library/Delphi/Graphics/ICOtoBMP.pas.txt

I settled on a solution that copied the bitmap from the imagelist, wrote the text to the bitmap canvas, then put the bitmap back into the imagelist.

The only problem with this was that I lost the transparency, and for the life of me couldn't figure out how to get it back.

I could extract and reassign the image OK, including transparency, if I used GetIcon instead of GetBitmap, but then I didn't have a Canvas in order to use TextOut.

If I set the colour so that the image looks correct in components that are linked to the imagelist, like my navbar, when you extract the image using GetBitmap, the transparency is lost and it looks white when applied directly to a TImage.

OK. No problem. Just use white as the transparency colour...

Nope. Even though Canvas.Pixels[0, 31] showed 16777215 as the colour, which is the same value as clWhite, using that for the TransparentColour had no effect.

To see what I mean, create a new VCL Forms Application in Delphi, drop on a couple of TButtons and a TImageList, and link the second button to the image list by setting the buttons Images property in the designer. Double-click the first button and set the event code to be this:

procedure TForm1.Button1Click(Sender: TObject);
var
  Bitmap : TBitMap;
begin
  Bitmap := TBitmap.Create;
  try
    ImageList1.GetBitmap(0, BitMap);
    BitMap.Canvas.Brush.Style := bsClear;
    BitMap.Canvas.Font.Size := 10;
    BitMap.Canvas.Font.Color := clBlack;
    BitMap.Canvas.Font.Style := [fsBold];
    BitMap.Canvas.TextOut(8, 0, '100');
    Bitmap.Transparent := True;
    Bitmap.TransParentColor := Bitmap.Canvas.Pixels[0, 31]; // Bottom left
    ImageList1.ReplaceMasked(0, BitMap, Bitmap.TransParentColor);
  finally
    Bitmap.Free;
  end;
end;

Now add a non-transparent bitmap to the image list (change the size according to how you want it. I use 32x32 pixel bitmaps). By default the component shows the Transparent Colour as being whatever the bottom left pixel is. Leave this as is and OK the imagelist change. Change the ImageIndex of the second button to 0.

You should now see the bitmap you added to the image list shown on the second button, with whatever was the transparent colour being, well, transparent.

Now click the first button. The image on the second button changes to have "100" being shown, but whatever was transparent is now white.

1

1 Answers

1
votes

The solution is to change the Transparent Colour on the TImageList UI when adding the image. I have found it best to pick clNone near the bottom of the colour list. This ensures that no transparency is being applied to the bitmap when it's added to the image list.

This means that the bitmap in the image list shows its "background", and the image on the second button in the designer also shows that colour, but, when the first button is clicked, the image changes to one with the "100" but with transparency now applied.

This is because the colour value returned from Canvas.Pixels[0, 31] is an actual colour value and not some pseudo-internal-made-up-stuff that looks like 16777215 but actually isn't. This allows the ReplaceMasked call to work correctly.