9
votes

I want to draw quite complex images with alpha-transparent rectangles and alpha-transparent images. There is GDI+ wrapper from Mitov, but it doesn't seem to support 32bit BMP files plus it rescales them and the documentation is terrible. BMPs are way faster than PNGs so I want to use them. There is SynGDI wrapper of GDI+, but it seems very basic and there is no documentation for it. There is also this trick for GDI:

procedure DrawAlphaAPI(Source: TBitmap; Destination: TCanvas;
  const X, Y: Integer; const Opacity: Byte = 255);
var  BlendFunc: TBlendFunction;
begin
  BlendFunc.BlendOp := AC_SRC_OVER;
  BlendFunc.BlendFlags := 0;
  BlendFunc.SourceConstantAlpha := Opacity;

  if Source.PixelFormat = pf32bit then
    BlendFunc.AlphaFormat := AC_SRC_ALPHA
  else
    BlendFunc.AlphaFormat := 0;

  Windows.AlphaBlend(Destination.Handle, X, Y, Source.Width, Source.Height,
  Source.Canvas.Handle, 0, 0, Source.Width, Source.Height, BlendFunc);
end;

But when I call it with Opacity = 255 it draws 32bit bitmaps not properly (something like they are half transparent where they should be fully). I don't want to use Scanline to make pixels transparent as this will be too complicated to draw all the transparent rectangles this way. Also I thin GDI+ should be faster on modern computers, am I right?

So the question is: how to draw an alpha transparent rectangle and bitmap easily (without tons of code)?

Preferred Delphi: 7. I also have 2005 and XE3 but since 7 is a speed demon I would most want something to work from 7 up.

1
If you could use this wrapper which supports Delphi 2009 up, you might write code like this which looks quite complicated, but you need to know that you can modify the color adjustment with that color matrix and that I'm loading a file to be alpha blended in that code (you might e.g. create a GPBitmap from a passed TBitmap object).TLama
@TLama Thanks, this one GDI+ seems best so far. The other are crappy. One from Progdigy doesn't compile on (7, nor 2005 nor XE3), the one from Mitov destroys images after drawing them, the one from Synopse is incomplete.Tom
FWIW: I found these articles quite interesting.Uli Gerhardt
@UliGerhardt Interesting, indeed. Thank you!Tom

1 Answers

12
votes

If you prepare the ordinary TBitmap, any of the GDI+ implementations can be used just assigning bmp.Canvas.Handle. Your problem in compiling might be caused by an old DirctDraw-Version in the Folder, just remove it.

implementation

uses GDIPAPI, GDIPOBJ;
{$R *.dfm}

Procedure PrepareBMP(bmp: TBitmap; Width, Height: Integer);
var
  p: Pointer;
begin
  bmp.PixelFormat := pf32Bit;
  bmp.Width := Width;
  bmp.Height := Height;
  bmp.HandleType := bmDIB;
  bmp.ignorepalette := true;
  bmp.alphaformat := afPremultiplied;
  // clear all Scanlines
  p := bmp.ScanLine[Height - 1];
  ZeroMemory(p, Width * Height * 4);
end;

procedure TForm2.Button1Click(Sender: TObject);
var
  bmp: TBitmap;
  G: TGPGRaphics;
  B: TGPSolidBrush;
begin
  bmp := TBitmap.Create;
  try
    PrepareBMP(bmp, 300, 300);
    G := TGPGRaphics.Create(bmp.Canvas.Handle);
    B := TGPSolidBrush.Create(MakeColor(100, 255, 0, 0));
    try
      G.SetSmoothingMode(SmoothingModeHighQuality);
      G.FillEllipse(B, MakeRect(0.0, 0, 300, 300));
      B.SetColor(MakeColor(100, 0, 255, 128));
      G.FillEllipse(B, MakeRect(40.0, 40, 260, 260));
    finally
      B.Free;
      G.Free;
    end;
    // draw overlapping in Form Canvas to display transparency
    Canvas.Draw(0, 0, bmp);
    Canvas.Draw(100, 100, bmp);
  finally
    bmp.Free;
  end;
end;

DEMO