I have an application that prepares a drawing to an Enhanced Metafile. To produce output, this metafile is copied to a canvas; either a Paintbox (in custom preview window on screen) or a printer canvas.
All works as expected when displaying in the custom preview or printing to a physical (!) printer (any paper format). However, when printing to PDF (I have tried NitroPDF, Adobe Acrobat and Microsoft Print to PDF) whatever was drawn within a clipping region shows up as blank as shown in the screen clips below (left is the expected output, right is the PDF output).
Note that the clipping is applied by column (all headers and columns shown are derived from a TBaseColumn). The columns header and border are drawn after the clipping region is released:
procedure TBaseColumn.Draw(ACanvas: TMetafileCanvas);
var
P: array [0 .. 1] of TPoint;
LClipRegion: HRGN;
begin
// Set temp reference to MetafileCanvas
FCanvas := ACanvas;
// Set clipping area
P[0] := FDrawingRect.TopLeft;
P[1] := FDrawingRect.BottomRight;
LPtoDP(FCanvas.Handle, P, 2);
LClipRegion := CreateRectRgn(P[0].X, P[0].Y, P[1].X, P[1].Y);
SelectClipRgn(FCanvas.Handle, LClipRegion);
try
DrawContent; // Protected method so we can override in derived columns
finally
// Reset clipping
SelectClipRgn(FCanvas.Handle, HRGN(nil));
DeleteObject(LClipRegion);
end;
DrawHeader;
DrawColumnBorder;
FCanvas := nil;
end;
Note that I have added the LPtoDP conversion based on this StackOverflow question but unfortunately it seems to make no difference.
There is one other "strange behavior" I have noticed. In the print method of my custom preview, I have several options to draw the metafile to the printer canvas (pmPlayMetaFile is default).
procedure TMyPrintPreview.Print(const APrintTitle: string; const APrintMethod: TSD_PrintMethod);
var
LMetaFileRect: TRect;
LBmp: Vcl.Graphics.TBitmap;
begin
if not assigned(FMetaFile) then
exit;
if APrintTitle = '' then
Printer.Title := 'Document_' + FormatDateTime('yymmdd_hhnn', Now)
else
Printer.Title := APrintTitle;
Printer.BeginDoc;
try
LMetaFileRect := FPreviewInfo.GetPrinterMetaFileRect(FMetaFileScaling);
case APrintMethod of
pmPlayMetaFile:
begin
PlayEnhMetaFile(Printer.Canvas.Handle, FMetaFile.Handle, LMetaFileRect);
end;
pmDirect:
begin
Printer.Canvas.StretchDraw(LMetaFileRect, FMetaFile);
end;
pmBitmap:
begin
LBmp := Vcl.Graphics.TBitmap.Create;
try
LBmp.Width := LMetaFileRect.Width;
LBmp.Height := LMetaFileRect.Height;
LBmp.Canvas.StretchDraw(Rect(0, 0, LBmp.Width, LBmp.Height), FMetaFile);
Printer.Canvas.StretchDraw(LMetaFileRect, LBmp);
finally
LBmp.Free;
end;
end;
end;
Printer.EndDoc;
except
on E: Exception do
begin
Printer.Abort;
raise;
end;
end;
end;
There is no notable difference using any of these methods. However (and this completely puzzles me), if use a modal dialog to allow the user to select the print method (see below) then the output to PDF is as expected.
procedure TfrmMain.btnPrintClick(Sender: TObject);
var
dlgMethod: TdlgPrintMethod;
LMethod: TSD_PrintMethod;
begin
if ParamStr(1) = '/p' then
begin
// DEBUG PRINTING. Show modal dialog to select "print method"....
dlgMethod := TdlgPrintMethod.Create(self);
try
if dlgMethod.ShowModal = mrOK then
begin
LMethod := TSD_PrintMethod(dlgMethod.PrintMethod);
MyPrintPreview.Print(FFileName, LMethod);
end;
finally
dlgMethod.Free;
end;
end
else
// NORMAL PRINTING. No dialog, use default method (pmPlayMetaFile)
MyPrintPreview.Print(FFileName);
end;
I am totally puzzled as to why this only happens when printing to PDF and all other output (screen and printer) works just fine. It must be related to some "setting" but I cannot seem to find it. I have invested a lot of time in this application and printing to PDF is a must (users must be able to share drawings with user that do not have the application). Rebuilding from scratch (i.e. not using metafile) is there what I am trying to avoid. So any suggestion or direction as to what I may try to fix this is very welcome. Thanks!
