{*******************************************************************} { } { Developer Express Visual Component Library } { ExpressPrinting System COMPONENT SUITE } { } { Copyright (C) 1998-2009 Developer Express Inc. } { ALL RIGHTS RESERVED } { } { The entire contents of this file is protected by U.S. and } { International Copyright Laws. Unauthorized reproduction, } { reverse-engineering, and distribution of all or any portion of } { the code contained in this file is strictly prohibited and may } { result in severe civil and criminal penalties and will be } { prosecuted to the maximum extent possible under the law. } { } { RESTRICTIONS } { } { THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES } { (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE } { SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS } { LICENSED TO DISTRIBUTE THE EXPRESSPRINTINGSYSTEM AND } { ALL ACCOMPANYING VCL CONTROLS AS PART OF AN } { EXECUTABLE PROGRAM ONLY. } { } { THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED } { FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE } { COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE } { AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT } { AND PERMISSION FROM DEVELOPER EXPRESS INC. } { } { CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON } { ADDITIONAL RESTRICTIONS. } { } {*******************************************************************} unit dxPSPDFFonts; interface {$I cxVer.inc} uses Windows, SysUtils, Classes, Graphics, cxClasses, dxCore, dxPSPDFExportCore, dxPSPDFStrings, dxPSTrueTypeFont; type TdxPSPDFCIDFont = class; TdxPSPDFCIDFontConversionTable = class; TdxPSPDFFontDescriptor = class; { TdxPSPDFFontInfo } TdxPSPDFFontInfo = class(TdxPSPDFObject) private FOwner: TdxPSPDFCustomFont; public constructor Create(AOwner: TdxPSPDFCustomFont); virtual; // property Owner: TdxPSPDFCustomFont read FOwner; end; { TdxPSPDFFontFile } TdxPSPDFFontFile = class(TdxPSPDFFontInfo) private FFontData: TMemoryStream; function GetFontDataValid: Boolean; protected procedure FontDataNeeded; virtual; function GetContentStreamType(out AType: TdxPSPDFStreamType): Boolean; override; procedure WriteContentStream(AWriter: TdxPSPDFWriter); override; procedure WriteHeader(AWriter: TdxPSPDFWriter); override; public destructor Destroy; override; // property FontData: TMemoryStream read FFontData; property FontDataValid: Boolean read GetFontDataValid; end; { TdxPSPDFFontDescriptor } TdxPSPDFFontDescriptor = class(TdxPSPDFFontInfo) private FAscent: Integer; FAveCharWidth: Integer; FCapHeight: Integer; FCharWidths: array[Byte] of Word; FDescent: Integer; FFirstChar: Byte; FFontBox: TRect; FFontFile: TdxPSPDFFontFile; FFontFlags: Cardinal; FItalicAngle: Integer; FLastChar: Byte; FLeading: Integer; FMaxCharWidth: Integer; FMetricValid: Boolean; FStemVertical: Integer; protected class function GetType: string; override; function CalculateFontFlags(const APanose: TPanose): Integer; virtual; function CreateFontFile: TdxPSPDFFontFile; virtual; function GetCharWidth(AIndex: Byte): Word; procedure CalculateMetric(DC: HDC; const AMetric: TOutlineTextmetricA); virtual; procedure MetricNeeded; virtual; procedure WriteHeader(AWriter: TdxPSPDFWriter); override; public destructor Destroy; override; procedure PopulateExportList(AList: TdxPSPDFObjectList); override; // property Ascent: Integer read FAscent; property AveCharWidth: Integer read FAveCharWidth; property CapHeight: Integer read FCapHeight; property CharWidth[Index: Byte]: Word read GetCharWidth; property Descent: Integer read FDescent; property FirstChar: Byte read FFirstChar; property FontBox: TRect read FFontBox; property FontFile: TdxPSPDFFontFile read FFontFile; property FontFlags: Cardinal read FFontFlags; property ItalicAngle: Integer read FItalicAngle; property LastChar: Byte read FLastChar; property MaxCharWidth: Integer read FMaxCharWidth; property MetricValid: Boolean read FMetricValid; property StemVertical: Integer read FStemVertical; end; { TdxPSPDFTrueTypeFontEncoding } TdxPSPDFTrueTypeFontEncoding = class(TdxPSPDFFontInfo) private function GetCharset: Integer; protected class function GetType: string; override; procedure WriteEncodingTable(AWriter: TdxPSPDFWriter); procedure WriteHeader(AWriter: TdxPSPDFWriter); override; public property Charset: Integer read GetCharset; end; { TdxPSPDFTrueTypeFont } TdxPSPDFTrueTypeFont = class(TdxPSPDFCustomFont) private FDescriptor: TdxPSPDFFontDescriptor; FEncoding: TdxPSPDFTrueTypeFontEncoding; protected function ConvertToAnsiString(const AText: WideString): AnsiString; class function GetSubType: string; override; procedure WriteCharWidths(AWriter: TdxPSPDFWriter); procedure WriteHeader(AWriter: TdxPSPDFWriter); override; public constructor Create(AOwner: TdxPSPDFFontList; AEmbed: Boolean; AFont: TFont); override; destructor Destroy; override; function EncodeText(const S: WideString): AnsiString; override; function TextWidth(const S: WideString): Integer; override; procedure PopulateExportList(AList: TdxPSPDFObjectList); override; // property Descriptor: TdxPSPDFFontDescriptor read FDescriptor; property Encoding: TdxPSPDFTrueTypeFontEncoding read FEncoding; end; { TdxPSPDFCIDSystemInfo } TdxPSPDFCIDSystemInfo = class(TObject) private FOrdering: string; FRegistry: string; FSupplement: Integer; public constructor Create(const AOrdering: string); virtual; procedure Write(AWriter: TdxPSPDFWriter); virtual; // property Ordering: string read FOrdering write FOrdering; property Registry: string read FRegistry write FRegistry; property Supplement: Integer read FSupplement write FSupplement; end; { TdxPSPDFCIDFontInfo } TdxPSPDFCIDFontInfo = class(TdxPSPDFFontInfo) private FDescriptor: TdxPSPDFFontDescriptor; FSystemInfo: TdxPSPDFCIDSystemInfo; function GetCharCache: TdxPSTTFCharCacheList; function GetGlyphIndexWidth(Index: Word): Integer; function GetOwner: TdxPSPDFCIDFont; protected class function GetSubType: string; override; class function GetType: string; override; procedure WriteCharWidths(AWriter: TdxPSPDFWriter); virtual; procedure WriteHeader(AWriter: TdxPSPDFWriter); override; public constructor Create(AOwner: TdxPSPDFCustomFont); override; destructor Destroy; override; procedure PopulateExportList(AList: TdxPSPDFObjectList); override; // property CharCache: TdxPSTTFCharCacheList read GetCharCache; property Descriptor: TdxPSPDFFontDescriptor read FDescriptor; property GlyphIndexWidth[Index: Word]: Integer read GetGlyphIndexWidth; property Owner: TdxPSPDFCIDFont read GetOwner; property SystemInfo: TdxPSPDFCIDSystemInfo read FSystemInfo; end; { TdxPSPDFCIDFontFile } TdxPSPDFCIDFontFile = class(TdxPSPDFFontFile) private function CanRebuildFont: Boolean; function GetOwner: TdxPSPDFCIDFont; function GetTTFFile: TdxPSTTFFile; protected procedure FontDataNeeded; override; public property Owner: TdxPSPDFCIDFont read GetOwner; property TTFFile: TdxPSTTFFile read GetTTFFile; end; { TdxPSPDFCIDFontDescriptor } TdxPSPDFCIDFontDescriptor = class(TdxPSPDFFontDescriptor) protected function CreateFontFile: TdxPSPDFFontFile; override; end; { TdxPSPDFCIDFont } TdxPSPDFCIDFont = class(TdxPSPDFCustomFont) private FCharCache: TdxPSTTFCharCacheList; FConversionTable: TdxPSPDFCIDFontConversionTable; FFontInfo: TdxPSPDFCIDFontInfo; FTTFFile: TdxPSTTFFile; protected class function GetSubType: string; override; procedure WriteHeader(AWriter: TdxPSPDFWriter); override; public constructor Create(AOwner: TdxPSPDFFontList; AEmbed: Boolean; AFont: TFont); override; destructor Destroy; override; function EncodeFontName: string; override; function EncodeText(const S: WideString): AnsiString; override; function TextWidth(const S: WideString): Integer; override; procedure PopulateExportList(AList: TdxPSPDFObjectList); override; // property CharCache: TdxPSTTFCharCacheList read FCharCache; property ConversionTable: TdxPSPDFCIDFontConversionTable read FConversionTable; property FontInfo: TdxPSPDFCIDFontInfo read FFontInfo; property TTFFile: TdxPSTTFFile read FTTFFile; end; { TdxPSPDFCIDFontConversionTable } TdxPSPDFCIDFontConversionTable = class(TdxPSPDFFontInfo) private FSystemInfo: TdxPSPDFCIDSystemInfo; function GetCharCache: TdxPSTTFCharCacheList; function GetCMapName: string; function GetGlyphIndex(ACharCode: Word): Integer; function GetOwner: TdxPSPDFCIDFont; protected function GetContentStreamType(out AType: TdxPSPDFStreamType): Boolean; override; procedure WriteContentStream(AWriter: TdxPSPDFWriter); override; procedure WriteConversionTable(AWriter: TdxPSPDFWriter); public constructor Create(AOwner: TdxPSPDFCustomFont); override; destructor Destroy; override; // property CharCache: TdxPSTTFCharCacheList read GetCharCache; property CMapName: string read GetCMapName; property GlyphIndex[CharCode: Word]: Integer read GetGlyphIndex; property Owner: TdxPSPDFCIDFont read GetOwner; property SystemInfo: TdxPSPDFCIDSystemInfo read FSystemInfo; end; function dxPDFCanCreateCIDFont(AFont: TFont): Boolean; function dxPDFCanEmbedFont(AFont: TFont): Boolean; implementation const dxPDF_FONT_FIXEDWIDTH = $2; dxPDF_FONT_SERIF = $4; dxPDF_FONT_SYMBOLIC = $8; dxPDF_FONT_SCRIPT = $10; dxPDF_FONT_USE_ADOBE_STD_CHARSET = $20; dxPDF_FONT_ITALIC = $40; dxPDF_FONT_ALLCAPFONT = $10000; dxPDF_FONT_SMALL_CAP = $20000; dxPDF_FONT_FORCE_BOLD_AT_SMALL_TEXT_SIZE = $40000; const sdxArabicEncoding = '128/Euro/afii57506/quotesinglbase/florin/quotedblbase' + '/ellipsis/dagger/daggerdbl/circumflex/perthousand/afii57511/guilsinglleft' + '/OE/afii57507/afii57508 144 /afii57509/quoteleft/quoteright/quotedblleft' + '/quotedblright/bullet/endash/emdash 153 /trademark/afii57513/guilsinglright' + '/oe/afii61664/afii301/afii57514 161 /afii57388 186 /afii57403 191 /afii57407' + ' 193 /afii57409/afii57410/afii57411/afii57412/afii57413/afii57414/afii57415' + '/afii57416/afii57417/afii57418/afii57419/afii57420/afii57421/afii57422' + '/afii57423/afii57424/afii57425/afii57426/afii57427/afii57428/afii57429' + '/afii57430 216 /afii57431/afii57432/afii57433/afii57434/afii57440/afii57441' + '/afii57442/afii57443/afii57444 227 /afii57445/afii57446/afii57470/afii57448' + '/afii57449/afii57450 240 /afii57451/afii57452/afii57453/afii57454/afii57455' + '/afii57456 248 /afii57457 250 /afii57458 253 /afii299/afii300/afii57519'; sdxBalticEncoding = '128/Euro/space/quotesinglbase/space/quotedblbase' + '/ellipsis/dagger/daggerdbl/space/perthousand/space/guilsinglleft/space' + '/dieresis/caron/cedilla/space/quoteleft/quoteright/quotedblleft/quotedblright' + '/bullet/endash/emdash/space/trademark/space/guilsinglright/space/macron' + '/ogonek/space 170/Rcommaaccent 175 /AE 184/oslash 186/rcommaaccent 191 /ae' + '/Aogonek/Iogonek/Amacron/Cacute 198/Eogonek/Emacron/Ccaron 202/Zacute' + '/Edotaccent/Gcommaaccent/Kcommaaccent/Imacron/Lcommaaccent/Scaron/Nacute' + '/Ncommaaccent/trademark/Omacron 216/Uogonek/Lslash/Sacute/Umacron 221' + '/Zdotaccent/Zcaron 224/aogonek/iogonek/amacron/cacute 230/eogonek/emacron' + '/ccaron 234/zacute/edotaccent/gcommaaccent/kcommaaccent/imacron/lcommaaccent' + '/scaron/nacute/ncommaaccent 244/omacron 248/uogonek/lslash/OE/umacron 253' + '/zdotaccent/zcaron/dotaccent'; sdxEastEuropeEncoding = '128 /Euro 140/Sacute/Tcaron/Zcaron/Zacute 156' + '/sacute/tcaron/zcaron/zacute 161/caron/breve/Lslash 165/Aogonek 170' + '/Scedilla 175/Zdotaccent 178/ogonek/lslash 185/aogonek/scedilla 188' + '/Lcaron/hungarumlaut/lcaron/zdotaccent/Racute 195/Abreve 197/Lacute' + '/Cacute 200/Ccaron 202/Eogonek 204/Ecaron 207/Dcaron/Dslash 209/Nacute' + '/Ncaron/Oacute 213/Ohungarumlaut 216/Rcaron/Uring 219/Uhungarumlaut 222' + '/Tcedilla 224/racute 227/abreve 229/lacute/cacute/ccedilla/ccaron 234' + '/eogonek 236/ecaron 239/dcaron/dmacron/nacute/ncaron 245/ohungarumlaut 248' + '/rcaron/uring 251/uhungarumlaut 254/tcedilla/dotaccent'; sdxGreekEncoding = '128/Euro 160/quoteleft/quoteright 175/afii00208 180/tonos' + '/dieresistonos/Alphatonos 184/Epsilontonos/Etatonos/Iotatonos 188' + '/Omicrontonos 190/Upsilontonos/Omegatonos/iotadieresistonos/Alpha/Beta' + '/Gamma/Delta/Epsilon/Zeta/Eta/Theta/Iota/Kappa/Lambda/Mu/Nu/Xi/Omicron' + '/Pi/Rho 211/Sigma/Tau/Upsilon/Phi/Chi/Psi/Omega/Iotadieresis' + '/Upsilondieresis/alphatonos/epsilontonos/etatonos/iotatonos' + '/upsilondieresistonos/alpha/beta/gamma/delta/epsilon/zeta/eta/theta' + '/iota/kappa/lambda/mu/nu/xi/omicron/pi/rho/sigma1/sigma/tau/upsilon' + '/phi/chi/psi/omega/iotadieresis/upsilondieresis/omicrontonos/upsilontonos' + '/omegatonos'; sdxHebrewEncoding = '128/Euro 130/quotesinglbase/florin/quotedblbase/ellipsis' + '/dagger/daggerdbl/circumflex/perthousand139/guilsinglleft 145/quoteleft' + '/quoteright/quotedblleft/quotedblright/bullet/endash/emdash/tilde' + '/trademark 155/perthousand 164/afii57636 170/multiply186/divide 192' + '/afii57799/afii57801/afii57800/afii57802/afii57793/afii57794/afii57795' + '/afii57798/afii57797/afii57806 203/afii57796/afii57807/afii57839' + '/afii57645/afii57841/afii57842/afii57804/afii57803/afii57658/afii57716' + '/afii57717/afii57718 224/afii57664/afii57665/afii57666/afii57667' + '/afii57668/afii57669/afii57670/afii57671/afii57672/afii57673/afii57674' + '/afii57675/afii57676/afii57677/afii57678/afii57679/afii57680/afii57681' + '/afii57682/afii57683/afii57684/afii57685/afii57686/afii57687/afii57688' + '/afii57689/afii57690253/afii299/afii300'; sdxRussianEncoding = '129 /afii10052/quotesinglbase/afii10100/quotedblbase' + '/ellipsis/dagger/daggerdbl/Euro/perthousand/afii10058/guilsinglleft' + '/afii10059/afii10061/afii10060/afii10145/afii10099/quoteleft/quoteright' + '/quotedblleft/quotedblright/bullet/endash/emdash/space/trademark/afii10106' + '/guilsinglright/afii10107/afii10109/afii10108/afii10193/space/afii10062' + '/afii10110/afii10057/currency/afii10050/brokenbar/section/afii10023' + '/copyright/afii10053/guillemotleft/logicalnot/hyphen/registered/afii10056' + '/degree/plusminus/afii10055/afii10103/afii10098/mu/paragraph/periodcentered' + '/afii10071/afii61352/afii10101/guillemotright/afii10105/afii10054/afii10102' + '/afii10104/afii10017/afii10018/afii10019/afii10020/afii10021/afii10022' + '/afii10024/afii10025/afii10026/afii10027/afii10028/afii10029/afii10030' + '/afii10031/afii10032/afii10033/afii10034/afii10035/afii10036/afii10037' + '/afii10038/afii10039/afii10040/afii10041/afii10042/afii10043/afii10044' + '/afii10045/afii10046/afii10047/afii10048/afii10049/afii10065/afii10066' + '/afii10067/afii10068/afii10069/afii10070/afii10072/afii10073/afii10074' + '/afii10075/afii10076/afii10077/afii10078/afii10079/afii10080/afii10081' + '/afii10082/afii10083/afii10084/afii10085/afii10086/afii10087/afii10088' + '/afii10089/afii10090/afii10091/afii10092/afii10093/afii10094/afii10095' + '/afii10096/afii10097/space'; sdxThaiEncoding = '128/Euro 133/ellipsis 145/quoteleft/quoteright/quotedblleft' + '/quotedblright/bullet/endash/emdash 160/space/kokaithai/khokhaithai/khokhuatthai' + '/khokhwaithai/khokhonthai/khorakhangthai/ngonguthai/chochanthai/chochingthai' + '/chochangthai/sosothai/chochoethai/yoyingthai/dochadathai/topatakthai' + '/thothanthai/thonangmonthothai/thophuthaothai/nonenthai/dodekthai/totaothai' + '/thothungthai/thothahanthai/thothongthai/nonuthai/bobaimaithai/poplathai' + '/phophungthai/fofathai/phophanthai/fofanthai/phosamphaothai/momathai' + '/yoyakthai/roruathai/ruthai/lolingthai/luthai/wowaenthai/sosalathai' + '/sorusithai/sosuathai/hohipthai/lochulathai/oangthai/honokhukthai' + '/paiyannoithai/saraathai/maihanakatthai/saraaathai/saraamthai/saraithai' + '/saraiithai/sarauethai/saraueethai/sarauthai/sarauuthai/phinthuthai 223' + '/bahtthai/saraethai/saraaethai/saraothai/saraaimaimuanthai/saraaimaimalaithai' + '/lakkhangyaothai/maiyamokthai/maitaikhuthai/maiekthai/maithothai/maitrithai' + '/maichattawathai/thanthakhatthai/nikhahitthai/yamakkanthai/fongmanthai' + '/zerothai/onethai/twothai/threethai/fourthai/fivethai/sixthai/seventhai' + '/eightthai/ninethai/angkhankhuthai/khomutthai'; sdxTurkishEncoding = '128/Euro 130/quotesinglbase/florin/quotedblbase/ellipsis' + '/dagger/daggerdbl/circumflex/perthousand/Scaron/guilsinglleft/OE 145' + '/quoteleft/quoteright/quotedblleft/quotedblright/bullet/endash/emdash' + '/tilde/trademark/scaron/guilsinglright/oe 159/Ydieresis 208/Gbreve 221' + '/Idotaccent/Scedilla 240/gbreve 253/dotlessi/scedilla'; sdxVietnameseEncoding = '128 /Euro 130/quotesinglbase/florin/quotedblbase/ellipsis' + '/dagger/daggerdbl/circumflex/perthousand 139/guilsinglleft/OE 145/quoteleft' + '/quoteright/quotedblleft/quotedblright/bullet/endash/emdash/tilde/trademark 155' + '/guilsinglright/oe 159/Ydieresis/space/exclamdown/cent/sterling/currency' + '/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot' + '/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu' + '/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright' + '/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex' + '/Abreve/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis' + '/gravetonecmb /Iacute /Icircumflex /Idieresis/Dcroat/Ntilde/hookabovecomb' + '/Oacute/Ocircumflex/Ohorn/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex' + '/Udieresis/Uhorn/tildecomb/germandbls/agrave/aacute/acircumflex/abreve' + '/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/acutetonecmb' + '/iacute/icircumflex/idieresis/dcroat/ntilde/dotbelowcomb/oacute/ocircumflex' + '/ohorn/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/uhorn' + '/dong/ydieresis'; function dxPDFCanCreateCIDFont(AFont: TFont): Boolean; begin Result := dxPDFCanEmbedFont(AFont); end; function dxPDFCanEmbedFont(AFont: TFont): Boolean; begin Result := (AFont.Charset <> SYMBOL_CHARSET) and dxPSGetFontData(nil, AFont); end; function GetABCWidth(const ABC: TABC): Integer; begin Result := ABC.abcA + Integer(ABC.abcB) + ABC.abcC; end; { TdxPSPDFTrueTypeFont } constructor TdxPSPDFTrueTypeFont.Create( AOwner: TdxPSPDFFontList; AEmbed: Boolean; AFont: TFont); begin inherited Create(AOwner, AEmbed, AFont); FEncoding := TdxPSPDFTrueTypeFontEncoding.Create(Self); FDescriptor := TdxPSPDFFontDescriptor.Create(Self); end; destructor TdxPSPDFTrueTypeFont.Destroy; begin FreeAndNil(FDescriptor); FreeAndNil(FEncoding); inherited Destroy; end; function TdxPSPDFTrueTypeFont.ConvertToAnsiString(const AText: WideString): AnsiString; var I: Integer; begin if Charset <> SYMBOL_CHARSET then Result := dxWideStringToAnsiString(AText, CodePage) else begin SetLength(Result, Length(AText)); for I := 1 to Length(AText) do Result[I] := AnsiChar(Word(AText[I]) and not $F000); end; end; function TdxPSPDFTrueTypeFont.EncodeText(const S: WideString): AnsiString; begin Result := '(' + ConvertToAnsiString(S) + ')'; end; class function TdxPSPDFTrueTypeFont.GetSubType: string; begin Result := sdxPDFSubTypeFontTrueType; end; function TdxPSPDFTrueTypeFont.TextWidth(const S: WideString): Integer; var ATempStr: AnsiString; I: Integer; begin Result := 0; ATempStr := ConvertToAnsiString(S); for I := 1 to Length(ATempStr) do Inc(Result, Descriptor.CharWidth[Ord(ATempStr[I])]); end; procedure TdxPSPDFTrueTypeFont.PopulateExportList(AList: TdxPSPDFObjectList); begin inherited PopulateExportList(AList); Encoding.PopulateExportList(AList); Descriptor.PopulateExportList(AList); end; procedure TdxPSPDFTrueTypeFont.WriteCharWidths(AWriter: TdxPSPDFWriter); var I: Integer; begin Descriptor.MetricNeeded; AWriter.WriteString(sdxPDFFirstChar + sdxPDFSpace + IntToStr(Descriptor.FirstChar)); AWriter.WriteString(sdxPDFLastChar + sdxPDFSpace + IntToStr(Descriptor.LastChar)); AWriter.WriteString(sdxPDFWidths + '[', False); for I := Descriptor.FirstChar to Descriptor.LastChar do AWriter.WriteString(IntToStr(Descriptor.CharWidth[I]) + sdxPDFSpace, False); AWriter.WriteString(']'); end; procedure TdxPSPDFTrueTypeFont.WriteHeader(AWriter: TdxPSPDFWriter); begin inherited WriteHeader(AWriter); AWriter.WriteString(sdxPDFEncoding + sdxPDFSpace + AWriter.MakeLinkToObject(Encoding)); AWriter.WriteString(sdxPDFFontDescriptor + sdxPDFSpace + AWriter.MakeLinkToObject(Descriptor)); WriteCharWidths(AWriter); end; { TdxPSPDFTrueTypeFontEncoding } function TdxPSPDFTrueTypeFontEncoding.GetCharset: Integer; begin Result := Owner.Charset; end; class function TdxPSPDFTrueTypeFontEncoding.GetType: string; begin Result := sdxPDFEncoding; end; procedure TdxPSPDFTrueTypeFontEncoding.WriteEncodingTable(AWriter: TdxPSPDFWriter); var AEncodingTable: string; begin case Charset of ARABIC_CHARSET: AEncodingTable := sdxArabicEncoding; BALTIC_CHARSET: AEncodingTable := sdxBalticEncoding; EASTEUROPE_CHARSET: AEncodingTable := sdxEastEuropeEncoding; HEBREW_CHARSET: AEncodingTable := sdxHebrewEncoding; GREEK_CHARSET: AEncodingTable := sdxGreekEncoding; RUSSIAN_CHARSET: AEncodingTable := sdxRussianEncoding; THAI_CHARSET: AEncodingTable := sdxThaiEncoding; TURKISH_CHARSET: AEncodingTable := sdxTurkishEncoding; VIETNAMESE_CHARSET: AEncodingTable := sdxVietnameseEncoding; else Exit; end; AWriter.WriteString(sdxPDFDifferences + ' [' + AEncodingTable + ']', False); end; procedure TdxPSPDFTrueTypeFontEncoding.WriteHeader(AWriter: TdxPSPDFWriter); const BaseEncodingMap: array[Boolean] of string = ( sdxPDFEncodingWinAnsi, sdxPDFEncodingMacRoman ); begin inherited WriteHeader(AWriter); AWriter.WriteString(sdxPDFBaseEncoding + BaseEncodingMap[Charset = SYMBOL_CHARSET]); WriteEncodingTable(AWriter); end; { TdxPSPDFFontDescriptor } destructor TdxPSPDFFontDescriptor.Destroy; begin FreeAndNil(FFontFile); inherited Destroy; end; procedure TdxPSPDFFontDescriptor.CalculateMetric( DC: HDC; const AMetric: TOutlineTextmetricA); var AABC: TdxPSPDFABCArray; I: Integer; begin ZeroMemory(@FCharWidths[0], SizeOf(FCharWidths)); FAscent := AMetric.otmAscent; FAveCharWidth := AMetric.otmTextMetrics.tmAveCharWidth; FCapHeight := AMetric.otmTextMetrics.tmHeight; FDescent := AMetric.otmDescent; FFontBox := AMetric.otmrcFontBox; FFontFlags := CalculateFontFlags(AMetric.otmPanoseNumber); FItalicAngle := AMetric.otmItalicAngle; FMaxCharWidth := AMetric.otmTextMetrics.tmMaxCharWidth; FStemVertical := 50 + Round(Sqr(AMetric.otmTextMetrics.tmWeight / 65)); FLastChar := Ord(AMetric.otmTextMetrics.tmLastChar); FFirstChar := Ord(AMetric.otmTextMetrics.tmFirstChar); FLeading := AMetric.otmTextMetrics.tmInternalLeading; GetCharABCWidths(DC, FFirstChar, FLastChar, AABC); for I := 0 to LastChar - FirstChar do begin if AMetric.otmTextMetrics.tmPitchAndFamily and TMPF_FIXED_PITCH = 0 then FCharWidths[FirstChar + I] := GetABCWidth(AABC[0]) else FCharWidths[FirstChar + I] := GetABCWidth(AABC[I]); end; end; procedure TdxPSPDFFontDescriptor.MetricNeeded; var AFont: TFont; AMetric: POutlineTextmetricA; AMetricLength: Integer; AOldFont: HFONT; DC: HDC; begin if not FMetricValid then begin FMetricValid := True; AFont := Owner.CreateFont; try DC := GetDC(0); AFont.PixelsPerInch := 96; AFont.Size := 750; AOldFont := SelectObject(DC, AFont.Handle); AMetricLength := GetOutlineTextMetricsA(DC, 0, nil); if AMetricLength > 0 then begin AMetric := AllocMem(AMetricLength); try AMetric^.otmSize := SizeOf(AMetric^); GetOutlineTextMetricsA(DC, AMetricLength, AMetric); CalculateMetric(DC, AMetric^); finally FreeMem(AMetric); end; end; SelectObject(DC, AOldFont); ReleaseDC(0, DC); finally AFont.Free; end; end; end; procedure TdxPSPDFFontDescriptor.PopulateExportList(AList: TdxPSPDFObjectList); begin inherited PopulateExportList(AList); if (FontFile = nil) and Owner.Embed then FFontFile := CreateFontFile; if Assigned(FontFile) then FontFile.PopulateExportList(AList); end; function TdxPSPDFFontDescriptor.CalculateFontFlags(const APanose: TPanose): Integer; begin Result := dxPDF_FONT_USE_ADOBE_STD_CHARSET; if APanose.bProportion = 9 then Result := Result or dxPDF_FONT_FIXEDWIDTH; if (APanose.bSerifStyle < 11) or (APanose.bSerifStyle > 13) then Result := Result or dxPDF_FONT_SERIF; if APanose.bFamilyType = 3 then Result := Result or dxPDF_FONT_SCRIPT; end; function TdxPSPDFFontDescriptor.CreateFontFile: TdxPSPDFFontFile; begin Result := TdxPSPDFFontFile.Create(Owner); end; function TdxPSPDFFontDescriptor.GetCharWidth(AIndex: Byte): Word; begin MetricNeeded; Result := FCharWidths[AIndex]; end; class function TdxPSPDFFontDescriptor.GetType: string; begin Result := sdxPDFFontDescriptor; end; procedure TdxPSPDFFontDescriptor.WriteHeader(AWriter: TdxPSPDFWriter); begin inherited WriteHeader(AWriter); MetricNeeded; AWriter.WriteString(sdxPDFFontName + '/' + Owner.EncodeFontName); AWriter.WriteString(sdxPDFFontFlags + sdxPDFSpace + IntToStr(FFontFlags)); AWriter.WriteString(sdxPDFItalicAngle + sdxPDFSpace + IntToStr(FItalicAngle)); AWriter.WriteString(sdxPDFAscent + sdxPDFSpace + IntToStr(FAscent)); AWriter.WriteString(sdxPDFDescent + sdxPDFSpace + IntToStr(FDescent)); AWriter.WriteString(sdxPDFCapHeight + sdxPDFSpace + IntToStr(FCapHeight)); AWriter.WriteString(sdxPDFStemV + sdxPDFSpace + IntToStr(FStemVertical)); AWriter.WriteString(sdxPDFAvgWidth + sdxPDFSpace + IntToStr(FAveCharWidth)); AWriter.WriteString(sdxPDFMaxWidth+ sdxPDFSpace + IntToStr(FMaxCharWidth)); AWriter.WriteString(sdxPDFMissingWidth + sdxPDFSpace + IntToStr(FAveCharWidth)); AWriter.WriteString(sdxPDFLeading + sdxPDFSpace + IntToStr(FLeading)); AWriter.WriteString(Format(sdxPDFFontBox + ' [%d %d %d %d]', [FontBox.Left, FontBox.Bottom, FontBox.Right, FontBox.Top])); if Assigned(FontFile) then AWriter.WriteString(sdxPDFFontFile + sdxPDFSpace + AWriter.MakeLinkToObject(FontFile)); end; { TdxPSPDFFontInfo } constructor TdxPSPDFFontInfo.Create(AOwner: TdxPSPDFCustomFont); begin inherited Create; FOwner := AOwner; end; { TdxPSPDFCIDFont } constructor TdxPSPDFCIDFont.Create( AOwner: TdxPSPDFFontList; AEmbed: Boolean; AFont: TFont); begin inherited Create(AOwner, True, AFont); FTTFFile := TdxPSTTFFile.Create(AFont); FCharCache := TdxPSTTFCharCacheList.Create; FFontInfo := TdxPSPDFCIDFontInfo.Create(Self); FConversionTable := TdxPSPDFCIDFontConversionTable.Create(Self); end; destructor TdxPSPDFCIDFont.Destroy; begin FreeAndNil(FConversionTable); FreeAndNil(FTTFFile); FreeAndNil(FFontInfo); FreeAndNil(FCharCache); inherited Destroy; end; function TdxPSPDFCIDFont.EncodeFontName: string; begin Result := 'DX+' + inherited EncodeFontName; end; function TdxPSPDFCIDFont.EncodeText(const S: WideString): AnsiString; function WideEncodeText(const S: WideString): AnsiString; var AChar: Word; AGlyphIndex: Word; I: Integer; begin Result := ''; for I := 1 to Length(S) do begin AChar := Word(S[I]); AGlyphIndex := TTFFile.GlyphIndex[AChar]; CharCache.Add(AChar, AGlyphIndex); Result := Result + dxStringToAnsiString(IntToHex(AGlyphIndex, 4)); end; end; begin Result := '<' + WideEncodeText(S) + '>'; end; function TdxPSPDFCIDFont.TextWidth(const S: WideString): Integer; var I: Integer; begin Result:= 0; for I := 1 to Length(S) do Inc(Result, TTFFile.CharWidthByCode[Word(S[I])]); end; class function TdxPSPDFCIDFont.GetSubType: string; begin Result := sdxPDFSubTypeFontType0; end; procedure TdxPSPDFCIDFont.PopulateExportList(AList: TdxPSPDFObjectList); begin inherited PopulateExportList(AList); FontInfo.PopulateExportList(AList); ConversionTable.PopulateExportList(AList); end; procedure TdxPSPDFCIDFont.WriteHeader(AWriter: TdxPSPDFWriter); begin inherited WriteHeader(AWriter); AWriter.WriteString(sdxPDFEncoding + sdxPDFSpace + sdxPDFEncodingIdentityH); AWriter.WriteString(sdxPDFDescendantFonts + ' [' + AWriter.MakeLinkToObject(FontInfo) + ']'); AWriter.WriteString(sdxPDFToUnicode + sdxPDFSpace + AWriter.MakeLinkToObject(ConversionTable)); end; { TdxPSPDFCIDFontInfo } constructor TdxPSPDFCIDFontInfo.Create(AOwner: TdxPSPDFCustomFont); begin inherited Create(AOwner); FDescriptor := TdxPSPDFCIDFontDescriptor.Create(AOwner); FSystemInfo := TdxPSPDFCIDSystemInfo.Create('Identity'); end; destructor TdxPSPDFCIDFontInfo.Destroy; begin FreeAndNil(FSystemInfo); FreeAndNil(FDescriptor); inherited Destroy; end; class function TdxPSPDFCIDFontInfo.GetSubType: string; begin Result := sdxPDFSubTypeFontTypeCID; end; class function TdxPSPDFCIDFontInfo.GetType: string; begin Result := sdxPDFFont; end; function TdxPSPDFCIDFontInfo.GetCharCache: TdxPSTTFCharCacheList; begin Result := Owner.CharCache; end; function TdxPSPDFCIDFontInfo.GetGlyphIndexWidth(Index: Word): Integer; begin Result := Owner.TTFFile.CharWidthByGlyphIndex[Index]; end; function TdxPSPDFCIDFontInfo.GetOwner: TdxPSPDFCIDFont; begin Result := TdxPSPDFCIDFont(inherited Owner); end; procedure TdxPSPDFCIDFontInfo.PopulateExportList(AList: TdxPSPDFObjectList); begin inherited PopulateExportList(AList); Descriptor.PopulateExportList(AList); end; procedure TdxPSPDFCIDFontInfo.WriteCharWidths(AWriter: TdxPSPDFWriter); procedure WriteConsecutiveWidths(AGlyphIndex, AConsecutiveLength: Integer); var I: Integer; begin if AConsecutiveLength > 0 then begin AWriter.WriteString(IntToStr(AGlyphIndex) + ' [', False); for I := AGlyphIndex to AGlyphIndex + AConsecutiveLength - 1 do begin AWriter.WriteString(IntToStr(GlyphIndexWidth[I]), False); if I + 1 - AGlyphIndex < AConsecutiveLength then AWriter.WriteString(sdxPDFSpace, False); end; AWriter.WriteString(']'); end; end; var AConsecutiveLength: Integer; AOldGlyphIndex: Integer; AStartsFromGlyphIndex: Integer; I: Integer; begin AWriter.WriteString('/W ['); try AOldGlyphIndex := 0; AConsecutiveLength := 1; AStartsFromGlyphIndex := 0; CharCache.SortByGlyphIndex; for I := 0 to CharCache.Count - 1 do begin if CharCache.CacheItem[I].GlyphIndex <> AOldGlyphIndex + 1 then begin WriteConsecutiveWidths(AStartsFromGlyphIndex, AConsecutiveLength); AStartsFromGlyphIndex := CharCache.CacheItem[I].GlyphIndex; AConsecutiveLength := 0; end; AOldGlyphIndex := CharCache.CacheItem[I].GlyphIndex; Inc(AConsecutiveLength); end; WriteConsecutiveWidths(AStartsFromGlyphIndex, AConsecutiveLength); finally AWriter.WriteString(']'); end; end; procedure TdxPSPDFCIDFontInfo.WriteHeader(AWriter: TdxPSPDFWriter); begin inherited WriteHeader(AWriter); AWriter.WriteString(sdxPDFCharSet + sdxPDFSpace + IntToStr(Owner.Charset)); AWriter.WriteString(sdxPDFBaseFont + sdxPDFSpace + '/' + Owner.EncodeFontName); AWriter.WriteString(sdxPDFFontDescriptor + sdxPDFSpace + AWriter.MakeLinkToObject(Descriptor)); SystemInfo.Write(AWriter); WriteCharWidths(AWriter); end; { TdxPSPDFCIDSystemInfo } constructor TdxPSPDFCIDSystemInfo.Create(const AOrdering: string); begin inherited Create; FRegistry := 'Adobe'; FOrdering := AOrdering; FSupplement := 0; end; procedure TdxPSPDFCIDSystemInfo.Write(AWriter: TdxPSPDFWriter); begin AWriter.WriteString(sdxPDFCIDSystemInfo); AWriter.BeginParamsSet; try AWriter.WriteString(sdxPDFRegistry + ' (' + Registry + ')'); AWriter.WriteString(sdxPDFOrdering + ' (' + Ordering + ')'); AWriter.WriteString(sdxPDFSupplement + sdxPDFSpace + IntToStr(Supplement)); finally AWriter.EndParamsSet; end; end; { TdxPSPDFCIDFontConversionTable } constructor TdxPSPDFCIDFontConversionTable.Create(AOwner: TdxPSPDFCustomFont); begin inherited Create(AOwner); FSystemInfo := TdxPSPDFCIDSystemInfo.Create(CMapName); end; destructor TdxPSPDFCIDFontConversionTable.Destroy; begin FreeAndNil(FSystemInfo); inherited Destroy; end; function TdxPSPDFCIDFontConversionTable.GetContentStreamType(out AType: TdxPSPDFStreamType): Boolean; begin AType := pstText; Result := True; end; function TdxPSPDFCIDFontConversionTable.GetGlyphIndex(ACharCode: Word): Integer; begin Result := Owner.TTFFile.GlyphIndex[ACharCode]; end; function TdxPSPDFCIDFontConversionTable.GetOwner: TdxPSPDFCIDFont; begin Result := TdxPSPDFCIDFont(inherited Owner); end; function TdxPSPDFCIDFontConversionTable.GetCharCache: TdxPSTTFCharCacheList; begin Result := Owner.CharCache; end; function TdxPSPDFCIDFontConversionTable.GetCMapName: string; begin Result := sdxPDFCIDFontPrefix + '+' + Owner.Name; end; procedure TdxPSPDFCIDFontConversionTable.WriteContentStream(AWriter: TdxPSPDFWriter); begin SystemInfo.Ordering := CMapName; AWriter.WriteString('/CIDInit /ProcSet findresource begin'); AWriter.WriteString('12 dict begin'); AWriter.WriteString('begincmap'); SystemInfo.Write(AWriter); AWriter.WriteString('def'); AWriter.WriteString(sdxPDFCMapName + ' /' + CMapName + ' def'); AWriter.WriteString(sdxPDFCMapType + ' 2 def'); AWriter.WriteString('1 begincodespacerange'); AWriter.WriteString('<0000> '); AWriter.WriteString('endcodespacerange'); WriteConversionTable(AWriter); AWriter.WriteString('endcmap'); AWriter.WriteString('CMapName currentdict /CMap defineresource pop'); AWriter.WriteString('end'); AWriter.WriteString('end', False); end; procedure TdxPSPDFCIDFontConversionTable.WriteConversionTable(AWriter: TdxPSPDFWriter); var ACacheItem: TdxPSTTFCharCacheListItem; I: Integer; begin AWriter.WriteString(IntToStr(CharCache.Count) + ' beginbfchar'); for I := 0 to CharCache.Count - 1 do begin ACacheItem := CharCache.CacheItem[I]; AWriter.WriteString('<' + IntToHex(ACacheItem.GlyphIndex, 4) + '>' + sdxPDFSpace + '<' + IntToHex(ACacheItem.CharCode , 4) + '>'); end; AWriter.WriteString('endbfchar'); end; { TdxPSPDFFontFile } destructor TdxPSPDFFontFile.Destroy; begin FreeAndNil(FFontData); inherited Destroy; end; function TdxPSPDFFontFile.GetContentStreamType(out AType: TdxPSPDFStreamType): Boolean; begin AType := pstText; Result := True; end; function TdxPSPDFFontFile.GetFontDataValid: Boolean; begin Result := Assigned(FontData); end; procedure TdxPSPDFFontFile.FontDataNeeded; var AFont: TFont; begin if not FontDataValid then begin FreeAndNil(FFontData); AFont := Owner.CreateFont; try FFontData := TMemoryStream.Create; dxPSGetFontData(FFontData, AFont); finally AFont.Free; end; end; end; procedure TdxPSPDFFontFile.WriteContentStream(AWriter: TdxPSPDFWriter); begin FontDataNeeded; AWriter.WriteStream(FontData); end; procedure TdxPSPDFFontFile.WriteHeader(AWriter: TdxPSPDFWriter); begin FontDataNeeded; inherited WriteHeader(AWriter); AWriter.WriteString(sdxPDFLength + '1' + sdxPDFSpace + IntToStr(FontData.Size)); end; { TdxPSPDFCIDFontFile } function TdxPSPDFCIDFontFile.CanRebuildFont: Boolean; begin Result := TTFFile.OS2Section.FamilyClass <> 5; end; procedure TdxPSPDFCIDFontFile.FontDataNeeded; begin if not FontDataValid then begin if CanRebuildFont then begin FreeAndNil(FFontData); FFontData := TMemoryStream.Create; TTFFile.Rebuild(Owner.CharCache); TTFFile.SaveToStream(FontData); FFontData.Position := 0; end else inherited FontDataNeeded; end; end; function TdxPSPDFCIDFontFile.GetOwner: TdxPSPDFCIDFont; begin Result := TdxPSPDFCIDFont(inherited Owner); end; function TdxPSPDFCIDFontFile.GetTTFFile: TdxPSTTFFile; begin Result := Owner.TTFFile; end; { TdxPSPDFCIDFontDescriptor } function TdxPSPDFCIDFontDescriptor.CreateFontFile: TdxPSPDFFontFile; begin Result := TdxPSPDFCIDFontFile.Create(Owner); end; end.