home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 10
/
AU_CD10.iso
/
Updates
/
GhostScript
/
!GhostScr
/
6_01
/
lib
/
pdf_font.ps
< prev
next >
Wrap
Text File
|
2000-03-29
|
22KB
|
695 lines
% Copyright (C) 1994, 2000 Aladdin Enterprises. All rights reserved.
%
% This file is part of Aladdin Ghostscript.
%
% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
% or distributor accepts any responsibility for the consequences of using it,
% or for whether it serves any particular purpose or works at all, unless he
% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
% License (the "License") for full details.
%
% Every copy of Aladdin Ghostscript must include a copy of the License,
% normally in a plain ASCII text file named PUBLIC. The License grants you
% the right to copy, modify and redistribute Aladdin Ghostscript, but only
% under certain conditions described in the License. Among other things, the
% License requires that the copyright notice and this notice be preserved on
% all copies.
% $Id: pdf_font.ps,v 1.2 2000/03/10 03:57:50 lpd Exp $
% pdf_font.ps
% PDF font operations.
/.setlanguagelevel where { pop 2 .setlanguagelevel } if
.currentglobal true .setglobal
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
GS_PDF_ProcSet begin
pdfdict begin
% We cache the PostScript font in an additional element of the
% font resource dictionary, called PSFont.
% ---------------- Encodings ---------------- %
% Apply a list of differences to an Encoding.
% Note that the differences may cause the array to grow.
/updateencoding { % <encoding> <differences> updateencoding <enc'>
% Calculate the length of the result.
exch 0 2 index {
dup type /nametype ne { exch pop } { pop 1 add } ifelse
} forall
1 index length .max array dup 0 4 -1 roll putinterval
exch 0 exch {
% Stack: enc' code element
dup type /nametype ne
{ exch pop }
{ 3 copy put pop 1 add }
ifelse
} forall pop
} bdef
% Get the Encoding for a font.
/getencoding % <base-encoding> <font-resource> getencoding <enc>
{ /Encoding knownoget
{ dup type /nametype eq
{ exch pop findencoding
}
{ dup /BaseEncoding knownoget
{ findencoding 3 -1 roll pop exch
}
if
/Differences knownoget { updateencoding } if
}
ifelse
}
if
} bdef
% Rename a font with a generated name.
/renamefont { % <fontdict> renamefont <font'>
dup /FontName 2 copy get genfontname dup 5 1 roll put definefont
} bind def
% Adjust a font according to the Encoding and Widths in the font resource.
/adjustfont { % <font-resource> <font> adjustfont <font'>
getfontencoding getfontmetrics 4 -1 roll pop .updatefont { renamefont } 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 .knownget { 2 index getencoding } { null } ifelse
} {
null
} ifelse
} bdef
% Get the metrics of a font, if specified.
/getfontmetrics % <font-resource> <font> <Encoding|null> getfontmetrics
% <font-resource> <font> <Encoding|null>
% <Metrics|null>
{ 2 index /Widths known
{ dup null eq { pop dup /Encoding get } if
2 dict begin
/Encoding exch def
/Metrics Encoding length dict def
exch
% Stack: font font-res
% Note that widths are always based on a 1000-unit
% character space, but the FontMatrix may specify
% some other scale factor. Compensate for this here,
% by scaling the Widths if necessary.
0.001 2 index /FontMatrix get 0 get div
% Stack: font font-res mscale
1 index /FirstChar oget dup 1 4 index /LastChar oget
{ % Stack: font font-res mscale first-char index
Encoding 1 index get
4 index /Widths oget 2 index 4 index sub get
% Stack: font font-res mscale first-char index charname width
4 index mul
% There is a hack here to deal with encodings where the
% same character appears more than once, because the Metrics
% dictionary works by character name, not by character code.
% Because of this, we can't deal with Width vectors that
% specify different widths for the same character name
% appearing multiple times in the Encoding.
Metrics 2 index .knownget not { 0 } if 0 ne {
pop pop
} {
% Work around a bug in pdfTeX, which can generate Encoding
% vectors containing nulls.
1 index null ne {
Metrics 3 1 roll put
} {
pop pop
} ifelse
}
ifelse pop
}
for pop
% Now fill in the MissingWidth for any encoded characters
% that aren't in Metrics already. Note that built-in
% fonts may have Widths/FirstChar/LastChar but no
% FontDescriptor, so we must check for this.
% Stack: font font-res mscale
1 index /FontDescriptor knownoget {
Metrics exch
/MissingWidth knownoget { 2 index mul } { 0 } ifelse exch
Encoding {
% Stack: font font-res mscale missing-width metrics charname
% Work around the abovementioned pdfTeX bug.
dup null ne {
2 copy known not { 2 copy 4 index put } if pop
} {
pop
} ifelse
} forall pop pop pop
} {
pop
} ifelse
exch Encoding Metrics end
}
{ null
}
ifelse
} bdef
% ---------------- 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 ---------------- %
% Fabricate a font name by adding ?'s on the end.
/genfontname % <name> genfontname <name>
{ dup length string cvs
{ (?) concatstrings
dup cvn FontDirectory exch known not { cvn exit } if
}
loop
} bdef
% Find a font, and adjust its encoding if necessary.
/pdffindfont { % <font-resource> <fontname> pdffindfont <font>
% If the font isn't available, synthesize one based on
% its descriptor.
dup /Font resourcestatus {
pop pop findfont
} {
1 index /FontDescriptor knownoget {
% Stack: font-res fontname fontdesc
dup /Flags oget
dup 16#40 and -6 bitshift % 1, oblique/italic
1 index 16#40000 and -17 bitshift add % 2, bold
exch 16#2 and 2 bitshift add % 8, serif
% We should look at the fixed flag, too.
% Stack: font-res fontname fontdesc properties
1 index /FontName oget exch
1 index .fontnameproperties or
.substitutefontname
% Stack: font-res fontname fontdesc substname|null
Fontmap 1 index known not {
% No available good substitution, use the standard one.
pop 1 index .substitutefont
} if
QUIET not {
(Substituting font ) print dup =only
( for ) print 2 index =only (.) = flush
} if
3 -1 roll pop findfont
% Stack: font-res fontdesc font
% If this is a small-caps font, replace the CharString
% entries for a..z.
exch /Flags oget 16#20000 and 0 ne {
true .copyfontdict
dup /CharStrings 2 copy get dup length dict .copydict
4 index /FirstChar get 97 .max
5 index /LastChar get 122 .min 1 exch {
% Stack: font-res font' font' /CharStrings charstrings code
% Note that this only remaps a-z, not accented characters.
5 index /Widths oget 1 index 7 index /FirstChar get sub oget
1 string dup 0 5 -1 roll put
% Stack: font-res font' font' /CharStrings charstrings code
% width (x)
2 index exch dup cvn exch
dup 0 2 copy get 32 sub put 4 -1 roll {
% Stack: operand (X) width
0 setcharwidth exch pop
currentfont /FontMatrix get matrix invertmatrix concat
0.7 dup scale 0 0 moveto show
} /exec cvx 4 packedarray cvx put
} for put
renamefont
} if
} {
% No descriptor available, use the default algorithm.
findfont
} ifelse
} ifelse adjustfont
} bdef
% ---------------- 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
% leftstr - string containing (non-negative) integer
% sectionstr - string containing a character 0 .. 2
% stream - (stream) dictionary
% proc - procedure of the form {-dict- type1read}
% 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 on the top of the stack.
count 0 gt { /topFontDict 1 index cvlit store } if
55665 /eexecDecode filter
//systemdict begin readtype1dictcopy begin cvx stopped
currentdict readtype1dictcopy eq { end } if
currentdict //systemdict eq { end } if
{ stop } if
} bdef
end readonly def
/readtype1 { % <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
7 dict begin
/leftstr ( ) 10 string copy def
dup /Length1 oget leftstr cvs pop
/sectionstr <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
currentdict end
/type1read cvx 2 array astore cvx dup 0 get /proc 2 index put
readfontfilter
% Some buggy embedded fonts leave extra junk on the stack,
% so we have to make a closure that records the stack depth
% in a fail-safe way.
//systemdict begin
% The PDF specification is somewhat muddy about whether
% an embedded font's name is supposed to be the BaseFont
% from the Font object or the FontName from the descriptor.
% Acrobat Distiller requires the former. Save away the
% name so we can substitute it at definefont time.
//readtype1dict dup length 3 add dict copy begin
1 index /BaseFont oget /savedFontName exch def
/topFontDict null def
/readtype1dictcopy currentdict def
{ run } aload pop count 1 sub 2 packedarray cvx exec
end end
count exch sub { pop } repeat
PDFfile 3 -1 roll setfileposition
/BaseFont oget findfont
adjustfont
} bdef
% Execute the appropriate reading procedure.
/type1read % <dict> type1read <string>
{ begin leftstr cvi
{ 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
DEBUG
{ dup =only ( read ) print
1 index length =only (: ) print
1 index == flush
} if
} bdef
% Read the next block of the initial text portion.
/type1read1 % <left> type1read1 <string> <left'>
{ DEBUG { (read1 ) print } if
dup 0 eq
{ pop sectionstr 0 1 put
stream /Length2 oget type1read2
}
{ buffer type1readdata
}
ifelse
} 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'>
{ DEBUG { (read2 ) print } if
dup 0 eq
{ pop sectionstr 0 2 put
stream /Length3 oget
dup 0 eq
{ DEBUG { (trailer ) print } if
type1trailer exch
}
{ type1read3
}
ifelse
}
{ buffer2 type1readdata exch
buffer /ASCIIHexEncode filter dup 3 -1 roll writestring closefile
buffer (>) search pop exch pop exch pop 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'>
{ DEBUG { (read3 ) print } if
buffer type1readdata
} bdef
% ---------------- Type 3 fonts ---------------- %
/.notdefEncoding 256 { /.notdef } repeat 256 packedarray def
/buildType3 { % <Type3-font-resource> buildType3 <font>
8 dict begin
/FontType 3 def
/Resources 1 index /Resources knownoget { oforce } { 0 dict } ifelse def
/FontBBox 1 index /FontBBox get cvx def
/FontMatrix 1 index /FontMatrix oget def
/CharProcs 1 index /CharProcs oget def
1 index /Widths knownoget {
/Widths exch def
/FirstChar 1 index /FirstChar oget def
/LastChar 1 index /LastChar oget def
} if
/FontName 1 index /Name get genfontname def
/Encoding .notdefEncoding 2 index getencoding def
% We have to define BuildChar rather than BuildGlyph:
% there is no PDF equivalent of glyphshow, and we need
% the character code to access the Widths.
/BuildChar {
% Stack: font charcode
1 index begin 3 dict begin
/Font 3 -1 roll def /CharCode 1 index def
Encoding exch get CharProcs exch oget
PDFfile fileposition exch
false resolvestream
% Stack: filepos stream
% Don't let setgcolor set the color inside the BuildGlyph
% procedure, because this causes an /undefined error.
q null /FillColor gput null /StrokeColor gput
Font /Resources get exch pdfopdict .pdfruncontext
Q
PDFfile exch setfileposition
end end
} bdef
FontName currentdict end definefont exch pop
} bdef
/.adjustcharwidth { % <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 get
dup TTfonts exch .knownget { exch pop } if pdffindfont
} 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
} {
.loadttfont
} 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
/WMode exch def
/CMapName exch def
begincmap
/CIDSystemInfo 3 dict dup begin
/Registry (Adobe) def
/Ordering (Japan1) def
/Supplement 0 def
end def
%/CMapName ... def
/CMapVersion 1 def
/CMapType 1 def
%/WMode ... def
% The PDF documentation says that these CMaps map CIDs
% "1 to 65,536". We think this is a misprint for 0 to 65,535.
2 begincodespacerange
% <0001> <00ff> <0100> <ffff>
<0000> <ffff>
endcodespacerange
2 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>
{ 10 dict begin
/FontType 0 def
/FontMatrix 1 index /FontMatrix knownoget not { matrix } if def
/FontName 1 index /BaseFont get def
/FMapType 9 def
/Encoding [
0 1 4 index /DescendantFonts oget length 1 sub { } for
] def
/FDepVector [
2 index /DescendantFonts oget { exec resourcefont } forall
] def
/CMap 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
} {
resolvestream
} ifelse
def
FontName currentdict end definefont 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.
/addCIDmetrics { % <CIDFont-resource> addCIDmetrics <fontdict>
dup /BaseFont get /CIDFont findresource
dup length 5 add dict .copydict
dup /FID undef
dup /UniqueID undef
dup /XUID undef
% Insert the widths into the font.
{W W2 DW DW2} {
% Stack: pdfresource newfont key
2 index 1 index .knownget {
2 index 3 1 roll put
} {
pop
} ifelse
} forall
dup /CDevProc 1 index /CIDWProc load /exec load 3 packedarray cvx put
exch pop
} bdef
% 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
% Look up and apply [D]W
10 index
currentdict /DW .knownget { 1000 div exch pop } if
currentdict /W .knownget {
% Search the W array for the CID.
% ****** NOT IMPLEMENTED YET ******
pop
} if
0 13 2 roll 11 -2 roll pop pop
% Look up and apply [D]W2
% ****** NOT IMPLEMENTED YET ******
pop end
} bdef
/buildCIDType0 { % <CIDFontType0-font-resource> buildCIDType0 <font>
addCIDmetrics dup /CIDFontName get exch /CIDFont defineresource
} bdef
/buildCIDType2 { % <CIDFontType2-font-resource> buildCIDType2 <font>
addCIDmetrics
%****** Handle CIDToGIDMap ******
dup /BaseFont get exch /CIDFont defineresource
} bdef
% ---------------- Other embedded fonts ---------------- %
/fontloadprocs mark
/Type1C /readType1C 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 findfont
adjustfont
} bdef
% ---------------- Font lookup ---------------- %
/fonttypeprocs mark % <font-resource> -proc- <font>
/Type0 /buildType0 cvx
/Type1 /buildType1 cvx
/MMType1 1 index
/Type3 /buildType3 cvx
/TrueType /buildTrueType cvx
/CIDFontType0 /buildCIDType0 cvx
/CIDFontType2 /buildCIDType2 cvx
.dicttomark readonly def
/resourcefont % <font-resource> resourcefont <font>
{ dup /PSFont .knownget
{ /FID .knownget { type /fonttype eq } { false } ifelse }
{ false }
ifelse
{ /PSFont get
}
{ dup dup /FontDescriptor knownoget
{ % Stack: font-res font-res font-desc
dup /FontFile knownoget
{ exch pop readtype1 true }
{ dup /FontFile2 knownoget
{ exch pop readtruetype true }
{ /FontFile3 knownoget
{ dup /Subtype get fontloadprocs exch get exec true }
{ false }
ifelse
}
ifelse
}
ifelse
}
{ false }
ifelse
% Stack: font-res font-res false
% -or-: font-res font true
not
{ dup /Subtype get fonttypeprocs exch get exec }
if
2 copy /PSFont exch put
exch pop
}
ifelse
} bdef
drawopdict begin
/d0 {
.adjustcharwidth setcharwidth
} bdef
/d1 {
6 -2 roll .adjustcharwidth 6 2 roll setcachedevice
} bdef
/Tf {
1 index Page /Font rget not { 1 index /invalidfont signalerror } if
resourcefont exch Tf pop
} bdef
end
end % pdfdict
end % GS_PDF_ProcSet
.setglobal