T O P I C R E V I E W |
Fellafoo |
Posted - May 04 2022 : 09:18:48 In our existing graphics pipeline we call our own procedure 'OutputDC' to get a handle to various canvases such as the main drawing form or the memory bitmap that is blitted to this form. Other destinations are the Printer (or a TMetafileCanvas used for print preview) and the Windows clipboard.
Now that I've got TIEBitmap.RenderToCanvasWithAlpha and TIECanvas.Rectangle (over clipping region) working for the drawing form I'm hoping I can leverage similar logic for the printer, etc.
If I have a handle (HDC) to Printer.Handle, should I be able to render/draw to this canvas in a similar way? For example...
ieCnv := TIECanvas.Create(Printer.Handle);
with ieCnv do begin
Pen.Color := BrClr;
Pen.Transparency := BrOp;
Pen.Width := 0;
{ Set unique brush property for ieCanvas }
Brush.Color := BrClr;
Brush.Transparency := BrOp; { 0 - 255 }
Brush.Style := bsSolid;
Rectangle(ClipRect);
Free;
end;
I've experimented with this a bit but I've been unable to get the transparent fills or bitmaps with an alpha channel to appear on the Printer canvas. Any insight would be greatly appreciated.
Thank You,
MFM |
4 L A T E S T R E P L I E S (Newest First) |
Fellafoo |
Posted - May 09 2022 : 05:03:59 I've not been able to find any way to reliably determine whether a canvas supports alphablending. I created the following test program. When I print to 'Microsoft Print to PDF' the blending works as expected. However, if I print to 'CutePDF Writer' Alphablend returns True but the image is rendered with an opaque background. Printing to 'Canon MF4500 Series UFRII LT' fails outright and Alphalend returns false.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool, CommDlg;
type
TForm1 = class(TForm)
BtnPrint: TButton;
procedure BtnPrintClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
iegdiplus, iexbitmaps, hyieutils, hyiedefs;
procedure DrawRectangles(aDC: HDC; PageRect: TRect);
var
R1, R2, R3: TRect;
PrintCnv: TCanvas; { For ImageEN to render to }
ieBmp: TIEBitmap; { ImageEN Bitmap }
ieCnv: TIECanvas; { ImageEN Canvas }
begin
PrintCnv := TCanvas.Create;
PrintCnv.Handle := aDC;
ieCnv := TIECanvas.Create(PrintCnv);
ieCnv.SetCompositingMode(ieCompositingModeSourceOver, ieCompositingQualityDefault);
{ Create bitmap same size as page }
ieBmp := TIEBitmap.Create(PageRect.Right, PageRect.Bottom, ie32RGB);
ieBmp.Fill(clWhite); { Paper Color }
ieBmp.AlphaFill(0); { Clear Alpha Channel }
R1 := PageRect;
{ Shrink Rectangle }
InflateRect(R1, -PageRect.Right div 4, -PageRect.Bottom div 4);
R2 := R1;
R3 := R2;
{ Move Rectangles }
OffSetRect(R1, MulDiv(-R1.Left, 5, 10), MulDiv(-R1.Top, 5, 10));
OffSetRect(R2, MulDiv(R2.Left, 5, 10), MulDiv(R2.Top, 5, 10));
{ Draw Rectangles }
with ieBmp.IECanvas do begin
Pen.Color := clBlack;
Pen.Width := 3;
Brush.Style := bsSolid;
Brush.Transparency := 128;
Brush.Color := RGB(192, 0, 192);
Rectangle(R1);
Brush.Color := RGB(0, 192, 0);
Rectangle(R2);
Brush.Color := RGB(192, 192, 0);
Rectangle(R3);
end;
ieBmp.DrawToCanvas(ieCnv.GDICanvas, PageRect.Left, PageRect.Top);
ieBmp.Free;
ieCnv.Free;
PrintCnv.Free;
end;
procedure AlphaBlendBitmapToCanvas(aDC: HDC; PageRect: TRect);
{ 'Transfer' TIEBitmap Bitmap/Alpha to TBitmap and Alphablend to Canvas }
type
TQuadColor = packed record
case Boolean of
True: (Blue, Green, Red, Alpha: Byte);
False: (Quad: Cardinal);
end;
pQuadColor = ^TQuadColor;
var
aBmpToBlend: TBitmap;
BmpWithAlpha: TIEBitmap; { 32Bit ImageEN Bitmap }
RowY,
ColX: Integer;
Alpha: Byte;
Pixel: PQuadColor;
bf: BLENDFUNCTION;
begin
BmpWithAlpha := TIEBitmap.Create('SomePngWithTransparentPixels.png');
aBmpToBlend := TBitmap.Create;
BmpWithAlpha.CopyToTBitmap(aBmpToBlend);
aBmpToBlend.PixelFormat := pf32Bit;
{ Transfer values from TIEBitmap to TBitmap }
for RowY := 0 to aBmpToBlend.Height - 1 do begin
Pixel := aBmpToBlend.Scanline[RowY];
for ColX := 0 to aBmpToBlend.Width - 1 do begin
Pixel.Alpha := BmpWithAlpha.Alpha[ColX, RowY];
Pixel.Red := BmpWithAlpha.Pixels[ColX, RowY].r;
Pixel.Green := BmpWithAlpha.Pixels[ColX, RowY].g;
Pixel.Blue := BmpWithAlpha.Pixels[ColX, RowY].b;
Inc(Pixel);
end;
end;
{ Blend using Alpha values in aBmpToBlend }
with bf do begin
BlendOp := AC_SRC_OVER;
BlendFlags := 0;
SourceConstantAlpha := 255;
AlphaFormat := AC_SRC_ALPHA;
end;
if not AlphaBlend(
aDC,
(PageRect.Right - aBmpToBlend.Width * 2) div 2,
(PageRect.Bottom - aBmpToBlend.Height * 2) div 2,
aBmpToBlend.Width * 2,
aBmpToBlend.Height * 2,
aBmpToBlend.Canvas.Handle,
0,
0,
aBmpToBlend.Width,
aBmpToBlend.Height,
bf
) then
ShowMessage('Alphablend Failed!');
aBmpToBlend.Free;
BmpWithAlpha.Free;
end;
procedure TForm1.BtnPrintClick(Sender: TObject);
var
pd: TPrintDlg;
ps: TPageSetupDlg;
DocInfo: TDocInfo;
PageRect: TRect;
PrintArea: TRect;
MaxPrintArea: TRect;
aDC: HDC;
begin
FillChar(ps, SizeOf(ps), #0);
ps.lStructSize := SizeOf(ps);
ps.hwndOwner := Form1.Handle;
//ps.Flags :=
(*
if PageSetupDlg(ps) then begin
PageRect := Rect(0, 0, ps.ptPaperSize.X, ps.ptPaperSize.Y);
PrintArea := ps.rtMargin;
MaxPrintArea := ps.rtMinMargin;
end;
*)
FillChar(pd, SizeOf(pd), #0);
pd.lStructSize := SizeOf(pd);
pd.hWndOwner := Form1.Handle;
pd.Flags := {PD_PRINTSETUP} PD_RETURNDC;
if PrintDlg(pd) then begin
FillChar(DocInfo, SizeOf(DocInfo), #0);
DocInfo.cbSize := SizeOf(DocInfo);
GetMem(DocInfo.lpszDocName, 32);
GetMem(DocInfo.lpszOutput, MAX_PATH);
lStrCpy(DocInfo.lpszDocName, 'Alphablend to Canvas');
StartDoc(pd.hDC, DocInfo);
DrawRectangles(pd.hDC, Rect(0, 0, Printer.PageWidth, Printer.PageHeight));
AlphaBlendBitmapToCanvas(pd.hDC, Rect(0, 0, Printer.PageWidth, Printer.PageHeight));
EndDoc(pd.hDC);
FreeMem(DocInfo.lpszDocName, 32);
FreeMem(DocInfo.lpszOutput, MAX_PATH);
end;
end;
end. |
xequte |
Posted - May 08 2022 : 16:10:18 Well, for destinations that do not support alpha, you might want to dispense with it before drawing, e.g. by parsing the AlphaChannel scanline or merging with a color:
https://www.imageen.com/help/TIEBitmap.RemoveAlphaChannel.html
Nigel Xequte Software www.imageen.com
|
Fellafoo |
Posted - May 05 2022 : 06:34:51 I've made some progress with bitmaps rendering to a TMetafileCanvas. Render to canvas works (without transparency of course). The transparent areas will 'match' the paper color if I set the transparent color to white. RenderToCanvas accepts a negative value for the destination height.
ieBmp.RenderToCanvas(ieCnv.GDICanvas, xDst, yDst, dxDst, -dyDst, xSrc, ySrc, dxSrc, dySrc, rfFastLinear, 0, clWhite, True); When I use RenderToCanvasWithAlpha, transparent areas render in black. How do I get them to render in white? The RenderToCanvasWithAlpha procedure does not accept a negative value for the destination height, so I must subtract it from yDst instead.
ieBmp.RenderToCanvasWithAlpha(ieCnv.GDICanvas, xDst, yDst - dyDst, dxDst, {-}dyDst, xSrc, ySrc, dxSrc, dySrc, 0, 0, ieBmp.Width, ieBmp.Height, 255, rfFastLinear, ielNormal, 1); Since the transparent areas are currently rendering in white, I cannot tell if transparency is working. If it's not, is there a way to merge the bitmap with a copy of the canvas before I render it to the destination? Since this occurs during the print preview process, speed is not as critical. |
xequte |
Posted - May 04 2022 : 14:30:26 Hi
When the destination canvas does not support alpha transparency, alpha objects will be downgraded to something that the destination understands.
Nigel Xequte Software www.imageen.com
|
|
|