1577 lines
52 KiB
PostScript
1577 lines
52 KiB
PostScript
% 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
|