home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 December
/
Chip_2001-12_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d3456
/
POWERPDF.ZIP
/
PowerPdf
/
PdfDoc.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2001-09-15
|
77KB
|
2,791 lines
{*
* << P o w e r P d f >> -- PdfDoc.pas
*
* Copyright (c) 1999-2001 Takezou. <takeshi_kanno@est.hi-ho.ne.jp>
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License, or any
* later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
* details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library.
*
* 2000.09.10 create.
* 2001.06.30 move FloatToStrR method to PdfTypes.pas.
* 2001.07.01 implemented text annotation.
* 2001.07.10 move TPDF_STR_TBL and TPDF_INT_TBL defination to top (for BCB).
* 2001.07.21 changed TPdfDictionaryWrapper's properties(Data and HasData) to
* public.
* 2001.07.28 fixed bug of TPdfCanvas.SetPage.
* 2001.08.01 added TPdfCatalog.PageLayout
* 2001.08.09 moved some constans from PdfTypes.pas.
* 2001.08.12 changed the implementation of outlines.
* 2001.08.12 changed the implementation of annotation.
* 2001.08.18 added GetNextWord routine.
* 2001.08.18 changed the parameter of MoveToTextPoint routine.
* 2001.08.20 added Text utility routines.
* 2001.08.20 added Leading property to TPdfCanvasAttribute.
* 2001.08.22 change the method name MesureText to MeasureText(Spelling mistake :-)
* 2001.08.26 changed some definations and methods to work with kylix.
* 2001.09.01 changed the implementation of the image.
* 2001.09.08 added OpenAction function.
* change AddAnnotation method to CreateAnnotation.
* 2001.09.13 added ViewerPreference functions.
*}
unit PdfDoc;
interface
// if use "FlateDecode" compression, comment out the next line.
// (this unit and PdfTypes.pas)
{$DEFINE NOZLIB}
uses
SysUtils, Classes, PdfTypes
{$IFDEF LINUX}
, Types
{$ELSE}
, Windows
{$ENDIF}
;
const
POWER_PDF_VERSION_TEXT = 'PowerPdf version 0.9';
{*
* PreDefined page size
*}
PDF_PAGE_WIDTH_A4 = 596;
PDF_PAGE_HEIGHT_A4 = 842;
{*
* Dafault page size.
*}
PDF_DEFAULT_PAGE_WIDTH = PDF_PAGE_WIDTH_A4;
PDF_DEFAULT_PAGE_HEIGHT = PDF_PAGE_HEIGHT_A4;
{*
* collection of flags defining various characteristics of the font.
*}
PDF_FONT_FIXED_WIDTH = 1;
PDF_FONT_SERIF = 2;
PDF_FONT_SYMBOLIC = 4;
PDF_FONT_SCRIPT = 8;
// Reserved = 16
PDF_FONT_STD_CHARSET = 32;
PDF_FONT_ITALIC = 64;
// Reserved = 128
// Reserved = 256
// Reserved = 512
// Reserved = 1024
// Reserved = 2048
// Reserved = 4096
// Reserved = 8192
// Reserved = 16384
// Reserved = 32768
PDF_FONT_ALL_CAP = 65536;
PDF_FONT_SMALL_CAP = 131072;
PDF_FONT_FOURCE_BOLD = 262144;
PDF_DEFAULT_FONT = 'Arial';
PDF_DEFAULT_FONT_SIZE = 10;
PDF_MIN_HORIZONTALSCALING = 10;
PDF_MAX_HORIZONTALSCALING = 300;
PDF_MAX_WORDSPACE = 300;
PDF_MIN_CHARSPACE = -30;
PDF_MAX_CHARSPACE = 300;
PDF_MAX_FONTSIZE = 300;
PDF_MAX_ZOOMSIZE = 10;
PDF_MAX_LEADING = 300;
PDF_PAGE_LAYOUT_NAMES: array[0..3] of string = ('SinglePage',
'OneColumn',
'TwoColumnLeft',
'TwoColumnRight');
PDF_PAGE_MODE_NAMES: array[0..3] of string = ('UseNone',
'UseOutlines',
'UseThumbs',
'FullScreen');
PDF_ANNOTATION_TYPE_NAMES: array[0..12] of string = ('Text',
'Link',
'Sound',
'FreeText',
'Stamp',
'Square',
'Circle',
'StrikeOut',
'Highlight',
'Underline',
'Ink',
'FileAttachment',
'Popup');
PDF_DESTINATION_TYPE_NAMES: array[0..7] of string = ('XYZ',
'Fit',
'FitH',
'FitV',
'FitR',
'FitB',
'FitBH',
'FitBV');
type
{*
* The pagemode determines how the document should appear when opened.
*}
TPdfPageMode = (pmUseNone,
pmUseOutlines,
pmUseThumbs,
pmFullScreen);
{*
* The line cap style specifies the shape to be used at the ends of open
* subpaths when they are stroked.
*}
TLineCapStyle = (lcButt_End,
lcRound_End,
lcProjectingSquareEnd);
{*
* The line join style specifies the shape to be used at the corners of paths
* that are stroked.
*}
TLineJoinStyle = (ljMiterJoin,
ljRoundJoin,
ljBevelJoin);
{*
* The text rendering mode determines whether text is stroked, filled, or used
* as a clipping path.
*}
TTextRenderingMode = (trFill,
trStroke,
trFillThenStroke,
trInvisible,
trFillClipping,
trStrokeClipping,
trFillStrokeClipping,
trClipping);
{*
* The annotation types determines the valid annotation subtype of TPdfDoc.
*}
TPdfAnnotationSubType = (asTextNotes,
asLink);
{*
* The TPdfDestinationType determines default user space coordinate system of
* Explicit destinations.
*}
TPdfDestinationType = (dtXYZ,
dtFit,
dtFitH,
dtFitV,
dtFitR,
dtFitB,
dtFitBH,
dtFitBV);
{*
* TPdfPageLayout specifying the page layout to be used when the document is
* opened:
*}
TPdfPageLayout = (plSinglePage,
plOneColumn,
plTwoColumnLeft,
plTwoColumnRight);
TPdfViewerPreference = (vpHideToolbar,
vpHideMenubar,
vpHideWindowUI,
vpFitWindow,
vpCenterWindow);
TPdfViewerPreferences = set of TPdfViewerPreference;
{$IFDEF NOZLIB}
TPdfCompressionMethod = (cmNone);
{$ELSE}
TPdfCompressionMethod = (cmNone, cmFlateDecode);
{$ENDIF}
TPdfColor = -$7FFFFFFF-1..$7FFFFFFF;
TXObjectID = integer;
TPDF_STR_TBL = record
KEY: string;
VAL: string;
end;
TPDF_INT_TBL = record
KEY: string;
VAL: integer;
end;
TPdfHeader = class(TObject)
protected
procedure WriteToStream(const AStream: TStream);
end;
TPdfTrailer = class(TObject)
private
FAttributes: TPdfDictionary;
FXrefAddress: integer;
protected
procedure WriteToStream(const AStream: TStream);
public
constructor Create(AObjectMgr: TPdfObjectMgr);
destructor Destroy; override;
property XrefAddress: integer read FXrefAddress write FXrefAddress;
property Attributes: TPdfDictionary read FAttributes;
end;
TPdfXrefEntry = class(TObject)
private
FEntryType: string;
FByteOffset: integer;
FGenerationNumber: integer;
FValue: TPdfObject;
function GetAsString: string;
public
constructor Create(AValue: TPdfObject);
destructor Destroy; override;
property EntryType: string read FEntryType write FEntryType;
property ByteOffset: integer read FByteOffSet write FByteOffset;
property GenerationNumber: integer
read FGenerationNumber write FGenerationNumber;
property AsString: string read GetAsString;
property Value: TPdfObject read FValue;
end;
TPdfXref = class(TPdfObjectMgr)
private
FXrefEntries: TList;
function GetItem(ObjectID: integer): TPdfXrefEntry;
function GetItemCount: integer;
protected
procedure WriteToStream(const AStream: TStream);
public
constructor Create;
destructor Destroy; override;
procedure AddObject(AObject: TPdfObject); override;
function GetObject(ObjectID: integer): TPdfObject; override;
property Items[ObjectID: integer]: TPdfXrefEntry read GetItem;
property ItemCount: integer read GetItemCount;
end;
TPdfCanvas = class;
TPdfInfo = class;
TPdfCatalog = class;
TPdfFont = class;
TPdfDestination = class;
// TPdfLink = class;
TPdfOutlineEntry = class;
TPdfOutlineRoot = class;
TAbstractPReport = class(TComponent);
TPdfDoc = class(TObject)
private
FRoot: TPdfCatalog;
FCurrentPages: TPdfDictionary;
FCanvas: TPdfCanvas;
FHeader: TPdfHeader;
FTrailer: TPdfTrailer;
FXref: TPdfXref;
FInfo: TPdfInfo;
FHasDoc: boolean;
FFontList: TList;
FObjectList: TList;
FOutlineRoot: TPdfOutlineRoot;
FXObjectList: TPdfArray;
FDefaultPageWidth: Word;
FDefaultPageHeight: Word;
FCompressionMethod: TPdfCompressionMethod;
FUseOutlines: boolean;
function GetCanvas: TPdfCanvas;
function GetInfo: TPdfInfo;
function GetRoot: TPdfCatalog;
function GetOutlineRoot: TPdfOutlineRoot;
protected
procedure CreateInfo;
procedure CreateOutlines;
function CreateCatalog: TPdfDictionary;
function CreateFont(FontName: string): TPdfFont;
function CreatePages(Parent: TPdfDictionary): TPdfDictionary;
public
procedure RegisterXObject(AObject: TPdfXObject; AName: string);
constructor Create;
destructor Destroy; override;
procedure NewDoc;
procedure FreeDoc;
procedure AddPage;
procedure AddXObject(AName: string; AXObject: TPdfXObject);
procedure SaveToStream(AStream: TStream);
procedure SetVirtualMode;
function GetFont(FontName: string): TPdfFont;
function GetXObject(AName: string): TPdfXObject;
function CreateAnnotation(AType: TPdfAnnotationSubType; ARect: TPdfRect): TPdfDictionary;
function CreateDestination: TPdfDestination;
property HasDoc: boolean read FHasDoc;
property Canvas: TPdfCanvas read GetCanvas;
property Info: TPdfInfo read GetInfo;
property Root: TPdfCatalog read GetRoot;
property OutlineRoot: TPdfOutlineRoot read GetOutlineRoot;
property DefaultPageWidth: word read FDefaultPageWidth write FDefaultPageWidth;
property DefaultPageHeight: word read FDefaultPageHeight write FDefaultPageHeight;
property CompressionMethod: TPdfCompressionMethod
read FCompressionMethod write FCompressionMethod;
property UseOutlines: boolean read FUseoutlines write FUseoutlines;
end;
TPdfCanvasAttribute = class(TObject)
private
FWordSpace: Single;
FCharSpace: Single;
FFontSize: Single;
FFont: TPdfFont;
FLeading: Single;
FHorizontalScaling: Word;
procedure SetWordSpace(Value: Single);
procedure SetCharSpace(Value: Single);
procedure SetFontSize(Value: Single);
procedure SetHorizontalScaling(Value: Word);
procedure SetLeading(Value: Single);
public
function TextWidth(Text: string): Single;
function MeasureText(Text: string; Width: Single): integer;
property WordSpace: Single read FWordSpace write SetWordSpace;
property CharSpace: Single read FCharSpace write SetCharSpace;
property HorizontalScaling: Word read FHorizontalScaling
write SetHorizontalScaling;
property Leading: Single read FLeading write SetLeading;
property FontSize: Single read FFontSize write SetFontSize;
property Font: TPdfFont read FFont write FFont;
end;
TPdfCanvas = class(TObject)
private
FContents: TPdfStream;
FPage: TPdfDictionary;
FPdfDoc: TPdfDoc;
FAttr: TPdfCanvasAttribute;
FIsVirtual: boolean;
procedure SetPageWidth(AValue: integer);
procedure SetPageHeight(AValue: integer);
procedure WriteString(S: string);
function GetDoc: TPdfDoc;
function GetPage: TPdfDictionary;
function GetPageWidth: Integer;
function GetPageHeight: Integer;
function GetColorStr(Color: TPdfColor): string;
protected
public
constructor Create(APdfDoc: TPdfDoc);
destructor Destroy; override;
{* Special Graphics State *}
procedure GSave; { q }
procedure GRestore; { Q }
procedure Concat(a, b, c, d, e, f: Single); { cm }
{* General Graphics State *}
procedure SetFlat(flatness: Byte); { i }
procedure SetLineCap(linecap: TLineCapStyle); { J }
procedure SetDash(aarray: array of Byte; phase: Byte); { d }
procedure SetLineJoin(linejoin: TLineJoinStyle); { j }
procedure SetLineWidth(linewidth: Single); { w }
procedure SetMiterLimit(miterlimit: Byte); { M }
{* Paths *}
procedure MoveTo(x, y: Single); { m }
procedure LineTo(x, y: Single); { l }
procedure CurveToC(x1, y1, x2, y2, x3, y3: Single); { c }
procedure CurveToV(x2, y2, x3, y3: Single); { v }
procedure CurveToY(x1, y1, x3, y3: Single); { y }
procedure Rectangle(x, y, width, height: Single); { re }
procedure Closepath; { h }
procedure NewPath; { n }
procedure Stroke; { S }
procedure ClosePathStroke; { s }
procedure Fill; { f }
procedure Eofill; { f* }
procedure FillStroke; { B }
procedure ClosepathFillStroke; { b }
procedure EofillStroke; { B* }
procedure ClosepathEofillStroke; { b* }
procedure Clip; { W }
procedure Eoclip; { W* }
{* Test state *}
procedure SetCharSpace(charSpace: Single); { Tc }
procedure SetWordSpace(wordSpace: Single); { Tw }
procedure SetHorizontalScaling(hScaling: Word); { Tz }
procedure SetLeading(leading: Single); { TL }
procedure SetFontAndSize(fontname: string; size: Single); { Tf }
procedure SetTextRenderingMode(mode: TTextRenderingMode); { Tr }
procedure SetTextRise(rise: Word); { Ts }
procedure BeginText; { BT }
procedure EndText; { ET }
procedure MoveTextPoint(tx, ty: Single); { Td }
procedure SetTextMatrix(a, b, c, d, x, y: Word); { Tm }
procedure MoveToNextLine; { T* }
procedure ShowText(s: string); { Tj }
procedure ShowTextNextLine(s: string); { ' }
{* external objects *}
procedure ExecuteXObject(xObject: string); { Do }
{* Device-dependent color space operators *}
procedure SetRGBFillColor(Value: TPdfColor); { rg }
procedure SetRGBStrokeColor(Value: TPdfColor); { RG }
{* utility routines *}
procedure SetPage(APage: TPdfDictionary);
procedure SetFont(AName: string; ASize: Single);
procedure TextOut(X, Y: Single; Text: string);
procedure TextRect(ARect: TPdfRect; Text: string;
Alignment: TPdfAlignment; Clipping: boolean);
procedure MultilineTextRect(ARect: TPdfRect;
Text: string; WordWrap: boolean);
procedure DrawXObject(X, Y, AWidth, AHeight: Single;
AXObjectName: string);
procedure DrawXObjectEx(X, Y, AWidth, AHeight: Single;
ClipX, ClipY, ClipWidth, ClipHeight: Single; AXObjectName: string);
procedure Ellipse(x, y, width, height: Single);
function TextWidth(Text: string): Single;
function MeasureText(Text: string; AWidth: Single): integer;
function GetNextWord(const S: string; var Index: integer): string;
property Attribute: TPdfCanvasAttribute read FAttr;
property Contents: TPdfStream read FContents;
property Page: TPdfDictionary read GetPage;
property Doc: TPdfDoc read GetDoc;
property PageWidth: integer read GetPageWidth write SetPageWidth;
property PageHeight: integer read GetPageHeight write SetPageHeight;
end;
TPdfDictionaryWrapper = class(TPersistent)
private
FData: TPdfDictionary;
function GetHasData: boolean;
protected
procedure SetData(AData: TPdfDictionary); virtual;
public
property Data: TPdfDictionary read FData write SetData;
property HasData: boolean read GetHasData;
end;
TPdfInfo = class(TPdfDictionaryWrapper)
private
function GetAuthor: string;
procedure SetAuthor(Value: string);
function GetCreationDate: TDateTime;
procedure SetCreationDate(Value: TDateTime);
function GetCreator: string;
procedure SetCreator(Value: string);
function GetKeywords: string;
procedure SetKeywords(Value: string);
function GetSubject: string;
procedure SetSubject(Value: string);
function GetTitle: string;
procedure SetTitle(Value: string);
function GetModDate: TDateTime;
procedure SetModDate(Value: TDateTime);
public
property Author: string read GetAuthor write SetAuthor;
property CreationDate: TDateTime read GetCreationDate write SetCreationDate;
property Creator: string read GetCreator write SetCreator;
property Keywords: string read GetKeywords write SetKeywords;
property ModDate: TDateTime read GetModDate write SetModDate;
property Subject: string read GetSubject write SetSubject;
property Title: string read GetTitle write SetTitle;
end;
TPdfCatalog = class(TPdfDictionaryWrapper)
private
FOpenAction: TPdfDestination;
procedure SetPageLayout(Value: TPdfPageLayout);
procedure SetPageMode(Value: TPdfPageMode);
procedure SetNonFullScreenPageMode(Value: TPdfPageMode);
procedure SetViewerPreference(Value: TPdfViewerPreferences);
procedure SetPages(APage: TPdfDictionary);
function GetPageLayout: TPdfPageLayout;
function GetPageMode: TPdfPageMode;
function GetNonFullScreenPageMode: TPdfPageMode;
function GetViewerPreference: TPdfViewerPreferences;
function GetPages: TPdfDictionary;
protected
procedure SaveOpenAction;
public
property OpenAction: TPdfDestination read FOpenAction write FOpenAction;
property PageLayout: TPdfPageLayout read GetPageLayout write SetPageLayout;
property NonFullScreenPageMode: TPdfPageMode
read GetNonFullScreenPageMode write SetNonFullScreenPageMode;
property PageMode: TPdfPageMode read GetPageMode write SetPageMode;
property ViewerPreference: TPdfViewerPreferences
read GetViewerPreference write SetViewerPreference;
property Pages: TPdfDictionary read GetPages write SetPages;
end;
TPdfFont = class(TPdfDictionaryWrapper)
private
FName: string;
protected
procedure AddStrElements(ADic: TPdfDictionary; ATable: array of TPDF_STR_TBL);
procedure AddIntElements(ADic: TPdfDictionary; ATable: array of TPDF_INT_TBL);
public
constructor Create(AXref: TPdfXref; AName: string); virtual;
function GetCharWidth(AText: string; APos: integer): integer; virtual;
property Name: string read FName;
end;
TPdfDestination = class(TObject)
private
FDoc: TPdfDoc;
FPage: TPdfDictionary;
FType: TPdfDestinationType;
FValues: array[0..3] of Integer;
FZoom: Single;
FReference: TObject;
procedure SetElement(Index: integer; Value: Integer);
procedure SetZoom(Value: Single);
function GetElement(Index: integer): Integer;
function GetPageWidth: Integer;
function GetPageHeight: Integer;
public
constructor Create(APdfDoc: TPdfDoc);
destructor Destroy; override;
function GetValue: TPdfArray;
property DestinationType: TPdfDestinationType read FType write FType;
property Doc: TPdfDoc read FDoc;
property Left: Integer index 0 read GetElement write SetElement;
property Top: Integer index 1 read GetElement write SetElement;
property Right: Integer index 2 read GetElement write SetElement;
property Bottom: Integer index 3 read GetElement write SetElement;
property PageHeight: Integer read GetPageHeight;
property PageWidth: Integer read GetPageWidth;
property Zoom: Single read FZoom write SetZoom;
property Reference: TObject read FReference write FReference;
end;
TPdfOutlineEntry = class(TPdfDictionaryWrapper)
private
FParent: TPdfOutlineEntry;
FNext: TPdfOutlineEntry;
FPrev: TPdfOutlineEntry;
FFirst: TPdfOutlineEntry;
FLast: TPdfOutlineEntry;
FDest: TPdfDestination;
FDoc: TPdfDoc;
FTitle: string;
FOpened: boolean;
FCount: integer;
FReference: TObject;
protected
constructor CreateEntry(AParent: TPdfOutlineEntry); virtual;
procedure Save; virtual;
public
destructor Destroy; override;
function AddChild: TPdfOutlineEntry;
property Doc: TPdfDoc read FDoc;
property Parent: TPdfOutlineEntry read FParent;
property Next: TPdfOutlineEntry read FNext;
property Prev: TPdfOutlineEntry read FPrev;
property First: TPdfOutlineEntry read FFirst;
property Last: TPdfOutlineEntry read FLast;
property Dest: TPdfDestination read FDest write FDest;
property Title: string read FTitle write FTitle;
property Opened: boolean read FOpened write FOpened;
property Reference: TObject read FReference write FReference;
end;
TPdfOutlineRoot = class(TPdfOutlineEntry)
protected
constructor CreateRoot(ADoc: TPdfDoc); virtual;
public
procedure Save; override;
end;
implementation
{ Utility functions }
// _Pages_AddKids
procedure _Pages_AddKids(AParent: TPdfDictionary; AKid: TPdfDictionary);
var
FKids: TPdfArray;
begin
// adding page object to the parent pages object.
FKids := AParent.PdfArrayByName('Kids');
FKids.AddItem(AKid);
AParent.PdfNumberByName('Count').Value := FKids.ItemCount;
end;
// _Page_GetResources
function _Page_GetResources(APage: TPdfDictionary; AName: string): TPdfDictionary;
var
FResources: TPdfDictionary;
begin
FResources := APage.PdfDictionaryByName('Resources');
Result := FResources.PdfDictionaryByName(AName);
end;
{ TPdfHeader }
// WriteToStream
procedure TPdfHeader.WriteToStream(const AStream: TStream);
begin
_WriteString('%PDF-1.2 '#13#10, AStream);
end;
{ TPdfTrailer }
// WriteToStream
procedure TPdfTrailer.WriteToStream(const AStream: TStream);
begin
_WriteString('trailer' + CRLF, AStream);
FAttributes.WriteToStream(AStream);
_WriteString(CRLF + 'startxref' + CRLF, AStream);
_WriteString(IntToStr(FXrefAddress) + CRLF, AStream);
_WriteString('%%EOF' + CRLF, AStream);
end;
// Create
constructor TPdfTrailer.Create(AObjectMgr: TPdfObjectMgr);
begin
inherited Create;
FAttributes := TPdfDictionary.CreateDictionary(AObjectMgr);
FAttributes.AddItem('Size', TPdfNumber.CreateNumber(0));
end;
// Destroy
destructor TPdfTrailer.Destroy;
begin
FAttributes.Free;
inherited;
end;
{ TPdfXrefEntry }
// Create
constructor TPdfXrefEntry.Create(AValue: TPdfObject);
begin
FByteOffset := -1;
if AValue <> nil then
begin
FEntryType := PDF_IN_USE_ENTRY;
FGenerationNumber := AValue.GenerationNumber;
FValue := AValue;
end
else
begin
FEntryType := PDF_FREE_ENTRY;
FGenerationNumber := 0;
end;
end;
// Destroy
destructor TPdfXrefEntry.Destroy;
begin
if FEntryType = PDF_IN_USE_ENTRY then
FValue.Free;
inherited;
end;
// GetAsString
function TPdfXrefEntry.GetAsString: string;
function FormatIntToString(Value: integer; Len: integer): string;
var
S: string;
i, j: integer;
begin
Result := '';
if Value < 0 then
S := '0'
else
S := IntToStr(Value);
i := Len - Length(S);
for j := 0 to i - 1 do
Result := Result + '0';
Result := Result + S;
end;
begin
Result := FormatIntToString(FByteOffset, 10) +
' ' +
FormatIntToString(FGenerationNumber, 5) +
' ' +
FEntryType;
end;
{ TPdfXref }
// Create
constructor TPdfXref.Create;
var
RootEntry: TPdfXrefEntry;
begin
FXrefEntries := TList.Create;
RootEntry := TPdfXrefEntry.Create(nil);
RootEntry.GenerationNumber := PDF_MAX_GENERATION_NUM;
FXrefEntries.Add(RootEntry);
end;
// Destroy
destructor TPdfXref.Destroy;
var
i: integer;
begin
for i := 1 to FXrefEntries.Count - 1 do
GetItem(i).Free;
FXrefEntries.Free;
inherited;
end;
// AddObject
procedure TPdfXref.AddObject(AObject: TPdfObject);
var
ObjectNumber: integer;
XrefEntry: TPdfXrefEntry;
begin
// register object to xref table, and set objectnumber.
if AObject.ObjectType <> otDirectObject then
raise EPdfInvalidOperation.Create('AddObject --wrong object type.');
XrefEntry := TPdfXrefEntry.Create(AObject);
ObjectNumber := FXrefEntries.Add(XrefEntry);
AObject.SetObjectNumber(ObjectNumber);
end;
// GetItem
function TPdfXref.GetItem(ObjectID: integer): TPdfXrefEntry;
begin
Result := TPdfXrefEntry(FXrefEntries.Items[ObjectID]);
end;
// GetItemCount
function TPdfXref.GetItemCount: integer;
begin
Result := FXrefEntries.Count;
end;
// GetObject
function TPdfXref.GetObject(ObjectID: integer): TPdfObject;
begin
Result := GetItem(ObjectID).Value;
end;
// WriteToStream
procedure TPdfXref.WriteToStream(const AStream: TStream);
var
i: integer;
S: string;
Count: integer;
begin
Count := FXrefEntries.Count;
S := 'xref' +
CRLF +
'0 ' +
IntToStr(Count) +
CRLF;
for i := 0 to Count - 1 do
S := S + Items[i].AsString + CRLF;
_WriteString(S, AStream);
end;
{ TPdfDoc }
// Create
constructor TPdfDoc.Create;
begin
inherited Create;
FHasDoc := false;
FCanvas := TPdfCanvas.Create(Self);
FDefaultPageWidth := PDF_DEFAULT_PAGE_WIDTH;
FDefaultPageHeight := PDF_DEFAULT_PAGE_HEIGHT;
FInfo := nil;
FRoot := nil;
end;
// GetCanvas
function TPdfDoc.GetCanvas: TPdfCanvas;
begin
if not HasDoc then
raise EPdfInvalidOperation.Create('GetCanvas --Document is null');
Result := FCanvas;
end;
// GetInfo
function TPdfDoc.GetInfo: TPdfInfo;
begin
if not HasDoc then
raise EPdfInvalidOperation.Create('GetInfo --this method can not use this state..');
if FInfo = nil then
CreateInfo;
Result := FInfo;
end;
// GetRoot
function TPdfDoc.GetRoot: TPdfCatalog;
begin
if not HasDoc then
raise EPdfInvalidOperation.Create('GetRoot --this method can not use this state..');
Result := FRoot;
end;
// GetOutlineRoot
function TPdfDoc.GetOutlineRoot: TPdfOutlineRoot;
begin
if not HasDoc then
raise EPdfInvalidOperation.Create('GetOutlineRoot --document is null..');
if not UseOutlines then
raise EPdfInvalidOperation.Create('GetOutlineRoot --not use outline mode..');
Result := FOutlineRoot;
end;
// Destroy
destructor TPdfDoc.Destroy;
begin
FreeDoc;
FCanvas.Free;
inherited;
end;
// CreateCatalog
function TPdfDoc.CreateCatalog: TPdfDictionary;
begin
// create catalog object and register to xref.
Result := TPdfDictionary.CreateDictionary(FXref);
FXref.AddObject(Result);
Result.AddItem('Type', TPdfName.CreateName('Catalog'));
FTrailer.Attributes.AddItem('Root', Result);
end;
// CreateFont
function TPdfDoc.CreateFont(FontName: string): TPdfFont;
var
PdfFont: TPdfFont;
begin
// create new font (not regist to xref -- because font object registed by
// TPdfFont).
PdfFont := TPdfFont(FindClass(FontName).Create);
if PdfFont = nil then
raise Exception.Create('CreateFont --InvalidFontName:' + FontName);
Result := PdfFont.Create(FXref, FontName);
Result.Data.AddItem('Name',
TPdfName.CreateName('F' + IntToStr(FFontList.Count)));
FFontList.Add(Result);
end;
// RegisterXObject
procedure TPdfDoc.RegisterXObject(AObject: TPdfXObject; AName: string);
begin
// check object and register it.
if AObject = nil then
raise EPdfInvalidValue.Create('RegisterXObject --AObject is null');
if _GetTypeOf(AObject.Attributes) <> 'XObject' then
raise EPdfInvalidValue.Create('RegisterXObject --not XObject');
if AObject.ObjectType <> otIndirectObject then
FXref.AddObject(AObject);
if AObject.Attributes.ValueByName('Name') = nil then
begin
if GetXObject(AName) <> nil then
raise EPdfInvalidValue.Createfmt('RegisterXObject --dupulicate name: %s', [AName]);
FXObjectList.AddItem(AObject);
AObject.Attributes.AddItem('Name', TPdfName.CreateName(AName));
end;
end;
// CreateInfo
procedure TPdfDoc.CreateInfo;
var
FInfoDictionary: TPdfDictionary;
begin
FInfoDictionary := TPdfDictionary.CreateDictionary(FXref);
FXref.AddObject(FInfoDictionary);
FInfoDictionary.AddItem('Producer', TPdfText.CreateText(POWER_PDF_VERSION_TEXT));
FTrailer.Attributes.AddItem('Info', FInfoDictionary);
FInfo := TPdfInfo.Create;
FInfo.SetData(FInfoDictionary);
FObjectList.Add(FInfo);
end;
// CreatePages
function TPdfDoc.CreatePages(Parent: TPdfDictionary): TPdfDictionary;
begin
// create pages object and register to xref.
result := TPdfDictionary.CreateDictionary(FXref);
FXref.AddObject(Result);
with Result do
begin
AddItem('Type', TPdfName.CreateName('Pages'));
AddItem('Kids', TPdfArray.CreateArray(FXref));
AddItem('Count', TPdfNumber.CreateNumber(0));
end;
if (Parent <> nil) and (_GetTypeOf(Parent) = 'Pages') then
_Pages_AddKids(Parent, Result)
else
FRoot.Pages := Result;
end;
// CreateOutlines
procedure TPdfDoc.CreateOutlines;
begin
FOutlineRoot := TPdfOutlineRoot.CreateRoot(Self);
FRoot.Data.AddItem('Outlines', FOutlineRoot.Data);
end;
// GetFont
function TPdfDoc.GetFont(FontName: string): TPdfFont;
var
FFont: TPdfFont;
i :integer;
begin
if not HasDoc then
raise EPdfInvalidOperation.Create('GetFont --document is null.');
// if specified font exists in fontlist, return it. otherwise, create the font.
Result := nil;
for i := 0 to FFontList.Count - 1 do
begin
FFont := TPdfFont(FFontList.Items[i]);
if FFont.Name = FontName then
begin
Result := FFont;
Break;
end;
end;
if Result = nil then
Result := CreateFont(FontName);
end;
// GetXObject
function TPdfDoc.GetXObject(AName: string): TPdfXObject;
var
FXObject: TPdfXObject;
i :integer;
begin
// return the XObject which name is muched with specified name.
Result := nil;
for i := 0 to FXObjectList.ItemCount - 1 do
begin
FXObject := TPdfXObject(FXObjectList.Items[i]);
if TPdfName(FXObject.Attributes.ValueByName('Name')).Value = AName then
begin
Result := FXObject;
Break;
end;
end;
end;
// CreateAnnotation
function TPdfDoc.CreateAnnotation(AType: TPdfAnnotationSubType; ARect: TPdfRect): TPdfDictionary;
var
FAnnotation: TPdfDictionary;
FArray: TPdfArray;
FPage: TPdfDictionary;
begin
if not HasDoc then
raise EPdfInvalidOperation.Create('AddAnotation --document is null.');
// create new annotation and set the properties.
FAnnotation := TPdfDictionary.CreateDictionary(FXref);
FXref.AddObject(FAnnotation);
with FAnnotation do
begin
AddItem('Type', TPdfName.CreateName('Annot'));
AddItem('Subtype', TPdfName.CreateName(PDF_ANNOTATION_TYPE_NAMES[ord(AType)]));
FArray := TPdfArray.CreateArray(nil);
with FArray, ARect do
begin
AddItem(TPdfReal.CreateReal(Left));
AddItem(TPdfReal.CreateReal(Top));
AddItem(TPdfReal.CreateReal(Right));
AddItem(TPdfReal.CreateReal(Bottom));
end;
AddItem('Rect', FArray);
end;
// adding annotation to the current page
FPage := FCanvas.Page;
FArray := FPage.PdfArrayByName('Annots');
if FArray = nil then
begin
FArray := TPdfArray.CreateArray(nil);
FPage.AddItem('Annots', FArray);
end;
FArray.AddItem(FAnnotation);
Result := FAnnotation;
end;
// CreateDestination
function TPdfDoc.CreateDestination: TPdfDestination;
begin
Result := TPdfDestination.Create(Self);
FObjectList.Add(Result);
end;
// NewDoc
procedure TPdfDoc.NewDoc;
begin
{*
* create new document.
*}
FreeDoc;
FXref := TPdfXref.Create;
FHeader := TPdfHeader.Create;
FTrailer := TPdfTrailer.Create(FXref);
FFontList := TList.Create;
FXObjectList := TPdfArray.CreateArray(FXref);
FObjectList := TList.Create;
FRoot := TPdfCatalog.Create;
FRoot.SetData(CreateCatalog);
FObjectList.Add(FRoot);
if UseOutlines then
CreateOutlines;
CreateInfo;
FInfo.CreationDate := now;
FCurrentPages := CreatePages(nil);
FRoot.SetPages(FCurrentPages);
FHasDoc := true;
end;
// AddXObject
procedure TPdfDoc.AddXObject(AName: string; AXObject: TPdfXObject);
begin
if GetXObject(AName) <> nil then
raise Exception.CreateFmt('AddImage --the image named %s is already exists..', [AName]);
// check whether AImage is valid PdfImage or not.
if (AXObject = nil) or (AXObject.Attributes = nil) or
(_GetTypeOf(AXObject.Attributes) <> 'XObject') or
(AXObject.Attributes.PdfNameByName('Subtype').Value <> 'Image') then
raise Exception.Create('AddImage --the image is not valid TPdfImage..');
FXref.AddObject(AXObject);
RegisterXObject(AXObject, AName);
end;
// AddPage
procedure TPdfDoc.AddPage;
var
FPage: TPdfDictionary;
FMediaBox: TPdfArray;
FContents: TPdfStream;
FResources: TPdfDictionary;
FProcSet: TPdfArray;
FFontArray: TPdfDictionary;
FXObjectArray: TPdfDictionary;
{$IFNDEF NOZLIB}
FFilter: TPdfArray;
{$ENDIF}
begin
if FCurrentPages = nil then
raise EPdfInvalidOperation.Create('AddPage --current pages null.');
// create new page object and add it to the current pages object.
FPage := TPdfDictionary.CreateDictionary(FXref);
FXref.AddObject(FPage);
_Pages_AddKids(FCurrentPages, FPage);
FPage.AddItem('Type', TPdfName.CreateName('Page'));
FPage.AddItem('Parent', FCurrentPages);
FMediaBox := TPdfArray.CreateArray(FXref);
with FMediabox do
begin
AddItem(TPdfNumber.CreateNumber(0));
AddItem(TPdfNumber.CreateNumber(0));
AddItem(TPdfNumber.CreateNumber(DefaultPageWidth));
AddItem(TPdfNumber.CreateNumber(DefaultPageHeight));
end;
FPage.AddItem('MediaBox', FMediaBox);
FResources := TPdfDictionary.CreateDictionary(FXref);
FPage.AddItem('Resources', FResources);
FFontArray := TPdfDictionary.CreateDictionary(FXref);
FResources.AddItem('Font', FFontArray);
FXObjectArray := TPdfDictionary.CreateDictionary(FXref);
FResources.AddItem('XObject', FXObjectArray);
FProcSet := TPdfArray.CreateArray(FXref);
with FProcSet do
begin
AddItem(TPdfName.CreateName('PDF'));
AddItem(TPdfName.CreateName('Text'));
AddItem(TPdfName.CreateName('ImageC'));
end;
FResources.AddItem('ProcSet', FProcSet);
FContents := TPdfStream.CreateStream(FXref);
FXref.AddObject(FContents);
{$IFNDEF NOZLIB}
FFilter := FContents.Attributes.PdfArrayByName('Filter');
if FCompressionMethod = cmFlateDecode then
FFilter.AddItem(TPdfName.CreateName('FlateDecode'));
{$ENDIF}
FPage.AddItem('Contents', FContents);
FCanvas.SetPage(FPage);
end;
// FreeDoc
procedure TPdfDoc.FreeDoc;
var
i: integer;
begin
if FHasDoc then
begin
FXObjectList.Free;
for i := FFontList.Count - 1 downto 0 do
TObject(FFontList.Items[i]).Free;
FFontList.Free;
for i := FObjectList.Count - 1 downto 0 do
TObject(FObjectList.Items[i]).Free;
FObjectList.Free;
FXref.Free;
FHeader.Free;
FTrailer.Free;
FInfo := nil;
FRoot := nil;
FOutlineRoot := nil;
FHasDoc := false;
end;
end;
// SaveToStream
procedure TPdfDoc.SaveToStream(AStream: TStream);
var
i: integer;
Pos: integer;
PdfNumber: TPdfNumber;
begin
if not HasDoc or (FCanvas.Page = nil) then
raise EPdfInvalidOperation.Create('SaveToStream --there is no document to save.');
// write all objects to specified stream.
FInfo.ModDate := Now;
FRoot.SaveOpenAction;
// saving outline tree.
if UseOutlines then
FOutlineRoot.Save;
AStream.Position := 0;
FHeader.WriteToStream(AStream);
for i := 1 to FXref.ItemCount - 1 do
begin
Pos := AStream.Position;
FXref.Items[i].Value.WriteValueToStream(AStream);
FXref.Items[i].ByteOffset := Pos;
end;
FTrailer.XrefAddress := AStream.Position;
FXref.WriteToStream(AStream);
PdfNumber := FTrailer.Attributes.PdfNumberByName('Size');
PdfNumber.Value := FXref.ItemCount;
FTrailer.WriteToStream(AStream);
end;
// SetVirtualMode
procedure TPdfDoc.SetVirtualMode;
begin
NewDoc;
AddPage;
FCanvas.FIsVirtual := true;
end;
{ TPdfCanvasAttribute }
// SetWordSpace
procedure TPdfCanvasAttribute.SetWordSpace(Value: Single);
begin
if Value < 0 then
raise EPdfInvalidValue.Create('SetWordSpace --invalid word space');
if Value <> FWordSpace then
FWordSpace := Value;
end;
// SetCharSpace
procedure TPdfCanvasAttribute.SetCharSpace(Value: Single);
begin
if (Value < PDF_MIN_CHARSPACE) or (VALUE > PDF_MAX_CHARSPACE) then
raise EPdfInvalidValue.Create('SetCharSpace --invalid char space');
if Value <> FCharSpace then
FCharSpace := Value;
end;
// SetFontSize
procedure TPdfCanvasAttribute.SetFontSize(Value: Single);
begin
if (Value < 0) or (Value > PDF_MAX_FONTSIZE) then
raise EPdfInvalidValue.Create('SetCharSpace --invalid font size');
if Value <> FFontSize then
FFontSize := Value;
end;
// SetHorizontalScaling
procedure TPdfCanvasAttribute.SetHorizontalScaling(Value: Word);
begin
if (Value < PDF_MIN_HORIZONTALSCALING) or
(Value > PDF_MAX_HORIZONTALSCALING) then
raise EPdfInvalidValue.Create('SetHorizontalScaling --invalid font size');
if Value <> FHorizontalScaling then
FHorizontalScaling := Value;
end;
// SetLeading
procedure TPdfCanvasAttribute.SetLeading(Value: Single);
begin
if (Value < 0) or (Value > PDF_MAX_LEADING) then
raise EPdfInvalidValue.Create('SetLeading --invalid font size');
if Value <> FLeading then
FLeading := Value;
end;
// TextWidth
function TPdfCanvasAttribute.TextWidth(Text: string): Single;
var
i: integer;
ch: char;
tmpWidth: Single;
begin
Result := 0;
// calculate width of specified text from current attributes
for i := 1 to Length(Text) do
begin
ch := Text[i];
tmpWidth := FFont.GetCharWidth(Text, i) * FFontSize / 1000;
if FHorizontalScaling <> 100 then
tmpWidth := tmpWidth * FHorizontalScaling / 100;
if tmpWidth > 0 then
tmpWidth := tmpWidth + FCharSpace
else
tmpWidth := 0;
if (ch = ' ') and (FWordSpace > 0) and (i <> Length(Text)) then
tmpWidth := tmpWidth + FWordSpace;
Result := Result + tmpWidth;
end;
Result := Result - FCharSpace;
end;
// MeasureText
function TPdfCanvasAttribute.MeasureText(Text: string; Width: Single): integer;
var
i: integer;
ch: char;
tmpWidth: Single;
tmpTotalWidth: Single;
begin
Result := 0;
tmpTotalWidth := 0;
// calculate number of charactor contain in the specified width.
for i := 1 to Length(Text) do
begin
ch := Text[i];
tmpWidth := FFont.GetCharWidth(Text, i) * FFontSize / 1000;
if FHorizontalScaling <> 100 then
tmpWidth := tmpWidth * FHorizontalScaling / 100;
if tmpWidth > 0 then
tmpWidth := tmpWidth + FCharSpace
else
tmpWidth := 0;
if (ch = ' ') and (FWordSpace > 0) and (i <> Length(Text)) then
tmpWidth := tmpWidth + FWordSpace;
tmpTotalWidth := tmpTotalWidth + tmpWidth;
if tmpTotalWidth > Width then
Break;
inc(Result);
end;
end;
{ TPdfCanvas }
// Create
constructor TPdfCanvas.Create(APdfDoc: TPdfDoc);
begin
FPdfDoc := APdfDoc;
FPage := nil;
FContents := nil;
FAttr := TPdfCanvasAttribute.Create;
FIsVirtual := false;
end;
// Destroy
destructor TPdfCanvas.Destroy;
begin
FAttr.Free;
inherited;
end;
// SetPageWidth
procedure TPdfCanvas.SetPageWidth(AValue: integer);
var
FMediaBox: TPdfArray;
begin
FMediaBox := TPdfArray(Page.ValueByName('MediaBox'));
if FMediaBox <> nil then
TPdfNumber(FMediaBox.Items[2]).Value := AValue
else
EPdfInvalidOperation.Create('Can not chenge width of this page..');
end;
// SetPageHeight
procedure TPdfCanvas.SetPageHeight(AValue: integer);
var
FMediaBox: TPdfArray;
begin
FMediaBox := TPdfArray(Page.ValueByName('MediaBox'));
if FMediaBox <> nil then
TPdfNumber(FMediaBox.Items[3]).Value := AValue
else
EPdfInvalidOperation.Create('Can not chenge width of this page..');
end;
// WriteString
procedure TPdfCanvas.WriteString(S: string);
begin
if (not FIsVirtual) and (FContents <> nil) then
_WriteString(S, FContents.Stream);
end;
// GetPage
function TPdfCanvas.GetPage: TPdfDictionary;
begin
if FPage <> nil then
result := FPage
else
raise EPdfInvalidOperation.Create('GetPage --the Page is nil');
end;
// GetPageWidth
function TPdfCanvas.GetPageWidth: Integer;
var
FMediaBox: TPdfArray;
begin
FMediaBox := TPdfArray(Page.ValueByName('MediaBox'));
if FMediaBox <> nil then
result := TPdfNumber(FMediaBox.Items[2]).Value
else
result := FPdfDoc.DefaultPageWidth;
end;
// GetPageHeight
function TPdfCanvas.GetPageHeight: Integer;
var
FMediaBox: TPdfArray;
begin
FMediaBox := TPdfArray(Page.ValueByName('MediaBox'));
if FMediaBox <> nil then
result := TPdfNumber(FMediaBox.Items[3]).Value
else
result := FPdfDoc.DefaultPageHeight;
end;
// GetColorStr
function TPDFCanvas.GetColorStr(Color: TPdfColor): string;
var
X: array[0..3] of Byte;
rgb: integer;
begin
if Color > 0 then
rgb := integer(Color)
else
rgb := 0;
Move(rgb, x[0], 4);
result := _FloatToStrR(X[0] / 255) + ' ' +
_FloatToStrR(X[1] / 255) + ' ' +
_FloatToStrR(X[2] / 255);
end;
// SetPage
procedure TPdfCanvas.SetPage(APage: TPdfDictionary);
procedure GetCurrentFont;
var
AFont: TPdfName;
begin
AFont := Page.PdfNameByName('_Font');
with FAttr do
if AFont <> nil then
begin
Font := FPdfDoc.GetFont(AFont.Value);
FontSize := FPage.PdfNumberByName('_Font_Size').Value;
WordSpace := FPage.PdfRealByName('_Word_Space').Value;
CharSpace := FPage.PdfRealByName('_Char_Space').Value;
HorizontalScaling := FPage.PdfNumberByName('_HScalling').Value;
Leading := FPage.PdfNumberByName('_Leading').Value;
end
else
begin
Font := nil;
SetFont(PDF_DEFAULT_FONT, PDF_DEFAULT_FONT_SIZE);
CharSpace := 0;
WordSpace := 0;
HorizontalScaling := 100;
Leading := 0;
end;
end;
begin
// save current canvas attributes to internal objects.
if FPage <> nil then
with FPage do
begin
AddInternalItem('_Font', TPdfName.CreateName(FAttr.Font.Name));
AddInternalItem('_Font_Size', TPdfReal.CreateReal(FAttr.FontSize));
AddInternalItem('_Word_Space', TPdfReal.CreateReal(FAttr.WordSpace));
AddInternalItem('_Char_Space', TPdfReal.CreateReal(FAttr.CharSpace));
AddInternalItem('_HScalling', TPdfNumber.CreateNumber(FAttr.HorizontalScaling));
AddInternalItem('_Leading', TPdfReal.CreateReal(FAttr.Leading));
end;
FPage := APage;
FContents := TPdfStream(FPage.ValueByName('Contents'));
GetCurrentFont;
end;
// SetFont
procedure TPdfCanvas.SetFont(AName: string; ASize: Single);
var
FFont: TPdfFont;
FFontList: TPdfDictionary;
FFontName: string;
begin
// get font object from pdfdoc object, then find fontlist from page object
// by internal name. if font is not registered, register it to page object.
FFont := FPdfDoc.GetFont(AName);
if (FAttr.Font = FFont) and (FAttr.FontSize = ASize) then Exit;
FFontList := _Page_GetResources(FPage, 'Font');
FFontName := FFont.Data.PdfNameByName('Name').Value;
if FFontList.ValueByName(FFontName) = nil then
FFontList.AddItem(FFontName, FFont.Data);
if FContents <> nil then
SetFontAndSize('/' + FFontName, ASize);
FAttr.Font := FFont;
FAttr.FontSize := ASize;
end;
// TextOut
procedure TPdfCanvas.TextOut(X, Y: Single; Text: string);
begin
BeginText;
MoveTextPoint(X, Y);
ShowText(Text);
EndText;
end;
// TextRect
procedure TPdfCanvas.TextRect(ARect: TPdfRect; Text: string;
Alignment: TPdfAlignment; Clipping: boolean);
var
tmpWidth: Single;
XPos: Single;
begin
// calculate text width.
tmpWidth := TextWidth(Text);
case Alignment of
paCenter: XPos := Round((ARect.Right - ARect.Left - tmpWidth) / 2);
paRightJustify: XPos := ARect.Right - ARect.Left - Round(tmpWidth);
else
XPos := 0;
end;
// clipping client rect if needed.
if Clipping then
begin
GSave;
with ARect do
begin
MoveTo(Left, Top);
LineTo(Left, Bottom);
LineTo(Right, Bottom);
LineTo(Right, Top);
end;
ClosePath;
Clip;
NewPath;
end;
BeginText;
MoveTextPoint(ARect.Left + XPos, ARect.Top - FAttr.FontSize * 0.85);
ShowText(Text);
EndText;
if Clipping then
GRestore;
end;
// MultilineTextRect
procedure TPdfCanvas.MultilineTextRect(ARect: TPdfRect;
Text: string; WordWrap: boolean);
var
i: integer;
S1, S2: string;
XPos, YPos: Single;
tmpXPos: Single;
tmpWidth: Single;
ln: integer;
FourceReturn: boolean;
FText: string;
procedure InternalShowText(S: string; AWidth: Single);
var
i: Integer;
begin
i := MeasureText(S, AWidth);
S := Copy(S, 1, i);
ShowText(S);
end;
begin
YPos := ARect.Top - FAttr.FontSize*0.85;
XPos := ARect.Left;
FText := Text;
BeginText;
MoveTextPoint(XPos, YPos);
i := 1;
S2 := GetNextWord(FText, i);
XPos := XPos + TextWidth(S2);
if (Length(S2) > 0) and (S2[Length(S2)] = ' ') then
XPos := XPos + FAttr.WordSpace;
while i <= Length(FText) do
begin
ln := Length(S2);
if (ln >= 2) and (S2[ln] = #10) and (S2[ln-1] = #13) then
begin
S2 := Copy(S2, 1, ln - 2);
FourceReturn := true;
end
else
FourceReturn := false;
S1 := GetNextWord(FText, i);
tmpWidth := TextWidth(S1);
TmpXPos := XPos + tmpWidth;
if (WordWrap and (TmpXPos > ARect.Right)) or
FourceReturn then
begin
if S2 <> '' then
InternalShowText(S2, ARect.Right - ARect.Left);
S2 := '';
MoveToNextLine;
ARect.Top := ARect.Top - FAttr.Leading;
if ARect.Top < ARect.Bottom + FAttr.FontSize then
Break;
XPos := ARect.Left;
end;
XPos := XPos + tmpWidth;
if (Length(S1) > 0) and (S1[Length(S1)] = ' ') then
XPos := XPos + FAttr.WordSpace;
S2 := S2 + S1;
end;
if S2 <> '' then
InternalShowText(S2, ARect.Right - ARect.Left);
EndText;
end;
// DrawXObject
procedure TPdfCanvas.DrawXObject(X, Y, AWidth, AHeight: Single;
AXObjectName: string);
var
XObject: TPdfXObject;
FXObjectList: TPdfDictionary;
begin
// drawing object must be registered. check object name.
XObject := FPdfDoc.GetXObject(AXObjectName);
if XObject = nil then
raise EPdfInvalidValue.CreateFmt('DrawXObject --XObject not found: %s', [AXObjectName]);
FXObjectList := _Page_GetResources(FPage, 'XObject');
if FXObjectList.ValueByName(AXObjectName) = nil then
FXObjectList.AddItem(AXObjectName, XObject);
GSave;
Concat(AWidth, 0, 0, AHeight, X, Y);
ExecuteXObject(XObject.Attributes.PdfNameByName('Name').Value);
GRestore;
end;
// DrawXObjectEx
procedure TPdfCanvas.DrawXObjectEx(X, Y, AWidth, AHeight: Single;
ClipX, ClipY, ClipWidth, ClipHeight: Single; AXObjectName: string);
var
XObject: TPdfXObject;
FXObjectList: TPdfDictionary;
begin
// drawing object must be registered. check object name.
XObject := FPdfDoc.GetXObject(AXObjectName);
if XObject = nil then
raise EPdfInvalidValue.CreateFmt('DrawXObjectEx --XObject not found: %s', [AXObjectName]);
FXObjectList := _Page_GetResources(FPage, 'XObject');
if FXObjectList.ValueByName(AXObjectName) = nil then
FXObjectList.AddItem(AXObjectName, XObject);
GSave;
Rectangle(ClipX, ClipY, ClipWidth, ClipHeight);
Clip;
NewPath;
Concat(AWidth, 0, 0, AHeight, X, Y);
ExecuteXObject(XObject.Attributes.PdfNameByName('Name').Value);
GRestore;
end;
{* Special Graphics State *}
// GSave
procedure TPdfCanvas.GSave;
begin
WriteString('q'#10);
end;
// GRestore
procedure TPdfCanvas.GRestore;
begin
WriteString('Q'#10);
end;
// Concat
procedure TPdfCanvas.Concat(a, b, c, d, e, f: Single);
var
S: string;
begin
S := _FloatToStrR(a) + ' ' +
_FloatToStrR(b) + ' ' +
_FloatToStrR(c) + ' ' +
_FloatToStrR(d) + ' ' +
_FloatToStrR(e) + ' ' +
_FloatToStrR(f) + ' cm'#10;
WriteString(S);
end;
{* General Graphics State *}
// SetFlat
procedure TPdfCanvas.SetFlat(flatness: Byte);
var
S: string;
begin
S := IntToStr(flatness) + ' i'#10;
WriteString(S);
end;
// SetLineCap
procedure TPdfCanvas.SetLineCap(linecap: TLineCapStyle);
var
S: string;
begin
S := IntToStr(ord(linecap)) + ' J'#10;
WriteString(S);
end;
// SetDash
procedure TPdfCanvas.SetDash(aarray: array of Byte; phase: Byte);
var
S: string;
i: integer;
begin
S := '[';
if (High(aarray) >= 0) and (aarray[0] <> 0) then
for i := 0 to High(aarray) do
S := S + IntToStr(aarray[i]) + ' ';
S := S + '] ' + IntToStr(phase) + ' d'#10;
WriteString(S);
end;
// SetLineJoin
procedure TPdfCanvas.SetLineJoin(linejoin: TLineJoinStyle);
var
S: string;
begin
S := IntToStr(ord(linejoin)) + ' j'#10;
WriteString(S);
end;
// SetLineWidth
procedure TPdfCanvas.SetLineWidth(linewidth: Single);
var
S: string;
begin
S := _FloatToStrR(linewidth) + ' w'#10;
WriteString(S);
end;
// SetMiterLimit
procedure TPdfCanvas.SetMiterLimit(miterlimit: Byte);
var
S: string;
begin
S := IntToStr(miterlimit) + ' M'#10;
WriteString(S);
end;
{* Paths *}
// MoveTo
procedure TPdfCanvas.MoveTo(x, y: Single);
var
S: string;
begin
S := _FloatToStrR(x) + ' ' + _FloatToStrR(y) + ' m'#10;
WriteString(S);
end;
// LineTo
procedure TPdfCanvas.LineTo(x, y: Single);
var
S: string;
begin
S := _FloatToStrR(x) + ' ' + _FloatToStrR(y) + ' l'#10;
WriteString(S);
end;
// CurveToC
procedure TPdfCanvas.CurveToC(x1, y1, x2, y2, x3, y3: Single);
var
S: string;
begin
S := _FloatToStrR(x1) + ' ' +
_FloatToStrR(y1) + ' ' +
_FloatToStrR(x2) + ' ' +
_FloatToStrR(y2) + ' ' +
_FloatToStrR(x3) + ' ' +
_FloatToStrR(y3) + ' c'#10;
WriteString(S);
end;
// CurveToV
procedure TPdfCanvas.CurveToV(x2, y2, x3, y3: Single);
var
S: string;
begin
S := _FloatToStrR(x2) + ' ' +
_FloatToStrR(y2) + ' ' +
_FloatToStrR(x3) + ' ' +
_FloatToStrR(y3) + ' v'#10;
WriteString(S);
end;
// CurveToY
procedure TPdfCanvas.CurveToY(x1, y1, x3, y3: Single);
var
S: string;
begin
S := _FloatToStrR(x1) + ' ' +
_FloatToStrR(y1) + ' ' +
_FloatToStrR(x3) + ' ' +
_FloatToStrR(y3) + ' y'#10;
WriteString(S);
end;
// Rectangle
procedure TPdfCanvas.Rectangle(x, y, width, height: Single);
var
S: string;
begin
S := _FloatToStrR(x) + ' ' +
_FloatToStrR(y) + ' ' +
_FloatToStrR(width) + ' ' +
_FloatToStrR(height) + ' re'#10;
WriteString(S);
end;
// Closepath
procedure TPdfCanvas.Closepath;
begin
WriteString('h'#10);
end;
// NewPath
procedure TPdfCanvas.NewPath;
begin
WriteString('n'#10);
end;
// Stroke
procedure TPdfCanvas.Stroke;
begin
WriteString('S'#10);
end;
// ClosePathStroke
procedure TPdfCanvas.ClosePathStroke;
begin
WriteString('s'#10);
end;
// Fill
procedure TPdfCanvas.Fill;
begin
WriteString('f'#10);
end;
// Eofill
procedure TPdfCanvas.Eofill;
begin
WriteString('f*'#10);
end;
// FillStroke
procedure TPdfCanvas.FillStroke;
begin
WriteString('B'#10);
end;
// ClosepathFillStroke
procedure TPdfCanvas.ClosepathFillStroke;
begin
WriteString('b'#10);
end;
// EofillStroke
procedure TPdfCanvas.EofillStroke;
begin
WriteString('B*'#10);
end;
// ClosepathEofillStroke
procedure TPdfCanvas.ClosepathEofillStroke;
begin
WriteString('b*'#10);
end;
// Clip
procedure TPdfCanvas.Clip;
begin
WriteString('W'#10);
end;
// Eoclip
procedure TPdfCanvas.Eoclip;
begin
WriteString('W*'#10);
end;
{* Test state *}
// SetCharSpace
procedure TPdfCanvas.SetCharSpace(charSpace: Single);
begin
if FAttr.CharSpace = charSpace then Exit;
FAttr.SetCharSpace(charSpace);
if Contents <> nil then
WriteString(_FloatToStrR(charSpace) + ' Tc'#10);
end;
// SetWordSpace
procedure TPdfCanvas.SetWordSpace(wordSpace: Single);
begin
if FAttr.WordSpace = wordSpace then Exit;
FAttr.SetWordSpace(wordSpace);
if Contents <> nil then
WriteString(_FloatToStrR(wordSpace) + ' Tw'#10);
end;
// SetHorizontalScaling
procedure TPdfCanvas.SetHorizontalScaling(hScaling: Word);
begin
if FAttr.HorizontalScaling = hScaling then Exit;
FAttr.SetHorizontalScaling(hScaling);
WriteString(IntToStr(hScaling) + ' Tz'#10);
end;
// SetLeading
procedure TPdfCanvas.SetLeading(leading: Single);
begin
if FAttr.Leading = leading then Exit;
FAttr.SetLeading(leading);
WriteString(_FloatToStrR(leading) + ' TL'#10);
end;
// SetFontAndSize
procedure TPdfCanvas.SetFontAndSize(fontname: string; size: Single);
var
S: string;
begin
S := fontname + ' ' +
_FloatToStrR(size) + ' Tf'#10;
WriteString(S);
end;
// SetTextRenderingMode
procedure TPdfCanvas.SetTextRenderingMode(mode: TTextRenderingMode);
begin
WriteString(IntToStr(ord(mode)) + ' Tr'#10);
end;
// SetTextRise
procedure TPdfCanvas.SetTextRise(rise: Word);
begin
WriteString(IntToStr(rise) + ' Ts'#10);
end;
// BeginText
procedure TPdfCanvas.BeginText;
begin
WriteString('BT'#10);
end;
// EndText
procedure TPdfCanvas.EndText;
begin
WriteString('ET'#10);
end;
// MoveTextPoint
procedure TPdfCanvas.MoveTextPoint(tx, ty: Single);
var
S: string;
begin
S := _FloatToStrR(tx) + ' ' +
_FloatToStrR(ty) + ' Td'#10;
WriteString(S);
end;
// SetTextMatrix
procedure TPdfCanvas.SetTextMatrix(a, b, c, d, x, y: Word);
var
S: string;
begin
S := IntToStr(a) + ' ' +
IntToStr(b) + ' ' +
IntToStr(c) + ' ' +
IntToStr(d) + ' ' +
IntToStr(x) + ' ' +
IntToStr(y) + ' Tm'#10;
WriteString(S);
end;
// MoveToNextLine
procedure TPdfCanvas.MoveToNextLine;
begin
WriteString('T*'#10);
end;
// ShowText
procedure TPdfCanvas.ShowText(s: string);
var
FString: string;
begin
if _HasMultiByteString(s) then
FString := '<' + _StrToHex(s) + '>'
else
FString := '(' + _EscapeText(s) + ')';
WriteString(FString + ' Tj'#10);
end;
// ShowTextNextLine
procedure TPdfCanvas.ShowTextNextLine(s: string);
var
FString: string;
begin
if _HasMultiByteString(s) then
FString := '<' + _StrToHex(s) + '>'
else
FString := '(' + _EscapeText(s) + ')';
WriteString(FString + ' '''#10);
end;
{* external objects *}
// ExecuteXObject
procedure TPdfCanvas.ExecuteXObject(xObject: string);
var
S: string;
begin
S := '/' + xObject + ' Do'#10;
WriteString(S);
end;
{* Device-dependent color space operators *}
// SetRGBFillColor
procedure TPdfCanvas.SetRGBFillColor(Value: TPdfColor);
var
S: string;
begin
S := GetColorStr(Value) + ' rg'#10;
WriteString(S);
end;
// SetRGBStrokeColor
procedure TPdfCanvas.SetRGBStrokeColor(Value: TPdfColor);
var
S: string;
begin
S := GetColorStr(Value) + ' RG'#10;
WriteString(S);
end;
{ TPdfCanvas common routine }
// TextWidth
function TPdfCanvas.TextWidth(Text: string): Single;
begin
result := FAttr.TextWidth(Text);
end;
// MeasureText
function TPdfCanvas.MeasureText(Text: string; AWidth: Single): integer;
begin
result := FAttr.MeasureText(Text, AWidth);
end;
// Ellipse
procedure TPdfCanvas.Ellipse(x, y, width, height: Single);
begin
MoveTo(x, y+height/2);
CurveToC(x,
y+height/2-height/2*11/20,
x+width/2-width/2*11/20,
y,
x+width/2,
y);
CurveToC(x+width/2+width/2*11/20,
y,
x+width,
y+height/2-height/2*11/20,
x+width,
y+height/2);
CurveToC(x+width,
y+height/2+height/2*11/20,
x+width/2+width/2*11/20,
y+height,
x+width/2,
y+height);
CurveToC(x+width/2-width/2*11/20,
y+height,
x,
y+height/2+height/2*11/20,
x,
y+height/2);
end;
// GetNextWord
function TPdfCanvas.GetNextWord(const S: string;
var Index: integer): string;
var
ln: integer;
i: integer;
begin
// getting a word from text.
result := '';
ln := Length(S);
if Index > ln then
Exit;
i := Index;
while true do
if (S[i] = #10) and (S[i-1] = #13) or (S[i] = ' ') then
begin
result := Copy(S, Index, i - (Index -1));
break;
end
else
if i >= ln then
begin
result := Copy(S, Index, i - (Index - 1));
break;
end
{$IFDEF USE_JPFONTS}
else
if ByteType(S, i) = mbTrailByte then
if ((Copy(S, i+1, 2) <> #129#66) and
(Copy(S, i+1, 2) <> #129#65)) then
begin
result := Copy(S, Index, i - (Index - 1));
break;
end
else
inc(i)
else
if ((i < ln) and (ByteType(S, i + 1) = mbLeadByte)) then
begin
result := Copy(S, Index, i - (Index - 1));
break;
end
{$ENDIF}
else
inc(i);
Index := i + 1;
end;
// GetDoc
function TPdfCanvas.GetDoc: TPdfDoc;
begin
result := nil;
if FPdfDoc <> nil then
result := FPdfDoc
else
EPdfInvalidOperation.Create('ERROR: GetDoc documant is nil.');
end;
{ TPdfDictionaryWrapper }
// SetData
procedure TPdfDictionaryWrapper.SetData(AData: TPdfDictionary);
begin
FData := AData;
end;
// GetHasData
function TPdfDictionaryWrapper.GetHasData: boolean;
begin
result := (FData = nil);
end;
{ TPdfInfo }
// SetAuthor
procedure TPdfInfo.SetAuthor(Value: string);
begin
FData.AddItem('Author', TPdfText.CreateText(Value));
end;
// SetCreationDate
procedure TPdfInfo.SetCreationDate(Value: TDateTime);
begin
FData.AddItem('CreationDate', TPdfText.CreateText(_DateTimeToPdfDate(Value)));
end;
// SetModDate
procedure TPdfInfo.SetModDate(Value: TDateTime);
begin
FData.AddItem('ModDate', TPdfText.CreateText(_DateTimeToPdfDate(Value)));
end;
// SetCreator
procedure TPdfInfo.SetCreator(Value: string);
begin
FData.AddItem('Creator', TPdfText.CreateText(Value));
end;
// SetTitle
procedure TPdfInfo.SetTitle(Value: string);
begin
FData.AddItem('Title', TPdfText.CreateText(Value));
end;
// SetSubject
procedure TPdfInfo.SetSubject(Value: string);
begin
FData.AddItem('Subject', TPdfText.CreateText(Value));
end;
// SetKeywords
procedure TPdfInfo.SetKeywords(Value: string);
begin
FData.AddItem('Keywords', TPdfText.CreateText(Value));
end;
// GetAuthor
function TPdfInfo.GetAuthor: string;
begin
if FData.ValueByName('Author') <> nil then
result := FData.PdfTextByName('Author').Value
else
result := '';
end;
// GetCreationDate
function TPdfInfo.GetCreationDate: TDateTime;
begin
if FData.ValueByName('CreationDate') <> nil then
try
result := _PdfDateToDateTime(FData.PdfTextByName('CreationDate').Value);
except
result := 0;
end
else
result := 0;
end;
// GetModDate
function TPdfInfo.GetModDate: TDateTime;
begin
if FData.ValueByName('ModDate') <> nil then
try
result := _PdfDateToDateTime(FData.PdfTextByName('ModDate').Value);
except
result := 0;
end
else
result := 0;
end;
// GetCreator
function TPdfInfo.GetCreator: string;
begin
if FData.ValueByName('Creator') <> nil then
result := FData.PdfTextByName('Creator').Value
else
result := '';
end;
// GetTitle
function TPdfInfo.GetTitle: string;
begin
if FData.ValueByName('Title') <> nil then
result := FData.PdfTextByName('Title').Value
else
result := '';
end;
// GetSubject
function TPdfInfo.GetSubject: string;
begin
if FData.ValueByName('Subject') <> nil then
result := FData.PdfTextByName('Subject').Value
else
result := '';
end;
// GetKeywords
function TPdfInfo.GetKeywords: string;
begin
if FData.ValueByName('Keywords') <> nil then
result := FData.PdfTextByName('Keywords').Value
else
result := '';
end;
{ TPdfCatalog }
// SaveOpenAction
procedure TPdfCatalog.SaveOpenAction;
begin
if (FOpenAction = nil) then
FData.RemoveItem('OpenAction')
else
FData.AddItem('OpenAction', FOpenAction.GetValue);
end;
// SetPageLayout
procedure TPdfCatalog.SetPageLayout(Value: TPdfPageLayout);
var
FPageLayout: TPdfName;
begin
FPageLayout := TPdfName(FData.ValueByName('PageLayout'));
if (FPageLayout = nil) or (not (FPageLayout is TPdfName)) then
FData.AddItem('PageLayout', TPdfName.CreateName(PDF_PAGE_LAYOUT_NAMES[Ord(Value)]))
else
FPageLayout.Value := PDF_PAGE_LAYOUT_NAMES[Ord(Value)];
end;
// GetPageLayout
function TPdfCatalog.GetPageLayout: TPdfPageLayout;
var
FPageLayout: TPdfName;
S: string;
i: integer;
begin
result := plSinglePage;
FPageLayout := TPdfName(FData.ValueByName('PageLayout'));
if (FPageLayout = nil) or (not (FPageLayout is TPdfName)) then
Exit
else
begin
S := FPageLayout.Value;
for i := 0 to High(PDF_PAGE_LAYOUT_NAMES) do
if PDF_PAGE_LAYOUT_NAMES[i] = S then
begin
result := TPdfPageLayout(i);
Break;
end;
end;
end;
function TPdfCatalog.GetNonFullScreenPageMode: TPdfPageMode;
var
FDictionary: TPdfDictionary;
FPageMode: TPdfName;
S: string;
i: integer;
begin
result := pmUseNone;
FDictionary := TPdfDictionary(FData.ValueByName('NonFullScreenPageMode'));
if FDictionary = nil then
Exit;
FPageMode := TPdfName(FDictionary.ValueByName('NonFullScreenPageMode'));
if (FPageMode = nil) or (not (FPageMode is TPdfName)) then
Exit;
S := FPageMode.Value;
for i := 0 to High(PDF_PAGE_MODE_NAMES) do
if PDF_PAGE_MODE_NAMES[i] = S then
begin
result := TPdfPageMode(i);
Break;
end;
end;
function TPdfCatalog.GetViewerPreference: TPdfViewerPreferences;
var
FDictionary: TPdfDictionary;
FValue: TPdfBoolean;
begin
result := [];
FDictionary := TPdfDictionary(FData.ValueByName('ViewerPreference'));
if FDictionary = nil then
Exit;
FValue := FData.PdfBooleanByName('HideToolbar');
if (FValue <> nil) or FValue.Value then
result := result + [vpHideToolbar];
FValue := FData.PdfBooleanByName('HideMenubar');
if (FValue <> nil) or FValue.Value then
result := result + [vpHideMenubar];
FValue := FData.PdfBooleanByName('HideWindowUI');
if (FValue <> nil) or FValue.Value then
result := result + [vpHideWindowUI];
FValue := FData.PdfBooleanByName('FitWindow');
if (FValue <> nil) or FValue.Value then
result := result + [vpFitWindow];
FValue := FData.PdfBooleanByName('CenterWindow');
if (FValue <> nil) or FValue.Value then
result := result + [vpCenterWindow];
end;
// SetPageMode
procedure TPdfCatalog.SetPageMode(Value: TPdfPageMode);
var
FPageMode: TPdfName;
begin
FPageMode := TPdfName(FData.ValueByName('PageMode'));
if (FPageMode = nil) or (not (FPageMode is TPdfName)) then
FData.AddItem('PageMode', TPdfName.CreateName(PDF_PAGE_MODE_NAMES[Ord(Value)]))
else
FPageMode.Value := PDF_PAGE_MODE_NAMES[Ord(Value)];
end;
procedure TPdfCatalog.SetNonFullScreenPageMode(Value: TPdfPageMode);
var
FDictionary: TPdfDictionary;
FPageMode: TPdfName;
begin
FDictionary := TPdfDictionary(FData.ValueByName('ViewerPreferences'));
if FDictionary = nil then
begin
FDictionary := TPdfDictionary.CreateDictionary(Data.ObjectMgr);
Data.AddItem('ViewerPreferences', FDictionary);
end;
// if Value is pmFullScreen, remove 'PageMode' element(use default value).
if (Value = pmFullScreen) or (Value = pmUseNone) then
FDictionary.RemoveItem('NonFullScreenPageMode')
else
begin
FPageMode := TPdfName(FDictionary.ValueByName('NonFullScreenPageMode'));
if (FPageMode = nil) or (not (FPageMode is TPdfName)) then
FDictionary.AddItem('NonFullScreenPageMode',
TPdfName.CreateName(PDF_PAGE_MODE_NAMES[Ord(Value)]))
else
FPageMode.Value := PDF_PAGE_MODE_NAMES[Ord(Value)];
end;
end;
procedure TPdfCatalog.SetViewerPreference(Value: TPdfViewerPreferences);
var
FDictionary: TPdfDictionary;
begin
FDictionary := TPdfDictionary(FData.ValueByName('ViewerPreferences'));
if (FDictionary = nil) and (Value <> []) then
begin
FDictionary := TPdfDictionary.CreateDictionary(Data.ObjectMgr);
FData.AddItem('ViewerPreferences', FDictionary);
end;
if (vpHideToolbar in Value) then
FDictionary.AddItem('HideToolbar', TPdfBoolean.CreateBoolean(true))
else
FDictionary.RemoveItem('HideToolbar');
if (vpHideMenubar in Value) then
FDictionary.AddItem('HideMenubar', TPdfBoolean.CreateBoolean(true))
else
FDictionary.RemoveItem('HideMenubar');
if (vpHideWindowUI in Value) then
FDictionary.AddItem('HideWindowUI', TPdfBoolean.CreateBoolean(true))
else
FDictionary.RemoveItem('HideWindowUI');
if (vpFitWindow in Value) then
FDictionary.AddItem('FitWindow', TPdfBoolean.CreateBoolean(true))
else
FDictionary.RemoveItem('FitWindow');
if (vpCenterWindow in Value) then
FDictionary.AddItem('CenterWindow', TPdfBoolean.CreateBoolean(true))
else
FDictionary.RemoveItem('CenterWindow');
end;
// GetPageMode
function TPdfCatalog.GetPageMode: TPdfPageMode;
var
FPageMode: TPdfName;
S: string;
i: integer;
begin
result := pmUseNone;
FPageMode := TPdfName(FData.ValueByName('PageMode'));
if (FPageMode = nil) or (not (FPageMode is TPdfName)) then
Exit
else
begin
S := FPageMode.Value;
for i := 0 to High(PDF_PAGE_MODE_NAMES) do
if PDF_PAGE_MODE_NAMES[i] = S then
begin
result := TPdfPageMode(i);
Break;
end;
end;
end;
// GetPages
function TPdfCatalog.GetPages: TPdfDictionary;
begin
result := TPdfDictionary(FData.ValueByName('Pages'));
if result = nil then
raise EPdfInvalidOperation.Create('GetPages --page object is null..');
end;
// SetPages
procedure TPdfCatalog.SetPages(APage: TPdfDictionary);
begin
if _GetTypeOf(APage) = 'Pages' then
FData.AddItem('Pages', APage);
end;
{ TPdfFont }
// AddStrElements
procedure TPdfFont.AddStrElements(ADic: TPdfDictionary;
ATable: array of TPDF_STR_TBL);
var
i: integer;
begin
{ utility routine for making font dictinary. }
for i := 0 to High(ATable) do
ADic.AddItem(ATable[i].KEY, TPdfName.CreateName(ATable[i].VAL));
end;
// AddIntElements
procedure TPdfFont.AddIntElements(ADic: TPdfDictionary;
ATable: array of TPDF_INT_TBL);
var
i: integer;
begin
{ utility routine for making font dictionary. }
for i := 0 to High(ATable) do
ADic.AddItem(ATable[i].KEY, TPdfNumber.CreateNumber(ATable[i].VAL));
end;
// GetCharWidth
function TPdfFont.GetCharWidth(AText: string; APos: integer): integer;
begin
result := 0;
end;
// Create
constructor TPdfFont.Create(AXref: TPdfXref; AName: string);
begin
inherited Create;
FName := AName;
end;
{ PdfDestination }
// Create
constructor TPdfDestination.Create(APdfDoc: TPdfDoc);
var
i: integer;
begin
inherited Create;
FDoc := APdfDoc;
if (FDoc = nil) or (not FDoc.HasDoc) then
raise EPdfInvalidOperation.Create('TPdfDestination --cannot destination object.');
FPage := FDoc.Canvas.Page;
for i := 0 to 4 do
FValues[i] := 0;
FZoom := 1;
end;
// Destroy
destructor TPdfDestination.Destroy;
begin
if FReference <> nil then
FReference.Free;
inherited;
end;
// GetElement
function TPdfDestination.GetElement(Index: integer): Integer;
begin
result := FValues[Index];
end;
// SetElement
procedure TPdfDestination.SetElement(Index: integer; Value: Integer);
begin
if FValues[Index] <> Value then
if Value < 0 then
FValues[Index] := -1
else
FValues[Index] := Value;
end;
// SetZoom
procedure TPdfDestination.SetZoom(Value: Single);
begin
if Value <> FZoom then
if Value < 0 then
raise EPdfInvalidValue.Create('Zoom property cannot set to under 0.')
else
if Value > PDF_MAX_ZOOMSIZE then
raise EPdfInvalidValue.CreateFmt('Zoom property cannot set to over %d.', [PDF_MAX_ZOOMSIZE])
else
FZoom := Value;
end;
// GetPageWidth
function TPdfDestination.GetPageWidth: Integer;
var
FMediaBox: TPdfArray;
begin
FMediaBox := FPage.PdfArrayByName('MediaBox');
if FMediaBox <> nil then
result := TPdfNumber(FMediaBox.Items[2]).Value
else
result := FDoc.DefaultPageWidth;
end;
// GetPageHeight
function TPdfDestination.GetPageHeight: Integer;
var
FMediaBox: TPdfArray;
begin
FMediaBox := FPage.PdfArrayByName('MediaBox');
if FMediaBox <> nil then
result := TPdfNumber(FMediaBox.Items[3]).Value
else
result := FDoc.DefaultPageHeight;
end;
// GetValue
function TPdfDestination.GetValue: TPdfArray;
const
DEST_MAX_VALUE = 100;
begin
// create TPdfArray object from the specified values.
// the values which are not used are ignored.
result := TPdfArray.CreateArray(FDoc.FXref);
with result do
begin
AddItem(FPage);
AddItem(TPdfName.CreateName(PDF_DESTINATION_TYPE_NAMES[ord(FType)]));
case FType of
// if the type is dtXYZ, only Left, Top and Zoom values are used,
// other properties are ignored.
dtXYZ:
begin
if FValues[0] >= -DEST_MAX_VALUE then
AddItem(TPdfNumber.CreateNumber(Left))
else
AddItem(TPdfNull.Create);
if FValues[1] >= -DEST_MAX_VALUE then
AddItem(TPdfNumber.CreateNumber(Top))
else
AddItem(TPdfNull.Create);
if FZoom < 0 then
FZoom := 0;
AddItem(TPdfReal.CreateReal(FZoom));
end;
// if the type is dtFitR, all values except Zoom are used.
dtFitR:
begin
if FValues[0] >= -DEST_MAX_VALUE then
AddItem(TPdfNumber.CreateNumber(Left))
else
AddItem(TPdfNull.Create);
if FValues[1] >= -DEST_MAX_VALUE then
AddItem(TPdfNumber.CreateNumber(Bottom))
else
AddItem(TPdfNull.Create);
if FValues[2] >= 0 then
AddItem(TPdfNumber.CreateNumber(Right))
else
AddItem(TPdfNull.Create);
if FValues[3] >= 0 then
AddItem(TPdfNumber.CreateNumber(Top))
else
AddItem(TPdfNull.Create);
end;
// if the type is dtFitH or dtFitBH, only Top property is used.
dtFitH, dtFitBH:
if FValues[1] >= -DEST_MAX_VALUE then
AddItem(TPdfNumber.CreateNumber(Top))
else
AddItem(TPdfNull.Create);
// if the type is dtFitV or dtFitBV, only Top property is used.
dtFitV, dtFitBV:
if FValues[0] >= -DEST_MAX_VALUE then
AddItem(TPdfNumber.CreateNumber(Left))
else
AddItem(TPdfNull.Create);
end;
end;
end;
{ TPdfOutlineEntry }
// CreateEntry
constructor TPdfOutlineEntry.CreateEntry(AParent: TPdfOutlineEntry);
begin
inherited Create;
if AParent = nil then
Raise Exception.Create('CreateEntry --invalid parent.');
FParent := AParent;
FCount := 0;
FDoc := AParent.Doc;
Data := TPdfDictionary.CreateDictionary(FDoc.FXref);
FDoc.FXref.AddObject(Data);
FDoc.FObjectList.Add(Self);
end;
// Destroy
destructor TPdfOutlineEntry.Destroy;
begin
if FReference <> nil then
FReference.Free;
inherited;
end;
// AddChild
function TPdfOutlineEntry.AddChild: TPdfOutlineEntry;
var
TmpEntry: TPdfOutlineEntry;
begin
// increment Count variable recursive.
inc(FCount);
TmpEntry := Parent;
while TmpEntry <> nil do
begin
TmpEntry.FCount := TmpEntry.FCount + 1;
TmpEntry := TmpEntry.Parent;
end;
result := TPdfOutlineEntry.CreateEntry(Self);
if FFirst = nil then
FFirst := Result;
if FLast <> nil then
FLast.FNext := Result;
Result.FPrev := FLast;
FLast := Result;
end;
// Save
procedure TPdfOutlineEntry.Save;
begin
if Opened then
Data.AddItem('Count', TPdfNumber.CreateNumber(FCount))
else
Data.AddItem('Count', TPdfNumber.CreateNumber(-FCount));
Data.AddItem('Title', TPdfText.CreateText(FTitle));
if FDest <> nil then
Data.AddItem('Dest', FDest.GetValue);
if FFirst <> nil then
begin
Data.AddItem('First', FFirst.Data);
FFirst.Save;
end;
if FLast <> nil then
Data.AddItem('Last', FLast.Data);
if FPrev <> nil then
Data.AddItem('Prev', FPrev.Data);
if FNext <> nil then
begin
Data.AddItem('Next', FNext.Data);
FNext.Save;
end;
end;
{ TPdfOutlineRoot }
// CreateRoot
constructor TPdfOutlineRoot.CreateRoot(ADoc: TPdfDoc);
begin
inherited Create;
FCount := 0;
FDoc := ADoc;
FOpened := true;
Data := TPdfDictionary.CreateDictionary(ADoc.FXref);
FDoc.FXref.AddObject(Data);
with Data do
AddItem('Type', TPdfName.CreateName('Outlines'));
FDoc.FObjectList.Add(Self);
end;
// Save
procedure TPdfOutlineRoot.Save;
begin
if Opened then
Data.AddItem('Count', TPdfNumber.CreateNumber(FCount))
else
Data.AddItem('Count', TPdfNumber.CreateNumber(-FCount));
if FFirst <> nil then
begin
Data.AddItem('First', FFirst.Data);
FFirst.Save;
end;
if FLast <> nil then
Data.AddItem('Last', FLast.Data);
end;
end.