1 {
2  /***************************************************************************
3                                 Printers.pas
4                                 ------------
5                             Basic Printer object
6 
7  ****************************************************************************/
8 
9  *****************************************************************************
10   This file is part of the Lazarus Component Library (LCL)
11 
12   See the file COPYING.modifiedLGPL.txt, included in this distribution,
13   for details about the license.
14  *****************************************************************************
15 
16   Author: Olivier Guilbaud
17 }
18 unit Printers;
19 
20 {$mode objfpc}{$H+}
21 
22 interface
23 
24 uses
25   Classes, SysUtils,
26   // LazUtils
27   LazLoggerBase, LazUTF8,
28   // LCL
29   LCLProc, Graphics;
30 
31 type
32   TPrinter = Class;
33   EPrinter = class(Exception);
34 
35   TPrinterOrientation = (poPortrait,poLandscape,poReverseLandscape,poReversePortrait);
36   TPrinterCapability  = (pcCopies, pcOrientation, pcCollation);
37   TPrinterCapabilities= Set of TPrinterCapability;
38   TPrinterState       = (psNoDefine,psReady,psPrinting,psStopped);
39   TPrinterType        = (ptLocal,ptNetWork);
40 
41   {
42    This object it's a base class for TCanvas for TPrinter Object.
43    Few properties it's replicate for can create an TPrinterCavas not
44    associated with TPrinter or override few values.
45 
46    BeginDoc,NewPage and EndDoc it's called in Printer.BeginDoc ...
47 
48    PaperWidth:  physical width of paper
49    PaperHeight: Physical height of paper
50    PageWidth:   Printable width on page
51    PageHeight:  Printable height of paper
52   }
53 
54   { TPrinterCanvas }
55 
56   TPrinterCanvas = class(TCanvas)
57   private
58     fPrinter      : TPrinter;
59     fTitle        : String;
60     fPageNum      : Integer;
61     fTopMargin    : Integer;
62     fLeftMargin   : Integer;
63     fBottomMargin : Integer;
64     fRightMargin  : Integer;
65     fPaperWidth   : Integer;
66     fPaperHeight  : Integer;
67     fOrientation  : TPrinterOrientation;
68     fXDPI,fYDPI    : Integer;
69 
GetOrientationnull70     function GetOrientation: TPrinterOrientation;
GetPageHeightnull71     function GetPageHeight: Integer;
GetPageWidthnull72     function GetPageWidth: Integer;
GetPaperHeightnull73     function GetPaperHeight: Integer;
GetPaperWidthnull74     function GetPaperWidth: Integer;
GetTitlenull75     function GetTitle: string;
GetXDPInull76     function GetXDPI: Integer;
GetYDPInull77     function GetYDPI: Integer;
78     procedure SetOrientation(const AValue: TPrinterOrientation);
79     procedure SetPaperHeight(const AValue: Integer);
80     procedure SetPaperWidth(const AValue: Integer);
81     procedure SetTitle(const AValue: string);
HasDefaultMarginsnull82     function HasDefaultMargins: boolean;
83     procedure SetXDPI(const AValue: Integer);
84     procedure SetYDPI(const AValue: Integer);
85   protected
GetLeftMarginnull86     function GetLeftMargin: Integer;
GetTopMarginnull87     function GetTopMargin: Integer;
GetBottomMarginnull88     function GetBottomMargin: Integer;
GetRightMarginnull89     function GetRightMargin: Integer;
90   public
91     constructor Create(APrinter: TPrinter); virtual;
92     procedure BeginDoc; virtual;
93     procedure NewPage;  virtual;
94     procedure BeginPage; virtual;
95     procedure EndPage; virtual;
96     procedure EndDoc; virtual;
97     procedure Changing; override;
98 
99     property Printer : TPrinter read fPrinter;
100 
101     property Title : string read GetTitle write SetTitle;
102     property PageHeight : Integer read GetPageHeight;
103     property PageWidth  : Integer read GetPageWidth;
104     property PaperWidth : Integer read GetPaperWidth write SetPaperWidth;
105     property PaperHeight: Integer read GetPaperHeight write SetPaperHeight;
106     property PageNumber : Integer read fPageNum;
107     property TopMargin : Integer read GetTopMargin write FTopMargin;
108     property LeftMargin: Integer read GetLeftMargin write FLeftMargin;
109     property BottomMargin: Integer read GetBottomMargin write FBottomMargin;
110     property RightMargin: Integer read GetRightMargin write FRightMargin;
111     property Orientation: TPrinterOrientation read GetOrientation Write SetOrientation;
112     property XDPI: Integer read GetXDPI write SetXDPI;
113     property YDPI: Integer read GetYDPI write SetYDPI;
114 
115   end;
116 
117   TPrinterCanvasRef = Class of TPrinterCanvas;
118 
119   { TFilePrinterCanvas }
120 
121   TFilePrinterCanvas = class(TPrinterCanvas)
122   protected
123     FOutputFileName: string;
124   public
125     property OutputFileName : string read FOutputFileName write FOutputFileName;
126   end;
127 
128   TFilePrinterCanvasClass = class of TFilePrinterCanvas;
129 
130   TPaperRect = Record
131     PhysicalRect : TRect;
132     WorkRect     : TRect;
133   end;
134 
135   TPaperItem = record
136     PaperName: string[40];
137     PaperRect: TPaperRect;
138   end;
139 
140   TCustomPaperItem = record
141     PaperSet: boolean;
142     Item: TPaperItem;
143   end;
144 
145   { TPaperSize }
146 
147   TPaperSize = Class(TObject)
148   private
149     //The width and length are in points;
150     //there are 72 points per inch.
151 
152     fOwnedPrinter      : TPrinter;
153     fSupportedPapers   : TStringList;  //List of Paper supported by the current printer
154     fLastPrinterIndex  : Integer;      //Last index of printer used
155 
GetDefaultPaperNamenull156     function GetDefaultPaperName: string;
GetPhysPaperHeightnull157     function GetPhysPaperHeight: Integer;
GetPaperNamenull158     function GetPaperName: string;
GetPaperRectnull159     function GetPaperRect: TPaperRect;
GetPhysPaperWidthnull160     function GetPhysPaperWidth: Integer;
GetSupportedPapersnull161     function GetSupportedPapers: TStrings;
162     procedure SetPaperName(const AName: string);
PaperRectOfNamenull163     function PaperRectOfName(const AName: string) : TPaperRect;
164     procedure CheckSupportedPapers;
165   private
166     fInternalPapers    : array of TPaperItem;
167     fDefaultPapers     : boolean;
168     fDefaultPaperIndex : Integer;
169     fCustomPaper       : TCustomPaperItem;
170     procedure CreateInternalPapers;
171     procedure FillDefaultPapers;
GetDefaultPaperRectnull172     function GetDefaultPaperRect(const AName: string; var APaperRect:TPaperRect): Integer;
IndexOfDefaultPapernull173     function IndexOfDefaultPaper(const AName: string): Integer;
174     procedure SetPaperRect(AValue: TPaperRect);
175   public
176     constructor Create(aOwner : TPrinter); overload;
177     destructor Destroy; override;
178 
179     property DefaultPapers   : boolean read fDefaultPapers;
180     property Width           : Integer read GetPhysPaperWidth;
181     property Height          : Integer read GetPhysPaperHeight;
182     property PaperName       : string read GetPaperName write SetPaperName;
183     property DefaultPaperName: string read GetDefaultPaperName;
184 
185     property PaperRect       : TPaperRect read GetPaperRect write SetPaperRect;
186     property SupportedPapers : TStrings read GetSupportedPapers;
187 
188     property PaperRectOf[aName : string] : TPaperRect read PaperRectOfName;
189   end;
190 
191   TPrinterFlags = set of
192     (
193       pfPrinting,                //Printing
194       pfAborted,                 //Abort  process
195       pfDestroying,              //Printer object is being destroyed
196       pfPrintersValid,           //fPrinters list is valid
197       pfRawMode                  //Printer is in raw mode
198     );
199 
200   { TPrinter }
201 
202   TPrinter = class(TObject)
203   private
204     fCanvas      : TCanvas;      //Active canvas object
205     FFileName    : string;       //Filename for output file
206     fFonts       : TStrings;     //Accepted font by printer
207     fPageNumber  : Integer;      //Current page number
208     fPrinters    : TStrings;     //Printers names list
209     fPrinterIndex: Integer;      //selected printer index
210     fTitle       : string;       //Title of current document
211     //fCapabilities: TPrinterCapabilities;
212     fPaperSize   : TPaperSize;
213     fCanvasClass : TPrinterCanvasRef;
214     fBins        : TStrings;
215     fFlags       : TPrinterFlags;
216 
GetAbortednull217     function GetAborted: Boolean;
GetCanvasnull218     function GetCanvas: TCanvas;
219     procedure CheckPrinting(Value: Boolean);
GetCanvasClassnull220     function GetCanvasClass: TPrinterCanvasRef;
GetCopiesnull221     function GetCopies: Integer;
GetFontsnull222     function GetFonts: TStrings;
GetOrientationnull223     function GetOrientation: TPrinterOrientation;
GetPageHeightnull224     function GetPageHeight: Integer;
GetPageWidthnull225     function GetPageWidth: Integer;
GetPaperSizenull226     function GetPaperSize: TPaperSize;
GetBinNamenull227     Function GetBinName: string;
GetDefaultBinNamenull228     function GetDefaultBinName: string;
GetPrinterIndexnull229     function GetPrinterIndex: integer;
GetPrinterNamenull230     function GetPrinterName: string;
GetPrintersnull231     function GetPrinters: TStrings;
GetPrintingnull232     function GetPrinting: Boolean;
GetRawModenull233     function GetRawMode: boolean;
234     procedure SetCanvasClass(const AValue: TPrinterCanvasRef);
235     procedure SetCopies(AValue: Integer);
236     procedure SetOrientation(const AValue: TPrinterOrientation);
237     procedure SetPrinterIndex(AValue: integer);
238     procedure SetRawMode(const AValue: boolean);
239     procedure SetBinName(const aName: string);
240   protected
241      procedure SelectCurrentPrinterOrDefault;
242 
243      procedure DoBeginDoc; virtual;
244      procedure DoNewPage; virtual;
245      procedure DoBeginPage; virtual;
246      procedure DoEndPage; virtual;
247      procedure DoEndDoc(aAborted : Boolean); virtual;
248      procedure DoAbort; virtual;
249      procedure DoResetPrintersList; virtual;
250      procedure DoResetFontsList; virtual;
251 
252      procedure DoEnumPrinters(Lst : TStrings); virtual;
253      procedure DoEnumFonts(Lst : TStrings); virtual;
254      procedure DoEnumPapers(Lst : TStrings); virtual;
255      procedure DoEnumBins(Lst : TStrings); virtual;
256      procedure DoInitialization; virtual;
DoSetPrinternull257      function DoSetPrinter(aName : string): Integer; virtual;
DoGetCopiesnull258      function DoGetCopies : Integer; virtual;
259      procedure DoSetCopies(aValue : Integer); virtual;
DoGetOrientationnull260      function DoGetOrientation: TPrinterOrientation; virtual;
261      procedure DoSetOrientation(aValue : TPrinterOrientation); virtual;
DoGetDefaultPaperNamenull262      function DoGetDefaultPaperName: string; virtual;
DoGetPaperNamenull263      function DoGetPaperName: string; virtual;
264      procedure DoSetPaperName(aName : string); virtual;
DoGetDefaultBinNamenull265      function DoGetDefaultBinName: string; virtual;
DoGetBinNamenull266      function DoGetBinName: string; virtual;
267      procedure DoSetBinName(aName: string); virtual;
DoGetPaperRectnull268      function DoGetPaperRect(aName : string; Var aPaperRc : TPaperRect) : Integer; virtual;
DoSetPaperRectnull269      function DoSetPaperRect(aPaperRc: TPaperRect): boolean; virtual;
DoGetPrinterStatenull270      function DoGetPrinterState: TPrinterState; virtual;
271      procedure DoDestroy; virtual;
272 
GetPrinterTypenull273      function GetPrinterType : TPrinterType; virtual;
GetCanPrintnull274      function GetCanPrint : Boolean; virtual;
GetCanRenderCopiesnull275      function GetCanRenderCopies : Boolean; virtual;
GetXDPInull276      function GetXDPI: Integer; virtual;
GetYDPInull277      function GetYDPI: Integer; virtual;
GetBinsnull278      function GetBins: TStrings; virtual;
279      procedure CheckRawMode(const Value: boolean; Msg:string='');
280      procedure RawModeChanging; virtual;
281      procedure PrinterSelected; virtual;
DoGetDefaultCanvasClassnull282      function  DoGetDefaultCanvasClass: TPrinterCanvasRef; virtual;
283 
284      property PrinterFlags: TPrinterFlags read fFlags write fFlags;
285   public
286      constructor Create; virtual;
287      destructor Destroy; override;
288 
289      procedure Abort;
290      procedure BeginDoc;
291      procedure EndDoc;
292      procedure NewPage;
293      procedure BeginPage;
294      procedure EndPage;
295      procedure Refresh;
296      procedure SetPrinter(aName : String);
297      Procedure RestoreDefaultBin; virtual;
Writenull298      function  Write(const Buffer; Count:Integer; out Written: Integer): Boolean; virtual;
Writenull299      function  Write(const s: ansistring): boolean; overload;
300 
301      property PrinterIndex : integer read GetPrinterIndex write SetPrinterIndex;
302      property PrinterName: string read GetPrinterName;
303      property PaperSize : TPaperSize read GetPaperSize;
304      property Orientation: TPrinterOrientation read GetOrientation write SetOrientation;
305      property PrinterState : TPrinterState read DoGetPrinterState;
306      property Copies : Integer read GetCopies write SetCopies;
307      property Printers: TStrings read GetPrinters;
308      property FileName: string read FFileName write FFileName;
309      property Fonts: TStrings read GetFonts;
310      property Canvas: TCanvas read GetCanvas;
311      property CanvasClass: TPrinterCanvasRef read GetCanvasClass write SetCanvasClass;
312      property PageHeight: Integer read GetPageHeight;
313      property PageWidth: Integer read GetPageWidth;
314      property PageNumber : Integer read fPageNumber;
315      property Aborted: Boolean read GetAborted;
316      property Printing: Boolean read GetPrinting;
317      property Title: string read fTitle write fTitle;
318      property PrinterType : TPrinterType read GetPrinterType;
319      property CanPrint : Boolean read GetCanPrint;
320      property CanRenderCopies : Boolean read GetCanRenderCopies;
321      property XDPI : Integer read GetXDPI;
322      property YDPI : Integer read GetYDPI;
323      property RawMode: boolean read GetRawMode write SetRawMode;
324      property DefaultBinName: string read GetDefaultBinName;
325      property BinName: string read GetBinName write SetBinName;
326      property SupportedBins: TStrings read GetBins;
327   end;
328 
329 // TPrinter it's an basic object. If you override this object,
330 // you must create an instance.
331 var
332   Printer: TPrinter = nil;
333 
334 implementation
335 
336 const
337   CUSTOM_PAPER_NAME = 'LCLCustomPaper';
338 
339 { TPrinter }
340 
341 constructor TPrinter.Create;
342 begin
343   if ClassType=TPrinter then
344     raise Exception.Create('TPrinter is an abstract base class.'
345     +' Please use a printer implementation like the package printers4lazarus.');
346   Inherited Create;
347   fPrinterIndex:=-1;  //By default, use the default printer
348   fCanvas:=nil;
349   fPaperSize:=nil;
350   fBins:=nil;
351   fTitle:='';
352 end;
353 
354 destructor TPrinter.Destroy;
355 begin
356   Include(fFlags, pfDestroying);
357   DoDestroy;
358   inherited Destroy;
359 end;
360 
361 //Abort the current document
362 procedure TPrinter.Abort;
363 begin
364   //Check if Printer print otherwise, exception
365   CheckPrinting(True);
366 
367   DoAbort;
368 
369   Include(fFlags, pfAborted);
370   EndDoc;
371 end;
372 
373 //Begin a new document
374 procedure TPrinter.BeginDoc;
375 begin
376   //Check if Printer not printing otherwise, exception
377   CheckPrinting(False);
378 
379   //If not selected printer, set default printer
380   SelectCurrentPrinterOrDefault;
381 
382   Include(fFlags, pfPrinting);
383   Exclude(fFlags, pfAborted);
384   fPageNumber := 1;
385 
386   if not RawMode then begin
387     Canvas.Refresh;
388     TPrinterCanvas(Canvas).BeginDoc;
389   end;
390   //Call the specifique Begindoc
391   DoBeginDoc;
392 
393   BeginPage;
394 
395   // Set font resolution
396   if not RawMode then
397     Canvas.Font.PixelsPerInch := YDPI;
398 end;
399 
400 //End the current document
401 procedure TPrinter.EndDoc;
402 begin
403 
404   EndPage;
405 
406   //Check if Printer print otherwise, exception
407   CheckPrinting(True);
408 
409   if not RawMode then
410     TPrinterCanvas(Canvas).EndDoc;
411 
412   DoEndDoc(pfAborted in fFlags);
413 
414   Exclude(fFlags, pfPrinting);
415   Exclude(fFlags, pfAborted);
416   fPageNumber := 0;
417 end;
418 
419 //Create an new page
420 procedure TPrinter.NewPage;
421 begin
422   Inc(fPageNumber);
423   if TMethod(@Self.DoNewPage).Code = Pointer(@TPrinter.DoNewPage) then
424   begin
425     // DoNewPage has not been overriden, use the new method
426     EndPage;
427     BeginPage;
428   end else
429   begin
430     // Use the old method as DoNewPage has been overriden in descendat TPrinter
431     CheckPrinting(True);
432     if not RawMode then
433       TPrinterCanvas(Canvas).NewPage;
434     DoNewPage;
435   end;
436 end;
437 
438 procedure TPrinter.BeginPage;
439 begin
440   CheckPrinting(True);
441   if not RawMode then
442     TPrinterCanvas(Canvas).BeginPage;
443   DoBeginPage;
444 end;
445 
446 procedure TPrinter.EndPage;
447 begin
448   if not RawMode then
449     TPrinterCanvas(Canvas).EndPage;
450   DoEndPage;
451 end;
452 
453 //Clear Printers & Fonts list
454 procedure TPrinter.Refresh;
455 var
456   OldPrinter: string;
457 begin
458   //Check if Printer not printing otherwise, exception
459   CheckPrinting(False);
460 
461   if FPrinterIndex>=0 then
462     OldPrinter := fPrinters[FPrinterIndex]
463   else
464     OldPrinter := '';
465 
466   if Assigned(fPrinters) then
467   begin
468     DoResetPrintersList;
469     FreeAndNil(fPrinters);
470   end;
471 
472   if Assigned(fFonts) then
473   begin
474     DoResetFontsList;
475     FreeAndNil(fFonts);
476   end;
477 
478   // need to refill printers here otherwise
479   // it wont be filled on getting printers
480   // due to only one initialization
481   GetPrinters;
482 
483   fPrinterIndex:=-1;
484 
485   // try to locate old selected printer
486   if OldPrinter<>'' then
487     SetPrinter(OldPrinter);
488 end;
489 
490 //Set the current printer
491 procedure TPrinter.SetPrinter(aName: String);
492 var
493   i,oldIndex : Integer;
494 begin
495   if aName='*' then begin
496     // select default printer
497     OldIndex := FPrinterIndex;
498     fPrinterIndex := -1; // avoid to remember last printer
499     Refresh;
500     if Printers.count>0 then begin
501       i:= doSetprinter(FPrinters[0]); // now first printer is default
502       if i<>0 then begin
503         // something went wrong, try to restore old printer
504         if OldIndex>=0 then
505           FPrinterIndex := doSetPrinter(FPrinters[OldIndex]);
506         raise EPrinter.Create('Unable to set default printer!');
507       end else
508         FPrinterIndex := i;
509     end;
510   end else
511   if (Printers.Count>0) then
512   begin
513     if (aName<>'') then
514     begin
515       //Printer changed ?
516       if fPrinters.IndexOf(aName)<>fPrinterIndex then
517       begin
518         i:=DoSetPrinter(aName);
519         if i<0 then
520           raise EPrinter.Create(Format('Printer "%s" doesn''t exist.',[aName]));
521         fPrinterIndex:=i;
522       end;
523     end;
524   end;
525   PrinterSelected;
526 end;
527 
528 procedure TPrinter.RestoreDefaultBin;
529 begin
530   DoSetBinName(DoGetDefaultBinName);
531 end;
532 
Writenull533 function TPrinter.Write(const Buffer; Count: Integer; out Written: Integer): Boolean;
534 begin
535   result := False;
536   Written := 0;
537 end;
538 
Writenull539 function TPrinter.Write(const s: ansistring): boolean;
540 var
541   Written: integer;
542 begin
543   Result := Write(S[1], Length(S), Written);
544 end;
545 
546 //Return an Canvas object
GetCanvasnull547 function TPrinter.GetCanvas: TCanvas;
548 begin
549   Result := nil;
550 
551   CheckRawMode(False, 'Canvas not allowed in Raw Mode');
552 
553   if not Assigned(fCanvas) then
554   begin
555     if not Assigned(CanvasClass) then
556       raise Exception.Create('Canvas Class not defined.');
557 
558     fCanvas:=CanvasClass.Create(Self);
559   end;
560 
561   Result:=fCanvas;
562 end;
563 
GetAbortednull564 function TPrinter.GetAborted: Boolean;
565 begin
566   Result := (pfAborted in fFlags);
567 end;
568 
569 //Raise error if Printer.Printing is not Value
570 procedure TPrinter.CheckPrinting(Value: Boolean);
571 begin
572   if Printing<>Value then
573   begin
574     if Value then
575       raise EPrinter.Create('Printer is not printing')
576     else
577       raise Eprinter.Create('Printer is printing');
578   end;
579 end;
580 
GetCanvasClassnull581 function TPrinter.GetCanvasClass: TPrinterCanvasRef;
582 begin
583   if RawMode then
584     result := nil
585   else
586   if FCanvasClass=nil then
587     Result := DoGetDefaultCanvasClass
588   else
589     Result := FCanvasClass;
590 end;
591 
592 procedure TPrinter.CheckRawMode(const Value: boolean; Msg: string);
593 begin
594   if RawMode<>Value then
595   begin
596     if msg='' then
597       if Value then
598         Msg:='Printer is in Raw Mode'
599       else
600         Msg:='Printer is not in Raw Mode';
601     raise EPrinter.Create(msg);
602   end;
603 end;
604 
605 procedure TPrinter.RawModeChanging;
606 begin
607   //
608 end;
609 
610 procedure TPrinter.PrinterSelected;
611 begin
612 end;
613 
DoGetDefaultCanvasClassnull614 function TPrinter.DoGetDefaultCanvasClass: TPrinterCanvasRef;
615 begin
616   result := TPrinterCanvas;
617 end;
618 
619 //Get current copies number
GetCopiesnull620 function TPrinter.GetCopies: Integer;
621 Var i : Integer;
622 begin
623   Result:=1;
624   i:=DoGetCopies;
625   if i>0 then
626     Result:=i;
627 end;
628 
629 //Return & initialize the Fonts list
GetFontsnull630 function TPrinter.GetFonts: TStrings;
631 begin
632   if not Assigned(fFonts) then
633     fFonts:=TStringList.Create;
634   Result:=fFonts;
635 
636   //Only 1 initialization
637   if fFonts.Count=0 then
638     DoEnumFonts(fFonts);
639 end;
640 
GetOrientationnull641 function TPrinter.GetOrientation: TPrinterOrientation;
642 begin
643   Result:=DoGetOrientation;
644 end;
645 
646 // Returns the height in points (pixels) of printable area
GetPageHeightnull647 function TPrinter.GetPageHeight: Integer;
648 begin
649   Result:=0;
650   if (Printers.Count>0) then
651     with PaperSize.PaperRect.WorkRect do
652       Result:=Bottom-Top;
653 end;
654 
655 // Returns the width in points (pixels) of the printable area
GetPageWidthnull656 function TPrinter.GetPageWidth: Integer;
657 begin
658   Result:=0;
659   if (Printers.Count>0) then
660     with PaperSize.PaperRect.WorkRect do
661       // PageWidth is the size in "pixels" of the printable area
662       Result:=Right-Left;
663 end;
664 
GetPaperSizenull665 function TPrinter.GetPaperSize: TPaperSize;
666 begin
667   if not Assigned(fPaperSize)  then
668     fPaperSize:=TPaperSize.Create(self);
669   Result:=fPaperSize;
670 end;
671 
GetBinNamenull672 function TPrinter.GetBinName: string;
673 begin
674   result := doGetBinName;
675 end;
676 
GetDefaultBinNamenull677 function TPrinter.GetDefaultBinName: string;
678 begin
679   result := doGetDefaultBinName;
680 end;
681 
682 //Return the current selected printer
GetPrinterIndexnull683 function TPrinter.GetPrinterIndex: integer;
684 begin
685   Result:=fPrinterIndex;
686   if (Result<0) and (Printers.Count>0) then
687      Result:=0; //printer by default
688 end;
689 
GetPrinterNamenull690 function TPrinter.GetPrinterName: string;
691 begin
692   if PrinterIndex<0 then
693     result := ''
694   else
695     result := Printers[PrinterIndex];
696 end;
697 
698 //Return & initialize the printers list
GetPrintersnull699 function TPrinter.GetPrinters: TStrings;
700 begin
701   if not Assigned(fPrinters) then
702     fPrinters:=TStringListUTF8Fast.Create;
703   Result:=fPrinters;
704 
705   //Only 1 initialization
706   if [pfPrintersValid, pfDestroying]*fFlags = [] then begin
707     Include(fFlags, pfPrintersValid);
708     DoEnumPrinters(fPrinters);
709     if FPrinters.Count>0 then
710       SelectCurrentPrinterOrDefault;
711     DoInitialization;
712   end;
713 end;
714 
GetPrintingnull715 function TPrinter.GetPrinting: Boolean;
716 begin
717   result := (pfPrinting in fFlags);
718 end;
719 
GetRawModenull720 function TPrinter.GetRawMode: boolean;
721 begin
722   result := (pfRawMode in fFlags);
723 end;
724 
725 procedure TPrinter.SetCanvasClass(const AValue: TPrinterCanvasRef);
726 begin
727   FCanvasClass := AValue;
728 end;
729 
730 //Return XDPI
GetXDPInull731 function TPrinter.GetXDPI: Integer;
732 begin
733   Result:=1;
734 end;
735 
736 //Return YDPI
GetYDPInull737 function TPrinter.GetYDPI: Integer;
738 begin
739   Result:=1;
740 end;
741 
GetBinsnull742 function TPrinter.GetBins: TStrings;
743 begin
744   if fBins=nil then
745     fBins := TStringList.Create;
746 
747   doEnumBins(fBins);
748 
749   result := fBins;
750 end;
751 
752 //Set copies number
753 procedure TPrinter.SetCopies(AValue: Integer);
754 begin
755   CheckPrinting(False);
756   if aValue<1 then aValue:=1;
757   if Printers.Count>0 then
758     DoSetCopies(aValue)
759   else
760     raise EPrinter.Create('No printers found.');
761 end;
762 
763 procedure TPrinter.SetOrientation(const AValue: TPrinterOrientation);
764 begin
765   DoSetOrientation(aValue);
766 end;
767 
768 //Set selected printer
769 procedure TPrinter.SetPrinterIndex(AValue: integer);
770 Var aName : String;
771 begin
772   if fPrinterIndex=AValue then exit;
773   CheckPrinting(False);
774   if Printers.Count>0 then
775   begin
776     if AValue=-1 then
777       aName:='*'
778     else
779       if (AValue>=0) and (AValue<Printers.Count) then
780         aName:=Printers.Strings[AValue]
781       else
782         raise EPrinter.Create('Printer index out of range!');
783     SetPrinter(aName);
784     DoResetFontsList;
785   end
786   else
787     raise EPrinter.Create('No printers defined!');
788 end;
789 
790 procedure TPrinter.SetRawMode(const AValue: boolean);
791 begin
792   if AValue<>RawMode then begin
793     CheckPrinting(False);
794     RawModeChanging;
795     if AValue then
796       Include(fFlags, pfRawMode)
797     else
798       Exclude(fFlags, pfRawMode);
799   end;
800 end;
801 
802 procedure TPrinter.SetBinName(const aName: string);
803 begin
804   CheckPrinting(False);
805   DoSetBinName(aName);
806 end;
807 
808 //If not Printer selected, Select the default printer
809 procedure TPrinter.SelectCurrentPrinterOrDefault;
810 begin
811   if (fPrinterIndex<0) and (Printers.Count>0) then
812     PrinterIndex:=0;
813 end;
814 
815 procedure TPrinter.DoBeginDoc;
816 begin
817   //Override this method
818 end;
819 
820 procedure TPrinter.DoNewPage;
821 begin
822   //Override this method
823 end;
824 
825 procedure TPrinter.DoBeginPage;
826 begin
827   //Override this method
828 end;
829 
830 procedure TPrinter.DoEndPage;
831 begin
832   //Override this method
833 end;
834 
835 procedure TPrinter.DoEndDoc(aAborted : Boolean);
836 begin
837   //Override this method
838 end;
839 
840 procedure TPrinter.DoAbort;
841 begin
842  //Override this method
843 end;
844 
845 procedure TPrinter.DoResetPrintersList;
846 begin
847  //Override this method
848   Exclude(fFlags, pfPrintersValid);
849 end;
850 
851 procedure TPrinter.DoResetFontsList;
852 begin
853   if fFonts<>nil then
854     fFonts.Clear;
855 end;
856 
857 //Initialize the Lst with all definied printers
858 procedure TPrinter.DoEnumPrinters(Lst: TStrings);
859 begin
860  //Override this method
861  //Warning: The default printer must be the first printer
862  //          (fPrinters[0])
863 end;
864 
865 //Initialize the Lst with all supported fonts
866 procedure TPrinter.DoEnumFonts(Lst: TStrings);
867 begin
868  //Override this method
869 end;
870 
871 //Initialize the Lst with all supported papers names
872 procedure TPrinter.DoEnumPapers(Lst: TStrings);
873 begin
874   //DebugLn(['TPrinter.DoEnumPapers ',dbgsName(Self)]);
875 
876  //Override this method
877 end;
878 
879 procedure TPrinter.DoEnumBins(Lst : TStrings);
880 begin
881   // Override this method
882 end;
883 
884 // This method is called once after the printer list
885 // is obtained for the first time.
886 procedure TPrinter.DoInitialization;
887 begin
888   //Override this method
889 end;
890 
891 
892 //Set the current printer
DoSetPrinternull893 function TPrinter.DoSetPrinter(aName : string): Integer;
894 begin
895   //Override this method. The result must be
896   //the index of aName printer in Printers list
897   //if the aName doesn't exist, return -1
898   Result:=-1;
899 end;
900 
901 //Get the current copies nulbers
TPrinter.DoGetCopiesnull902 function TPrinter.DoGetCopies: Integer;
903 begin
904  //Override this method
905  Result:=1;
906 end;
907 
908 //Set copies number
909 procedure TPrinter.DoSetCopies(aValue: Integer);
910 begin
911  //Override this method
912 end;
913 
914 //Return current paper orientation
TPrinter.DoGetOrientationnull915 function TPrinter.DoGetOrientation: TPrinterOrientation;
916 begin
917   Result:=poPortrait;
918   //Override this method
919 end;
920 
921 //Set paper Orientation
922 procedure TPrinter.DoSetOrientation(aValue: TPrinterOrientation);
923 begin
924  //Override this method
925 end;
926 
927 //Return the default paper name for the selected printer
TPrinter.DoGetDefaultPaperNamenull928 function TPrinter.DoGetDefaultPaperName: string;
929 begin
930   Result:='';
931   //Override this methode
932 end;
933 
934 //Return selected paper name for the current printer
TPrinter.DoGetPaperNamenull935 function TPrinter.DoGetPaperName: string;
936 begin
937   Result:='';
938   //Override this method
939 end;
940 
941 procedure TPrinter.DoSetPaperName(aName: string);
942 begin
943   //Override this method
944 end;
945 
TPrinter.DoGetDefaultBinNamenull946 function TPrinter.DoGetDefaultBinName: string;
947 begin
948   Result:='';
949 end;
950 
TPrinter.DoGetBinNamenull951 function TPrinter.DoGetBinName: string;
952 begin
953   result := '';
954 end;
955 
956 procedure TPrinter.DoSetBinName(aName: string);
957 begin
958   if SupportedBins.Count>0 then
959     DebugLn('Warning: bin %s is not allowed',[aName]);
960 end;
961 
962 //Initialise aPaperRc with the aName paper rect
963 //Result : -1 no result
964 //          0 aPaperRc.WorkRect is a margins
965 //          1 aPaperRc.WorkRect is really the work rect
DoGetPaperRectnull966 function TPrinter.DoGetPaperRect(aName : string; var aPaperRc: TPaperRect): Integer;
967 begin
968   Result:=-1;
969   //Override this method
970 end;
971 
DoSetPaperRectnull972 function TPrinter.DoSetPaperRect(aPaperRc: TPaperRect): boolean;
973 begin
974   result := false;
975 end;
976 
977 //Get a state of current printer
TPrinter.DoGetPrinterStatenull978 function TPrinter.DoGetPrinterState: TPrinterState;
979 begin
980   //Override this method
981   Result:=psNoDefine;
982 end;
983 
984 procedure TPrinter.DoDestroy;
985 begin
986   if Printing then
987     Abort;
988 
989   fBins.free;
990 
991   if Assigned(fCanvas) then
992     fCanvas.Free;
993 
994   if Assigned(fPaperSize) then
995      fPaperSize.Free;
996 
997 
998   if Assigned(fPrinters) then
999   begin
1000     DoResetPrintersList;
1001     FreeAndNil(fPrinters);
1002   end;
1003 
1004   if Assigned(fFonts) then
1005   begin
1006     DoResetFontsList;
1007     FreeAndNil(fFonts);
1008   end;
1009 end;
1010 
1011 //Return the type of selected printer
GetPrinterTypenull1012 function TPrinter.GetPrinterType: TPrinterType;
1013 begin
1014   Result:=ptLocal;
1015 end;
1016 
1017 //Return True if selected printer is able to print
GetCanPrintnull1018 function TPrinter.GetCanPrint: Boolean;
1019 begin
1020   Result:=True;
1021 end;
1022 
GetCanRenderCopiesnull1023 function TPrinter.GetCanRenderCopies: Boolean;
1024 begin
1025   Result:=True;
1026 end;
1027 
1028 { TPaperSize }
1029 
1030 procedure TPaperSize.CreateInternalPapers;
1031   procedure add(AnIndex:Integer; aname:string; aPhysRect,aWrkRect:TRect);
1032   begin
1033     with fInternalPapers[AnIndex] do begin
1034       PaperName := aName;
1035       PaperRect.PhysicalRect := aPhysRect;
1036       PaperRect.WorkRect := aWrkRect;
1037     end;
1038   end;
PRRectnull1039   function PRRect(const ALeft,ATop,ARight,ABottom: Integer): TRect;
1040   begin
1041     Result.Left := ALeft;
1042     Result.Top := ATop;
1043     Result.Right  := round(ARight * FOwnedPrinter.XDPI / 72);
1044     Result.Bottom := round(ABottom * FOwnedPrinter.XDPI / 72);
1045   end;
1046 begin
1047   if Length(fInternalPapers)=0 then
1048   begin
1049     SetLength(fInternalPapers, 3);
1050     add(0, 'Letter',    PRRect(0, 0, 612,  792 ), PRRect(0,   0,   612, 792 ));
1051     add(1, 'A4',        PRRect(0, 0, 595,  892 ), PRRect(0,   0,   595, 892 ));
1052     add(2, 'Legal',     PRRect(0, 0, 612,  1008), PRRect(0,   0,   612, 1008));
1053   end;
1054 end;
1055 
1056 procedure TPaperSize.FillDefaultPapers;
1057 var
1058   i: Integer;
1059 begin
1060   FSupportedPapers.Clear;
1061   CreateInternalPapers;
1062   for i:=0 to Length(FInternalPapers)-1 do
1063     FSupportedPapers.Add(FInternalPapers[i].PaperName);
1064   FDefaultPaperIndex := 0;
1065   FDefaultPapers := true;
1066 end;
1067 
TPaperSize.GetDefaultPaperNamenull1068 function TPaperSize.GetDefaultPaperName: string;
1069 begin
1070   CheckSupportedPapers;
1071 
1072   if fDefaultPapers then
1073     Result := FSupportedPapers[0]
1074   else
1075     Result := fOwnedPrinter.DoGetDefaultPaperName;
1076 end;
1077 
TPaperSize.GetDefaultPaperRectnull1078 function TPaperSize.GetDefaultPaperRect(const AName: string;
1079   var APaperRect:TPaperRect): Integer;
1080 var
1081   PR: TPaperRect;
1082 begin
1083   Result := IndexOfDefaultPaper(AName);
1084   if Result>=0 then
1085   PR:=FInternalPapers[Result].PaperRect;
1086   if FOwnedPrinter.Orientation in [poPortrait, poReversePortrait] then
1087   begin
1088     APaperRect.PhysicalRect := PR.PhysicalRect;
1089     APaperRect.WorkRect     := PR.WorkRect;
1090   end else
1091   begin
1092     APaperRect.PhysicalRect.Left   := 0;
1093     APaperRect.PhysicalRect.Top    := 0;
1094     APaperRect.PhysicalRect.Right  := PR.PhysicalRect.Bottom;
1095     APaperRect.Physicalrect.Bottom := PR.PhysicalRect.Right;
1096 
1097     APaperRect.WorkRect.Left   := PR.WorkRect.Top;
1098     APaperRect.WorkRect.Top    := PR.PhysicalRect.Right-PR.WorkRect.Right;
1099     APaperRect.WorkRect.Right  := PR.WorkRect.Bottom;
1100     APaperRect.WorkRect.Bottom := PR.PhysicalRect.Right-PR.Workrect.Left;
1101   end;
1102 end;
1103 
GetPhysPaperHeightnull1104 function TPaperSize.GetPhysPaperHeight: Integer;
1105 begin
1106   result := PaperRect.PhysicalRect.Bottom - PaperRect.PhysicalRect.Top;
1107 end;
1108 
TPaperSize.GetPaperNamenull1109 function TPaperSize.GetPaperName: string;
1110 begin
1111   CheckSupportedPapers;
1112 
1113   if fCustomPaper.PaperSet then
1114     result := fCustomPaper.Item.PaperName
1115   else
1116   if fDefaultPapers then
1117     Result := SupportedPapers[FDefaultPaperIndex]
1118   else
1119     Result := fOwnedPrinter.DoGetPaperName;
1120 
1121   if Result='' then
1122     Result:=DefaultPaperName;
1123 end;
1124 
GetPaperRectnull1125 function TPaperSize.GetPaperRect: TPaperRect;
1126 begin
1127   if fCustomPaper.PaperSet then
1128     result := fCustomPaper.Item.PaperRect
1129   else
1130   Result:=PaperRectOfName(PaperName);
1131 end;
1132 
GetPhysPaperWidthnull1133 function TPaperSize.GetPhysPaperWidth: Integer;
1134 begin
1135   result := PaperRect.PhysicalRect.Right - PaperRect.PhysicalRect.Left;
1136 end;
1137 
TPaperSize.GetSupportedPapersnull1138 function TPaperSize.GetSupportedPapers: TStrings;
1139 begin
1140   CheckSupportedPapers;
1141 
1142   Result:=fSupportedPapers;
1143 end;
1144 
TPaperSize.IndexOfDefaultPapernull1145 function TPaperSize.IndexOfDefaultPaper(const AName: string): Integer;
1146 var
1147   i: Integer;
1148 begin
1149   Result := -1;
1150   for i:=0 to Length(fInternalPapers)-1 do
1151     if CompareText(fInternalPapers[i].PaperName, AName)=0 then
1152     begin
1153       Result := i;
1154       break;
1155     end;
1156 end;
1157 
1158 procedure TPaperSize.SetPaperRect(AValue: TPaperRect);
1159 begin
1160   fCustomPaper.PaperSet := true;
1161   fCustomPaper.Item.PaperRect := AValue;
1162   if not fDefaultPapers then
1163     fOwnedPrinter.DoSetPaperRect(AValue);
1164 end;
1165 
1166 procedure TPaperSize.SetPaperName(const AName: string);
1167 begin
1168 
1169   if fCustomPaper.PaperSet and (AName=fCustomPaper.Item.PaperName) then
1170   begin
1171     // update printer custom paper dimensions
1172     if not fDefaultPapers and not fCustomPaper.Item.PaperRect.PhysicalRect.IsEmpty then
1173       fOwnedPrinter.DoSetPaperRect(fCustomPaper.Item.PaperRect);
1174     exit;
1175   end;
1176 
1177   if SupportedPapers.IndexOf(aName)<>-1 then
1178   begin
1179     if aName<>PaperName then
1180     begin
1181       if fDefaultPapers then
1182         FDefaultPaperIndex := IndexOfDefaultPaper(AName)
1183       else
1184         FOwnedPrinter.DoSetPaperName(aName);
1185 
1186       fCustomPaper.PaperSet := false;
1187     end;
1188   end
1189   else
1190     raise EPrinter.Create(Format('Paper "%s" not supported!',[aName]));
1191 end;
1192 
1193 //Return an TPaperRect corresponding at an paper name
TPaperSize.PaperRectOfNamenull1194 function TPaperSize.PaperRectOfName(const AName: string): TPaperRect;
1195 var TmpPaperRect : TPaperRect;
1196     Margins      : Integer;
1197 begin
1198 
1199   if (fCustomPaper.PaperSet) and (AName=fCustomPaper.Item.PaperName) then
1200   begin
1201     result := fCustomPaper.Item.PaperRect;
1202     exit;
1203   end;
1204 
1205   FillChar(Result,SizeOf(Result),0);
1206 
1207   if SupportedPapers.IndexOf(AName)<>-1 then
1208   begin
1209 
1210     if fDefaultPapers then
1211       Margins := GetDefaultPaperRect(AName, TmpPaperRect)
1212     else
1213       Margins := fOwnedPrinter.DoGetPaperRect(aName,TmpPaperRect);
1214 
1215     if Margins>=0 then
1216       Result := TmpPaperRect
1217     else
1218       raise EPrinter.Create(Format('The paper "%s" has no defined rectangle!',[aName]));
1219 
1220   end
1221   else raise EPrinter.Create(Format('Paper "%s" not supported!',[aName]));
1222 end;
1223 
1224 procedure TPaperSize.CheckSupportedPapers;
1225 begin
1226   if (fSupportedPapers.Count=0) or
1227      (fLastPrinterIndex<>fOwnedPrinter.PrinterIndex) then
1228   begin
1229     fOwnedPrinter.SelectCurrentPrinterOrDefault;
1230 
1231     fSupportedPapers.Clear;
1232     fDefaultPapers := false;
1233     //DebugLn(['TPaperSize.GetSupportedPapers ',dbgsName(fOwnedPrinter),' ',dbgsName(Printer),' ',fOwnedPrinter=Printer]);
1234     fOwnedPrinter.DoEnumPapers(fSupportedPapers);
1235 
1236     if fSupportedPapers.Count=0 then
1237       FillDefaultPapers;
1238 
1239     fLastPrinterIndex:=fOwnedPrinter.PrinterIndex;
1240   end;
1241 end;
1242 
1243 constructor TPaperSize.Create(aOwner: TPrinter);
1244 begin
1245   if not assigned(aOwner) then
1246     raise Exception.Create('TMediaSize.Create, aOwner must be defined!');
1247   Inherited Create;
1248 
1249   fLastPrinterIndex:=-2;
1250   fOwnedPrinter:=aOwner;
1251   fSupportedPapers:=TStringList.Create;
1252 
1253   FillChar(fCustomPaper, sizeOf(fCustomPaper), 0);
1254   fCustomPaper.Item.PaperName := CUSTOM_PAPER_NAME;
1255 end;
1256 
1257 destructor TPaperSize.Destroy;
1258 begin
1259   fSupportedPapers.Free;
1260 
1261   inherited Destroy;
1262 end;
1263 
1264 { TPrinterCanvas }
1265 
TPrinterCanvas.GetTitlenull1266 function TPrinterCanvas.GetTitle: string;
1267 begin
1268   if Assigned(fPrinter) then
1269     Result:=fPrinter.Title
1270   else
1271     Result:=fTitle;
1272 end;
1273 
GetXDPInull1274 function TPrinterCanvas.GetXDPI: Integer;
1275 begin
1276   if Printer<>nil then
1277     result := Printer.XDPI
1278   else
1279   if fXDPI <= 0 then
1280     result := 300
1281   else
1282     result := fXDPI;
1283 end;
1284 
TPrinterCanvas.GetYDPInull1285 function TPrinterCanvas.GetYDPI: Integer;
1286 begin
1287   if Printer<>nil then
1288     result := Printer.YDPI
1289   else
1290   if fYDPI <= 0 then
1291     result := 300
1292   else
1293     result := fYDPI;
1294 end;
1295 
1296 procedure TPrinterCanvas.SetOrientation(const AValue: TPrinterOrientation);
1297 begin
1298   if Assigned(fPrinter) then
1299     fPrinter.Orientation := AValue
1300   else
1301     fOrientation := AValue;
1302 end;
1303 
TPrinterCanvas.GetOrientationnull1304 function TPrinterCanvas.GetOrientation: TPrinterOrientation;
1305 begin
1306   if fPrinter<>nil then
1307     result := fPrinter.Orientation
1308   else
1309     result := fOrientation;
1310 end;
1311 
TPrinterCanvas.GetPageHeightnull1312 function TPrinterCanvas.GetPageHeight: Integer;
1313 begin
1314   if Assigned(fPrinter) and HasDefaultMargins then
1315     Result:=fPrinter.PageHeight
1316   else
1317     Result:= PaperHeight - TopMargin - BottomMargin;
1318 end;
1319 
GetPageWidthnull1320 function TPrinterCanvas.GetPageWidth: Integer;
1321 begin
1322   if Assigned(fPrinter) and HasDefaultMargins then
1323     Result:=fPrinter.PageWidth
1324   else
1325     Result:= PaperWidth - LeftMargin - RightMargin;
1326 end;
1327 
GetPaperHeightnull1328 function TPrinterCanvas.GetPaperHeight: Integer;
1329 begin
1330   if Assigned(fPrinter) then
1331     result := fPrinter.PaperSize.Height
1332   else
1333   if fPaperHeight<=0 then
1334     result :=  round(YDPI * 842 / 72)   // default to A4 paper
1335   else
1336     result := fPaperHeight;
1337 end;
1338 
TPrinterCanvas.GetPaperWidthnull1339 function TPrinterCanvas.GetPaperWidth: Integer;
1340 begin
1341   if Assigned(fPrinter) then
1342     result := fPrinter.PaperSize.Width
1343   else
1344   if fPaperWidth<=0 then
1345     result := round(XDPI * 595 / 72)    // default to A4 paper
1346   else
1347     result := fPaperWidth;
1348 end;
1349 
1350 procedure TPrinterCanvas.SetPaperHeight(const AValue: Integer);
1351 begin
1352   fPaperHeight := AValue;
1353 end;
1354 
1355 procedure TPrinterCanvas.SetPaperWidth(const AValue: Integer);
1356 begin
1357   fPaperWidth := AValue;
1358 end;
1359 
1360 procedure TPrinterCanvas.SetTitle(const AValue: string);
1361 begin
1362   if Assigned(fPrinter) then
1363     fPrinter.Title:=aValue
1364   else
1365     fTitle:=aValue;
1366 end;
1367 
HasDefaultMarginsnull1368 function TPrinterCanvas.HasDefaultMargins: boolean;
1369 begin
1370   result := (FLeftMargin=0) and (FRightMargin=0) and
1371             (FTopMargin=0) and (FBottomMargin=0);
1372 end;
1373 
1374 procedure TPrinterCanvas.SetXDPI(const AValue: Integer);
1375 begin
1376   fXDPI := AValue;
1377 end;
1378 
1379 procedure TPrinterCanvas.SetYDPI(const AValue: Integer);
1380 begin
1381   fYDPI := AValue;
1382 end;
1383 
1384 constructor TPrinterCanvas.Create(APrinter: TPrinter);
1385 begin
1386   inherited Create;
1387   fPrinter:=aPrinter;
1388 end;
1389 
1390 procedure TPrinterCanvas.Changing;
1391 begin
1392   if Assigned(fPrinter)  then
1393     fPrinter.CheckPrinting(True);
1394   inherited Changing;
1395 end;
1396 
1397 procedure TPrinterCanvas.BeginDoc;
1398 begin
1399   fPageNum:=1;
1400 end;
1401 
1402 procedure TPrinterCanvas.NewPage;
1403 begin
1404   Inc(fPageNum);
1405   BeginPage;
1406 end;
1407 
1408 procedure TPrinterCanvas.BeginPage;
1409 begin
1410 
1411 end;
1412 
1413 procedure TPrinterCanvas.EndPage;
1414 begin
1415 
1416 end;
1417 
1418 procedure TPrinterCanvas.EndDoc;
1419 begin
1420   //No special action
1421 end;
1422 
GetLeftMarginnull1423 function TPrinterCanvas.GetLeftMargin: Integer;
1424 begin
1425   if (fLeftMargin=0) and (fPrinter<>nil) then
1426     Result:=fPrinter.PaperSize.PaperRect.WorkRect.Left
1427   else
1428     Result:=fLeftMargin;
1429 end;
1430 
TPrinterCanvas.GetTopMarginnull1431 function TPrinterCanvas.GetTopMargin: Integer;
1432 begin
1433   if (fTopMargin=0) and (fPrinter<>nil) then
1434     Result:=fPrinter.PaperSize.PaperRect.WorkRect.Top
1435   else
1436     Result:=fTopMargin;
1437 end;
1438 
TPrinterCanvas.GetBottomMarginnull1439 function TPrinterCanvas.GetBottomMargin: Integer;
1440 begin
1441   if (fBottomMargin=0) and (fPrinter<>nil) then
1442   begin
1443     with fPrinter.Papersize.PaperRect do
1444       Result := PhysicalRect.Bottom-WorkRect.Bottom;
1445   end else
1446     Result := fBottomMargin;
1447 end;
1448 
TPrinterCanvas.GetRightMarginnull1449 function TPrinterCanvas.GetRightMargin: Integer;
1450 var
1451   PR: TPaperRect;
1452 begin
1453   if (fRightMargin=0) and (fPrinter<>nil) then
1454   begin
1455     PR:=fPrinter.Papersize.PaperRect;
1456     Result := PR.PhysicalRect.Right-PR.WorkRect.Right;
1457   end else
1458     Result := fRightMargin;
1459 end;
1460 
1461 
1462 procedure doFreePrinter;
1463 begin
1464   if Assigned(Printer) then
1465     Printer.Free;
1466   Printer := nil;
1467 end;
1468 
1469 initialization
1470   RegisterInterfaceFinalizationHandler(@doFreePrinter);
1471 
1472 end.
1473