ref: 45f7b30244297a8bf87789793eec875246ed063c
dir: /sys/src/cmd/gs/lib/pdf_font.ps/
% Copyright (C) 1994, 2000 Aladdin Enterprises. All rights reserved. % % This software is provided AS-IS with no warranty, either express or % implied. % % This software is distributed under license and may not be copied, % modified or distributed except as expressly authorized under the terms % of the license contained in the file LICENSE in this distribution. % % For more information about licensing, please refer to % http://www.ghostscript.com/licensing/. For information on % commercial licensing, go to http://www.artifex.com/licensing/ or % contact Artifex Software, Inc., 101 Lucas Valley Road #110, % San Rafael, CA 94903, U.S.A., +1(415)492-9861. % $Id: pdf_font.ps,v 1.80 2005/09/29 15:24:53 leonardo Exp $ % PDF font operations. % Finding a font by name can't give a proper result when PDF font names aren't unique. % But it is only the way to obtain a font in Postscript after a font file is executed. % Therefore using a FontName (and findfont) is allowed only % immediately after a font file is executed. % In all other cases the font to be found by a pointer through PDF structures. % % This ideal logics can't work for documents, % which define a font resource with an embedded font, % and another font resource with same BaseFont but with no embedded font % (and possibly with no font descriptor). % Our testbase does contain such examples. % In this case we do find font by FontName (with findfont), % since there is no other way to get a reasonable result. /.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 ---------------- % /.notdefEncoding 256 { /.notdef } repeat 256 packedarray def % Apply a list of differences to an Encoding. % Note that the differences may cause the array to grow. /updateencoding { % <encoding|null> <differences> updateencoding <enc'> % Calculate the length of the result. % in case the incoming Encoding is null, use .notdefEncoding exch dup null eq { pop .notdefEncoding } if 0 0 3 index { dup type /nametype ne { exch pop oforce } { pop 1 add } ifelse % Differences list may not be in order, update the largest_index % stack: <Differences> <encoding> <largest_index> <at_index> 2 copy lt { exch pop dup } if % at_index is new largest } forall pop 1 index length .max array dup 0 4 -1 roll putinterval exch 0 exch { % Stack: enc' code element dup type /nametype ne { exch pop oforce } { 3 copy put pop 1 add } ifelse } forall pop } bdef % Get the Encoding for a font. /getencoding % <base-encoding> <font-resource> getencoding <enc> { /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 { dup / eq { pop ( **** Warning: Ignoring bad BaseEncoding name.\n) pdfformaterror % as found in a PDF file from J.D.Edwards OneWorld (B7333), bug 687786 } { findencoding 3 -1 roll pop exch } ifelse } if /Differences knownoget { updateencoding } if } ifelse } if } bdef /checkGlyphNames2Unicode % <dict> checkGlyphNames2Unicode - { PDFDEBUG { dup /FontInfo .knownget { /GlyphNames2Unicode .knownget { (Has GlyphNames2Unicode) = pop % { exch == ==} forall } if } if } if pop } bind def % Define a font using it's FontName as the key. % Adjust a font according to the Encoding and Widths in the font resource. /adjustfont { % <font-resource> <font> adjustfont <font'> getfontencoding 3 copy .processToUnicode getfontmetrics 5 -1 roll pop .updatefont { dup /FontName get exch definefont } if } bind def % Get the (possibly modified) encoding of a font. /getfontencoding { % <font-resource> <font> getfontencoding % <font-resource> <font> <Encoding|null> 1 index /Encoding known { dup /Encoding knownoget { 2 index getencoding } { null } ifelse } { null } ifelse } bdef % Returns true if the current glyph is in the Differences array at % the specified index value. This is needed because the Widths % array may map to the same glyph at different positions from the % Encoding. We want to use the Width that was associated with the % one specified in the Encoding::Differences list. /match_in_diff % <Differences> <index> <glyphname> match_in_diff <bool> { false 4 1 roll 0 4 -1 roll % stack: false index glyphname at_index==0 Differences { exch 1 index type /nametype ne { % stack: false index glyphname Diff_element at_index pop % Diff_element is new at_index } { % stack: false index glyphname Diff_element at_index exch 2 index eq { % stack: false index glyphname at_index dup 3 index eq { true 5 1 roll % stack: true false index glyphname at_index pop exit } if } if 1 add % at_index++ stack: false index glyphname at_index' } ifelse } forall % stack: true false index glyphname % or : false index glyphname at_index pop pop pop } bdef /unique_name { % <dict> </root> unique_name </unique> % % Note : this function interacts with pdf_write_encoding in src/gdevpdtw.c % and with copied_drop_extension_glyphs in src\gxfcopy.c % by adding a reserved substring (~GS~). % .namestring % <<>> (root) 0 1 65535 { 5 string cvs % <<>> (root) (0) (~GS~) exch concatstrings 1 index exch % <<>> (root) (root) (~GS~0) concatstrings % <<>> (root) (root~GS~0) dup % <<>> (root) (root~GS~0) (root~GS~0) 3 index exch % <<>> (root) (root~GS~0) <<>> (root~GS~0) known not { exch pop exit % <<>> (root~GS~0) } if pop } for exch pop cvn % /root0 } bdef % Get the metrics of a font, if specified. /getfontmetrics { % <font-resource> <font> <Encoding|null> getfontmetrics % <font-resource> <font> <Encoding|null> % <Metrics|null> <GlyphMap|null> 2 index /Widths known { dup null eq { pop dup /Encoding get } if 4 dict begin dup length dict /Metrics exch def /Encoding exch def /GlyphMap //null 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 dup 2 index length ge { ( **** Warning: Font Encoding array size is smaller than character range.\n) pdfformaterror pop pop /.notdef } { get } ifelse Widths 2 index 4 index sub dup 2 index length ge { ( **** Warning: Font Widths array size is smaller than character range.\n) pdfformaterror % use MissingWidth if it's available, if not, default to 1000 (full width) pop pop 4 index /FontDescriptor knownoget { /MissingWidth knownoget not { 1000 } if } { 1000 } ifelse } { oget } ifelse % 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 Metrics 2 index .knownget { 1 index ne } { //false } ifelse { % Two or more Encoding elements refer same glyph name, % and Widths specify different wihts for it. % Since a Postscript font can't have different % Metrics for same glyph name, % we generate an unique name, and create a new % Charstrings entry with same glyph value. GlyphMap //null eq { /Encoding Encoding dup length array copy def /GlyphMap 4 dict def } if % To prevent too many new names, check whether % we can use one already created for same glyph. //true GlyphMap { % f r s c i n w b n1 n2 4 index eq { % f r s c i n w b n1 dup Metrics exch get % f r s c i n w b n1 w1 3 index eq { % f r s c i n w b n1 4 3 roll pop % f r s c i w b n1 3 1 roll pop % f r s c i n1 w Encoding 3 index 3 index put //false % f r s c i n1 w b exit } { pop } ifelse } { % f r s c i n w b n1 pop } ifelse } forall % f r s c i n w b { % Do create a new name. Metrics 2 index //unique_name exec % f r s c i n w nn Encoding 4 index 2 index put GlyphMap 1 index 5 -1 roll put % f r s c i w nn exch % Stack: font font-res mscale first-char index new_name width } 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 GlyphMap end } { //null //null } ifelse } bdef currentdict /unique_name undef currentdict /match_in_diff undef /ToUnicodeCMapReader 3 dict def //ToUnicodeCMapReader begin /defineresource % <name> <dict> <cat-name> defineresource <dict> { pop dup userdict exch /.lastToUnicode exch put exch pop } bind def /CIDSystemInfo { ( **** Warning: ToUnicode CMap has invalid syntax near CIDSystemInfo.\n) pdfformaterror /CIDSystemInfo } bind def % A work around a bug in Altona.Page_3.2002-09-27.pdf - a slash is missed. end /string2number % <string> string2number <number> { 0 exch dup 0 exch 1 exch length 1 sub { % n () i 1 index exch get % n () v 3 2 roll 256 mul add exch % v+n*256 () } for pop % N } bind def /copy&def % <key> <value> <bool> copy&def - { { true } { currentdict gcheck { dup gcheck not } { false } ifelse } ifelse { currentglobal currentdict gcheck setglobal exch dup length string copy exch setglobal } if def } bind def /.convert_ToUnicode-into-g2u % <GlyphNames2Unicode> <Encoding|null> <CMap> .convert_ToUnicode-into-g2u - { PDFDEBUG { (.convert_ToUnicode-into-g2u beg) = } if 3 2 roll begin /.CodeMapData get % About the data format see gs_cmap.ps, the comment after "CMap operators". 1 get % code maps { PDFDEBUG { dup == } if dup length 1 sub 0 exch 5 exch { % e [] i 2 copy get % e [] i (prefix) string2number % e [] i prefix 2 index 2 index 1 add get % e [] i prefix (key_size,?is_range,value_type,value_size) dup 0 get 8 mul % e [] i prefix (key_size,?is_range,value_type,value_size) key_size*8 3 2 roll exch bitshift exch % e [] i prefix<<key_size*8 (key_size,?is_range,value_type,value_size) dup 0 get exch 3 get % e [] i offset key_size value_size 4 index 4 index 2 add get % e [] i offset key_size value_size (keys) 5 index 5 index 3 add get % e [] i offset key_size value_size (keys) (values) PDFDEBUG { ( offset=) print 4 index =string cvs print ( key_size=) print 3 index =string cvs print ( value_size=) print 2 index = ( keys=) print 1 index == ( values=) print dup == } if 1 index length 0 eq { % A single pair. exch pop exch pop exch pop exch % e [] i (values) offset 4 index null ne { 4 index exch get } if % e [] i (values) cid|name exch PDFDEBUG { ( defined single: ) print 1 index =string cvs print ( ) print dup == } if false copy&def % e [] i pop % e [] } { % A range. % e [] i offset key_size value_size (keys) (values) dup length string copy % protect the original string from modifications below. 0 4 index 2 mul 3 index length 1 sub { % e [] i offset key_size value_size (keys) (values) j 2 index 1 index 6 index getinterval string2number % e [] i offset key_size value_size (keys) (values) j keyL PDFDEBUG { ( keyL=) print dup =string cvs print } if 3 index 2 index 7 index add 7 index getinterval string2number % e [] i offset key_size value_size (keys) (values) j keyL keyH PDFDEBUG { ( keyH=) print dup = } if 3 2 roll 6 index idiv 5 index mul % e [] i offset key_size value_size (keys) (values) keyL keyH J 3 index exch 6 index getinterval % e [] i offset key_size value_size (keys) (values) keyL keyH (valueL) 3 1 roll 1 exch { % e [] i offset key_size value_size (keys) (values) (value) k 9 index null ne { 9 index exch get % e [] i offset key_size value_size (keys) (values) (value) name } if % e [] i offset key_size value_size (keys) (values) (value) cid|name 1 index % e [] i offset key_size value_size (keys) (values) (value) cid|name (value) PDFDEBUG { ( defined from range: ) print 1 index =string cvs print ( ) print dup == } if true copy&def % e [] i offset key_size value_size (keys) (values) (value) % Assuming the lowest byte of 'value' changes, others don't. dup dup length 1 sub % e [] i offset key_size value_size (keys) (values) (value) (value) l 2 copy get % e [] i offset key_size value_size (keys) (values) (value) (value) l v 1 add put % e [] i offset key_size value_size (keys) (values) (value') } for % e [] i offset key_size value_size (keys) (values) (value) } for pop pop pop pop pop pop pop % e [] } ifelse } for pop % e } forall end pop % PDFDEBUG { (.convert_ToUnicode-into-g2u end) = } if } bind def /.processToUnicode % <font-resource> <font-dict> <encoding|null> .processToUnicode - { % Currently pdfwrite is only device which can handle GlyphNames2Unicoide to % generate a ToUnicode CMaps. So don't bother with other devices. currentdevice .devicename /pdfwrite eq { PDFDEBUG { (.processToUnicode beg) = } if 2 index /ToUnicode knownoget { dup type /nametype eq { % Bug687351.pdf defines /ToUnicode /Identity-H, what is incorrect. ( **** Warning: Ignoring bad ToUnicode CMap.\n) pdfformaterror pop } { PDFfile fileposition exch false resolvestream //ToUnicodeCMapReader begin cvx exec end PDFfile exch setfileposition 1 index /FontInfo .knownget not { 1 index /FontInfo 5 dict dup 4 1 roll put } if dup /GlyphNames2Unicode .knownget not { currentglobal exch dup gcheck setglobal dup /GlyphNames2Unicode 100 dict dup 4 1 roll .forceput 3 2 roll setglobal } if % font-res font-dict encoding|null font-info g2u exch pop exch % font-res font-dict g2u encoding|null userdict /.lastToUnicode get % font-res font-dict g2u Encoding|null CMap .convert_ToUnicode-into-g2u % font-res font-dict null % font-res font-dict null } ifelse } if PDFDEBUG { (.processToUnicode end) = } if } if pop pop pop } bind def % ---------------- 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 ---------------- % /.pdforigfontcache_g 20 dict def currentglobal false setglobal systemdict /.pdforigfontcache_l 20 dict .forceput setglobal % Find an original font, using cache to prevent adjustfont to accumulate changes. /pdffindcachedfont { % <font_name> pdffindcachedfont <font> dup //.pdforigfontcache_g exch .knownget { exch pop } { dup .pdforigfontcache_l exch .knownget { exch pop } { dup findfont dup dup gcheck { //.pdforigfontcache_g } { .pdforigfontcache_l } ifelse % Stack : font_name font font cache 4 2 roll .growput } ifelse } ifelse } bind def % Add original font to cache to prevent adjustfont to accumulate changes. /pdfaddcachedfont { % <font_name> pdfaddcachedfont <font> dup findfont dup % name font font dup gcheck { //.pdforigfontcache_g } {.pdforigfontcache_l} ifelse 4 2 roll % font d name font put % font } bind def /.remove_font_name_prefix { % <name> .remove_font_name_prefix <name> dup .namestring (+) search { true exch { dup 65 lt exch 90 gt or { pop false exit } if } forall { pop exch pop cvn } { pop pop } ifelse } { pop } ifelse } bind def % Find a font (except for embedded ones), and adjust its encoding if necessary. /.pdfdfndict mark /defaultfontname /Helvetica .dicttomark readonly def /pdffindfont { % <font-resource> <fontname> pdffindfont <font> % If the font isn't available, synthesize one based on % its descriptor. dup /Font resourcestatus { pop pop pdffindcachedfont } { 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 % Even though /FontName is a required key in FontDescriptor dict % (As of the PDF 1.4 Reference Manual), In the case of missing % /FontName key, we substitue /BaseFont for the value of /FontName. % Yet another case of broken PDF's that Adobe Reader accepts. 1 index dup /FontName known { /FontName oget } { ( **** FontDescriptor missing required /FontName key. BaseFont name used.\n) pdfformaterror pop 2 index % grab the BaseFont from the stack. } ifelse .remove_font_name_prefix 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 dup 3 index ne QUIET not and { (Substituting font ) print dup =only ( for ) print 2 index =only (.) = flush } if pdffindcachedfont % Stack: font-res fontname 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 % stack: font-res fontname font font /CharStrings CharStringsdict 5 index /FirstChar get 97 .max 6 index /LastChar get 122 .min 1 exch { % Stack: font-res fontname font' font' /CharStrings charstrings code % Note that this only remaps a-z, not accented characters. 6 index /Widths oget 1 index 8 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 } if dup /FontName get 2 index ne { true .copyfontdict 2 copy exch /FontName exch put } if definefont } { % No descriptor available, use the default algorithm. pdffindcachedfont } ifelse } ifelse exch pop } bdef % ---------------- Type 1 fonts ---------------- % /buildType1 % <Type1-font-resource> buildType1 <font> { 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 { % <proc> readfontfilter <filter> 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 //.eexec_param_dict /eexecDecode filter //systemdict begin readtype1dictcopy begin cvx stopped currentdict readtype1dictcopy eq { end } if currentdict //systemdict eq { end } if { stop } if } bdef /undef_proc_warning { /Repaired true store % flag that we have warnings UndefProcList exch 2 copy .knownget { 1 add } { 1 } ifelse put } bdef /-| { string currentfile exch readstring pop /-| undef_proc_warning } executeonly bdef /RD { string currentfile exch readstring pop /RD undef_proc_warning } executeonly bdef /|- { noaccess def /|- undef_proc_warning } executeonly bdef /ND { noaccess def /ND undef_proc_warning } executeonly bdef /| { noaccess put /| undef_proc_warning } executeonly bdef /NP { noaccess put /NP undef_proc_warning } executeonly bdef end readonly def /readtype1 { % <font-resource> <stream-dict> readtype1 <font> % 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. Also restore dictstack depth. //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 % clean up the dictstack { currentdict /topFontDict known not { end } { end end exit } ifelse } loop count exch sub { pop } repeat PDFfile 3 -1 roll setfileposition /BaseFont oget pdfaddcachedfont exch pop } bdef % Execute the appropriate reading procedure. /type1read % <dict> type1read <string> { 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 % <left> <buffer> type1readdata <substring> <left'> { 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 PDFDEBUG { 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 { % <left> type1read0 <string> <left'> sectionstr 0 1 put % either way we go to the next stage pfbhdr type1readdata 1 index 0 get 16#80 eq { ( **** Warning: Embedded Type1 font in PFB format is not valid PDF.\n) pdfformaterror PDFDEBUG { (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 PDFDEBUG { (PFB segment length = ) print dup = } if exch pop % discard the string keeping the PFB segment length 2 copy ne { ( **** Warning: Type 1 PFB segment length and Length 1 value do not match.\n) 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 { % <left> type1read1 <string> <left'> PDFDEBUG { (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. } { PDFDEBUG { (read2 ) print } if pfbhdr 0 get 16#80 eq { % eat 6 more bytes of PFB junk before proceeding PDFDEBUG { (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 PDFDEBUG { (PFB segment length = ) print dup = } if exch pop % discard the string keeping the PFB segment length 2 copy ne { ( **** Warning: Type 1 PFB segment length and Length 2 value do not match.\n) pdfformaterror 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 { % <string> buf2hex <hexstring> 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 { % <left> type1read2 <string> <left'> PDFDEBUG { (read2 ) print } if dup 0 eq { pop sectionstr 0 3 put stream /Length3 oget dup 0 eq { PDFDEBUG { (trailer ) print } if type1trailer exch } { pfbhdr 0 get 16#80 eq { % eat 6 more bytes of PFB junk before proceeding PDFDEBUG { (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 PDFDEBUG { (PFB segment length = ) print dup = } if exch pop % discard the string keeping the PFB segment length 2 copy ne { ( **** Warning: Type 1 PFB segment length and Length 3 value do not match.\n) pdfformaterror exch % keep the PFB length instead } if pop } 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 % <left> type1read3 <string> <left'> { PDFDEBUG { (read3 ) print } if buffer type1readdata } bdef % ---------------- Type 3 fonts ---------------- % /buildType3 { % <Type3-font-resource> buildType3 <font> 8 dict begin /FontType 3 def % If the font does not contain a Resources entry, then we use % the resources from our current context. Page 391 of the PDF % 1.6 spec says that the Resources dict is optional and if not % present then we should use the Resources for the page. % However we have a test file (687989) which uses a Type3 font % inside a form XObject and the desired Resources are in the % XObject dict and not in the Page dict. So we are going to % the parent object to find resources instead of only going to % the page dict when a font does not specify its required % resources. /Resources 1 index /Resources knownoget { oforce } { LocalResources } 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 .knownget not { PDFfile fileposition 16 10 string cvrs cvn } if 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 dup currentdict Encoding .processToUnicode FontName currentdict end definefont exch pop } bdef /.adjustcharwidth { % <wx> <wy> .adjustcharwidth <wx'> <wy'> /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 .dicttomark readonly def /buildTrueType { % <TrueType-font-resource> buildTrueType <font> dup /BaseFont oget /Repaired true store % flag that we had warnings TTFWarnList 1 index true put % Add fontname to the list dup TTfonts exch .knownget { QUIET not { (Substituting font ) print dup =only ( for ) print 1 index =only (.) = flush } if exch 3 1 roll pdffindfont true .copyfontdict 2 copy exch /FontName exch put definefont } { pdffindfont } ifelse } bdef % Read an embedded TrueType font. /readtruetype { % <font-resource> <stream-dict> readtruetype <font> % 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 } { % filepos fontres stream 1 index /FontDescriptor oget % filepos fontres stream fd /Flags get 4 and 0 ne % filepos fontres stream is_symbolic dup { 2 index null exch getencoding % filepos fontres stream is_symbolic Encoding dup 4 index exch % filepos fontres stream is_symbolic Encoding fontres Encoding /prebuilt_encoding exch put % filepos fontres stream is_symbolic Encoding } { null } ifelse .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 { % <cmapname> <wmode> .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> <ffff> <0000> <ffff> endcodespacerange 1 begincidrange % <0001> <00ff> 1 <0100> <ffff> 256 <0000> <ffff> 0 endcidrange endcmap CMapName currentdict /CMap defineresource knownCMaps CMapName 2 index put end % CMap end % CIDInit ProcSet exch .setglobal } bdef /buildType0 { % <Type0-font-resource> buildType0 <font> 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 % composefont must insert FontInfo dictionary - see gs_cmap.ps . % Stack: fontres font 2 copy null .processToUnicode 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" 2nd ed., p314 "5.6.3 CIDFonts". % It notes default DW is 0, but Acrobat Reader uses 1000 as default. % If DW is 0, currentpoint does not move by default in rendering text % horizontally, the result is unreadable. You can check it by Acrobat. /.pdfDefaultDW 1000 def /.pdfDefaultDW2 [ 880 -1000 ] def /addCIDmetrics { % <CIDFont-resource> <CIDFont> addCIDmetrics <fontdict> 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 { % <mtx_array> <item_size> .pdfConvertInternalW <mtx_array'> % 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 itemSize idiv 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 { % <internalMTXArray> <cid> % .pdfGetMTXByCID % { <MTXEntry> true | false } % get values for given CID from internal format of /W or /W2 exch { { dup 0 get {} forall % Stack: <cid> <entry> <cid_0> <cid_1> 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 { % <w0x> <w0y> <llx> <lly> <urx> <ury> % <w1x> <w1y> <vx> <vy> <cid> <font> CIDWproc % <w0x'> ... <vy'> begin % push <font> to currentdict % <w1x> <w1y> <vx> <vy> won't be used and replaced, discard now 5 1 roll pop pop pop pop { currentdict /DW .knownget not { % no DW .pdfDefaultDW exit % replace <w0x> 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 FontType 11 eq { 1000 div % <w0x'> (normalized W) } if 0 % <w0y'> % Stack: <w0x> <w0y> <llx> <lly> <urx> <ury> <cid> <w0x'> <w0y'> 9 -2 roll pop pop % discard <w0x> <w0y> 7 2 roll % put <w0x'> <w0y'> % Stack: <w0x'> <w0y'> <llx> <lly> <urx> <ury> <cid> 0 % <w1x'> exch % put <w1x'> % Stack: <w0x'> <w0y'> <llx> <lly> <urx> <ury> <w1x'> <cid> { 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 <cid> % Stack: <w0x'> <w0y'> <llx> <lly> <urx> <ury> <w1x'> { [<vy'> <w1y'>] | [<w1y'> <vx'> <vy'>] } dup length 2 eq { % this is DW2 FontType 11 eq {{1000 div}} {{}} ifelse forall exch 8 index 2 div % <vx'> = <w0x'> / 2 exch }{ % assume W2 FontType 11 eq {{1000 div}} {{}} ifelse forall } ifelse end % recover currentdict } def % <string> <match> tailmatch ==> <pre> true % ==> <string> 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 /makeboldfont { 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 % <CIDFont-resource> <CIDFontName> findCIDFont <CIDFont-resource> <font> % CIDFont-resource is not modified. /findCIDFont { { dup /CIDFont resourcestatus { pop pop /CIDFont findresource exit } if .remove_font_name_prefix dup dup length string cvs (,Bold) tailmatch { exch pop cvn findCIDFont 0.03 makeboldfont 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 makeboldfont [ 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 CID font resource) print dup ==only ( for ) print 1 index ==only (.\n) print } if exch pop /CIDFont findresource exit } loop } bdef /buildCIDType0 { % <CIDFontType0-font-resource> buildCIDType0 <font> dup /BaseFont get findCIDFont exch pop } bdef /buildCIDType2 { % <CIDFontType2-font-resource> buildCIDType2 <font> dup /BaseFont get findCIDFont exch pop } bdef /processCIDToGIDMap { % <fontres> <cidfont> processCIDToGIDMap <fontres> <cidfont> 1 index /CIDToGIDMap knownoget { PDFfile fileposition 4 1 roll dup /Identity eq { pop } { true resolvestream % Stack: filepos fontres font mapstream % Can't know the length of the decompressed stream, so allocate a big buffer... dup 65534 string readstring { % Length exceeded max string size, use an array of two strings 1 index 65534 string readstring pop % maybe a null string - not important. 2 array astore % Stack: filepos fontres font mapstream array dup 1 get length 65534 add } { dup length } ifelse 2 idiv % Stack: filepos fontres font mapstream array/string CIDCount 3 index exch /CIDCount exch put exch closefile exch dup /CIDMap 4 -1 roll put } ifelse 3 2 roll PDFfile exch setfileposition } if } bdef % Adjust a CIDFontType0 DW[2] in the font resource. /adjustCIDType0 { % <font-resource> <font> adjustfont <font'> addCIDmetrics dup /CIDFontName get exch /CIDFont defineresource } bind def % Adjust a CIDFontType2 DW[2] and CIDToGIDMap in the font resource. /adjustCIDType2 { % <font-resource> <font> adjustfont <font'> addCIDmetrics processCIDToGIDMap dup /CIDFontName get exch /CIDFont defineresource } bind def % ---------------- Other embedded fonts ---------------- % /fontloadprocs mark /Type1C /readType1C cvx /CIDFontType0C /readCIDFontType0C cvx .dicttomark readonly def % Read an embedded compressed font. /readType1C { % <font-resource> <stream-dict> readType1C <font> 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 pdfaddcachedfont exch pop } bdef % Read an embedded CFF CIDFont. /readCIDFontType0C { % <font-resource> <stream-dict> readCIDFontType0C <font> 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 % <font-resource> -proc- <font> /Type0 //buildType0 /Type1 //buildType1 /MMType1 //buildType1 /Type3 //buildType3 /TrueType //buildTrueType /CIDFontType0 //buildCIDType0 /CIDFontType2 //buildCIDType2 .dicttomark readonly def /adjustfonttypes mark /Type1 //adjustfont /MMType1 //adjustfont /TrueType //adjustfont /CIDFontType0 //adjustCIDType0 /CIDFontType2 //adjustCIDType2 .dicttomark readonly def /resourcefont % <font-resource> resourcefont <font> { dup /PSFont .knownget { /FID knownoget { type /fonttype eq } { //false } ifelse } { //false } ifelse { /PSFont get } { dup dup /FontDescriptor knownoget { % Stack: font-res font-res font-desc dup /FontObject .knownget { 3 1 roll pop pop } { dup /FontFile knownoget { dup /Length oget 0 eq { pop pop dup /Subtype get fonttypeprocs exch get exec } { exch pop readtype1 } ifelse } { dup /FontFile2 knownoget { exch pop readtruetype } { /FontFile3 knownoget { dup /Subtype get fontloadprocs exch get exec } { dup /Subtype get fonttypeprocs exch get exec } ifelse } ifelse } ifelse 1 index /FontDescriptor oget 1 index /FontObject exch put % Save pointer to the font } ifelse } { dup /Subtype get fonttypeprocs exch dup () cvn eq { ( **** Warning: Font missing required Subtype, /Type1 assumed.\n) pdfformaterror pop /Type1 } if get exec } ifelse % Stack: font-res font 1 index 3 1 roll 1 index /Subtype get //adjustfonttypes exch .knownget { exec } { exch pop } ifelse dup 3 1 roll /PSFont exch put } ifelse dup checkGlyphNames2Unicode } bdef drawopdict begin /d0 { .adjustcharwidth setcharwidth } bdef /d1 { 4 index 0 ne { % invalid wy parameter for d1 in Type3 font (must be 0) % Even though the PDF 1.4 specification states that this must be 0, % Distiller sometimes creates Type3 fonts with non-zero wy. We set % it to 0 since this is apparently what Acrobat Reader 4 and 5 do, % but if the specification is ever changed to allow non-zero wy, this % will not work. 5 -1 roll pop 0 5 1 roll % set wy to 0 } if 2 copy % ... llx lly urx ury | urx ury 0 ne exch 0 ne % ... llx lly urx ury | ury!=0 urx!=0 3 index 6 index eq and % ... llx lly urx ury | ury!=0 (urx!=0 && llx==urx) exch 2 index 5 index eq and or { % ... llx lly urx ury | (urx!=0 && llx==urx) || (ury!=0 && lly==ury) % The bounding box is empty and likely incorrect. Don't cache. pop pop pop pop .adjustcharwidth setcharwidth } { 6 -2 roll .adjustcharwidth 6 2 roll setcachedevice } ifelse } 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