How to draw PNG transparently on TMetaFileCanvas

I need to draw PNG transparently on MetaFileCanvas. This works fine when I draw a bitmap (which I use when displaying on the screen), but I need a MetaFile for printing. How can I achieve this?

Here is some code that demonstrates the problem. Put the attached PNG somewhere and update the paths in the code.

procedure TForm1.Test; var vPNG : TPNGImage; vBMP : TBitmap; vMeta : TMetafile; vMetaCanvas : TMetafileCanvas; LDC : HDC; begin vPNG := TPNGImage.Create; try vPNG.LoadFromFile('c:\temp\pic\pic.png'); //1. Draw to bitmap. Draw stuff behind PNG to demonstrate transparency vBMP := TBitmap.Create; try vBMP.SetSize(vPNG.Width + 20,vPNG.Height + 20); vBMP.Canvas.Pen.Color := clLime; vBMP.Canvas.Pen.Width := 5; vBMP.Canvas.MoveTo(0,0); vBMP.Canvas.LineTo(vBMP.Width,vBMP.Height); vBMP.Canvas.MoveTo(vBMP.Width,0); vBMP.Canvas.LineTo(0,vBMP.Height); vBMP.Canvas.Draw(10,10,vPNG); //This is drawn correctly and transparently Canvas.Draw(10,10,vBMP); //Draw to demo form finally vBMP.Free; end; //2. Draw to metafile vMeta := TMetaFile.Create; try LDC := GetDC(0); vMetaCanvas := TMetafileCanvas.Create(vMeta,LDC); try vMetaCanvas.Pen.Color := clLime; vMetaCanvas.Pen.Width := 5; vMetaCanvas.MoveTo(0,0); vMetaCanvas.LineTo(vPNG.Width+20,vPNG.Height+20); vMetaCanvas.MoveTo(vPNG.Width+20,0); vMetaCanvas.LineTo(0,vPNG.Height+20); vMetaCanvas.Draw(10,10,vPNG); //Not correct. Can't see the green line finally vMetaCanvas.Free; end; //Demonstrate that resizing works fine: Canvas.Draw(10,130,vMeta); vMeta.MMWidth := vMeta.MMWidth * 2; Canvas.Draw(150,130,vMeta); vMeta.MMHeight := vMeta.MMHeight * 2; Canvas.Draw(400,130,vMeta); finally vMeta.Free; ReleaseDC(0,LDC); end; finally vPNG.Free; end; end; 

Sample picture with transparent areas

+7
source share
2 answers

Probably the only way to do this is to use the AlphaBlend () function. When you convert PNG to 32-bit RGBA file. What you need to do:

  • Download PNG to 32-bit BMP

  • Pre-multiply RGB values ​​with the value A in the bitmap (this is a prerequisite for calling AlphaBlend)

      for y := 0 to FHeight - 1 do begin Src := BM.ScanLine[ y ]; Dest := FBitmap.ScanLine[ y ]; for x := 0 to FWidth - 1 do begin A := Src^; Inc( Src ); Dest^ := MulDiv( Dest^, A, 255 ); Inc( Dest ); Dest^ := MulDiv( Dest^, A, 255 ); Inc( Dest ); Dest^ := MulDiv( Dest^, A, 255 ); Inc( Dest ); Dest^ := A; Inc( Dest ); end; end; 
  • Call Alphablend with the original HDC as Canvas.Handle of a pre-multiplied bitmap and destination descriptor as a metafile canvas handler.

     BF.BlendOp := AC_SRC_OVER; BF.BlendFlags := 0; BF.SourceConstantAlpha := 255; BF.AlphaFormat := AC_SRC_ALPHA; AlphaBlend( Bitmap.Canvas.Handle, X, Y, BM.Width, BM.Height, BM.Canvas.Handle, 0, 0, BM.Width, BM.Height, BF ); 
0
source

I think you can just use the TransparentBlt function

0
source

All Articles