% Copyright (C) 1994-2002 artofcode LLC. All rights reserved. % % This program is free software; you can redistribute it and/or modify it % under the terms of the GNU General Public License as published by the % Free Software Foundation; either version 2 of the License, or (at your % option) any later version. % % This program 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 General % Public License for more details. % % You should have received a copy of the GNU General Public License along % with this program; if not, write to the Free Software Foundation, Inc., % 59 Temple Place, Suite 330, Boston, MA, 02111-1307. % $Id: pdf_font.ps,v 1.23.2.6.2.1 2003/04/12 14:02:39 giles Exp $ % pdf_font.ps % PDF font operations. /.setlanguagelevel where { pop 2 .setlanguagelevel } if .currentglobal true .setglobal /pdfdict where { pop } { /pdfdict 100 dict def } ifelse GS_PDF_ProcSet begin pdfdict begin % We cache the PostScript font in an additional element of the % font resource dictionary, called PSFont. % ---------------- Encodings ---------------- % % Apply a list of differences to an Encoding. % Note that the differences may cause the array to grow. /updateencoding { % updateencoding % Calculate the length of the result. exch 0 2 index { dup type /nametype ne { exch pop } { pop 1 add } ifelse } forall 1 index length .max array dup 0 4 -1 roll putinterval exch 0 exch { % Stack: enc' code element dup type /nametype ne { exch pop } { 3 copy put pop 1 add } ifelse } forall pop } bdef % Get the Encoding for a font. /getencoding % getencoding { /Encoding knownoget { dup type /nametype eq { % The published PDF specification says the Encoding name % "must be" one of the 3 predefined Encodings, implying % that an error should occur if it isn't. However, Acrobat % Reader simply ignores unknown names, and since there are % some buggy applications that rely on this, we do the same. dup dup dup /MacRomanEncoding eq exch /MacExpertEncoding eq or exch /WinAnsiEncoding eq or { exch pop findencoding } { pop } ifelse } { dup /BaseEncoding knownoget { findencoding 3 -1 roll pop exch } if /Differences knownoget { updateencoding } if } ifelse } if } bdef % Rename a font with a generated name. /renamefont { % renamefont dup /FontName 2 copy get genfontname dup 5 1 roll put definefont } bind def % Adjust a font according to the Encoding and Widths in the font resource. /adjustfont { % adjustfont getfontencoding getfontmetrics 4 -1 roll pop .updatefont { renamefont } if } bind def % Get the (possibly modified) encoding of a font. /getfontencoding { % getfontencoding % 1 index /Encoding known { dup /Encoding .knownget { 2 index getencoding } { null } ifelse } { null } ifelse } bdef /find_in_diff % find_in_diff { false exch 0 4 3 roll { dup type /nametype ne { exch pop } { pop 1 add } ifelse 2 copy eq { pop pop pop true 0 0 exit } if } forall pop pop } bdef % Get the metrics of a font, if specified. /getfontmetrics { % getfontmetrics % % 2 index /Widths known { dup null eq { pop dup /Encoding get } if 4 dict begin /Encoding exch def /Metrics Encoding length dict def exch dup /Widths oget /Widths exch def % Stack: font font-res % Note that widths are always based on a 1000-unit % character space, but the FontMatrix may specify % some other scale factor. Compensate for this here, % by scaling the Widths if necessary. 0.001 2 index /FontMatrix get 0 get div % Stack: font font-res mscale 1 index /FirstChar oget dup 1 4 index /LastChar oget { % Stack: font font-res mscale first-char index Encoding 1 index get Widths 2 index 4 index sub oget % Stack: font font-res mscale first-char index charname width 4 index mul % The following 'loop' is only context for 'exit'. { % Work around a bug in pdfTeX, which can generate Encoding % vectors containing nulls : 1 index null eq { exit } if % There is a hack here to deal with encodings where the % same character appears more than once, because the Metrics % dictionary works by character name, not by character code. % We prefer to take (1) non-zero width, and (2) width for % the character code which appears in Differences. Metrics 2 index .knownget not { 0 } if 0 ne { 5 index /Encoding knownoget not { exit } if dup type /dicttype ne { pop exit } if /Differences knownoget not { exit } if 3 index //find_in_diff exec not { exit } if } if 2 copy Metrics 3 1 roll put exit } loop pop pop pop } for pop % Now fill in the MissingWidth for any encoded characters % that aren't in Metrics already. Note that built-in % fonts may have Widths/FirstChar/LastChar but no % FontDescriptor, so we must check for this. % Stack: font font-res mscale 1 index /FontDescriptor knownoget { Metrics exch /MissingWidth knownoget { 2 index mul } { 0 } ifelse exch Encoding { % Stack: font font-res mscale missing-width metrics charname % Work around the abovementioned pdfTeX bug. dup null ne { 2 copy known not { 2 copy 4 index put } if pop } { pop } ifelse } forall pop pop pop } { pop } ifelse exch Encoding Metrics end } { null } ifelse } bdef currentdict /find_in_diff undef % ---------------- Descriptors ---------------- % % Partial descriptors for the 14 built-in fonts. Note that % from PDF 1.1 to PDF 1.2, the meaning of the Flag 6 in the FontDescriptor % object has undergone a subtle change in its meaning which has serious % consequences for searching with Acrobat: % In PDF 1.1, the flag meant: Font has StandardEncoding % In PDF 1.2, the flag means: Font has (subset of) StandardRomanCharacterSet /standardfontdescriptors mark /Courier mark /Flags 16#23 .dicttomark /Courier-Oblique 1 index /Courier-Bold 1 index /Courier-BoldOblique 1 index /Helvetica mark /Flags 16#20 .dicttomark /Helvetica-Oblique 1 index /Helvetica-Bold 1 index /Helvetica-BoldOblique 1 index /Times-Roman mark /Flags 16#22 .dicttomark /Times-Bold 1 index /Times-Italic mark /Flags 16#62 .dicttomark /Times-BoldItalic 1 index /Symbol mark /Flags 16#4 .dicttomark /ZapfDingbats 1 index .dicttomark readonly def % ---------------- Utilities ---------------- % /.glyphpath { % .glyphpath - % another glyphpath written in addxchar.ps does not work here... currentfont 3 1 roll exch currentfont dup length dict begin { 1 index /Encoding eq { pop [ 3 -1 roll ] def } { def } ifelse } forall currentdict end /.glyphpathfont exch definefont setfont <00> exch charpath setfont } bdef /makeboldfont { % makeboldfont 10 dict begin /strokewidth exch def /basefont exch def /FontMatrix matrix def %/FontName basefont /FontName get def /FontName /.boldfont def /FontType 3 def /Encoding basefont /Encoding get def /FontBBox [ basefont /FontBBox get cvx exec 4 2 roll basefont /FontMatrix get transform 4 2 roll basefont /FontMatrix get transform ] def /BuildGlyph { gsave exch begin basefont setfont strokewidth setlinewidth 1 setlinejoin newpath 0 0 moveto dup false .glyphpath stroke 0 0 moveto glyphshow currentpoint setcharwidth end grestore } bind def currentdict end dup /FontName get exch definefont } bind def % Fabricate a font name by adding ?'s on the end. /genfontname % genfontname { dup length string cvs { (?) concatstrings dup cvn FontDirectory exch known not { cvn exit } if } loop } bdef % Find a font, and adjust its encoding if necessary. /.pdfdfndict mark /defaultfontname /Helvetica .dicttomark readonly def /pdffindfont { % pdffindfont % If the font isn't available, synthesize one based on % its descriptor. dup /Font resourcestatus { pop pop findfont } { 1 index /FontDescriptor knownoget { % Stack: font-res fontname fontdesc dup /Flags oget dup 16#40 and -6 bitshift % 1, oblique/italic 1 index 16#40000 and -17 bitshift add % 2, bold exch 16#2 and 2 bitshift add % 8, serif % We should look at the fixed flag, too. % Stack: font-res fontname fontdesc properties 1 index /FontName oget exch % Analyzes font name and extract "Narrow" property % which is not described by the FontDescriptor Flags. 0 2 index .fontnameproperties 4 and or % Rebind the default font name to Helvetica so that % fonts with no properties are handled correctly. //.pdfdfndict begin .substitutefontname end % Stack: font-res fontname fontdesc substname|null Fontmap 1 index known not { % No available good substitution, use the standard one. pop 1 index .substitutefont } if QUIET not { (Substituting font ) print dup =only ( for ) print 2 index =only (.) = flush } if 3 -1 roll pop findfont % Stack: font-res fontdesc font % If this is a small-caps font, replace the CharString % entries for a..z. exch /Flags oget 16#20000 and 0 ne { true .copyfontdict dup /CharStrings 2 copy get dup length dict .copydict 4 index /FirstChar get 97 .max 5 index /LastChar get 122 .min 1 exch { % Stack: font-res font' font' /CharStrings charstrings code % Note that this only remaps a-z, not accented characters. 5 index /Widths oget 1 index 7 index /FirstChar get sub oget 1 string dup 0 5 -1 roll put % Stack: font-res font' font' /CharStrings charstrings code % width (x) 2 index exch dup cvn exch dup 0 2 copy get 32 sub put 4 -1 roll { % Stack: operand (X) width 0 setcharwidth exch pop currentfont /FontMatrix get matrix invertmatrix concat 0.7 dup scale 0 0 moveto show } /exec cvx 4 packedarray cvx put } for put renamefont } if } { % No descriptor available, use the default algorithm. findfont } ifelse } ifelse adjustfont } bdef /findpdffont { % findpdffont {} 3 1 roll % proc fnres fnname [ [ (,Bold) { .03 makeboldfont } ] [ (,BoldItalic) { .03 makeboldfont [ 1 0 .3 1 0 0 ] makefont } bind ] [ (,Italic) { [ 1 0 .3 1 0 0 ] makefont } bind ] ] { 1 index dup length string cvs 1 index 0 get tailmatch { % proc fnres fnname [] 3 -1 roll pop exch 1 get % proc fnres pre-fnname proc 4 -1 roll pop 3 1 roll % proc fnres pre-fnname exit } { pop pop } ifelse % proc fnres fnname } forall pdffindfont exch exec } bdef % ---------------- Type 1 fonts ---------------- % /buildType1 % buildType1 { dup /BaseFont get pdffindfont } bdef % The state dictionary for the embedded Type 1 font reading procedure % has the following keys and values: % data - stream (filter) % buffer, buffer2 - string % hexify - procedure to convert buffer to hex if needed % leftstr - string containing (non-negative) integer % sectionstr - string containing a character 0 .. 3 % stream - (stream) dictionary % proc - procedure of the form {-dict- type1read} % pfbhdr - string containing 16#80 if PFB, 0 otherwise % When the procedure is executing, this dictionary is current. % leftstr and sectionstr are strings so that we can change their values % reliably in case the font executes a restore! % We also have to do something special about embedded fonts that % execute definefont more than once -- that is the function of topFontDict. % Read an embedded Type 1 font. /readfontfilter { % readfontfilter 0 () /SubFileDecode filter } bdef /readtype1dict 5 dict dup begin /definefont { dup topFontDict eq topFontDict null eq or { dup wcheck not { dup length dict copy } if exch pop savedFontName exch } if //systemdict /definefont get exec } bdef /eexec { % Assume the font dictionary is directly below the file on the stack count 0 gt { /topFontDict 2 index cvlit store } if 55665 /eexecDecode filter //systemdict begin readtype1dictcopy begin cvx stopped currentdict readtype1dictcopy eq { end } if currentdict //systemdict eq { end } if { stop } if } bdef end readonly def /readtype1 { % readtype1 % Read the definition, using a procedure-based filter % that turns binary/hex conversion on and off % at the right times. 1 index exch PDFfile fileposition 3 1 roll 11 dict begin /leftstr ( ) 10 string copy def dup /Length1 oget leftstr cvs pop /sectionstr <00> 1 string copy def /pfbhdr <00> 1 string copy def /stream 1 index def true resolvestream /data exch def /buffer 1000 string def % arbitrary /buffer2 buffer length 2.1 div cvi 1 sub string def /hexify /buf2hex load def currentdict end /type1read cvx 2 array astore cvx dup 0 get /proc 2 index put readfontfilter % Some buggy embedded fonts leave extra junk on the stack, % so we have to make a closure that records the stack depth % in a fail-safe way. //systemdict begin % The PDF specification is somewhat muddy about whether % an embedded font's name is supposed to be the BaseFont % from the Font object or the FontName from the descriptor. % Acrobat Distiller requires the former. Save away the % name so we can substitute it at definefont time. //readtype1dict dup length 3 add dict copy begin 1 index /BaseFont oget /savedFontName exch def /topFontDict null def /readtype1dictcopy currentdict def { run } aload pop count 1 sub 2 packedarray cvx exec end end count exch sub { pop } repeat PDFfile 3 -1 roll setfileposition /BaseFont oget findfont adjustfont } bdef % Execute the appropriate reading procedure. /type1read % type1read { begin leftstr cvi { type1read0 type1read1 type1read2 type1read3 } sectionstr 0 get get exec ( ) leftstr copy cvs pop end } bdef % Read the next block of data into the buffer. /type1readdata % type1readdata { 0 2 index 2 index length .min getinterval % Adobe requires readstring to signal an error if given % an empty string. Work around this nonsense here. dup length 0 ne { data exch readstring pop } if dup length 3 -1 roll exch sub DEBUG { dup =only ( read ) print 1 index length =only (: ) print 1 index == flush } if } bdef % Read the initial byte to see if we need to skip a 6 byte PFB header /type1read0 { % type1read0 sectionstr 0 1 put % either way we go to the next stage pfbhdr type1readdata 1 index 0 get 16#80 eq { (\n **** Warning: Embedded Type1 font in PFB format is not valid PDF.) pdfformaterror DEBUG { (skipping PFB header) = flush } if exch pop buffer 0 5 getinterval type1readdata exch dup 4 get 256 mul 1 index 3 get add 256 mul 1 index 2 get add 256 mul 1 index 1 get add DEBUG { (PFB segment length = ) print dup = } if exch pop % discard the string keeping the PFB segment length 2 copy ne { (\n **** Warning: Type 1 PFB segment length and Length 1 value do not match.) pdfformaterror exch % keep the PFB length instead } if pop buffer type1readdata % go ahead and read a block } if % if not PFB, return pfbhdr string (first char of file, usually %). } bdef % Read the next block of the initial text portion. /type1read1 { % type1read1 DEBUG { (read1 ) print } if dup 0 eq { pop sectionstr 0 2 put stream /Length2 oget % Determine whether to hexify data for eexec. dup 8 lt { type1read2 % Hexify. } { DEBUG { (read2 ) print } if pfbhdr 0 get 16#80 eq { % eat 6 more bytes of PFB junk before proceeding DEBUG { (skipping PFB header in segment 2) = flush } if buffer 0 6 getinterval type1readdata exch dup 5 get 256 mul 1 index 4 get add 256 mul 1 index 3 get add 256 mul 1 index 2 get add DEBUG { (PFB segment length = ) print dup = } if exch pop % discard the string keeping the PFB segment length 2 copy ne { (\n **** Warning: Type 1 PFB segment length and Length 2 value do not match.) pdfformaterror dup = exch % keep the PFB length instead } if pop } if buffer2 type1readdata exch % The check doesn't have to be 100% accurate: % hexifying is always OK. dup 0 8 getinterval 0 exch { or } forall 128 ge { /hexify { } store /buffer2 buffer def % We don't need an intermediate buffer. } if hexify exch } ifelse } { buffer type1readdata } ifelse } bdef % Convert a string from binary to hex for eexec. % Free variables: buffer. /buf2hex { % buf2hex buffer /ASCIIHexEncode filter dup 3 -1 roll writestring closefile buffer (>) search pop exch pop exch pop } bdef % Read the next block of the encrypted portion. /type1trailer (0000000000000000000000000000000000000000000000000000000000000000\n\ 0000000000000000000000000000000000000000000000000000000000000000\n\ 0000000000000000000000000000000000000000000000000000000000000000\n\ 0000000000000000000000000000000000000000000000000000000000000000\n\ 0000000000000000000000000000000000000000000000000000000000000000\n\ 0000000000000000000000000000000000000000000000000000000000000000\n\ 0000000000000000000000000000000000000000000000000000000000000000\n\ 0000000000000000000000000000000000000000000000000000000000000000\n\ cleartomark\n) readonly def /type1read2 { % type1read2 DEBUG { (read2 ) print } if dup 0 eq { pop sectionstr 0 3 put stream /Length3 oget dup 0 eq { DEBUG { (trailer ) print } if type1trailer exch } { pfbhdr 0 get 16#80 eq { % eat 6 more bytes of PFB junk before proceeding DEBUG { (skipping PFB header in segment 3) = flush } if buffer 0 6 getinterval type1readdata exch dup 5 get 256 mul 1 index 4 get add 256 mul 1 index 3 get add 256 mul 1 index 2 get add DEBUG { (PFB segment length = ) print dup = } if exch pop % discard the string keeping the PFB segment length 2 copy ne { (\n **** Warning: Type 1 PFB segment length and Length 3 value do not match.) pdfformaterror exch % keep the PFB length instead } if pop (\n) pdfformaterror } if type1read3 } ifelse } { buffer2 type1readdata exch hexify exch } ifelse } bdef % Read the next block of the final text portion. % When finished, this procedure returns an empty string. /type1read3 % type1read3 { DEBUG { (read3 ) print } if buffer type1readdata } bdef % ---------------- Type 3 fonts ---------------- % /.notdefEncoding 256 { /.notdef } repeat 256 packedarray def /buildType3 { % buildType3 8 dict begin /FontType 3 def /Resources 1 index /Resources knownoget { oforce } { 0 dict } ifelse def /FontBBox 1 index /FontBBox get cvx def /FontMatrix 1 index /FontMatrix oget def /CharProcs 1 index /CharProcs oget def 1 index /Widths knownoget { /Widths exch def /FirstChar 1 index /FirstChar oget def /LastChar 1 index /LastChar oget def } if /FontName 1 index /Name get genfontname def /Encoding .notdefEncoding 2 index getencoding def % We have to define BuildChar rather than BuildGlyph: % there is no PDF equivalent of glyphshow, and we need % the character code to access the Widths. /BuildChar { % Stack: font charcode 1 index begin 3 dict begin /Font 3 -1 roll def /CharCode 1 index def % Make unknown characters map to /.notdef Encoding exch get dup CharProcs exch known { CharProcs exch oget } { pop CharProcs /.notdef oget } ifelse PDFfile fileposition exch false resolvestream % Stack: filepos stream % Don't let setgcolor set the color inside the BuildGlyph % procedure, because this causes an /undefined error. q null /FillColor gput null /StrokeColor gput Font /Resources get exch pdfopdict .pdfruncontext Q PDFfile exch setfileposition end end } bdef FontName currentdict end definefont exch pop } bdef /.adjustcharwidth { % .adjustcharwidth /Widths where { begin CharCode FirstChar ge CharCode LastChar le and { exch pop Widths CharCode FirstChar sub get exch } if end } if } bdef % ---------------- TrueType fonts ---------------- % /TTfonts mark /Arial /Helvetica /Arial,Italic /Helvetica-Oblique /Arial,Bold /Helvetica-Bold /Arial,BoldItalic /Helvetica-BoldOblique /CourierNew /Courier /CourierNew,Bold /Courier-Bold /TimesNewRoman /Times-Roman /TimesNewRoman,Italic /Times-Italic /TimesNewRoman,Bold /Times-Bold /TimesNewRoman,BoldItalic /Times-BoldItalic % /ArialBlack,Italic /Arial-BlackItalic /ArialNarrow,Bold /ArialNarrow-Bold /ArialNarrow,BoldItalic /ArialNarrow-BoldItalic /ArialNarrow,Italic /ArialNarrow-Italic /BookAntiqua,Bold /BookAntiqua-Bold /BookAntiqua,BoldItalic /BookAntiqua-BoldItalic /BookAntiqua,Italic /BookAntiqua-Italic /BookmanOldStyle,Bold /BookmanOldStyle-Bold /BookmanOldStyle,BoldItalic /BookmanOldStyle-BoldItalic /BookmanOldStyle,Italic /BookmanOldStyle-Italic /CenturyGothic,Bold /CenturyGothic-Bold /CenturyGothic,BoldItalic /CenturyGothic-BoldItalic /CenturyGothic,Italic /CenturyGothic-Italic /ComicSansMS,Bold /ComicSansMS-Bold /CourierNew,Bold /CourierNewPS-BoldMT /CourierNew,BoldItalic /CourierNewPS-BoldItalicMT /CourierNew,Italic /CourierNewPS-ItalicMT /FranklinGothicMedium,Italic /FranklinGothic-MediumItalic /Garamond,Bold /Garamond-Bold /Garamond,Italic /Garamond-Italic /Georgia,Bold /Georgia-Bold /Georgia,BoldItalic /Georgia-BoldItalic /Georgia,Italic /Georgia-Italic /Tahoma,Bold /Tahoma-Bold /TrebuchetMS,Bold /TrebuchetMS-Bold /TrebuchetMS,BoldItalic /Trebuchet-BoldItalic /TrebuchetMS,Italic /TrebuchetMS-Italic /Verdana,Bold /Verdana-Bold /Verdana,BoldItalic /Verdana-BoldItalic /Verdana,Italic /Verdana-Italic .dicttomark readonly def /buildTrueType { % buildTrueType dup /BaseFont get dup TTfonts exch .knownget { exch pop % Hack required by the PDF specification: if the % font resource has Subtype = /TrueType but the actual % (installed) font is not a TrueType font, ignore the % Encoding in the font resource. However, all current % versions of Acrobat Reader have the 14 base TrueType % fonts built in, so this produces incorrect output for % badly designed PDF files that specify these file names % with /Subtype = /TrueType but no embedded definition. % Compensate for this by removing the /Subtype key when % looking up the font. exch dup length dict copy dup /Subtype null put exch } if pdffindfont % findfont for PDF % disable the auto-bold and auto-italic since it sometimes applies % so an already bold or italic substitute font %findpdffont % findfont and auto-bold and/or auto-italic font for PDF } bdef % Read an embedded TrueType font. /readtruetype { % readtruetype % This is much simpler than readtype1, because we don't % have to deal with the tripartite .PFB format. 1 index exch PDFfile fileposition 3 1 roll true resolvestream readfontfilter % Stack: filepos fontres stream 1 index /Subtype get /CIDFontType2 eq { .loadttcidfont % Stack: filepos fontres cidfont 1 index /CIDToGIDMap knownoget { dup /Identity eq { pop } { true resolvestream % The following doesn't work for CIDToGIDMaps with more % than 32K-1 entries. We'll fix it later if necessary. % Stack: filepos fontres font mapstream dup 2 index /CIDCount oget 2 mul string readstring pop exch closefile exch dup length 5 add dict .copydict dup /FID undef dup /CIDMap 4 -1 roll put dup /CIDFontName get exch /CIDFont defineresource } ifelse } if } { null 2 index getencoding .loadpdfttfont } ifelse exch pop PDFfile 3 -1 roll setfileposition % Ignore both the Encoding and the Widths. exch pop } bdef % ---------------- Type 0 fonts ---------------- % % Predefine the known CMaps, but only create them on demand. /knownCMaps mark /Identity-H { /Identity-H 0 makeIdentityCMap } /Identity-V { /Identity-V 1 makeIdentityCMap } .dicttomark def /makeIdentityCMap { % .makeIdentityCMap - .currentglobal true .setglobal 3 1 roll /CIDInit /ProcSet findresource begin 12 dict begin begincmap /WMode exch def /CMapName exch def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering (Identity) def /Supplement 0 def end def %/CMapName (see above) /CMapVersion 1 def /CMapType 1 def %WMode (see above) % The PDF documentation says that these CMaps map CIDs % "1 to 65,536". This is a misprint for 0 to 65,535. 1 begincodespacerange % <0001> <00ff> <0100> <0000> endcodespacerange 1 begincidrange % <0001> <00ff> 1 <0100> 256 <0000> 0 endcidrange endcmap CMapName currentdict /CMap defineresource knownCMaps CMapName 2 index put end % CMap end % CIDInit ProcSet exch .setglobal } bdef /buildType0 { % buildType0 dup /BaseFont get % FontName 1 index /Encoding oget dup type /nametype eq { dup /CMap resourcestatus { pop pop /CMap findresource } { knownCMaps 1 index .knownget { exch pop exec } { /undefined signalerror } ifelse } ifelse } { PDFfile fileposition exch dup /CMapName get exch true resolvestream cvx exec /CMap findresource exch PDFfile exch setfileposition } ifelse % CMap [ 3 index /DescendantFonts oget { exec resourcefont } forall ] % subfonts composefont % Stack: fontres font 1 index /FontMatrix knownoget { dup aload pop true {0 0 1 0 0 1} {3 -1 roll eq and} forall { 1 index exch makefont exch /FontName get exch definefont } { pop } ifelse } if exch pop } bdef % ---------------- CIDFontType0/2 fonts ---------------- % % Insert metrics into a CIDFont, by saving the PDF W, W2, DW, and DW2 % arrays and using a (currently very inefficient) CDevProc. % For detail, refer "PDF Reference" third edition, p. 337, % "5.6.3 CIDFonts" and table "Entries in a CIDFont dictionary". /.pdfDefaultDW 1000 def /.pdfDefaultDW2 [ 880 -1000 ] def /addCIDmetrics { % addCIDmetrics dup length 5 add dict .copydict dup /FID undef dup /UniqueID undef dup /XUID undef % Insert the widths into the font. % Stack: pdfresource newfont 1 index /DW .knownget { 1 index /DW 3 -1 roll put } { dup /DW .pdfDefaultDW put } ifelse 1 index /W .knownget { dup 2 index /W 3 -1 roll put .pdfMakeInternalW 1 index /.internalW 3 -1 roll put } if 1 index /DW2 .knownget { 1 index /DW2 3 -1 roll put } { dup /DW2 .pdfDefaultDW2 put } ifelse 1 index /W2 .knownget { dup 2 index /W2 3 -1 roll put .pdfMakeInternalW2 1 index /.internalW2 3 -1 roll put } if dup /CDevProc 1 index /CIDWProc load /exec load 3 packedarray cvx put exch pop } bdef /.pdfMakeInternalMTXArray { % .pdfConvertInternalW % convert /W or /W2 to internal expression % % mtx_array: original /W or /W2 array % item_size: number of metrics values per CID % % for detail of the metrics list format in PDF, % refer PDF Ref. p.317 "Glyph Metrics in CIDFonts". % % format of single entry in internal expression % % [ % [cid_begin cid_end] % value_is_varied (bool) % [ [values for cid_begin...] % [values for cid_begin + 1] % ... ] % ] % 7 dict begin /itemSize exch def /M exch def % original /W or /W2 /Msize M length def /Mi { M i get } def % W[i] /Mi1 { M i 1 add get } def % W[i + 1] /putMTXEntry << /arraytype { [ [Mi Mi Mi1 length add 1 sub] true [ 0 itemSize Mi1 length 1 sub { [ exch 1 1 index itemSize add 1 sub { Mi1 exch get } for ] } for ] ] /i i 2 add def } /integertype { [ [Mi Mi1] false [[ i 2 add 1 i 1 add itemSize add { M exch get } for ]] ] /i i 3 add def } >> def /i 0 def [ { putMTXEntry Mi1 type get exec i Msize ge { exit } if } loop ] end } def /.pdfMakeInternalW { dup length 0 gt { 1 .pdfMakeInternalMTXArray } if } def /.pdfMakeInternalW2 { dup length 0 gt { 3 .pdfMakeInternalMTXArray } if } def /.pdfGetMTXByCID { % % .pdfGetMTXByCID % { true | false } % get values for given CID from internal format of /W or /W2 exch { { dup 0 get {} forall % Stack: 3 index lt { pop pop false exit } if 2 index exch sub dup 0 lt { pop pop false exit } if 1 index 1 get not { pop 0 } if exch 2 get exch get true exit } loop { exit } if } forall dup type /arraytype eq { exch pop true } { pop false } ifelse } def % Apply the [D]W[2] metrics to a character before displaying. /CIDWProc { % % CIDWproc % ... begin % push to currentdict % won't be used and replaced, discard now 5 1 roll pop pop pop pop { currentdict /DW .knownget not { % no DW .pdfDefaultDW exit % replace by defaultDW } if currentdict /.internalW .knownget not { % no W exit % use already-stacked DW } if dup length 0 eq { % W is null array pop % discard unusable W exit % use already-stacked DW } if % W is finite array, try to get W_cid 2 index .pdfGetMTXByCID { % got W, discard DW exch pop {} forall exit } if exit } loop 1000 div % (normalized W) 0 % % Stack: 9 -2 roll pop pop % discard 7 2 roll % put % Stack: 0 % exch % put % Stack: { currentdict /DW2 .knownget not { % no DW2, use defaultDW2 .pdfDefaultDW2 exit } if currentdict /.internalW2 .knownget not { % has DW2, no W2 exit % use already-stacked DW2 } if dup length 0 eq { % W2 is null array pop % discard unusable W2 exit % use already-stacked DW2 } if 2 index .pdfGetMTXByCID { % got W2_cid, discard DW2 exch pop exit } if % could not get W2_cid exit } loop exch pop % discard % Stack: { [ ] | [ ] } dup length 2 eq { % this is DW2 {1000 div} forall exch 4 index 7 index add 2 div % = ( + ) / 2 exch }{ % assume W2 {1000 div} forall } ifelse end % recover currentdict } def %---------------------------------------------------------------- % tailmatch ==>
 true
%                            ==>  false
/tailmatch {
  2 copy length 1 index length .min
  dup 2 index length exch sub exch getinterval
  1 index eq {
    length 1 index length exch sub
    0 exch getinterval true
  } {
    pop false
  } ifelse
} bind def

/makeboldcidfont {
  16 dict begin
    /strokewidth exch def
    /basecidfont exch def
    /FontMatrix [ 1 0 0 1 0 0 ] def

    /CIDFontName /.boldfont def
    /CIDFontType 1 def

    /basefont-H /.basefont-H /Identity-H [ basecidfont ] composefont def
    /basefont-V /.basefont-V /Identity-V [ basecidfont ] composefont def

    /CIDSystemInfo dup basecidfont exch get def
    /FontBBox [ basecidfont /FontBBox get cvx exec
      4 2 roll basecidfont /FontMatrix get transform
      4 2 roll basecidfont /FontMatrix get transform
    ] def

    /tmpstr 2 string def
    /BuildGlyph {
      gsave
      exch begin
        dup 256 idiv tmpstr exch 0 exch put
        256 mod tmpstr exch 1 exch put
        rootfont /WMode known { rootfont /WMode get 1 eq } { false } ifelse
        { basefont-V } { basefont-H } ifelse setfont
        strokewidth setlinewidth
        1 setlinejoin
        newpath
        0 0 moveto tmpstr false charpath stroke
        0 0 moveto tmpstr show
        currentpoint setcharwidth
      end
      grestore
    } bind def

   currentdict
  end
  dup /CIDFontName get exch /CIDFont defineresource
} bind def

%   findCIDFont  
%   CIDFont-resource is not modified.
/findCIDFont {
  {
    dup /CIDFont resourcestatus {
      pop pop /CIDFont findresource
      exit
    } if

    dup dup length string cvs
    (,Bold) tailmatch {
      exch pop
      cvn findCIDFont 0.03 makeboldcidfont
      exit
    } if
    (,Italic) tailmatch {
      exch pop
      cvn findCIDFont
      [ 1 0 0.3 1 0 0 ] makefont
      exit
    } if
    (,BoldItalic) tailmatch {
      exch pop
      cvn findCIDFont 0.03 makeboldcidfont
      [ 1 0 0.3 1 0 0 ] makefont
      exit
    } if
    pop

    1 index /CIDSystemInfo get begin Registry (-) Ordering end
    concatstrings concatstrings
    cvn
    QUIET not {
      (Substituting ) print dup ==only
      ( for ) print 1 index ==only (.\n) print
    } if
    exch pop
    /CIDFont findresource
    exit
  } loop
} bdef

/buildCIDType0 {	%  buildCIDType0 
  dup /BaseFont get exch 1 index findCIDFont
  addCIDmetrics /CIDFont defineresource
} bdef

/buildCIDType2 {	%  buildCIDType2 
  dup /BaseFont get exch 1 index findCIDFont
  addCIDmetrics /CIDFont defineresource
} bdef

% ---------------- Other embedded fonts ---------------- %

/fontloadprocs mark
  /Type1C /readType1C cvx
  /CIDFontType0C /readCIDFontType0C cvx
.dicttomark readonly def

% Read an embedded compressed font.
/readType1C {		%   readType1C 
  1 index exch
  PDFfile fileposition 3 1 roll
  dup true resolvestream dup readfontfilter
		% Stack: pos resource streamdict stream filter
  3 index /FontDescriptor oget /FontName oget
  1 index FRD
  closefile closefile pop
  PDFfile 3 -1 roll setfileposition
  /FontDescriptor oget /FontName oget findfont
  adjustfont
} bdef

% Read an embedded CFF CIDFont.
/readCIDFontType0C {  %   readCIDFontType0C 
  PDFfile fileposition 3 1 roll
  dup true resolvestream dup readfontfilter
		% Stack: pos resource streamdict stream filter
  3 index /FontDescriptor oget /FontName oget
  1 index FRD
  closefile closefile pop
  PDFfile 3 -1 roll setfileposition
		% Some broken Adobe software produces PDF files in which
		% the FontName of the CFF font and the FontName in the
		% FontDescriptor don't match the BaseFont in the font.
		% Use the FontName, rather than the BaseFont, here.
  dup /FontDescriptor oget /FontName oget /CIDFont findresource
  addCIDmetrics dup /CIDFontName get exch /CIDFont defineresource
} bdef

% ---------------- Font lookup ---------------- %

/fonttypeprocs mark		%  -proc- 
  /Type0 /buildType0 cvx
  /Type1 /buildType1 cvx
  /MMType1 1 index
  /Type3 /buildType3 cvx
  /TrueType /buildTrueType cvx
  /CIDFontType0 /buildCIDType0 cvx
  /CIDFontType2 /buildCIDType2 cvx
.dicttomark readonly def

/resourcefont			%  resourcefont 
 { dup /PSFont .knownget
    { /FID .knownget { type /fonttype eq } { false } ifelse }
    { false }
   ifelse
    { /PSFont get
    }
    { dup dup /FontDescriptor knownoget
       {	% Stack: font-res font-res font-desc
	 dup /FontFile knownoget
	  { exch pop readtype1 true }
	  { dup /FontFile2 knownoget
	     { exch pop readtruetype true }
	     { /FontFile3 knownoget
		{ dup /Subtype get fontloadprocs exch get exec true }
		{ false }
	       ifelse
	     }
	    ifelse
	  }
	 ifelse
       }
       { false }
      ifelse
		% Stack: font-res font-res false
		%  -or-: font-res font true
      not
       { dup /Subtype get fonttypeprocs exch get exec }
      if
      2 copy /PSFont exch put
      exch pop
    }
   ifelse
 } bdef

drawopdict begin
  /d0 {
    .adjustcharwidth setcharwidth
  } bdef
  /d1 {
    6 -2 roll .adjustcharwidth 6 2 roll setcachedevice
  } bdef
  /Tf {
    1 index Page /Font rget not { 1 index /invalidfont signalerror } if
    resourcefont exch Tf pop
  } bdef
end

end			% pdfdict
end			% GS_PDF_ProcSet
.setglobal