5

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?

Little Helper
  • 2,419
  • 9
  • 37
  • 67

3 Answers3

11

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:

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • Yes, it works. But if i want to draw a border around the form? – Little Helper May 11 '11 at 16:27
  • I want to create skinable form. – Little Helper May 11 '11 at 16:30
  • 4
    Nice! BTW, your code works with the regular gdi function declaration, i.e. `windows.AlphaBlend()`, no need to declare the constants, the record and the function.. – Sertac Akyuz May 12 '11 at 00:18
  • 1
    @Sertac: I am very well aware of that, but I am not sure if `AlphaBlend` is declared in the `Windows.pas` that ships with the old Delphi 7, the Delphi version of the OP. In addition, the declaration of `AlphaBlend` in `Windows.pas` in Delphi 2009 (my Delphi version) is very 'ugly': `function AlphaBlend(DC: HDC; p2, p3, p4, p5: Integer; DC6: HDC; p7, p8, p9, p10: Integer; p11: TBlendFunction): BOOL; stdcall;` But I guess I should have written a footnote about this. – Andreas Rejbrand May 12 '11 at 16:43
  • And why in the world is every post I make at SO downvoted?!?! – Andreas Rejbrand May 12 '11 at 16:45
1

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...

ivo
  • 19
  • 1
1

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.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384