1

Similar to this question I would like to both blend colors, and bitmaps (png or bmp, but in my case I'm using a png) while preserving transparency.

As with the linked question, I would like to (a) not use third party libraries, (b) use VCL built in techniques where possible but with recourse to the Win32 GDI APIs where needed, and (c) not use GDI+.

This simple code, based on the code in the linked question I see that the color blending works but the PNG file's transparency is not preserved, when I do this:

Things I tried: - Different pixel formats (pf32bit,pf24bit) - Different values for TBitmap.Transparent.

I tried this in Delphi XE5 and XE6, in this case, but I suspect that the same thing will work for XE2 and up.

Demo code:

unit BlendUnit2;


{ Investigating VCL alpha blending GDI capability }

interface

uses
   Winapi.Windows,
   Winapi.Messages,
   System.SysUtils,
   System.Variants,
   System.Classes,
   Vcl.Graphics,
   Vcl.Controls,
   Vcl.Forms,
   Vcl.Dialogs,
   Vcl.ExtCtrls,
   Vcl.Imaging.pngimage,
   Vcl.StdCtrls;

type
  TForm2 = class(TForm)
    BackgroundImage: TImage;
    TransparentImageInDFM: TImage;
    GeneratedImage: TImage;
    Label1: TLabel;
    Shape1: TShape;
    Shape2: TShape;
    Label2: TLabel;
    Label3: TLabel;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  public
    { Public declarations }
    procedure Blend(ACanvas:TCanvas);
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure ColorBlend(const ACanvas: TCanvas; const ARect: TRect;
  const ABlendColor: TColor; const ABlendValue: Integer);
var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
//  bmp.PixelFormat := pf32bit;
//  bmp.AlphaFormat := afPremultiplied;
//  bmp.Transparent  := True;
  try
    bmp.Canvas.Brush.Color := ABlendColor;
    bmp.Width := ARect.Right - ARect.Left;
    bmp.Height := ARect.Bottom - ARect.Top;
    bmp.Canvas.FillRect(Rect(0,0,bmp.Width, bmp.Height));
    ACanvas.Draw(ARect.Left, ARect.Top, bmp, ABlendValue);
  finally
    bmp.Free;
  end;
end;


procedure TForm2.Blend(ACanvas:TCanvas);
var
  Image: TPNGImage;
begin
  Image := TPNGImage.Create;
  try
    Image.LoadFromFile('..\..\AppIcon2013.png');
    ColorBlend(Image.Canvas, Image.Canvas.ClipRect, $00CCFF80, 85);
    ACanvas.Draw(0, 0, Image);
  finally
    Image.Free;
  end;
end;


procedure TForm2.FormDestroy(Sender: TObject);
begin
//
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
//   GeneratedImage.Picture.Bitmap.Transparent := false;
//   GeneratedImage.Picture.Bitmap.PixelFormat := pf32bit;
   GeneratedImage.Picture.Bitmap.SetSize(280,280);

   Blend( GeneratedImage.Picture.Bitmap.Canvas );
end;

end.

Screenshot showing the unblended but correctly transparent image on the right, and a blended, but no longer transparent image on the left:

enter image description here

Note: I think that pre-blending the background and the foreground with a Win32 API call to AlphaBlend MAY be the only way to go, in which case the VCL does NOT contain any built in transparency support worth mentioning. (Someone on StackOverflow told me that he thought that third party libraries to this purpose were not worthwhile since this is built into the VCL, and I wondered if he's right, so I'm trying to do this with the VCL only.)

Community
  • 1
  • 1
Warren P
  • 65,725
  • 40
  • 181
  • 316
  • How about you blend it manually? You would have to convert your png image to 32bit bitmap. From this site you can learn how to get bitmap bits: http://ksymeon.blogspot.com/2010/02/getdibits-vs-scanline-vs-pixels-in.html . Then, given that you have bitmap bits of your rectangle (the one you want to blend) use this formula (it's in C++): `(BYTE)(((Source*Alpha) + (Destination*(255 - Alpha))) / 255);` where Source is TImage bit; Destination is Background TImage bit; Alpha is TImage alpha bit. – FrogTheFrog May 17 '14 at 08:48
  • I should at **least** be able to call the Win32 AlphaBlend function, and not do it pixel by pixel. However David H. suggested that the VCL contains enough transparency features on its own to do this. So I'm wondering if he or anyone else knows how to actually do it with just VCL, or if a Win32API call to AlphaBlend (after converting PNG to 32 bit bitmap) is required. – Warren P May 20 '14 at 12:42
  • 2
    Pure VCL can't do it, and Win32 AlphaBlend requires pre-multiplied alpha. Best option is probably to use http://graphics32.org/wiki/ – Eric Grange May 21 '14 at 13:12
  • Okay. Sounds like a good approach. I think your comment is really an answer, feel free to convert it. Implementing your own pre-multiplied alpha is a large enough task to make using Graphics32 more or less Essential. – Warren P May 21 '14 at 15:25
  • I found it's pretty easy indeed to use `graphics32` – Warren P May 28 '14 at 12:50

0 Answers0