5
votes

I want to a draw a translucent image on a Delphi form, but for some reason it is not working.

Here is the original PNG (border is semi transparent):
Transparent border

I load the image in a TImage object:

Image1.Transparent := True;
Form1.Color := clWhite;
Form1.TransparentColor := True;
Form1.TransparentColorValue := clWhite;

TImage

The application:
Application


The image isn't translucent. I am working with a BMP image that contains the alpha channel. Am I missing something?

3
I don't understand how you could use a PNG image in a Delphi 7 TImage control. Delphi 7 does not support PNG...Andreas Rejbrand
hmmmmm. It loads as PNGObject.Little Helper
D7 doesn't support png. You have installed 3rd party component. Why are you against 3rd party components?David Heffernan
OK, with thir party components! ooooo. Sorry i am using TNT Unicode controls. TTntImage.Little Helper
@Robrok: Your English is not a problem, but it is a bit confusing when you say that you are using TImage but in fact is using a TntImage!Andreas Rejbrand

3 Answers

11
votes

I found a solution that will let you draw a BMP image with an alpha channel onto a form using only the Windows API:

const
  AC_SRC_OVER = 0;
  AC_SRC_ALPHA = 1;

type
  BLENDFUNCTION = packed record
    BlendOp,
    BlendFlags,
    SourceConstantAlpha,
    AlphaFormat: byte;
  end;

function WinAlphaBlend(hdcDest: HDC; xoriginDest, yoriginDest, wDest, hDest: integer;
  hdcSrc: HDC; xoriginSrc, yoriginSrc, wSrc, hSrc: integer; ftn: BLENDFUNCTION): LongBool;
  stdcall; external 'Msimg32.dll' name 'AlphaBlend';

procedure TForm4.FormClick(Sender: TObject);
var
  hbm: HBITMAP;
  bm: BITMAP;
  bf: BLENDFUNCTION;
  dc: HDC;
begin
  hbm := LoadImage(0,
    'C:\Users\Andreas Rejbrand\Skrivbord\RatingCtrl.bmp',
    IMAGE_BITMAP,
    0,
    0,
    LR_LOADFROMFILE);
  if hbm = 0 then
    RaiseLastOSError;
  try
    if GetObject(hbm, sizeof(bm), @bm) = 0 then RaiseLastOSError;
    dc := CreateCompatibleDC(0);
    if dc = 0 then RaiseLastOSError;
    try
      if SelectObject(dc, hbm) = 0 then RaiseLastOSError;
      bf.BlendOp := AC_SRC_OVER;
      bf.BlendFlags := 0;
      bf.SourceConstantAlpha := 255;
      bf.AlphaFormat := AC_SRC_ALPHA;
      if not WinAlphaBlend(Canvas.Handle,
        10,
        10,
        bm.bmWidth,
        bm.bmHeight,
        dc,
        0,
        0,
        bm.bmWidth,
        bm.bmHeight,
        bf) then RaiseLastOSError;
    finally
      DeleteDC(dc);
    end;
  finally
    DeleteObject(hbm);
  end;
end;

Using The GIMP, I converted the PNG image

found here to a 32-bit RGBA bitmap, found here, and the result is very good:

1
votes

Why not try do draw your png onto new image with regular bmp. Draw what you want onto image 2 and redraw /or assign/ all to your image 1 when finish. Must works...

1
votes

The TransparentColorValue approach cannot possibly work, because this only works with images in which a single colour represents full transparency. [In addition, you are toying with the form's transparent colour instead of image's transparent colour!] The above PNG image is supposed to have an alpha channel, so it's not like every pixel is either shown or transparent -- instead, each pixel has an opacity between 0 and 1 (0.37, for instance). That is, in addition to the R, G, and B components of each pixel, there is an 'alpha' component A.

The above image appears to be corrupt, however. A 'correct' PNG is shown below:


(source: rejbrand.se)

You can try to blend the above one onto different backgrounds, and you will find that the shadow blends nicely.

So, if one has a 'correct' PNG, how to draw it onto a form? Well, that is going to be very difficult in your case, since Delphi 7 does not support PNG images. It only supports BMP images, and these normally do not have alpha channels.