ImageEn for Delphi and C++ Builder ImageEn for Delphi and C++ Builder

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 Printer Canvas / TMetafileCanvas - Transparent Bitmaps & Fills

Note: You must be registered in order to post a reply.
To register, click here. Registration is FREE!

View 
UserName:
Password:
Format  Bold Italicized Underline  Align Left Centered Align Right  Horizontal Rule  Insert Hyperlink   Browse for an image to attach to your post Browse for a zip to attach to your post Insert Code  Insert Quote Insert List
   
Message 

 

Emoji
Smile [:)] Big Smile [:D] Cool [8D] Blush [:I]
Tongue [:P] Evil [):] Wink [;)] Black Eye [B)]
Frown [:(] Shocked [:0] Angry [:(!] Sleepy [|)]
Kisses [:X] Approve [^] Disapprove [V] Question [?]

 
Check here to subscribe to this topic.
   

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