3

I can get a 32-bit image to be displayed in TImage with GDIPlus that has partial (masked) transparency but the alpha values are either 0 or 255 with no values in between. I have tried loading PngImage, 32-bit bitmaps and icons all produce the same... masked transparency but not full transparency.

Is there another way to get TImage to display a GDI+ graphic with full transparency as shown in the Desired Result image?

enter image description here GDI Plus After Open

enter image description here Desired Result

procedure TFormMain.Open1Click ( Sender: TObject );
// Load a GDIPlus Bitmap into TImage
var
  GPBitmap: TGPBitmap;
  iHBitmap: HBITMAP;
  iStatus: TStatus;
const
  TRANS_COLOR = clBlack;
begin

  if OpenPictureDialog1.Execute then
  begin

    FilePath := OpenPictureDialog1.FileName;
    begin

      GPBitmap := TGpBitmap.Create ( FilePath );
      try

        iStatus := GPBitmap.GetHBITMAP ( aclBlack, iHBitmap );
        // As best as I can determine from the internet, the GetHBitmap which is needed to assign a GPbitmap to TImage
        // does not hold an alphachannel, so loaded images alpha are either 0 or 255, but drawing with alphachannel values does work.
        if iStatus = Ok then
        begin

          Image1.Picture.Bitmap.Handle := iHBitmap;
          Image1.Picture.Bitmap.TransparentColor := Image1.Picture.Bitmap.Canvas.Pixels [ 0, Image1.Picture.Bitmap.Height - 1 ];
          StatusBar1.Panels [ 0 ].Text := FileCtrl.MinimizeName ( ExtractFileDir ( FilePath ), Canvas, 200 ); // Folder
          StatusBar1.Panels [ 1 ].Text := FileCtrl.MinimizeName ( ExtractFileName ( FilePath ), Canvas, 75 ); // Filename
          StatusBar1.Panels [ 2 ].Text := 'Width: ' + IntegerToString ( Image1.Picture.Bitmap.Width ); // Width
          StatusBar1.Panels [ 3 ].Text := 'Height: ' + IntegerToString ( Image1.Picture.Bitmap.Height ); // Height
          StatusBar1.Panels [ 4 ].Text := BitDepthToColorString ( GetPixelFormatSize ( GPBitmap.GetPixelFormat ) ); // Bitdepth

          Image1.Refresh;

        end;

      finally
        GPBitmap.Free;
      end;

    end;

  end;

end;
Bill
  • 2,993
  • 5
  • 37
  • 71
  • Not sure if I am surprised that TImage (which is not rendering to your canvas using GDI+) doesn't work perfectly with TGPBitmap. Instead, check the other questions on here that show how to load a Png with transparency into a TImage. This question is like asking why my commodore 64 doesn't understand IP V6. – Warren P Apr 13 '12 at 15:12
  • @Warren- I searched but did not find anything that shows how to fix this. Do you have any links? Is TImage or HBitmap causing the problem? – Bill Apr 13 '12 at 15:37
  • See this question for one way that `TImage.Picture`'s PNG support can get broken. You might have a bogus component set or alternative PNG component set installed that actually BREAKS Delphi/VCL PNG support. See this link: http://stackoverflow.com/questions/7163594/a-button-control-and-underlying-replacement-for-tbitmap-that-properly-handles-pn – Warren P Apr 13 '12 at 16:39
  • @Warren- Thank-you for the link, but I am not sure you are correct. I can open a bmp, png and ico with WIC and full transparency is maintained. Also I can load bmp, png and ico with SynGdiPlus and full transparency is maintained, but not with GDIPLus. Is it possible that GetHBITMAP does not transfer the bitmap correctly with GDIPlus? – Bill Apr 13 '12 at 16:53
  • Then, clearly, the bug is in GDIPLUS, not in TIMAGE. – Warren P Apr 13 '12 at 18:18
  • I don't know about any of the delphi stuff, but you can easily get raw bitmap data with alpha information out of a GDI+ bitmap, using GdipBitmapLockBits. If TImage is capable of using that data (which it would have to, to get it correctly from WIC), then this is technically possible. – Esme Povirk Apr 14 '12 at 01:36

1 Answers1

2

What you need to do is to choose a background color that will blend with the surface that the image is drawn on when it is transferred. I.e. instead of

iStatus := GPBitmap.GetHBITMAP ( aclBlack, iHBitmap );

use

iStatus := GPBitmap.GetHBITMAP(ColorRefToARGB(ColorToRGB(clBtnFace)), iHBitmap);

if the image is on a default colored form for instance.

At this point you already know that the image has no alpha channel, but it has been flattened using a suitable color. The Transparent.. properties of 'TBitmap' will not help with partial transparency. If you set the Transparent property of the TBitmap, it will still be like the first image of your question when you put it on a different colored background, probably with a nicer edge color. In any case, if you use it, do not forget to set the 'TransparentColor' to 'clBtnFace' instead of 'clBlack'.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • I have tried what you suggest, but still can not get it to work. Please post the code you used to open the image? – Bill Apr 14 '12 at 12:49
  • @Bill - You don't see any difference? I used the code you posted. Say, if you use 'aclRed' in your original code instead of aclBlack isn't the edges of the picture turn red? – Sertac Akyuz Apr 14 '12 at 13:39
  • Ok it is working now for png and ico but not bmp. 32-bit bitmaps do not show any transparency at all. I stll can not get the alpha value under the cursor either. Do you know how to do that? – Bill Apr 14 '12 at 16:04
  • @Bill - I'm pretty sure that after transferring the image 'Image1.Picture.Bitmap' have no transparency at all, that's why you can't read any meaningful value. – Sertac Akyuz Apr 15 '12 at 02:21
  • So you are saying that there is no way to open an image with GDIPlus to TImage and have the alpha values maintained. If there are no alpha values in 'Image1.Picture.Bitmap' how does it appear correctly visually? Does it just apply the color and alpha value to create a color with alpha of 255? – Bill Apr 15 '12 at 12:40
  • @Bill - (1) Yes. I know of no way how to pass alpha information on a picture of TImage, and my thinking is that it is not possible at all. (2) Exactly! – Sertac Akyuz Apr 15 '12 at 13:43