%!PS-Adobe-2.0
%
% Copyright (C) 2002 Artifex Software, Inc. 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: opdfread.ps 9504 2009-02-23 11:35:26Z ken $
% pdfread.ps - A procset for interpreting an ordered PDF 1.3 file.
% This module defines routines for interpreting a PDF file with
% a Postscript interpreter. To convert a PDF file into Postscript
% just pre-contcatenate this file. The PDF file must satisfy
% few constraints :
%
% 1. It must contain only Postscript level 2 objects encoded with
% the PDF 1.3 language. Higher PDF levels must be re-distilled
% with CompatibilityLevel=1.3 .
%
% 2. Objects must be ordered so that any resource be defined before
% its usage.
%
% 3. The PDF file must not include other PDF files.
% Consequently we have a single instance of the PDF reader.
% We use this fact to simplify binding of the routines.
%
% 4. The PDF root object must always have the object id 1.
%
% 5. Generations besides 0 are not allowed.
%
% 6. xref must appear after all objects.
%
% Assuming the currentfile isn't positionable.
% As a consequence, the reader fully ignores xref.
% ====================== Error handler =======================
% A general error handler prints an error to page.
10 dict begin % A dictionary for local binding
/this currentdict def
/y 720 def
/ebuf 200 string def
/prnt {
36 //this /y get moveto //ebuf cvs show
//this /y 2 copy get 12 sub put
} bind def
/newline {
36 //this /y get moveto
//this /y 2 copy get 12 sub put
} bind def
errordict /handleerror
{ systemdict begin
$error begin
newerror
{ (%%[ Error handled by opdfread.ps : ) print errorname //ebuf cvs print (; OffendingCommand: )
print /command load //ebuf cvs print ( ]%%) = flush
/newerror false store vmstatus pop pop 0 ne
{ grestoreall
} if
errorname (VMerror) ne
{ showpage
} if
initgraphics
0 720 moveto
errorname (VMerror) eq
{ //this /ehsave known
{ clear //this /ehsave get restore 2 vmreclaim
} if
vmstatus exch pop exch pop
}
/Courier 12 selectfont
{
(ERROR: ) //prnt exec errorname //prnt exec
(OFFENDING COMMAND: ) //prnt exec
/command load //prnt exec
$error /ostack known {
(%%[STACK:) =
(STACK:) //prnt exec
$error /ostack get aload length {
//newline exec
dup mark eq {
(-mark-) dup = show
} {
dup type /nametype eq {
dup xcheck not {
(/) show
(/) print
} if
} if
dup = //ebuf cvs show
} ifelse
} repeat
} if
} ifelse
(%%]%) =
//systemdict /showpage get exec
quit
} if
end
end
} bind readonly put
end % A dictionary for local binding
50 dict begin
% ===================== Debugging =========================================
/DefaultSwitch % DefaultSwitch -
{
dup where {
pop pop
} {
false def
} ifelse
} bind def
/=string 256 string def
/=only {
//=string cvs print
} bind def
/HexDigits (0123456789ABCDEF) readonly def
/PrintHex % PrintHex -
{ 8 {
dup -28 bitshift //HexDigits exch 1 getinterval //=only exec
4 bitshift
} repeat
pop
} bind def
/PDFR_DEBUG DefaultSwitch
/PDFR_DUMP DefaultSwitch
/PDFR_STREAM DefaultSwitch
/TTFDEBUG DefaultSwitch
/RotatePages DefaultSwitch
/FitPages DefaultSwitch
/CenterPages DefaultSwitch
/SetPageSize DefaultSwitch
/error % mark .... error -
{ % A stub for a while.
counttomark 1 sub -1 0 {
index dup type /arraytype eq { == } { =only } ifelse
} for
() =
cleartomark
% Assuming ....Undefined is never defined.
% Use it to emit an error.
....Undefined
} bind def
//SetPageSize {
//RotatePages //FitPages or //CenterPages or{
mark (/RotatePages, /FitPages and CenterPages are not allowed with /SetPageSize) //error exec
} if
}
{
//FitPages //CenterPages and {
mark (CenterPages is not allowed with /FitPages) //error exec
} if
}
ifelse
% ===================== Utilities =========================================
/knownget % knownget true
% knownget false
{
2 copy known {
get true
} {
pop pop false
} ifelse
} bind def
/IsUpper % IsUpper
{ dup (A) 0 get ge exch (Z) 0 get le and
} bind def
% Copy (recursive) packedarray|array to to global VM
% NOTE: a packedarray will be converted to non-packed (too bad)
/cpa2g { % cpa2g
dup length array %
0 1 2 index length 1 sub {
% index
dup 3 index exch get cp2g
% index
3 copy put pop pop
} for
exch pop
} bind def
% Copy (recursive) dict to to global VM
/cpd2g {
dup length dict exch {
cp2g 2 index 3 1 roll put
} forall
} bind def
% Copy string to to global VM
/cps2g { % cps2g
dup length string copy
} bind def
/cp2gprocs
<< /arraytype //cpa2g /dicttype //cpd2g /packedarraytype //cpa2g /stringtype //cps2g >>
def
/cp2g { % cp2g
% where is array | dict | string | packedarray
% NOTE: The object must be readable (not executeonly or noaccess)
dup gcheck not {
dup //cp2gprocs 1 index type
2 copy known {
get currentglobal 3 1 roll true setglobal exec exch setglobal
% set the attributes appropriately (we must have 'read' access to get this far)
1 index wcheck not { readonly } if
1 index xcheck { cvx } if
exch pop % discard original (local) object
} {
pop pop % discard type
} ifelse
} if
} bind def
% ===================== Work Data =========================================
/BlockBuffer 65535 string def % Make it big to load entire TrueType font
/PDFReader currentdict def
/ObjectRegistry 50 array def % may grow later
/CurrentObject null def
/DoneDocumentStructure false def
/GraphicState 20 dict begin
/InitialTextMatrix matrix def
/InitialMatrix matrix currentmatrix def
currentdict end def
/TempMatrix matrix def
/GraphicStateStack 20 array def
/GraphicStateStackPointer 0 def
/PDFColorSpaces 50 dict def
/InstalledFonts 50 dict def
/MacRomanEncodingInverse null def
% We need some structures in local VM, put then into the userdict :
currentglobal false setglobal
userdict /PDFR_InitialGS gstate put
userdict /PDFR_Patterns 50 dict put
userdict /FuncDataReader 10 dict put
setglobal
% ===================== Constants =========================================
% The ExtGState elements are composite, thus need to be copied to
% global VM (in case they aren't already global).
/InitialExtGState 20 dict begin
/BG2 currentblackgeneration cp2g def
/UCR2 currentundercolorremoval cp2g def
/TR2 currentglobal false setglobal [ currentcolortransfer ] exch setglobal cp2g def
/HT currenthalftone cp2g def
currentdict end readonly def
/InitialGraphicState 20 dict begin
/FontSize 0 def
/CharacterSpacing 0 def
/TextLeading 0 def
/TextRenderingMode 0 def
/WordSpacing 0 def
currentdict end readonly def
/SimpleColorSpaceNames 15 dict begin
/DeviceGray true def
/DeviceRGB true def
/DeviceCMYK true def
currentdict end readonly def
/1_24_bitshift_1_sub 1 24 bitshift 1 sub def
/ReadFontProcs 10 dict def % Will be filled below.
% ===================== Reading PDF objects ===============================
/Register % Register -
{
exch dup % d obj id id
//PDFReader /ObjectRegistry get length ge {
dup dup 2 idiv add array dup % d obj id [n] [n]
//PDFReader /ObjectRegistry get dup length % d obj id [n] [n] [o] l
3 2 roll exch % d obj id [n] [o] [n] l
0 exch getinterval copy pop % d obj id [n]
//PDFReader exch /ObjectRegistry exch put % d obj id
} if
exch //PDFReader /ObjectRegistry get % d id obj r
3 1 roll % d r id obj
3 copy pop get % d r id obj e
dup xcheck { % d r id obj e
5 4 roll pop % r id obj e
//PDFR_DEBUG {
(Have a daemon for ) print 2 index =
} if
% We've got a definition daemon, execute it :
exec
} { % d r id obj e
dup null ne { % d r id obj e
mark (The object ) 4 index ( already defined : ) 4 index //error exec
} {
pop
} ifelse
4 3 roll % r id obj d
% Execute the default daemon :
exec
} ifelse % r id obj
put %
} bind def
/IsRegistered % GetRegistered
{
//PDFReader /ObjectRegistry get % id r
dup length % id r l
2 index le { % id r
pop pop false
} {
exch get % id e
null ne
} ifelse
} bind def
/GetRegistered % GetRegistered
{
//PDFReader /ObjectRegistry get % id r
dup length % id r l
2 index le { % id r
exch mark exch (Object ) exch ( isn't defined before needed (1).) //error exec
} if
1 index get % id e
dup xcheck {
exch mark exch (Object ) exch ( isn't defined before needed (2).) //error exec
} {
dup null eq {
exch mark exch (Object ) exch ( isn't defined before needed (3).) //error exec
} if
exch pop % e
} ifelse
} bind def
/StandardFontNames <<
/Times-Roman true
/Helvetica true
/Courier true
/Symbol true
/Times-Bold true
/Helvetica-Bold true
/Courier-Bold true
/ZapfDingbats true
/Times-Italic true
/Helvetica-Oblique true
/Courier-Oblique true
/Times-BoldItalic true
/Helvetica-BoldOblique true
/Courier-BoldOblique true
>> def
/CleanAllResources % - CleanAllResources -
{ //PDFR_DEBUG {
(CleanAllResources beg) =
} if
//PDFReader /ObjectRegistry get
dup length 0 exch 1 exch 1 sub { % R i
2 copy get dup xcheck {
% Don't clean a daemon.
pop pop
} {
dup null eq {
pop pop
} {
dup type /dicttype eq { /.Global known } { pop false } ifelse {
pop
} {
//PDFR_DEBUG {
(Dropping ) print dup =
} if
1 index exch /DroppedObject put
} ifelse
} ifelse
} ifelse
} for
pop
FontDirectory length dict begin
FontDirectory {
pop
dup //StandardFontNames exch known not {
dup null def
} if
pop
} forall
currentdict
end {
pop
//PDFR_DEBUG {
(Undefining font ) print dup =
} if
undefinefont
} forall
//PDFR_DEBUG {
(CleanAllResources end) =
} if
} bind def
/PrintReference % PrintReference
{
//PDFR_DEBUG {
({ ) print
dup {
=only ( ) print
} forall
( }) =
} if
} bind def
/R % R
{ % Make a reference daemon.
0 ne {
exch mark exch (A referred object generation ) exch ( isn't 0.) //error exec
} if % id
[ % proc
exch //GetRegistered /exec load
] cvx
//PrintReference exec
} bind def
/IsObjRef % IsObjRef
{
dup type /arraytype eq {
dup length 3 eq {
dup xcheck exch
dup 0 get type /integertype eq 3 2 roll and exch
dup 1 get //GetRegistered eq 3 2 roll and exch
2 get /exec load eq and
} {
pop false
} ifelse
} {
pop false
} ifelse
} bind def
/DoNothing
{
} def
/RunTypeDaemon % RunTypeDaemon
{
dup type /dicttype eq {
dup /Type //knownget exec {
//PDFReader /TypeDaemons get exch
//knownget exec {
exec
} if
} if
} if
} bind def
/obj % obj
{
//PDFR_DEBUG {
(Defining ) print 1 index =only ( ) print dup =only ( obj) =
} if
0 ne {
exch mark exch (An object generation ) exch ( isn't 0.) //error exec
} if
} bind def
/endobj % endobj -
{
//PDFR_DEBUG {
(endobj ) =
} if
dup type /dicttype eq {
dup /.endobj_daemon //knownget exec {
//PDFR_DEBUG { (.endobj_daemon for ) print 2 index = } if
exec
} if
} if
dup type /dicttype eq { dup /ImmediateExec known } { false } ifelse {
pop pop
} {
//PDFR_DEBUG {
(Storing ) print 1 index =
} if
//RunTypeDaemon exec
//DoNothing 3 1 roll //Register exec
} ifelse
} bind def
/StoreBlock % StoreBlock -
{ % Stores a (encoded) stream data block to the current object.
//PDFR_DEBUG {
(StoreBlock ) print //PDFReader /BlockCount get =only (, Length = ) print dup length =
} if
dup length string copy
//PDFReader /BlockCount get exch % i s
//PDFReader /CurrentObject get 3 1 roll % o i s
put %
//PDFReader /BlockCount get 1 add
//PDFReader exch /BlockCount exch put
} bind def
/CheckLength % CheckNumber
{ dup type /integertype ne {
mark (Object length isn't an integer.) //error exec
} if
} bind def
/ResolveD % ResolveD
{
3 copy pop get % <> key {} e
dup //IsObjRef exec {
% We've got a reference daemon, execute it :
//PDFR_DEBUG {
(Resolving ) print //PrintReference exec
} if
exec % <> key {} val
exch exec % <> key val
} {
exch pop
} ifelse
dup 4 1 roll % val <> key val
put % val
} bind def
/ResolveA % ResolveA
{ 2 index 2 index get
dup //IsObjRef exec {
exec
exch exec
3 copy put
} {
exch pop
} ifelse
exch pop exch pop
} bind def
/StoreStream % StoreStream
{ % Stores a (encoded) data stream copy to the current object.
dup //PDFReader exch /CurrentObject exch put % id obj
//PDFReader /BlockCount 0 put
dup /Length //CheckLength //ResolveD exec % id obj l
//PDFR_DEBUG {
(StoreStream Length = ) print dup =
} if
currentfile exch () /SubFileDecode filter % id obj file
{ dup //BlockBuffer readstring { % id obj file buf
//StoreBlock exec
} {
//StoreBlock exec
exit
} ifelse % id obj file
} loop
pop % id obj
//PDFReader /CurrentObject null put
//PDFR_DEBUG {
(StoreStream end.) =
} if
} bind def
/MakeStreamDumper % MakeStreamDumper
{ % Debug purpose only.
//PDFR_DEBUG {
(MakeStreamDumper beg.) =
} if
currentglobal exch dup gcheck setglobal
[ exch % f
1 dict dup /c 0 put exch % d f
1024 string % d f s
{ readstring pop % d s
(StreamDumper ) print 1 index /c get =string cvs print ( ) print
dup length =string cvs print ( <) print dup print (>\n) print
dup length % d s l
3 2 roll % s l d
dup /c get % s l d c
3 2 roll % s d c l
add /c exch put % s
} /exec load
]
cvx 0 () /SubFileDecode filter
exch setglobal
//PDFR_DEBUG {
(MakeStreamDumper end.) =
} if
} bind def
/ShortFilterNames 15 dict begin
/AHx /ASCIIHexDecode def
/A85 /ASCII85Decode def
/LZW /LZWDecode def
/Fl /FlateDecode def
/RL /RunLengthDecode def
/CCF /CCITTFaxDecode def
/DCT /DCTDecode def
currentdict end readonly def
/AppendFilters % AppendFilters
{
//PDFR_DEBUG {
(AppendFilters beg.) =
} if
dup 3 1 roll % d f d
/Filter //knownget exec { % d f F
dup type /nametype eq { % d f /F
dup //ShortFilterNames exch //knownget exec {
exch pop
} if
2 index /DecodeParms //knownget exec { % d f p /F
exch
} if
filter % d f'
} { % d f []
dup 0 exch 1 exch length 1 sub { % d f [] i
2 copy get % d f [] i /F
dup //ShortFilterNames exch //knownget exec {
exch pop
} if
3 1 roll % d f /F [] i
4 index /DecodeParms //knownget exec { % d f /F [] i DP
exch get % d f /F [] dp
} { % d f /F [] i
pop null % d f /F [] dp
} ifelse
dup null eq { % d f /F [] dp
pop 3 1 roll filter exch % d f' []
} { % d f /F [] dp
3 1 roll % d f dp /F []
4 1 roll filter exch % d f' []
} ifelse
} for
pop % d f'
} ifelse
//PDFR_DEBUG //PDFR_DUMP and {
//MakeStreamDumper exec
} if
} if
exch pop
//PDFR_DEBUG {
(AppendFilters end.) =
} if
} bind def
/ExecuteStream % ExecuteStream
{ % Executes a (encoded) data stream.
dup //PDFReader exch /CurrentObject exch put % id obj
dup /Length //CheckLength //ResolveD exec % id obj l
//PDFR_DEBUG {
(ExecuteStream id = ) print 2 index =only ( Length = ) print dup =
} if
//PDFReader /InitialGraphicState get
//PDFReader /GraphicState get copy pop
//PDFReader /Operators get begin
% currentfile exch () /SubFileDecode filter % id obj file
% We would like to use the code above,
% but HP LaserJet 1320 continues parsing after the byte count exceeds.
pop currentfile 0 (endstream) /SubFileDecode filter % id obj file
1 index //AppendFilters exec
cvx mark exch % id obj mark file
exec
counttomark 0 ne {
mark (Data left on ostack after an immediate stream execution.) //error exec
} if
cleartomark % id obj
end % Operators
//PDFR_DEBUG {
(ExecuteStream end.) =
} if
//PDFReader /CurrentObject null put
dup /IsPage known {
dup /Context get /NumCopies //knownget exec {
1 sub {
copypage
} repeat
} if
showpage
} if
} bind def
/stream % stream
{
//PDFR_DEBUG {
1 index =only ( stream) =
} if % id obj
% Run the object definition daemon, if exists :
//PDFReader /ObjectRegistry get dup length 3 index % id obj r l id
gt { % id obj r
2 index get
dup xcheck {
exec
% Disable the daemon :
//PDFReader /ObjectRegistry get 2 index null put
} {
pop
} ifelse
} {
pop
} ifelse % id obj
dup /ImmediateExec known {
dup /GlobalExec //knownget exec {
currentglobal 4 1 roll
setglobal
//ExecuteStream exec
3 2 roll setglobal
} {
//ExecuteStream exec
} ifelse
} {
//StoreStream exec
} ifelse
dup /.CleanResources //knownget exec {
/All eq {
//CleanAllResources exec
} if
} if
} bind def
/HookFont % HookFont
{
//PDFR_DEBUG {
(Loaded the font ) print dup /FontName get =
} if
{
dup /FontFileType get dup /Type1 eq exch /MMType1 eq or { % id obj fd
% We assume that the Type 1 font has same name with no prefix
% due to pdfwrite specifics.
% We use it to find the font after it is defined.
% We could redefine 'definefont' for hooking the font,
% but we don't think that it could be guaranteedly portable :
% a 3d party PS interpreter may set a special context
% when running the font file.
% Note that this mechanizm does not depend on the
% font name uniquity, because the last 'definefont'
% is only important.
dup /FontName get % id obj fd fn
//PDFReader /RemoveFontNamePrefix get exec
findfont % id obj fd g f
exit
} if
dup /FontFileType get /TrueType eq { % id obj fd
//PDFReader /MakeType42 get exec
//PDFR_DEBUG {
(Font dict <<) =
dup {
1 index /sfnts eq {
exch pop
(/sfnts [) print
{
(-string\() print length //=only exec (\)- ) =
} forall
(]) =
} {
exch //=only exec ( ) print ==
} ifelse
} forall
(>>) =
} if
dup /FontName get exch definefont
exit
} if
mark (FontHook has no proc for ) 2 index /FontFileType get //error exec
} loop
/Font exch put % id obj
} bind def
/endstream % endstream
{
} bind def
/xref % - xref -
{
//PDFR_DEBUG {
(xref) =
//PDFR_DUMP {
//PDFReader /ObjectRegistry get ==
} if
} if
end % The procset
count 0 ne {
mark (Excessive data on estack at the end of the interpretation.) //error exec
} if
currentfile 1 (%%EOF) /SubFileDecode filter
flushfile
cleardictstack
} bind def
% ===================== Restoring the PDF Document Structure ===============
/ResolveDict % /ResolveDict -
{ dup { % d key val
pop 1 index exch % d cp key
//DoNothing //ResolveD exec % d obj
pop % d
} forall
pop %
} bind def
/SetupPageView % SetupPageView -
{
//PDFR_DEBUG {
(SetupPageView beg) =
} if
//GraphicState /InitialMatrix get setmatrix
/MediaBox get aload pop % bx0 by0 bx1 by1
3 index neg 3 index neg translate % Temporary move to origin
3 -1 roll sub 3 1 roll exch sub exch % bw bh
userdict /.HWMargins //knownget exec {
aload pop
} {
currentpagedevice /.HWMargins //knownget exec {
aload pop
} {
0 0 0 0
} ifelse
} ifelse
currentpagedevice /PageSize get aload pop
3 -1 roll sub 3 1 roll exch sub exch % bw bh px0 py0 px1 py1
exch 3 index sub exch 3 index sub % bw bh px0 py0 pw ph
//SetPageSize {
//PDFR_DEBUG {
(Setting page size to ) print 1 index //=only exec ( ) print dup =
} if
pop pop 3 index 3 index 2 copy % bw bh px0 py0 bw bh bw bh
currentglobal false setglobal 3 1 roll % bw bh px0 py0 bw bh bool bw bh
2 array astore % bw bh px0 py0 bw bh bool []
<< exch /PageSize exch >> setpagedevice % bw bh px0 py0 bw bh bool
userdict /PDFR_InitialGS gstate put
setglobal % bw bh px0 py0 bw bh
} if
//RotatePages {
2 copy gt 6 index 6 index gt ne {
% a rotation is useful except it fits with no rotation.
1 index 5 index le 1 index 5 index le and not
} {
false
} ifelse
} {
false
} ifelse
{ //CenterPages {
//PDFR_DEBUG {
(Rotating page, and then centering it) ==
} if
90 rotate
0 5 index neg translate
5 index 1 index exch sub 2 div
2 index 6 index sub 2 div neg % bw bh px0 py0 pw ph lm bm
translate
} {
//FitPages {
1 index 5 index div 1 index 7 index div % bw bh px0 py0 pw ph sx sy
2 copy gt {
exch
} if
pop dup scale % bw bh px0 py0 pw ph
} if
90 rotate
0 5 index neg translate
} ifelse
} {
//CenterPages {
//PDFR_DEBUG {
(Ccentering page) ==
} if
1 index 6 index sub 2 div
1 index 6 index sub 2 div % bw bh px0 py0 pw ph lm bm
translate
} {
//FitPages {
1 index 6 index div 1 index 6 index div % bw bh px0 py0 pw ph sx sy
2 copy gt {
exch
} if
pop dup scale % bw bh px0 py0 pw ph
} if
} ifelse
} ifelse
pop pop % bw bh px0 py0
translate % bw bh
pop pop %
//PDFR_DEBUG {
(SetupPageView end) =
} if
} bind def
/PageContentsDaemon % PageContentsDaemon
{ % Note: an excessive operand from a prebond procedure.
//PDFR_DEBUG {
(Executing PageContentsDaemon for ) print 2 index =
} if % id obj node
1 index exch /Context exch put % id obj
dup /ImmediateExec true put
dup /IsPage true put
dup /Context get //SetupPageView exec
} bind def
/FontFileDaemon % FontFileDaemon
{ % Note: an excessive operand from a prebond procedure.
//PDFR_DEBUG {
(Executing FontFileDaemon for ) print 2 index =
} if
% We need any font resource that refers this descriptor
% to know the font type. Assuming that FontDescriptorDaemon
% provided FontFileType.
dup /FontFileType get % id obj fd ft
2 index exch % id obj fd obj ft
dup //ReadFontProcs exch //knownget exec { % id obj fd obj ft proc
exch pop exec % id obj fd
} {
mark (FontFile reader for ) 2 index ( isn't implemented yet.) //error exec
} ifelse
//PDFR_DEBUG {
(FontFileDaemon end) =
} if % id obj fd
pop
} bind def
/FontDescriptorDaemon % FontDescriptorDaemon
{ % Note: an excessive operand from a prebond procedure.
//PDFR_DEBUG {
(Executing FontDescriptorDaemon for ) print 2 index =
} if % id obj fr
%HACK BEG assuming an own font for each font descriptor
% to provide an access to PDFEncoding
% from MakeType42, ComposeCharStrings.
2 copy /FontResource exch put
%HACK END
/Subtype get 1 index exch /FontFileType exch put
} bind def
/UnPDFEscape { % UnPDFEscape
dup dup length string cvs % /namepdf (name)
dup (#) search {
% name contains PDF-style escapes ("#hh") that need to be removed
{ % ... (po..st) (#) (pre)
pop % ... (po..st) (#)
(16#--) 2 index 0 2 getinterval % ... (po..st) (#) (16#--) (po)
1 index 3 2 getinterval copy pop % ... (po..st) (#) (16#po)
cvi % ... (po..st) (#) 16#po
0 exch put % ... (po..st); 16#po patched into (#)
0 % ... (po..st) 0
1 index 2 1 index length 2 sub getinterval % ... (po..st) 0 (..st)
3 copy putinterval % ... (..stst) 0 (XXst)
length % ... (..stst) 0 LEN_OF_(po..st)-2
3 copy exch put % ... (..st\0t) 0 LEN_OF_(po..st)-2
getinterval % ... (..st), stored at begining of old (po..st)
(#) search not {
pop exit % /namepdf (nameps\0..)
} if
} loop
% we have a '\0' marker (not allowed in PDF names) after all usefull characters
(\0) search pop exch pop exch pop
cvn
exch pop
} {
pop pop
} ifelse
} bind def
/TypeDaemons << % proc
/Page
{ //PDFR_DEBUG {
(Recognized a page.) =
} if
dup /Contents //knownget exec { % id obj c
0 get //DoNothing exch % id obj dn id1
[ % proc
3 index //PageContentsDaemon /exec load
] cvx % id obj {}
//Register exec % id obj
} {
(fixme: page with no Contents won't be printed.) =
} ifelse
} bind
/FontDescriptor
{ //PDFR_DEBUG {
(Recognized a font descriptor.) =
} if
dup /FontName //knownget exec {
1 index /FontName 3 -1 roll //UnPDFEscape exec put
} if
dup dup /FontFile known {/FontFile} {/FontFile2} ifelse
//knownget exec { % id obj ff
0 get //DoNothing exch % id obj dn id1
[ % proc
3 index //FontFileDaemon /exec load
] cvx % id obj {}
//Register exec % id obj
} {
% FontFile3 are not implemented yet.
(Font descriptor ) print 1 index =only ( has no FontFile.) =
} ifelse
} bind
/Font
{ //PDFR_DEBUG {
(Recognized a font resource.) =
} if
dup /BaseFont //knownget exec {
//UnPDFEscape exec 2 copy /BaseFont exch put
% cache the installed font (if any) before replacing it.
//PDFReader /RemoveFontNamePrefix get exec
currentglobal exch % A hack against HP LaserJet 1320 bug :
% It sets the local allocation mode
% when 'resourcestatus' fails.
dup /Font resourcestatus {
pop pop
//PDFReader /GetInstalledFont get exec pop
} {
pop
} ifelse
setglobal
} if
dup /FontDescriptor //knownget exec { % id obj fd
0 get % id obj id1
dup //IsRegistered exec { % id obj id1
//PDFR_DEBUG {
(already registered ) print dup =
} if
pop
} {
//DoNothing exch % id obj dn id1
[ % proc
3 index //FontDescriptorDaemon /exec load
] cvx % id obj {}
//Register exec % id obj
} ifelse
} if
} bind
>> def
/MakeStreamReader % MakeStreamReader
{ dup
[
exch
//PDFR_DEBUG {
(Stream proc )
/print load
//PDFR_STREAM {
(<)
/print load
} if
} if
1 dict dup /i -1 put
/dup load
/i
/get load
1
/add load
/dup load
3
1
/roll load
/i
/exch load
/put load
//knownget
/exec load
/not load
{ () }
/if load
//PDFR_DEBUG {
//PDFR_STREAM {
/dup load
/print load
(>)
/print load
} if
( end of stream proc.\n)
/print load
} if
] cvx
//PDFR_DEBUG {
(Stream reader ) print dup ==
} if
0 () /SubFileDecode filter
exch //AppendFilters exec
} bind def
/RunDelayedStream % RunDelayedStream -
{
//MakeStreamReader exec % file
mark exch
cvx exec %
counttomark 0 ne {
mark (Data left on ostack after a delayed stream execution.) //error exec
} if
cleartomark
} bind def
% ===================== Font Management ======================
//ReadFontProcs begin
/Type1 % Type1
{ //PDFR_DEBUG {
(ReadFontProcs.Type1) =
} if
dup /.endobj_daemon [ 4 index //HookFont /exec load ] cvx put
dup /ImmediateExec true put
/GlobalExec true put
} bind def
/MMType1 //Type1 def
/TrueType % TrueType
{ //PDFR_DEBUG {
(ReadFontProcs.TrueType) =
} if
dup /.endobj_daemon [ 4 index //HookFont /exec load ] cvx put
pop
} bind def
end
% A working dictionary to hold items related to reading a TrueType font
% and converting into a type 42 font, especially regarding creating the sfnts
% array of strings, and ensuring strings are split on table boundaries and
% for the glyf table, on glyph boundaries.
%
/.opdloadttfontdict 50 dict def
.opdloadttfontdict begin
/maxstring 65400 def % less than the maximum length of a PostScript string,
% must be a multiple of 4 (for hmtx / loca / vmtx)
end
% Uses an insertion sort to sort the contents of an array,
% the sorted array is returned. Takes the array to sort and a
% comparison procedure. The comparison procedure must take two
% arguments, and return a boolean. The return value should be
% false if arguments incorrectly ordered, true if they are
% already in the correct order.
%
% [Array to sort] {comparisaon proc} InsertionSort [Sorted array]
%
/.InsertionSort
{
/CompareProc exch def
/Array exch def
1 1 Array length 1 sub
{
/Ix exch def
/Value1 Array Ix get def
/Jx Ix 1 sub def
{
Jx 0 lt {
exit
} if
/Value2 Array Jx get def
Value1 Value2 CompareProc {
exit
} if
Array Jx 1 add Value2 put
/Jx Jx 1 sub def
} loop
Array Jx 1 add Value1 put
} for
Array
} bind def
%
% Utility rourtines to insert a TrueType data type
%
% putu16 -
/putu16 {
3 copy -8 bitshift put
exch 1 add exch 16#ff and put
} bind def
% putu32 -
/putu32 {
3 copy -16 bitshift putu16
exch 2 add exch 16#ffff and putu16
} bind def
%
% Utility routines to read TrueType table data, returning
% either a string or an array of strings depending on the
% table length.
%
% Read a table as a single string.
% .readtable
/.readtable {
dup dup 1 and add string
% Stack: f len str
dup 0 4 -1 roll getinterval
% Stack: f str str1
% Because of the absurd PostScript specification that gives an
% error for reading into an empty string, we have to check for
% this explicitly here.
3 -1 roll exch
dup () ne { readstring } if pop pop
} bind def
% Read a big table (one that may exceed 64K).
% .readbigtable
/.readbigtable {
dup maxstring lt {
.readtable
} {
currentuserparams /VMReclaim get -2 vmreclaim
[ 4 2 roll {
% Stack: mark ... f left
dup maxstring le { exit } if
1 index maxstring string readstring pop 3 1 roll maxstring sub
} loop .readtable ]
exch vmreclaim
} ifelse
} bind def
% ReadTTF reads the tables and so on from a TreuType font into memory
% so that they are available for later processing.
%
% ReadTTF -
%
/ReadTTF
{
.opdloadttfontdict begin
/TTFontFile exch def
% Table directory:
% version - fixed (4 bytes)
% numTables - USHORT (2 bytes)
% searchRange - USHORT (2 bytes)
% entrySelector - USHORT (2 bytes)
% Read Table
/TableDir TTFontFile 12 string readstring pop def
% There are numTables table directory entries:
% tag - ULONG (4 bytes)
% checkSum - ULONG (4 bytes)
% offset - ULONG (4 bytes)
% length - ULONG (4 bytes)
% Read entries
/tables TTFontFile TableDir 4 getu16 16 mul string readstring pop def
% Create dictionary to store directory entries.
/tabarray tables length 16 idiv array def
% Check version for TrueType collection
TableDir 0 4 getinterval (ttcf) eq {
QUIET not { (Can't handle TrueType font Collections.) = } if
/.loadttfonttables cvx /invalidfont signalerror
} {
% There are ((length of tables string) / 16) Table directory entries
% Get and store each in turn
0 16 tables length 1 sub {
% Get each directory entry as a 16-byte string
dup % index index
tables exch 16 getinterval % index (string)
exch 16 div cvi exch % index/16 (string)
tabarray 3 1 roll put
} for
} ifelse
% We need the tables in the order they occur in the file, so sort
% by 'offset'.
tabarray { exch 8 getu32 exch 8 getu32 gt} .InsertionSort pop
% Now we read the content of each table in turn. If the table is < 64K
% then we store it in a single string. If its more, we store it in an
% array of strings. The table contents are stored in 'tabs' in the same
% order as they are read from the file, as per the sorted array 'tabarray'.
/Read TableDir length tables length add def
/tabs [
tabarray {
% Get offset (from start of file) of next table
dup 8 getu32 % () offset
% Subtract amount read so far
Read sub % () offset-Read
dup 0 gt {
% Read and discard any extra padding bytes % () offset-Read
dup string TTFontFile exch readstring pop pop % () offset-Read
% Update bytes read
Read add /Read exch def % ()
} {
pop % ()
} ifelse
% Find length of this table and add it to bytes read
12 getu32 % () tablelength
dup Read add % () tablelength tablelength+Read
/Read exch def % () tablelength
TTFontFile exch .readbigtable
} forall
] def
end % .opdloadttfontdict
} bind def
% GetLocaType finds the head table in tabarray, which gives
% an index into the 'tabs' array where the data is stored.
% From that data we extract the loca type (short or long).
%
% - GetLocaType -
%
/GetLocaType
{
0 1 tabarray length 1 sub{
% control-variable
dup tabarray exch get % control-variable ()
0 4 getinterval (head) eq{ % control-variable bool
tabs exch get % ()
50 gets16
/LocaType exch def
exit
} {
pop % control variable % -
} ifelse
} for
} bind def
% GetNumGlyphs finds the maxp table in tabarray, which gives
% an index into the 'tabs' array where the data is stored.
% From that data we extract the number of glyphs in the font.
%
% - GetNumGlyphs -
%
/GetNumGlyphs
{
0 1 tabarray length 1 sub{
% control-variable
dup tabarray exch get % control-variable ()
0 4 getinterval (maxp) eq{ % control-variable bool
% Get the maxp string
% from the tabs array
tabs exch get % ()
4 getu16 % int
/NumGlyphs exch def
exit % int
} {
pop % control variable % -
} ifelse
} for
} bind def
% StringtoLoca takes a string, and an index in to an array
% where the loca results should be stored from. It reads
% along the string getting either 2-byte or 4-byte values
% (depends on loca type) and stores them in the array at
% successive locations. Leaves the next unused location
% on the stack at end (easy to process multiple strings).
%
% string ArrayIndex StringToLoca ArrayIndex
%
/StringToLoca
{
/LocaIndex exch def % ()
/StringOffset 0 def % ()
{
dup length StringOffset gt { % ()
dup % ()
LocaType 1 eq{
StringOffset getu32 % () loca
LocaArray LocaIndex 3 -1 roll put % ()
/LocaIndex LocaIndex 1 add def % ()
/StringOffset StringOffset 4 add % ()
def
} {
dup % () loca
StringOffset getu16 % ()
LocaArray LocaIndex 3 -1 roll put % ()
/LocaIndex LocaIndex 1 add def % ()
/StringOffset StringOffset 4 add % ()
def
} ifelse
}{ % ()
pop % -
LocaIndex % return index
exit
}ifelse
} loop
} bind def
% GetSortedLoca reads the loca table, and sorts it by offset
% this is so that we can walk up the array looking for an approporiate
% place to split strings. The result is stored in LocArray
%
% - GetSortedLoca -
%
/GetSortedLoca
{
NumGlyphs 1 add array /LocaArray exch def
% Get the loca table
0 1 tabarray length 1 sub{
% control-variable
dup tabarray exch get % control-variable ()
0 4 getinterval (loca) eq{ % control-variable bool
% Get the loca string
% from the tabs array
tabs exch get % ()
exit
} {
pop % control variable % -
} ifelse
} for
% If its a single string handle the easy way
dup type /stringtype eq {
0 StringToLoca pop
}{
% Otherwise its an array, process each string in the array
0 exch % Starting LocaArray index
{
exch StringToLoca
}forall
pop % final LocaArray index
}ifelse
% Now we've read all the locations, sort them so
% we can figure out where to break the strings
LocaArray {gt} .InsertionSort pop
} bind def
% Updates internal storage with a new string from the
% GlyfArray
% - GetWorkingString -
/GetWorkingString
{
WorkString 0
GlyfArray GlyfStringIndex get
putinterval
% Update the available bytes
/WorkBytes GlyfArray GlyfStringIndex get length def
% Set index to get data from next string in array
/GlyfStringIndex GlyfStringIndex 1 add def
} bind def
% Returns a string with the requested number of bytes taken
% from WorkingString. There must be enough data in WorkingString to
% satisfy the request
%
/GetWorkingBytes
{
/BytesToRead exch def
% Get 'BytesToRead' bytes from working store
WorkString 0 BytesToRead getinterval
dup length string copy
% Get remaining bytes from working store
WorkString BytesToRead WorkBytes BytesToRead sub getinterval
dup length string copy
% replace first 'n' bytes of working store with unread bytes
WorkString 0 3 -1 roll putinterval
% Subtract bytes read from bytes available
/WorkBytes WorkBytes BytesToRead sub def
} bind def
% Read 'int' bytes from GlyfArray strings, return string composed
% of those bytes
%
% int GetGlyfBytes string
/GetGlyfBytes
{
/ToRead exch def
% If we have no available data, get soem from the array of
% glyf strings
WorkBytes 0 eq {
GetWorkingString
} if
WorkBytes ToRead ge {
ToRead string dup 0
ToRead GetWorkingBytes putinterval
}{
% Create a string sized to hold the target data
ToRead string
% Get remaining stored bytes, and put at the start
% of the string
dup
% Start of string
0
% Get remaining bytes
WorkString 0 WorkBytes getinterval
% store at start of output string
putinterval
dup
% Location in output to store data from next string
WorkBytes
% amout of data required to read from next string
ToRead WorkBytes sub
% Get the next string from the array of strings
GetWorkingString
% Get a string containing the required data, updating
% the internal data storage
GetWorkingBytes
% put the data at the end of the stored data in the
% output string
putinterval
} ifelse
} bind def
% Given an array of glyf strings, returns an array of strings
% split on glyf boundaries
%
% [] SplitGlyf []
%
/SplitGlyf
{
/GlyfArray exch def
/DestArray GlyfArray length 2 mul array def
/DestArrayIndex 0 def
/LastLoca 0 def
/NextLocaIndex 0 def
/LastLocaIndex 0 def
/GlyfStringIndex 0 def
/WorkString maxstring string def
/WorkBytes 0 def
% Find appropriate next loca
{
% Get location of next glyph
LocaArray NextLocaIndex get % int
% subtract location of last point to get
% the actual bytes between
LastLoca sub maxstring gt % int bool
{
LocaArray LastLocaIndex get LastLoca sub
GetGlyfBytes % ()
DestArray DestArrayIndex 3 -1 roll put % -
/DestArrayIndex DestArrayIndex 1 add def % -
LocaArray LastLocaIndex get /LastLoca exch def % -
} { % int
/LastLocaIndex NextLocaIndex def % -
/NextLocaIndex NextLocaIndex 1 add def % -
NextLocaIndex NumGlyphs gt % bool
{
WorkBytes % int
GlyfStringIndex GlyfArray length lt { % int bool
GlyfArray GlyfStringIndex get length % int
add string dup % (d) (d)
0 % (d) (d) 0
WorkString 0 WorkBytes getinterval % (d) (d) (s)
putinterval % (d)
dup % (d) (d)
WorkBytes % (d) (d) int
GetWorkingString % (d) (d) int
WorkString 0 WorkBytes getinterval % (d) (d) int (s)
putinterval % (d)
} {
pop % -
WorkString 0 WorkBytes getinterval % ()
} ifelse
dup length string copy
DestArray DestArrayIndex 3 -1 roll put
exit
} if
} ifelse
} loop
DestArray
} bind def
% ProcessTTData looks at the data stored in the 'tabs' array and does several things:
% 1) Make sure strings representing tables are multiples of 4 bytes long
% 2) For arrays representing tables, make sure the total string length is a multiple
% of 4 bytes long, to ensure the table is a multiple of 4 bytes.
% 3) Handle the glyf table specislly, each string in this array must be split on the
% boundary of a glyf. Use the loca table to determine where the split should happen
% and build a new array of strings split appropriately.
%
% - ProcessTTData -
%
/ProcessTTData
{
.opdloadttfontdict begin
% Make sure all the strings are a multiple of 4 bytes
0 1 tabarray length 1 sub{
/ix exch def
tabarray ix get
12 getu32 dup maxstring le {
% String < 64Kb, still need to check if its a multiple of 4
dup 4 mod 0 ne {
4 div cvi 1 add 4 mul string /newstring exch def
/oldstring tabs ix get def
newstring 0 oldstring putinterval
0 1 newstring length oldstring length sub 1 sub {
newstring exch oldstring length add 0 put
} for
tabs ix newstring put
} {
% table size is a multiple of 4, don't need to promote it
pop
} ifelse
}{
% table size > 64K, so this is an array of strings, not a string
% We still need to make sure that the tables end on 4-byte
% boundaries.
dup 4 mod 0 ne {
% First we need to work out how many strings of size maxstring
% are present, and how much they contribute to the overall size.
dup maxstring idiv maxstring mul sub
% Promote final string length to multiple of 4
4 idiv 1 add 4 mul string /newstring exch def
% Get array of strings
tabs ix get
% find size of table and get last string
dup length 1 sub dup /iy exch def get /oldstring exch def
newstring 0 oldstring putinterval
0 1 newstring length oldstring length sub 1 sub {
newstring exch oldstring length add 0 put
} for
tabs ix get iy newstring put
} {
% table size is a multiple of 4, don't need to promote it
pop
} ifelse
} ifelse
} for
% Now, if glyf table > 64Kb, then it will be an array of strings
% We need to make sure the strings are split on glyph boundaries
0 1 tabarray length 1 sub { % int
dup tabarray exch get % int ()
dup 12 getu32 maxstring gt { % int () bool
0 4 getinterval dup (glyf) eq{ % int () bool
% Need to split the glyf strings on glyph boundaries, hmmm.
pop % int
% We need to know the number of glyphs (from the maxp table) and the
% position of each glyph (from the loca table).
GetLocaType % int
GetNumGlyphs % int
GetSortedLoca % int
% Get the array of strings from tabs
dup tabs exch get % int
SplitGlyf % int []
tabs 3 1 roll put % -
} { % int ()
(Warning, table ) print print ( > 64Kb\n) print
pop % -
} ifelse
}{ % int ()
% Table less than 64K, so don't worry
pop % directory entry % int
pop % 'for' control variable % -
} ifelse
} for
end % .opdloadttfontdict
} bind def
% Makesfnts uses the accumulated data to create an array of strings
% containing only the required data.
%
% - Makesfnts array
%
/Makesfnts
{
.opdloadttfontdict begin
% Determine size of sfnts array
% length of tabarray + header
0
tabs { % int obj
dup type /stringtype eq { % int obj bool
pop % int
1 add % int
}{ % int obj
{ % int obj
type /stringtype eq { % int bool
1 add % int
} if
} forall
} ifelse
} forall
1 add % add header and table directory
% to determine total # strings
% Need to recalculate the lengths of the TT
% tables, just in case any have changed. If required we
% could also resort the tables here, ideally we should do so
% and recalculate checksums, but this should never be necessary
% for fonts produced by pdfwrite.
/TTOffset
TableDir length % initial table offset is header length
tabarray length 16 mul add % + (NumTables * 16) bytes
def
0
tabarray { % index ()
exch dup 1 add % () index index+1
3 1 roll % index+1 () index
dup % index+1 () index index
tabs exch get % index+1 () index ()/[]
dup type /stringtype eq { % index+1 () index ()/[] bool
length % index+1 () index int
2 index exch % index+1 () index () int
TTOffset
dup 3 1 roll add % add the running total of offsets
/TTOffset exch def % update running total of offsets
8 exch putu32 % index+1 () index
exch tabarray 3 1 roll % index+1 [] index ()
put % index+1
} { % index+1 () index ()/[]
0 exch % add all string lengths
{ % starting from 0
dup type /stringtype eq {
length add %
} {
pop
} ifelse
} forall %
2 index exch % index+1 () index () int
TTOffset
dup 3 1 roll add % add the running total of offsets
/TTOffset exch def % update running total of offsets
8 exch putu32 % index+1 () index
exch tabarray 3 1 roll % index+1 [] index ()
put % index+1
} ifelse
} forall
pop % index+1
array % []
dup 0 % [] [] 0
TableDir length
tables length add % [] [] 0 header_length
string % [] [] 0 ()
dup 0 TableDir putinterval % [] [] 0 ()
dup 12 tables putinterval % [] [] 0 ()
put % []
dup % [] []
/ix 1 def
tabs { % [] [] obj
dup type /stringtype eq { % [] [] obj bool
ix exch % [] [] int obj
put dup % [] []
/ix ix 1 add def % [] []
}{
{
dup type /stringtype eq { % [] [] obj bool
ix exch put dup % [] []
/ix ix 1 add def %
} {
pop % [] []
} ifelse
} forall
} ifelse
} forall
pop % []
end %.opdloadttfontdict
} bind def
/MakeType42 % MakeType42
{
//PDFR_DEBUG {
(MakeType42 beg) =
} if
10 dict begin
/FontName 1 index /FontName get def
/FontType 42 def
/FontMatrix [1 0 0 1 0 0] def
/FontBBox 1 index /FontBBox get def % fo fd
dup /FontResource get % fo fd fr
dup /Encoding known { % fo fd fr
//PDFReader /ObtainEncoding get exec % fo fd fr
/Encoding get % fo fd e
} {
pop null
} ifelse
/PDFEncoding exch def % fo fd
/CharStrings 2 index //PDFReader /MakeTTCharStrings get exec def
/sfnts 2 index //MakeStreamReader exec
ReadTTF
ProcessTTData
Makesfnts
def
/Encoding StandardEncoding def % A stub - will be replaced by font resource.
/PaintType 0 def
currentdict end
//PDFR_DEBUG {
(MakeType42 end) =
} if
} bind def
/GetInstalledFont % GetInstalledFont
{
dup //InstalledFonts exch knownget { % n f
exch pop % f
} { % n
dup findfont dup 3 1 roll % f n f
//InstalledFonts 3 1 roll put % f
} ifelse
} bind def
/RemoveFontNamePrefix % RemoveFontNamePrefix
{ //=string cvs true
0 1 5 {
2 index exch get //IsUpper exec not {
pop false exit
} if
} for
{ (+) search {
pop pop
} if
} if
cvn
} bind def
/CheckFont % CheckFont
{ dup /Type get /Font ne {
mark (Resource ) 3 index ( must have /Type/Font .) //error exec
} if
} bind def
/CheckEncoding % CheckEncoding
{ dup type /nametype ne {
dup /Type get /Encoding ne {
mark (Resource ) 3 index ( must have /Type/Encoding .) //error exec
} if
} if
} bind def
/ObtainEncoding % ObtainEncoding
{ dup /Encoding known {
dup dup /Encoding //CheckEncoding //ResolveD exec % fr fr er|e|n
dup type dup /arraytype eq exch /packedarraytype eq or {
% Already resolved.
pop pop
} {
dup type /nametype eq {
/Encoding findresource % fr fr e
} {
dup /BaseEncoding //knownget exec not {
/StandardEncoding
} if
/Encoding findresource % fr fr er e
exch % fr fr e er
/Differences //knownget exec { % fr fr e d
exch dup length array copy exch
0 exch % fr fr e 0 d
{ % fr fr e i v
dup type /integertype eq {
exch pop
} {
3 copy put pop % fr fr e i
1 add
} ifelse
} forall
pop % fr fr e
} if % fr fr e
} ifelse % fr fr e
/Encoding exch put % fr
} ifelse
} {
dup /Encoding /StandardEncoding /Encoding findresource put
} ifelse
} bind def
/ObtainMetrics % ObtainMetrics
{ dup /Widths //knownget exec { % fr W
1 index /Encoding get % fr W E
256 dict % fr W E M
3 index /Subtype get /TrueType eq {
1000
} {
1
} ifelse % fr W E M s
4 index /MissingWidth //knownget exec not {
0
} if % fr W E M s mw
5 index /FirstChar //knownget exec not {
0
} if % fr W E M s mw c0
6 5 roll % fr E M s mw c0 W
dup 0 exch 1 exch length 1 sub { % fr E M s mw c0 W i
2 copy get % fr E M s mw c0 W i w
exch 3 index add % fr E M s mw c0 W w c
7 index exch get % fr E M s mw c0 W w n
dup null ne {
6 index 3 1 roll exch % fr E M s mw c0 W M n w
6 index div
3 copy pop //knownget exec {
0 eq
} {
true
} ifelse
{ put % fr E M s mw c0 W
} {
pop pop pop
} ifelse
} {
pop pop
} ifelse
} for
pop pop pop pop exch pop % fr M
1 index exch /Metrics exch put % fr
} {
dup /MissingWidth //knownget exec { % fr mw
256 dict % fr mw M
2 index /Encoding get { % fr mw M e
dup null ne {
3 copy 3 2 roll put % fr mw M e
} if
pop % fr mw M
} forall
exch pop % fr M
1 index exch /Metrics exch put % fr
} if
} ifelse
} bind def
/NotDef % - NotDef -
{ % A Type 3 font is on dstack.
FontMatrix aload pop pop pop exch pop exch pop % sx sy
1 exch div exch
1 exch div exch % wx wy
1 index 0 setcharwidth
o setlinewidth
0 0 moveto
2 copy rlineto
1 index 0 rlineto
neg exch neg exch rlineto %
closepath stroke
} bind def
/BuildChar % BuildChar -
{ //PDFR_DEBUG {
(BuildChar ) print dup //=only exec ( ) print
} if
exch begin
Encoding exch get % n
//PDFR_DEBUG {
dup =
} if
dup null eq {
pop //NotDef exec %
} { % n
CharProcs exch //knownget exec { % cp_stream
//RunDelayedStream exec
} {
//NotDef exec
} ifelse
} ifelse %
end % font
} bind def
/printdict % printdict -
{ (<<) =
{ exch = == } forall
(>>) =
} bind def
/printfont % printfont -
{
dup {
exch dup =
dup /Encoding eq {
pop =
} {
dup /FontInfo eq exch /Private eq or {
//printdict exec
} {
==
} ifelse
} ifelse
} forall
} bind def
/ScaleMetrics % ScaleMetrics
{ 1 index { % M s n v
2 index div % M s n v'
3 index % M s n v' M
3 1 roll put % M s
} forall
pop
} bind def
/ResolveAndSetFontAux % ResolveAndSetFont -
{ exch dup % s rn rn
//PDFReader /CurrentObject get /Context get /Resources get
/Font //DoNothing //ResolveD exec
exch //CheckFont //ResolveD exec % s rn fr
dup /Font //knownget exec { % s rn fr f
exch pop exch pop
} {
{
dup /Subtype get dup dup /Type1 eq exch /TrueType eq or exch /MMType1 eq or {
% s rn fr
exch pop % s fr
dup /BaseFont get % s fr n
//RemoveFontNamePrefix exec % s fr n
//PDFR_DEBUG {
(Font ) print dup =
} if % s fr n
1 index /FontDescriptor known { % s fr n
//PDFR_DEBUG {
(Font from a font descriptor.) =
} if
1 index % s fr n fr
/FontDescriptor //DoNothing //ResolveD exec % s fr n fd
/Font //knownget exec {
exch pop % s fr fd
} {
//PDFR_DEBUG {
(Font descriptor has no Font resolved.) =
} if
//GetInstalledFont exec % s fr f
} ifelse
} {
//GetInstalledFont exec % s fr f
} ifelse
exch % s f fr
dup /Encoding known not {
1 index /Encoding get 1 index exch /Encoding exch put
} if
//ObtainEncoding exec
//ObtainMetrics exec
exch
dup length dict copy % s fr f
dup 2 index /Encoding get % s fr f f e
/Encoding exch put % s fr f
1 index /Metrics //knownget exec { % s fr f M
2 index /Subtype get /TrueType ne {
1 index /FontMatrix get 0 get
dup 0 eq {
% FontMatrix[0] == 0, so cannot downscale by it
% HACK: downscale by FontMatrix[1], and will get the target value of wx as wy
pop
1 index /FontMatrix get 1 get
dup 0 eq { pop 1 } if % sorry, FontMatrix is singular so cannot enforce the PDF metrics
} if
0.001 div
//ScaleMetrics exec
}{
% Check if we got a /sfnts key in the dict
% If we did then we are probably OK (TT font from GS)
1 index /sfnts known not {
% otherwise we need to check the FontMatrix
1 index /FontMatrix get 0 get
dup 0 eq {
% FontMatrix[0] == 0, so cannot downscale by it
% HACK: downscale by FontMatrix[1], and will get the target value of wx as wy
pop
1 index /FontMatrix get 1 get
dup 0 eq { pop 1 } if % sorry, FontMatrix is singular so cannot enforce the PDF metrics
} if
//ScaleMetrics exec
} if
} ifelse
1 index exch /Metrics exch put % s fr f
} if
1 index /BaseFont get % s fr f n
exch
dup /FID undef
dup /UniqueID undef
definefont % s fr f
dup 3 1 roll % s f fr f
/Font exch put % s f
exit
} if
dup /Subtype get /Type3 eq { % s rn fr
//ObtainEncoding exec
2 copy exch /FontName exch put
dup /CharProcs get //ResolveDict exec
dup /FontType 3 put
dup /BuildChar //BuildChar put
dup dup /Font exch put
% Ignore Metrics because pdfwrite duplicates it
% from setcharwidth/setcachedevice.
dup 3 1 roll % s fr rn fr
definefont % s fr f
2 copy ne {
% The interpreter copied the font dictionary while 'definefont'
% Need to update the font pointer in the resource.
2 copy /Font exch put % s fr f
} if
exch pop % s f
exit
} if
dup /Subtype get /Type0 eq { % s rn fr
} if
dup /Subtype get /CIDFontType0 eq { % s rn fr
} if
dup /Subtype get /CIDFontType2 eq { % s rn fr
} if
mark (Unknown font type ) 2 index /Subtype get //error exec
} loop
} ifelse % s f
exch scalefont setfont %
} bind def
/ResolveAndSetFont % ResolveAndSetFont -
{
//ResolveAndSetFontAux exec
} bind def
%%beg TrueType
% ================= Auxiliary procedures for True Type cmap Decoder =============
/.knownget
{ 2 copy known {
get true
} {
pop pop false
} ifelse
} bind def
/.min
{ 2 copy lt {
exch
} if
pop
} bind def
/.max
{ 2 copy gt {
exch
} if
pop
} bind def
/.dicttomark
{ >>
} bind def
% ===================== True Type cmap Decoder =============
% The following procedures are copied from gs/lib/gs_ttf.ps with no change.
% getu16
/getu16 {
2 copy get 8 bitshift 3 1 roll 1 add get add
} bind def
% gets16
/gets16 {
getu16 16#8000 xor 16#8000 sub
} bind def
% getu32
/getu32 {
2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
} bind def
% gets32
/gets32 {
2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
} bind def
% Each procedure in this dictionary is called as follows:
% proc
/cmapformats mark
0 { % Apple standard 1-to-1 mapping.
6 256 getinterval { } forall 256 packedarray
} bind
2 { % Apple 16bit CJK (ShiftJIS etc)
% /sHK_sz subHeaderKey_size % 1 * uint16
% /sH_sz subHeader_size % 4 * uint16
% /sH_len subHeader_length
% /cmapf2_tblen total table length
% /cmapf2_lang language code (not used)
% /sHKs subHeaderKeys
/sHK_sz 2 def
/sH_sz 8 def
dup 2 getu16 /cmapf2_tblen exch def
dup 4 getu16 /cmapf2_lang exch def
dup 6 256 sHK_sz mul getinterval /sHKs exch def
0 % initialization value for /sH_len
0 1 255 {
sHKs exch
2 mul getu16
1 index % get current max
1 index % get current subHeaderKey
lt {exch} if pop
} for
/sH_len exch def
dup 6 256 sHK_sz mul add
cmapf2_tblen 1 index sub getinterval
/sH_gIA exch def
/cmapf2_glyph_array 65535 array def
/.cmapf2_putGID {
/cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def
firstCode cmapf2_ch_lo le
cmapf2_ch_lo firstCode entryCount add lt
and { % true: j is inside
sH_offset idRangeOffset add % offset to gI
cmapf2_ch_lo firstCode sub 2 mul % rel. pos. in range
add 6 add % offset in sH_gIA
sH_gIA exch getu16
dup 0 gt { %
idDelta add
cmapf2_glyph_array exch cmapf2_ch exch put
} {
pop
% cmapf2_glyph_array cmapf2_ch 0 put
} ifelse
} { % false: j is outside
% cmapf2_glyph_array cmapf2_ch 0 put
} ifelse
} def
16#00 1 16#ff { % hi_byte scan
/cmapf2_ch_hi exch def
sHKs cmapf2_ch_hi sHK_sz mul getu16
/sH_offset exch def
sH_gIA sH_offset sH_sz getinterval
dup 0 getu16 /firstCode exch def
dup 2 getu16 /entryCount exch def
dup 4 gets16 /idDelta exch def
dup 6 getu16 /idRangeOffset exch def
pop
sH_offset 0 eq {
/cmapf2_ch_lo cmapf2_ch_hi def
/cmapf2_ch_hi 0 def
.cmapf2_putGID
} {
16#00 1 16#ff { % lo_byte scan
/cmapf2_ch_lo exch def
.cmapf2_putGID
} for
} ifelse
} for
pop
0 1 cmapf2_glyph_array length 1 sub { % rewrite null -> 0.
dup cmapf2_glyph_array exch get
null eq { cmapf2_glyph_array exch 0 put } {pop} ifelse
} for
cmapf2_glyph_array
} bind
4 { % Microsoft/Adobe segmented mapping.
/etab exch def
/nseg2 etab 6 getu16 def
14 /endc etab 2 index nseg2 getinterval def
% The Apple TrueType documentation omits the 2-byte
% 'reserved pad' that follows the endCount vector!
2 add
nseg2 add /startc etab 2 index nseg2 getinterval def
nseg2 add /iddelta etab 2 index nseg2 getinterval def
nseg2 add /idroff etab 2 index nseg2 getinterval def
% The following hack allows us to properly handle
% idiosyncratic fonts that start at 0xf000:
pop
/firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
/putglyph {
glyphs code 3 -1 roll put /code code 1 add def
} bind def
% Do a first pass to compute the size of the glyphs array.
/numcodes 0 def /glyphs 0 0 2 nseg2 3 sub {
% Stack: /glyphs numglyphs i2
/i2 exch def
/scode startc i2 getu16 def
/ecode endc i2 getu16 def
numcodes scode firstcode sub
% Hack for fonts that have only 0x0000 and 0xf000 ranges
%dup 16#e000 ge { 255 and } if
% the previous line is obstructive to CJK fonts, so it was removed
exch sub 0 .max ecode scode sub 1 add add
exch 1 index add exch
numcodes add /numcodes exch def
} for array def
% prefill the array with 0's faster than a { 0 putglyph } repeat
glyphs length 1024 ge {
.array1024z 0 1024 glyphs length 1023 sub { glyphs exch 2 index putinterval } for
glyphs dup length 1024 sub 3 -1 roll
putinterval
} {
0 1 glyphs length 1 sub { glyphs exch 0 put } for
} ifelse
% Now fill in the array.
/numcodes 0 def /code 0 def
0 2 nseg2 3 sub {
/i2 exch def
/scode startc i2 getu16 def
/ecode endc i2 getu16 def
numcodes scode firstcode sub
% Hack for fonts that have only 0x0000 and 0xf000 ranges
%dup 16#e000 ge { 255 and } if
% the previous line is obstructive to CJK fonts, so it was removed
exch sub 0 .max dup /code exch code exch add def
ecode scode sub 1 add add numcodes add /numcodes exch def
/delta iddelta i2 gets16 def
TTFDEBUG {
(scode=) print scode =only
( ecode=) print ecode =only
( delta=) print delta =only
( droff=) print idroff i2 getu16 =
} if
idroff i2 getu16 dup 0 eq {
pop scode delta add 65535 and 1 ecode delta add 65535 and
{ putglyph } for
} { % The +2 is for the 'reserved pad'.
/gloff exch 14 nseg2 3 mul add 2 add i2 add add def
0 1 ecode scode sub {
2 mul gloff add etab exch getu16
dup 0 ne { delta add 65535 and } if putglyph
} for
} ifelse
} for glyphs /glyphs null def % for GC
} bind
6 { % Single interval lookup.
dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
firstcode ng add array
% Stack: tab array
% Fill elements 0 .. firstcode-1 with 0
0 1 firstcode 1 sub { 2 copy 0 put pop } for
dup firstcode ng getinterval
% Stack: tab array subarray
% Fill elements firstcode .. firstcode+nvalue-1 with glyph values
0 1 ng 1 sub {
dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
} for pop exch pop
} bind
.dicttomark readonly def % cmapformats
% cmaparray
/cmaparray {
dup 0 getu16 cmapformats exch .knownget {
TTFDEBUG {
(cmap: format ) print 1 index 0 getu16 = flush
} if exec
} {
(Can't handle format ) print 0 getu16 = flush
0 1 255 { } for 256 packedarray
} ifelse
TTFDEBUG {
(cmap: length=) print dup length = dup ==
} if
} bind def
% Define remapping for misnamed glyphs in TrueType 'post' tables.
% There are probably a lot more than this!
/postremap mark
/Cdot /Cdotaccent
/Edot /Edotaccent
/Eoverdot /Edotaccent
/Gdot /Gdotaccent
/Ldot /Ldotaccent
/Zdot /Zdotaccent
/cdot /cdotaccent
/edot /edotaccent
/eoverdot /edotaccent
/gdot /gdotaccent
/ldot /ldotaccent
/zdot /zdotaccent
.dicttomark readonly def
/get_from_stringarray % get_from_stringarray
{ 1 index type /stringtype eq {
get
} {
exch { % o ()
2 copy length ge {
length sub
} {
exch get exit
} ifelse
} forall
} ifelse
} bind def
/getinterval_from_stringarray % getinterval_from_stringarray
{ % May allocate a string in VM.
2 index type /stringtype eq {
getinterval
} {
string exch 0 % [] s o p
4 3 roll { % s o p Si
dup length % s o p Si lSi
dup 4 index lt {
3 index exch sub % s o p Si o'
exch pop 3 1 roll exch pop % s o' p
} { % s o p Si lSi
dup 3 1 roll % s o p lSi Si lSi
4 index sub % s o p lSi Si lSi-o
5 index length 4 index sub % s o p lSi Si lSi-o ls-p
2 copy gt { exch } if pop % s o p lSi Si minl
dup 3 1 roll % s o p lSi minl Si minl
5 index exch getinterval % s o p lSi minl from
5 index 4 index 3 index % s o p lSi minl from s p minl
getinterval % s o p lSi minl from to
copy pop % s o p lSi minl
exch pop add exch pop 0 exch % s 0 p'
dup 3 index length ge { exit } if
} ifelse
} forall
pop pop % s
} ifelse
} bind def
/string_array_size % string_array_size
{ dup type /stringtype eq {
length
} {
0 exch { length add } forall
} ifelse
} bind def
% Each procedure in this dictionary is called as follows:
% posttable <> glyphencoding
/postformats mark
16#00010000 { % 258 standard Macintosh glyphs.
pop MacGlyphEncoding
}
16#00020000 { % Detailed map, required by Microsoft fonts.
dup dup type /arraytype eq { 0 get } if length 36 lt {
TTFDEBUG { (post format 2.0 invalid.) = flush } if
pop [ ]
} {
/postglyphs exch def
/post_first postglyphs dup type /arraytype eq { 0 get } if def
post_first 32 getu16 /numglyphs exch def
/glyphnames numglyphs 2 mul 34 add def
% Build names array in the order they occur in the 'post' table
/postpos glyphnames def
/total_length postglyphs //string_array_size exec def
numglyphs array 0 1 numglyphs 1 sub {
postpos total_length ge {
% Fill the rest with .notdef
1 numglyphs 1 sub { 1 index exch /.notdef put } for
exit
} if
% No name available, /postnames will be defined as an empty
% array and the glyph won't get a name attached.
postglyphs postpos //get_from_stringarray exec
postglyphs postpos 1 add 2 index //getinterval_from_stringarray exec cvn
exch postpos add 1 add /postpos exch def
2 index 3 1 roll
put
} for
/postnames exch def
numglyphs array 0 1 numglyphs 1 sub {
dup 2 mul 34 add postglyphs exch 2 //getinterval_from_stringarray exec
dup 0 get 8 bitshift exch 1 get add dup 258 lt {
MacGlyphEncoding exch get
} {
dup 32768 ge {
% According to the published TrueType spec, such values are
% "reserved for future use", but at least some PDF files
% produced by the Adobe PDF library contain entries with a
% value of 16#ffff.
pop /.notdef
} {
% Get the name for this glyph
258 sub dup postnames length ge {
TTFDEBUG { ( *** warning: glyph index past end of 'post' table) = flush } if
pop
exit
} if
postnames exch get
% At least some of Microsoft's TrueType fonts use incorrect
% (Adobe-incompatible) names for some glyphs.
% Correct for this here.
postremap 1 index .knownget { exch pop } if
} ifelse
} ifelse
2 index 3 1 roll put
} for
}
ifelse
} bind
16#00030000 { % No map.
pop [ ]
} bind
.dicttomark readonly def % postformats
/first_post_string % - first_post_string
{
post dup type /arraytype eq { 0 get } if
} bind def
% - .getpost -
% Uses post, defines glyphencoding
/.getpost {
/glyphencoding post null eq {
TTFDEBUG { (post missing) = flush } if [ ]
} {
postformats first_post_string 0 getu32 .knownget {
TTFDEBUG {
(post: format ) print
first_post_string
dup 0 getu16 =only (,) print 2 getu16 = flush
} if
post exch exec
} {
TTFDEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
} ifelse
} ifelse def
} bind def
% ===================== True Type Interpretation =============
/TTParser <<
/Pos 0
/post null
>> def
/readu8 % readu8
{ read not {
mark (Insufficient data in the stream.) //error exec
} if
} bind def
/readu16 % readu16
{ dup //readu8 exec 8 bitshift exch //readu8 exec or
} bind def
/reads16 % reads16
{ //readu16 exec 16#8000 xor 16#8000 sub
} bind def
/readu32 % readu32
{ dup //readu16 exec 16 bitshift exch //readu16 exec or
} bind def
/reads32 % reads32
{ dup //reads16 exec 16 bitshift exch //readu16 exec or
} bind def
/SkipToPosition % SkipToPosition -
{ dup //TTParser /Pos get % f P P p
exch //TTParser exch /Pos exch put % f P p
sub % f P-p
//PDFR_DEBUG {
(Skipping ) print dup //=only exec ( bytes.) =
} if
dup 0 eq {
pop pop
} {
dup 3 1 roll % P-p f P-p
() /SubFileDecode filter % P-p f'
exch % f' P-p
{ 1 index //BlockBuffer readstring pop length
dup 0 eq { pop exch pop exit } if
sub
} loop
0 ne {
mark (Insufficient data in the stream for SkipToPosition.) //error exec
} if
} ifelse
} bind def
/TagBuffer 4 string def
/ParseTTTableDirectory % ParseTTTableDirectory
{ //PDFR_DEBUG {
(ParseTTTableDirectory beg) =
} if
15 dict begin
dup //readu32 exec 16#00010000 ne {
mark (Unknown True Type version.) //error exec
} if
dup //readu16 exec /NumTables exch def
dup //readu16 exec /SearchRange exch def
dup //readu16 exec /EntrySelector exch def
dup //readu16 exec /RangeShift exch def
//PDFR_DEBUG {
(NumTables = ) print NumTables =
} if
NumTables {
dup //TagBuffer readstring not {
mark (Could not read TT tag.) //error exec
} if
cvn
[ 2 index //readu32 exec pop % CheckSum
2 index //readu32 exec % Offset
3 index //readu32 exec % Length
]
//PDFR_DEBUG {
2 copy exch //=only exec ( ) print ==
} if
def
} repeat
pop % file
//TTParser /Pos 12 NumTables 16 mul add put
currentdict end
//PDFR_DEBUG {
(ParseTTTableDirectory end) =
} if
} bind def
/ParseTTcmap % ParseTTcmap
{ //PDFR_DEBUG {
(ParseTTcmap beg) =
} if
/cmap get aload pop % f o L
3 1 roll % L f o
7 dict begin
//PDFR_DEBUG {
(Current position = ) print //TTParser /Pos get =
(cmap position = ) print dup =
} if
1 index exch //SkipToPosition exec % L f
//TTParser /Pos get /TablePos exch def
dup //readu16 exec pop % version
dup //readu16 exec /NumEncodings exch def
//PDFR_DEBUG {
(NumEncodings = ) print NumEncodings =
} if
null % L f null
NumEncodings {
1 index //readu32 exec % platformID, specificID % L f null id
2 index //readu32 exec % offset % L f null id o
3 array dup 3 2 roll 0 exch put % L f []|null id []
2 index null ne {
dup 0 get 3 index 0 get sub % L f []|null id [] l
3 index exch 1 exch put % L f []|null id []
} if
dup 4 3 roll pop 3 1 roll % L f [] id []
def
} repeat % L f []
dup 0 get % L f [] o
4 3 roll exch sub % f [] L-o
1 exch put % f
//PDFR_DEBUG {
currentdict {
exch dup type /integertype eq {
//PrintHex exec ( ) print ==
} {
pop pop
} ifelse
} forall
} if
4 NumEncodings 8 mul add /HeaderLength exch def
//TTParser /Pos //TTParser /Pos get HeaderLength add put
0 % f o
NumEncodings {
16#7FFFFFF null % f o om null|[]
% Choosing a table with minimal offset greater than 'o' :
currentdict {
1 index type /integertype eq { % f o om null|[] id []
exch pop dup 0 get % f o om null|[] [] oi
dup 5 index gt {
dup 4 index lt {
4 1 roll % f o oi om null|[] []
exch pop exch pop % f o oi []
} {
pop pop
} ifelse
} {
pop pop
} ifelse % f o oi []
} {
pop pop
} ifelse
} forall % f o om' []
//PDFR_DEBUG {
(Obtaining subtable for ) print dup ==
} if
3 2 roll pop % f o' []
3 copy pop % f o' [] f o'
TablePos add //SkipToPosition exec % f o' []
3 copy exch pop 1 get % f o' [] l
//TTParser /Pos //TTParser /Pos get 3 index add put
string % f o' [] f ()
readstring not {
mark (Can't read a cmap subtable.) //error exec
} if % f o' [] ()
2 exch put % f o'
} repeat
pop pop %
currentdict end
//PDFR_DEBUG {
(ParseTTcmap end) =
} if
} bind def
/GetTTEncoding % GetTTEncoding
{ //PDFR_DEBUG {
(GetTTEncoding beg) =
} if
get % f []
exch pop % []
2 get
10 dict begin % For local variables.
/TTFDEBUG //PDFR_DEBUG def
//cmaparray exec
end
//PDFR_DEBUG {
(GetTTEncoding end) =
dup ==
} if
} bind def
/InverseEncoding % InverseEncoding
{
256 dict begin
dup length 1 sub -1 0 { % E i
2 copy get % E i n
exch % E n i
1 index currentdict exch //knownget exec { % E n i e
dup type /arraytype eq {
aload length 1 add array astore % E n e'
} {
2 array astore % E n e'
} ifelse
} if
def
} for
pop
currentdict end
} bind def
/GetMacRomanEncodingInverse
{ //PDFReader /MacRomanEncodingInverse get
dup null eq {
pop
MacRomanEncoding //InverseEncoding exec
dup //PDFReader exch /MacRomanEncodingInverse exch put
} if
} bind def
/PutCharStringSingle % PutCharStringSingle
{
dup 3 index length lt { % cmap name code
2 index exch get % cmap name glyphindex
dup 0 ne {
def % cmap
} {
pop pop
} ifelse
} {
pop pop % cmap
} ifelse
} bind def
/PutCharString % PutCharString
{ 1 index type /nametype ne {
mark (Bad charstring name) //error exec
} if
dup type /arraytype eq {
{ % cmap name code
3 copy //PutCharStringSingle exec % cmap name code cmap
pop pop % cmap name
} forall
pop % cmap
} {
//PutCharStringSingle exec
} ifelse
} bind def
/ComposeCharStrings % ComposeCharStrings
{
//PDFR_DEBUG {
(ComposeCharStrings beg) =
} if
1 index length 1 add dict begin % cmap d
% fixme : the dict length estimation doesn't account 'post'.
/.notdef 0 def
exch % d cmap
//TTParser /post get % d cmap [post]|null
dup null ne {
exch % d [] cmap
1 index length 1 sub -1 0 { % d [] cmap code
dup 3 index exch get exch % d [] cmap name code
dup 0 eq {
pop pop
} {
def
} ifelse
} for
} if
exch pop exch % cmap d
{ % cmap name code
//PutCharString exec
} forall % cmap
pop %
currentdict end
//PDFR_DEBUG {
(ComposeCharStrings end) =
} if
} bind def
/ParseTTpost % ParseTTpost -
{ % Defines TTparser.post - an array,
% which maps glyph indices to glyph names.
//PDFR_DEBUG {
(ParseTTpost beg) =
} if
/post get aload pop % f o L
3 1 roll % L f o
//PDFR_DEBUG {
(Current position = ) print //TTParser /Pos get =
(post position = ) print dup =
} if
1 index exch //SkipToPosition exec % L f
//TTParser /Pos //TTParser /Pos get 4 index add put
exch dup 65535 le {
string % f s
readstring not {
mark (Insufficient data in the stream for ParseTTpost.) //error exec
} if % s
} {
% f s
[ 3 1 roll % [ f s
dup 16384 div floor cvi % [ f s numblocks
exch 1 index 16384 mul % [ f numblocks s bytesinblocks
sub exch % [ f remainder numblocks
1 sub 0 1 3 -1 roll % [ f remainder 0 1 numblocks
{
1 add index % [ f remainder () ()... f
16384 string readstring not {
mark (Insufficient data in the stream for ParseTTpost.) //error exec
} if
} for
% [ f remainder () ()...
counttomark -2 roll % [ () ()... f remainder
string readstring not{
mark (Insufficient data in the stream for ParseTTpost.) //error exec
} if
]
} ifelse
1 dict begin % A bridge to the code from /gs/lib/gs_ttf.ps .
/post exch def
//.getpost exec
//TTParser /post glyphencoding put
//PDFR_DEBUG {
(ParseTTpost end) =
glyphencoding ==
} if
end
} bind def
/MakeTTCharStrings % MakeTTCharStrings
{ //MakeStreamReader exec % f
dup dup //ParseTTTableDirectory exec % f f d
% Since the file isn't positionable,
% we must pick up either 'post' or 'cmap' first.
% Deside which one we do first :
//TTParser /post null put
dup /post //knownget exec {
0 get
1 index /cmap get 0 get
lt {
2 copy //ParseTTpost exec % f f d
//ParseTTcmap exec % f ch
} {
2 copy //ParseTTcmap exec % f f d ch
3 1 roll % f ch f d
//ParseTTpost exec % f ch
} ifelse
} {
//ParseTTcmap exec % f ch
} ifelse
{
dup 16#00030001 known {
//PDFR_DEBUG {
(Using the TT cmap encoding for Windows Unicode.) =
} if
16#00030001 //GetTTEncoding exec
AdobeGlyphList //ComposeCharStrings exec
exit
} if
dup 16#00010000 known {
//PDFR_DEBUG {
(Using the TT cmap encoding for Macintosh Roman.) =
} if
16#00010000 //GetTTEncoding exec
PDFEncoding dup null eq {
pop //GetMacRomanEncodingInverse exec
} {
//InverseEncoding exec
} ifelse
//ComposeCharStrings exec
exit
} if
dup 16#00030000 known {
//PDFR_DEBUG {
(Using the TT cmap encoding 3.0 - not sure why Ghostscript writes it since old versions.) =
} if
% Same algorithm as for 16#00010000.
16#00030000 //GetTTEncoding exec
PDFEncoding dup null eq {
pop //GetMacRomanEncodingInverse exec
} {
//InverseEncoding exec
} ifelse
//ComposeCharStrings exec
exit
} if
mark (True Type cmap has no useful encodings.) //error exec
} loop
//PDFR_DEBUG {
(CharStrings <<) =
dup {
exch
dup type /nametype eq {
//=only exec
} {
==
} ifelse
( ) print ==
} forall
(>>) =
} if
} bind def
%%end TrueType
% ===================== Functions ============================
/ScaleVal % ScaleVal
{
aload pop % v r0 r1
1 index sub % v r0 r1-r0
3 2 roll mul add
} bind def
/ScaleArg % ScaleArg
{
aload pop % a d0 d1
1 index sub % a d0 d1-d0
3 1 roll % d1-d0 a d0
sub exch div % (a-d0)/(d1-d0)
} bind def
/ScaleArgN % ... ScaleArg ...
{
dup length 2 sub -2 0 { % a1 ... an [] 2i
2 % a1 ... an [] 2i 2
2 index 3 1 roll getinterval % a1 ... an [] []
3 2 roll % a1 ... [] [] an
exch //ScaleArg exec % a1 ... [] an'
1 index length 2 idiv 1 add 1 roll % an' a1 ... []
} for % a1' ... an' []
pop % a1' ... an'
} bind def
/ComputeFunction_10 % ComputeFunction_10