Printing¶
A drawing is printed through a print job: you start a page, render onto it like onto any other surface, and end the page. This page shows how to fit a drawing to the page, how to print several drawings, and how to print a drawing at its real size, so that 100 mm on screen is 100 mm on paper.
Print jobs are available on the Direct2D and GDI+ render contexts, which includes the VCL default. On the Skia render context a print job writes a PDF file instead of printing; see PDF through Skia.
A print job¶
TSVGRenderContextManager.CreatePrintJob starts a job on the printer that is
currently selected, for example with a TPrintDialog. Each call to
BeginPage starts a page and returns a render context for it; EndPage
finishes the page. The job is sent to the printer when the last reference to
it is released.
The page and its render context work in 1/96 inch, the unit of SVG pixels,
whatever the printer's resolution, on both Direct2D and GDI+. A drawing laid
out at 96 to the inch therefore prints at its real size, and a position of 96
on the page is one inch from its origin. Printer.PageWidth and
Printer.PageHeight are in printer dots, so convert them first:
function PageWidth96: TSVGFloat;
begin
Result := Printer.PageWidth * 96 / GetDeviceCaps(Printer.Handle, LOGPIXELSX);
end;
function PageHeight96: TSVGFloat;
begin
Result := Printer.PageHeight * 96 / GetDeviceCaps(Printer.Handle, LOGPIXELSY);
end;
Changed in update 25
Until update 24, a page on the GDI+ render context worked in printer dots, while Direct2D already worked in 1/96 inch. Code written for GDI+ that passes printer dots now prints too large; pass 1/96 inch instead.
What works today
The other print jobs have units of their own, taken from the PrintPreview example and not measured: on macOS (Quartz) a page works in points, 1/72 inch, and with the FMX canvas render context in printer dots.
Fitting drawings to the page¶
This prints a list of drawings, each on its own page and scaled to fill the printable area:
uses
Winapi.Windows,
Vcl.Printers,
BVE.SVG2Types,
BVE.SVG2Intf,
BVE.SVG2SaxParser,
BVE.SVG2Elements.VCL;
function LoadDrawing(const aFileName: string): ISVGRoot;
var
Parser: TSVGSaxParser;
begin
Result := TSVGRootVcl.Create;
Parser := TSVGSaxParser.Create(nil);
try
Parser.Parse(aFileName, Result);
finally
Parser.Free;
end;
end;
procedure PrintFitted(const aFileNames: TStrings);
var
i: Integer;
PrintJob: ISVGPrintJob;
Context: ISVGRenderContext;
begin
PrintJob := TSVGRenderContextManager.CreatePrintJob('Drawings');
for i := 0 to aFileNames.Count - 1 do
begin
Context := PrintJob.BeginPage(PageWidth96, PageHeight96);
try
Context.BeginScene;
try
SVGRenderToRenderContext(LoadDrawing(aFileNames[i]), Context,
PageWidth96, PageHeight96, [sroFilters, sroClippath], True);
finally
Context.EndScene;
end;
finally
PrintJob.EndPage;
end;
end;
end;
The last parameter, True, scales the drawing into the area given by the
width and height before it, keeping its aspect ratio and centring it.
Printing at real size¶
Drawings made to scale, such as floor plans, die-lines and labels, have to
come out at their real size. SVGRenderAtRealSize renders a drawing at its
own size, with its top left corner at a position on the page, in 1/96 inch:
procedure PrintRealSize(const aFileName: string);
const
Mm = 96 / 25.4; // 1/96 inch per millimetre
var
PrintJob: ISVGPrintJob;
Context: ISVGRenderContext;
begin
PrintJob := TSVGRenderContextManager.CreatePrintJob(ExtractFileName(aFileName));
Context := PrintJob.BeginPage(PageWidth96, PageHeight96);
try
Context.BeginScene;
try
// 20 mm from the top and the left of the page
SVGRenderAtRealSize(LoadDrawing(aFileName), Context, 20 * Mm, 20 * Mm);
finally
Context.EndScene;
end;
finally
PrintJob.EndPage;
end;
end;
A drawing with width="100mm" prints 100 mm wide, on Direct2D and on GDI+.
The same size is used for
bitmaps at a print resolution, where a
50 mm shape renders to 590 pixels at 300 dpi.
Two things to keep in mind:
- The drawing needs a real size. Its
widthandheightmust be in absolute units such asmm,cmorin. A drawing without them, or with percentages, has no real size;SVGRenderAtRealSizethen lays it out in 300 by 150, or in the area you pass to its overload. - The page may start at the printable area, not the paper edge. Most
printers cannot print in a margin of a few millimetres. On GDI+, position
(0, 0)is the top-left corner of the area the printer can print on, and to place a drawing at an exact distance from the paper edge you subtractGetDeviceCaps(Printer.Handle, PHYSICALOFFSETX)andPHYSICALOFFSETY, converted to 1/96 inch. Whether Direct2D does the same has not been checked on such a printer yet.
Drawings larger than the page¶
A drawing at real size that does not fit on the page is cut off at the page
edge. To print it as large as possible while keeping its proportions, use the
smaller of the two scale factors, which is what fitting to the page does. To
print it across several pages, render it once per page with the page's part
of the drawing moved into view; the page render context accepts a
transformation matrix through MultiplyMatrix for this.
PDF files¶
Printing to a PDF printer driver, such as Microsoft Print to PDF, produces a PDF file. See PDF for what that gives you.