1337 lines
40 KiB
PostScript
1337 lines
40 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_draw.ps,v 1.98 2005/10/05 14:37:59 ray Exp $
|
|
% pdf_draw.ps
|
|
% PDF drawing operations (graphics, text, and images).
|
|
|
|
/.setlanguagelevel where { pop 2 .setlanguagelevel } if
|
|
.currentglobal true .setglobal
|
|
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
|
|
GS_PDF_ProcSet begin
|
|
pdfdict begin
|
|
|
|
% For simplicity, we use a single interpretation dictionary for all
|
|
% PDF graphics operations, even though this is too liberal.
|
|
/drawopdict 100 dict def
|
|
|
|
% ================================ Graphics ================================ %
|
|
|
|
% ---------------- Functions ---------------- %
|
|
|
|
% Note that resolvefunction converts a PDF Function to a PostScript Function;
|
|
% resolve*fnproc converts a PDF function to a PostScript procedure.
|
|
% We need to process all required and optional parameters to resolve any
|
|
% use of indirect references.
|
|
|
|
/fnrdict mark
|
|
0 { .resolvefn0 }
|
|
2 { .resolvefn2 }
|
|
3 { .resolvefn3 }
|
|
4 { .resolvefn4 }
|
|
.dicttomark readonly def
|
|
|
|
/.resolvefn0 {
|
|
dup length 1 add dict .copydict % make room for DataSource
|
|
% now resolve any indirect references
|
|
dup /Size 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /BitsPerSample 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /Order 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /Encode 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /Decode 2 copy knownoget { put } { pop pop } ifelse
|
|
|
|
% Don't lose our place in PDFfile.
|
|
PDFfile fileposition exch
|
|
dup true resolvestream
|
|
% The stream isn't positionable, so read all the data now.
|
|
% Stack: filepos fndict stream
|
|
1 index /Range get length 2 idiv 2 index /BitsPerSample get mul
|
|
2 index /Size get { mul } forall
|
|
7 add 8 idiv string
|
|
1 index exch readstring pop exch closefile
|
|
% Stack: filepos fndict data
|
|
exch dup /DataSource 4 -1 roll put
|
|
exch PDFfile exch setfileposition
|
|
} bdef
|
|
|
|
/.resolvefn2 {
|
|
dup length dict .copydict
|
|
dup /C0 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /C1 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /N 2 copy knownoget { put } { pop pop } ifelse
|
|
} bdef
|
|
|
|
/.resolvefn3 {
|
|
dup length dict .copydict
|
|
dup /Bounds 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /Encode 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /Functions 2 copy oget mark exch dup {
|
|
oforce .resolvefn
|
|
} forall
|
|
counttomark -1 roll astore exch pop put
|
|
} bdef
|
|
|
|
/.resolvefn4 {
|
|
PDFfile fileposition exch % filepos fndict
|
|
dup true resolvestream % filepos fndict stream
|
|
exch dup length dict copy % filepos stream fndict2
|
|
dup /Function undef % filepos stream fndict2
|
|
exch dup token not {
|
|
() /rangecheck cvx signalerror
|
|
} if
|
|
exch token {
|
|
/rangecheck cvx signalerror
|
|
} if
|
|
% Use .bind to avoid idiom recognition.
|
|
.bind
|
|
1 index /Function 3 -1 roll put
|
|
exch PDFfile exch setfileposition
|
|
} bdef
|
|
|
|
/.resolvefn { % <fndict> .resolvefn <fndict'>
|
|
dup length dict .copydict
|
|
dup /Domain 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /Range 2 copy knownoget { put } { pop pop } ifelse
|
|
dup /FunctionType oget //fnrdict exch get exec
|
|
} bdef
|
|
|
|
/resolvefunction { % <fndict> resolvefunction <function>
|
|
.resolvefn
|
|
PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { true } ifelse { (%Function: ) print dup === flush } if } if
|
|
} bdef
|
|
|
|
/resolvefnproc { % <fndict> resolvefnproc <proc>
|
|
resolvefunction .buildfunction
|
|
} bdef
|
|
|
|
/resolveidfnproc { % <fndict> resolveidfnproc <proc>
|
|
dup /Identity eq { pop { } } { resolvefnproc } ifelse
|
|
} bdef
|
|
|
|
/resolvedefaultfnproc { % <fndict> <default> resolved'fnproc <proc>
|
|
1 index /Default eq { exch pop } { pop resolveidfnproc } ifelse
|
|
} bdef
|
|
|
|
% ---------------- Shadings ---------------- %
|
|
|
|
/shrdict mark
|
|
/ColorSpace {
|
|
resolvecolorspace
|
|
}
|
|
/Function {
|
|
dup type /dicttype eq {
|
|
resolvefunction
|
|
} {
|
|
[ exch { oforce resolvefunction } forall ]
|
|
} ifelse
|
|
}
|
|
.dicttomark readonly def
|
|
|
|
/resolveshading { % <shadingstream> resolveshading <shading>
|
|
PDFfile fileposition exch
|
|
mark exch {
|
|
oforce //shrdict 2 index .knownget { exec } if
|
|
} forall .dicttomark
|
|
dup /ShadingType get 4 ge {
|
|
dup dup true resolvestream
|
|
% Make a reusable stream so that the shading doesn't
|
|
% reposition PDFfile at unexpected times.
|
|
/ReusableStreamDecode filter /DataSource exch put
|
|
} if exch PDFfile exch setfileposition
|
|
} bdef
|
|
/resolvesh { % <shname> resolveshading <shading>
|
|
Page /Shading rget {
|
|
resolveshading
|
|
} {
|
|
null
|
|
}ifelse
|
|
} bdef
|
|
|
|
% ---------------- Halftones ---------------- %
|
|
|
|
/spotfunctions mark
|
|
/Round {
|
|
abs exch abs 2 copy add 1 le {
|
|
dup mul exch dup mul add 1 exch sub
|
|
} {
|
|
1 sub dup mul exch 1 sub dup mul add 1 sub
|
|
} ifelse
|
|
}
|
|
/Diamond {
|
|
abs exch abs 2 copy add .75 le {
|
|
dup mul exch dup mul add 1 exch sub
|
|
} {
|
|
2 copy add 1.23 le {
|
|
.85 mul add 1 exch sub
|
|
} {
|
|
1 sub dup mul exch 1 sub dup mul add 1 sub
|
|
} ifelse
|
|
} ifelse
|
|
}
|
|
/Ellipse {
|
|
abs exch abs 2 copy 3 mul exch 4 mul add 3 sub dup 0 lt {
|
|
pop dup mul exch .75 div dup mul add 4 div 1 exch sub
|
|
} {
|
|
dup 1 gt {
|
|
pop 1 exch sub dup mul exch 1 exch sub
|
|
.75 div dup mul add 4 div 1 sub
|
|
} {
|
|
.5 exch sub exch pop exch pop
|
|
} ifelse
|
|
} ifelse
|
|
}
|
|
/EllipseA { dup mul .9 mul exch dup mul add 1 exch sub }
|
|
/InvertedEllipseA { dup mul .9 mul exch dup mul add 1 sub }
|
|
/EllipseB { dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub }
|
|
/EllipseC { dup mul .9 mul exch dup mul add 1 exch sub }
|
|
/InvertedEllipseC { dup mul .9 mul exch dup mul add 1 sub }
|
|
/Line { exch pop abs neg }
|
|
/LineX { pop }
|
|
/LineY { exch pop }
|
|
/Square { abs exch abs 2 copy lt { exch } if pop neg }
|
|
/Cross { abs exch abs 2 copy gt { exch } if pop neg }
|
|
/Rhomboid { abs exch abs 0.9 mul add 2 div }
|
|
/DoubleDot { 2 {360 mul sin 2 div exch } repeat add }
|
|
/InvertedDoubleDot { 2 {360 mul sin 2 div exch } repeat add neg }
|
|
/SimpleDot { dup mul exch dup mul add 1 exch sub }
|
|
/InvertedSimpleDot { dup mul exch dup mul add 1 sub }
|
|
/CosineDot { 180 mul cos exch 180 mul cos add 2 div }
|
|
/Double { exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add }
|
|
/InvertedDouble {
|
|
exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add neg
|
|
}
|
|
.dicttomark readonly def
|
|
|
|
/htrdict mark
|
|
1 { .resolveht1 }
|
|
5 { .resolveht5 }
|
|
% We don't support types 6, 10, or 16 yet.
|
|
.dicttomark readonly def
|
|
|
|
/.resolveht1 {
|
|
mark exch {
|
|
oforce
|
|
1 index /SpotFunction eq {
|
|
dup type /nametype eq
|
|
{ //spotfunctions exch get } { resolvefnproc }
|
|
ifelse
|
|
} {
|
|
1 index /TransferFunction eq {
|
|
resolveidfnproc
|
|
} if
|
|
} ifelse
|
|
} forall .dicttomark
|
|
} bdef
|
|
|
|
/.resolveht5 {
|
|
mark exch {
|
|
oforce dup type /dicttype eq { resolvehalftone } if
|
|
} forall .dicttomark
|
|
} bdef
|
|
|
|
/resolvehalftone { % <dict> resolvehalftone <halftone>
|
|
dup /HalftoneType get
|
|
dup //htrdict exch .knownget {
|
|
exch pop exec
|
|
} {
|
|
(\n\n **** Unsupported HalftoneType ) pdfformaterror
|
|
=string cvs pdfformaterror (. ***\n\n) pdfformaterror
|
|
/resolvehalftone cvx /unregistered signalerror
|
|
} ifelse
|
|
} bdef
|
|
|
|
% ---------------- Graphics state management ---------------- %
|
|
|
|
/cmmatrix matrix def
|
|
drawopdict begin
|
|
% Graphics state stack
|
|
/q { q } def
|
|
/Q { Q } def
|
|
% Graphics state setting
|
|
/cm { { //false upath } stopped {
|
|
pop % discard 'false' (upath failed, probably no currentpoint).
|
|
//cmmatrix astore concat
|
|
} {
|
|
% update the CTM, then uappend.
|
|
7 1 roll //cmmatrix astore concat
|
|
newpath { mark exch uappend } stopped
|
|
cleartomark
|
|
} ifelse
|
|
} def
|
|
/i { 1 .min setflat } def
|
|
/J /setlinecap load def
|
|
/d /setdash load def
|
|
/j /setlinejoin load def
|
|
/w /setlinewidth load def
|
|
/M { 1 .max setmiterlimit } bdef
|
|
/gs { gs } def
|
|
end
|
|
|
|
% Each entry in this dictionary is
|
|
% <gsres> <value> -proc- <gsres>
|
|
/gsbg {
|
|
/BGDefault load resolvedefaultfnproc setblackgeneration
|
|
} bdef
|
|
/gsucr {
|
|
/UCRDefault load resolvedefaultfnproc setundercolorremoval
|
|
} bdef
|
|
/gstr {
|
|
dup type /arraytype eq {
|
|
{ oforce /TRDefault load resolvedefaultfnproc } forall
|
|
setcolortransfer
|
|
} {
|
|
/TRDefault load resolvedefaultfnproc settransfer
|
|
} ifelse
|
|
} bdef
|
|
/gsparamdict mark
|
|
/SA { setstrokeadjust }
|
|
/OP { 1 index /op known not { dup op } if OP }
|
|
% The PDF 1.3 specification says that the name /Default is only
|
|
% recognized for {BG,UCR,TR}2. However, PDF 1.3 files produced
|
|
% by Adobe Acrobat Distiller 4.0 for Windows use the name /Default
|
|
% with the older keys, so we have to implement this.
|
|
/BG { 1 index /BG2 known { pop } { gsbg } ifelse }
|
|
/UCR { 1 index /UCR2 known { pop } { gsucr } ifelse }
|
|
/TR { 1 index /TR2 known { pop } { gstr } ifelse }
|
|
/HT {
|
|
dup /Default eq {
|
|
pop .setdefaulthalftone
|
|
} {
|
|
%****** DOESN'T IMPLEMENT THE STREAM CASE YET ******
|
|
resolvehalftone sethalftone
|
|
} ifelse
|
|
% the transfer function may dependent on the halftone, so make sure
|
|
% it is set if included in the graphic state (otherwise this is
|
|
% subject to order of a dictionary forall, which is unpredictable)
|
|
dup /TR2 .knownget {
|
|
dup /Default eq { oforce gsparamdict /TR2 get exec } { pop } ifelse
|
|
} {
|
|
dup /TR .knownget {
|
|
/dup /Default eq { oforce gsparamdict /TR get exec } { pop } ifelse
|
|
} if
|
|
} ifelse
|
|
}
|
|
/HTP {
|
|
% HTP may be present even if this isn't a DPS interpreter.
|
|
/sethalftonephase where { pop aload pop sethalftonephase } { pop } ifelse
|
|
}
|
|
% PDF 1.3
|
|
/Font { aload pop Tf }
|
|
/LW { setlinewidth }
|
|
/LC { setlinecap }
|
|
/LJ { setlinejoin }
|
|
/ML { 1 .max setmiterlimit }
|
|
/D { aload pop setdash }
|
|
/RI { ri }
|
|
/op { op }
|
|
/OPM { OPM }
|
|
/BG2 { gsbg }
|
|
/UCR2 { gsucr }
|
|
/TR2 { gstr }
|
|
/FL { 1 .min setflat }
|
|
/SM {
|
|
% SM may be present even if this is only a Level 2 interpreter.
|
|
/setsmoothness where { pop setsmoothness } { pop } ifelse
|
|
}
|
|
% PDF 1.4
|
|
% All of these require the "transparency" feature in the interpreter.
|
|
/ca { ca }
|
|
/CA { CA }
|
|
/SMask { gssmask }
|
|
/AIS { AIS }
|
|
/BM { BM }
|
|
/TK { TK }
|
|
.dicttomark readonly def
|
|
/gs { % <gsres> gs -
|
|
Page /ExtGState rget {
|
|
% We keep the dictionary on the stack during the forall so that
|
|
% keys that interact with each other have access to it.
|
|
dup {
|
|
oforce exch gsparamdict exch .knownget { exec } { pop } ifelse
|
|
} forall pop
|
|
} if
|
|
} bdef
|
|
|
|
% ------ Transparency support ------ %
|
|
|
|
/gssmask {
|
|
dup /None eq PDFusingtransparency not or {
|
|
pop null
|
|
} {
|
|
% Preprocess the SMask value into a parameter dictionary for
|
|
% .begintransparencymaskgroup, with added /BBox and /Draw keys.
|
|
mark exch % Stack: mark smaskdict
|
|
dup /S oget /Subtype exch 3 2 roll
|
|
% Stack: mark ... smaskdict
|
|
dup /BC knownoget {
|
|
dup /Background exch 4 2 roll
|
|
gsave
|
|
1 index /G oget /Group oget /CS knownoget {
|
|
csresolve dup setgcolorspace csput
|
|
} if
|
|
aload pop setcolor [ currentgray ]
|
|
grestore
|
|
/GrayBackground exch 3 2 roll
|
|
} if
|
|
dup /TR knownoget {
|
|
resolveidfnproc /TransferFunction exch 3 2 roll
|
|
} if
|
|
dup /G oget dup /BBox oget /BBox exch 4 2 roll
|
|
/.execmaskgroup cvx 2 packedarray cvx /Draw exch 3 2 roll
|
|
pop .dicttomark
|
|
} ifelse SMask
|
|
} bdef
|
|
|
|
% This procedure is called to actually render the soft mask.
|
|
/.execmaskgroup { % <masknum> <paramdict> <formdict> .execmaskgroup -
|
|
% Save our place in PDFfile, and do a gsave to avoid resetting
|
|
% the color space.
|
|
currentcolorspace 4 1 roll
|
|
PDFfile fileposition 4 1 roll
|
|
% We have to select the group's color space so that the
|
|
% background color will be interpreted correctly.
|
|
dup /Group oget /CS knownoget { csresolve dup setgcolorspace csput } if
|
|
exch dup /BBox get aload pop .begintransparencymaskgroup {
|
|
dup /Resources knownoget { oforce } { 0 dict } ifelse
|
|
exch false resolvestream
|
|
.execgroup .endtransparencymask
|
|
} stopped {
|
|
.discardtransparencymask stop
|
|
} if
|
|
PDFfile exch setfileposition
|
|
setcolorspace
|
|
} bdef
|
|
% Paint a Form+Group XObject, either for a transparency mask or for a Do.
|
|
/.execgroup { % <resdict> <stream> .execgroup -
|
|
gsave //nodict begin
|
|
null SMask
|
|
1 .setopacityalpha 1 .setshapealpha
|
|
0 .inittransparencymask 1 .inittransparencymask
|
|
/Compatible .setblendmode
|
|
% Execute the body of the Form, similar to DoForm.
|
|
pdfopdict .pdfruncontext
|
|
end grestore
|
|
} bdef
|
|
|
|
/.beginformgroup { % groupdict bbox .beginformgroup -
|
|
exch mark exch % bbox mark groupdict
|
|
dup /CS knownoget { csresolve setgcolorspace } if
|
|
dup /I knownoget { /Isolated exch 3 2 roll } if
|
|
dup /K knownoget { /Knockout exch 3 2 roll } if
|
|
pop .dicttomark
|
|
% Stack: bbox paramdict
|
|
exch aload pop
|
|
.begintransparencygroup
|
|
} bdef
|
|
|
|
% .paintgroupform implements the Form PaintProc in the case where the
|
|
% Form XObject dictionary includes a Group key. See .paintform below.
|
|
/.paintgroupform { % <resdict> <stream> <formdict> .paintgroupform -
|
|
dup /Group oget exch /BBox oget
|
|
% Stack: resdict stream groupdict bbox
|
|
.beginformgroup {
|
|
.execgroup
|
|
} stopped {
|
|
.discardtransparencygroup stop
|
|
} if .endtransparencygroup
|
|
} bdef
|
|
|
|
% Make an ImageType 103 (soft-masked) image.
|
|
/makesoftmaskimage { % <datasource> <imagemask> <SMask> makesoftmaskimage
|
|
% <datasource> <imagemask>, updates currentdict =
|
|
% imagedict
|
|
% See the ImageType 3 case of makemaskimage below.
|
|
% SMask is a stream, another Image XObject.
|
|
% Stack: datasource imagemask(false) smaskstreamdict
|
|
PDFfile fileposition exch
|
|
dup /Matte knownoget { /Matte exch def } if
|
|
dup length dict makeimagedict pop
|
|
% In order to prevent the two data sources from being
|
|
% aliased, we need to make at least one a reusable stream.
|
|
% We pick the mask, since it's smaller (in case we need to
|
|
% read all its data now).
|
|
% Stack: datasource imagemask(false) savedpos
|
|
% maskdict is currentdict
|
|
/DataSource DataSource mark
|
|
/Intent 1
|
|
/AsyncRead true
|
|
.dicttomark .reusablestreamdecode def
|
|
PDFfile exch setfileposition
|
|
currentdict end currentdict end
|
|
5 dict begin
|
|
/ImageType 103 def
|
|
/DataDict exch def
|
|
dup /InterleaveType 3 put
|
|
DataDict /Matte knownoget {
|
|
/Matte exch def
|
|
} if
|
|
AlphaIsShape { /ShapeMaskDict } { /OpacityMaskDict } ifelse exch def
|
|
/ColorSpace DataDict /ColorSpace get def
|
|
} bdef
|
|
|
|
% ---------------- Color setting ---------------- %
|
|
|
|
/01_1 [0 1] readonly def
|
|
/01_3 [0 1 0 1 0 1] readonly def
|
|
/01_4 [0 1 0 1 0 1 0 1] readonly def
|
|
|
|
% The keys here are resolved (PostScript, not PDF) color space names.
|
|
/csncompdict mark
|
|
/DeviceGray { pop 1 }
|
|
/DeviceRGB { pop 3 }
|
|
/DeviceCMYK { pop 4 }
|
|
/CIEBasedA { pop 1 }
|
|
/CIEBasedABC { pop 3 }
|
|
/ICCBased { 1 oget /N oget }
|
|
/Separation { pop 1 }
|
|
/DeviceN { 1 oget length }
|
|
.dicttomark readonly def
|
|
|
|
/csrdict mark
|
|
/DeviceGray { }
|
|
/DeviceRGB { }
|
|
/DeviceCMYK { }
|
|
/CalGray {
|
|
1 oget 6 dict begin
|
|
dup /Gamma knownoget {
|
|
/exp load 2 packedarray cvx /DecodeA exch def
|
|
} if
|
|
dup /BlackPoint knownoget { /BlackPoint exch def } if
|
|
dup /WhitePoint knownoget {
|
|
dup /WhitePoint exch def
|
|
dup /MatrixA exch def
|
|
/RangeLMN [ 3 2 roll { 0 exch } forall ] def
|
|
} if
|
|
/PDFColorSpace exch def [ /CIEBasedA currentdict end ]
|
|
}
|
|
/CalRGB {
|
|
1 oget 6 dict begin
|
|
dup /Gamma knownoget {
|
|
[ exch { /exp load 2 packedarray cvx } forall
|
|
] /DecodeABC exch def
|
|
} if
|
|
dup /Matrix knownoget { /MatrixABC exch def } if
|
|
dup /BlackPoint knownoget { /BlackPoint exch def } if
|
|
dup /WhitePoint knownoget { /WhitePoint exch def } if
|
|
/PDFColorSpace exch def [ /CIEBasedABC currentdict end ]
|
|
}
|
|
/CalCMYK {
|
|
pop /DeviceCMYK % not defined by Adobe
|
|
}
|
|
/Lab {
|
|
1 oget 6 dict begin
|
|
dup /Range knownoget not { [-100 100 -100 100] } if
|
|
[0 100 null null null null] dup 2 4 -1 roll putinterval
|
|
/RangeABC exch def
|
|
/DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind] def
|
|
/MatrixABC [1 1 1 1 0 0 0 0 -1] def
|
|
dup /BlackPoint knownoget { /BlackPoint exch def } if
|
|
dup /WhitePoint knownoget { /WhitePoint exch def } {
|
|
( **** Warning: Lab colorspace is missing WhitePoint.\n)
|
|
pdfformaterror
|
|
/WhitePoint [0.9505 1 1.089] def
|
|
} ifelse
|
|
% scaling function g() for DecodeLMN construction
|
|
{ dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse }
|
|
/DecodeLMN [
|
|
% Store white point implicitly inside procedures.
|
|
[ 3 index aload pop WhitePoint 0 get /mul .systemvar ] cvx bind
|
|
[ 4 index aload pop WhitePoint 1 get /mul .systemvar ] cvx bind
|
|
[ 5 index aload pop WhitePoint 2 get /mul .systemvar ] cvx bind
|
|
] def pop
|
|
/PDFColorSpace exch def [ /CIEBasedABC currentdict end ]
|
|
}
|
|
/ICCBased {
|
|
dup 1 get type /dicttype ne { % don't resolve more than once
|
|
PDFfile fileposition exch
|
|
dup dup 1 oget
|
|
mark exch { oforce } forall .dicttomark
|
|
dup dup true resolvestream
|
|
/ReusableStreamDecode filter /DataSource exch put
|
|
1 exch put
|
|
exch PDFfile exch setfileposition
|
|
% Resolve alternate color space
|
|
dup 1 get % Get colorspace dictionary
|
|
dup /Alternate .knownget % Check for alternate color space
|
|
{ oforce resolvecolorspace /Alternate exch put } % resolve and replace
|
|
{ pop } % remove colorspace dictionary
|
|
ifelse
|
|
} if
|
|
} bind
|
|
/Separation {
|
|
aload pop exch oforce resolvecolorspace
|
|
% Contrary to PDF manuals up to v.1.5, Acrobat Distiller 3.01
|
|
% can use /Identity name here instead of a function.
|
|
exch oforce resolveidfnproc
|
|
4 array astore
|
|
}
|
|
/DeviceN {
|
|
0 4 getinterval % ignore attributes
|
|
aload pop 3 -1 roll oforce % resolve names array
|
|
[ exch { oforce } forall ] % resolve each of the names
|
|
3 -1 roll oforce resolvecolorspace
|
|
3 -1 roll oforce resolvefnproc
|
|
4 array astore
|
|
}
|
|
/Indexed {
|
|
aload pop 3 -1 roll oforce resolvecolorspace
|
|
% Stack: /Indexed hival lookup basespace
|
|
% If the underlying space is a Lab space, we must scale
|
|
% the output of the lookup table as part of DecodeABC.
|
|
dup dup type /arraytype eq { 0 get } if /CIEBasedABC eq {
|
|
dup 1 get /DecodeLMN known {
|
|
1 get dup length dict copy
|
|
begin /DecodeABC [ 0 2 4 {
|
|
RangeABC 1 index 1 add get RangeABC 2 index get sub /mul load
|
|
RangeABC 3 index get /add load
|
|
DecodeABC 6 -1 roll 2 idiv get [ 6 1 roll aload pop ] cvx
|
|
} for ] def
|
|
/RangeABC //01_3 def
|
|
currentdict end /CIEBasedABC exch 2 array astore
|
|
} if
|
|
} if
|
|
3 1 roll
|
|
oforce dup type /stringtype ne {
|
|
% The color lookup table is a stream.
|
|
% Get its contents. Don't lose our place in PDFfile.
|
|
% Stack: /Indexed basespace hival lookup
|
|
PDFfile fileposition 5 1 roll true resolvestream
|
|
% Stack: filepos /Indexed basespace hival lookupstream
|
|
1 index 1 add
|
|
% Stack: filepos /Indexed basespace hival lookupstream len
|
|
3 index
|
|
dup dup type /arraytype eq { 0 get } if
|
|
//csncompdict exch get exec mul
|
|
string readstring pop
|
|
% Stack: filepos /Indexed basespace hival table
|
|
5 -1 roll PDFfile exch setfileposition
|
|
}
|
|
if 4 array astore
|
|
% Replace the PDFColorSpace with the Indexed space if needed.
|
|
dup 1 get
|
|
dup type /arraytype eq {
|
|
dup length 2 ge {
|
|
dup 1 get type /dicttype eq {
|
|
dup 1 get /PDFColorSpace known {
|
|
dup 1 get /PDFColorSpace 3 index put
|
|
} if
|
|
} if
|
|
} if
|
|
} if pop
|
|
}
|
|
/Pattern {
|
|
dup type /nametype ne {
|
|
dup length 1 gt {
|
|
1 oget resolvecolorspace
|
|
/Pattern exch 2 array astore
|
|
} if
|
|
} if
|
|
}
|
|
.dicttomark readonly def
|
|
|
|
/cssubst { % <csname> cssubst <cspace'> true
|
|
% <csname> cssubst false
|
|
dup resolvecolorspace
|
|
dup 1 index ne { exch pop true } { pop pop false } ifelse
|
|
} bdef
|
|
|
|
/csnames mark
|
|
/DeviceGray dup /DeviceRGB dup /DeviceCMYK dup /Pattern dup
|
|
.dicttomark readonly def
|
|
/csresolve { % <csresourcename> csresolve <cspace>
|
|
dup type /nametype ne {
|
|
(\n **** Warning: CS/cs (setcolorspace) operand not a name: ) pdfformaterror
|
|
dup stderrfile dup 3 -1 roll write==only flushfile
|
|
( ****\n) pdfformaterror
|
|
dup type /arraytype eq { % Adobe InDesign + PDF Library has array
|
|
resolvecolorspace
|
|
} if
|
|
} {
|
|
dup Page /ColorSpace rget {
|
|
exch pop resolvecolorspace
|
|
} {
|
|
//csnames 1 index known not { /undefined cvx signalerror } if
|
|
} ifelse
|
|
} ifelse
|
|
} bdef
|
|
/resolvecolorspace { % <cspace> resolvecolorspace <cspace'>
|
|
dup dup type /arraytype eq { 0 get } if
|
|
//csrdict exch .knownget
|
|
{
|
|
exec dup type /nametype ne { dup length 1 eq { 0 get } if } if
|
|
} {
|
|
dup type /nametype eq { csresolve } { csset exch pop } ifelse
|
|
} ifelse
|
|
} bdef
|
|
|
|
/scresolve { % <c0> ... scresolve <multi>
|
|
% We can't really make sc[n] and SC[N] work, because
|
|
% the color space information isn't available at
|
|
% conversion time; so we hack it by assuming that
|
|
% all the operands on the stack are used, and that
|
|
% if the top operand is a name, it's a Pattern resource.
|
|
dup type /nametype eq
|
|
{ Page /Pattern rget { resolvepattern } { null } ifelse }
|
|
if
|
|
dup type /dicttype eq {
|
|
% Check the PaintType, if any (shading patterns don't
|
|
% have one).
|
|
dup /PaintType knownoget { 2 eq } { false } ifelse
|
|
} {
|
|
.pdfcount 1 gt
|
|
} ifelse
|
|
} bdef
|
|
|
|
/.pdfpaintproc { % <patdict> <resdict> .pdfpaintproc -
|
|
PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { true } ifelse { (%Begin PaintProc) print dup === flush } if } if
|
|
% For uncolored patterns, we have to unbind the current
|
|
% color and color space before running the PaintProc.
|
|
% There's no harm in doing this for colored patterns,
|
|
% so for simplicity, we always do it.
|
|
PDFfile fileposition 3 1 roll
|
|
q
|
|
null sc1 null SC1
|
|
|
|
% save old value of pdfemptycount on opstack, set to new value
|
|
pdfemptycount /pdfemptycount count 3 sub def 3 1 roll
|
|
exch false resolvestream pdfopdict .pdfruncontext
|
|
% restore pdfemptycount
|
|
/pdfemptycount exch def
|
|
|
|
Q
|
|
PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { true } ifelse { (%End PaintProc) print dup === flush } if } if
|
|
PDFfile exch setfileposition
|
|
} bdef
|
|
|
|
/resolvepattern { % <patternstreamdict> resolvepattern <patterndict>
|
|
% Don't do the resolvestream now: just capture the data
|
|
% from the file if necessary.
|
|
dup length dict copy
|
|
dup /FilePosition .knownget {
|
|
1 index /File get dup fileposition 3 1 roll
|
|
% Stack: dict savepos pos file
|
|
dup 3 -1 roll setfileposition
|
|
dup 3 index /Length oget
|
|
|
|
dup 65535 le {
|
|
string readstring pop
|
|
} {
|
|
() /SubFileDecode filter /ReusableStreamDecode filter
|
|
} ifelse
|
|
% Stack: dict savepos file string
|
|
3 1 roll exch setfileposition
|
|
1 index /File 3 -1 roll put
|
|
dup /FilePosition undef
|
|
} if
|
|
dup /Shading knownoget {
|
|
resolveshading 1 index /Shading 3 -1 roll put
|
|
} if
|
|
dup /PaintProc [
|
|
% Bind the resource dictionary into the PaintProc.
|
|
2 index /Resources knownoget { oforce } { 0 dict } ifelse
|
|
/.pdfpaintproc cvx
|
|
] cvx put
|
|
PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { true } ifelse { (%Pattern: ) print dup === flush } if } if
|
|
} bdef
|
|
|
|
drawopdict begin
|
|
/g { /DeviceGray cssubst { cs sc1 } { g } ifelse } bdef
|
|
/rg { /DeviceRGB cssubst { cs sc* } { rg } ifelse } bdef
|
|
/k { k } bdef
|
|
/cs { csresolve cs } bdef
|
|
/sc { scresolve { sc* } { sc1 } ifelse } bdef
|
|
/scn /sc load def
|
|
/G { /DeviceGray cssubst { CS SC1 } { G } ifelse } bdef
|
|
/RG { /DeviceRGB cssubst { CS SC* } { RG } ifelse } bdef
|
|
/K { K } bdef
|
|
/CS { csresolve CS } bdef
|
|
/ri { ri } bdef
|
|
/SC { scresolve { SC* } { SC1 } ifelse } bdef
|
|
/SCN /SC load def
|
|
end
|
|
|
|
% ---------------- Paths ---------------- %
|
|
|
|
drawopdict begin
|
|
% Path construction
|
|
/m /moveto load def
|
|
/l /lineto load def
|
|
/c /curveto load def
|
|
/v { currentpoint 6 2 roll curveto } def
|
|
/y { 2 copy curveto } def
|
|
/re {
|
|
4 2 roll moveto exch dup 0 rlineto 0 3 -1 roll rlineto neg 0 rlineto
|
|
closepath
|
|
} def
|
|
/h /closepath load def
|
|
% Path painting and clipping
|
|
/n { n } def
|
|
/S { S } def
|
|
/s { s } def
|
|
/f { f } def
|
|
/f* { f* } def
|
|
/B { B } def
|
|
/b { b } def
|
|
/B* { B* } def
|
|
/b* { b* } def
|
|
/W { W } def
|
|
/W* { W* } def
|
|
/sh { setfillstate resolvesh shfill } def
|
|
end
|
|
|
|
% ---------------- XObjects ---------------- %
|
|
|
|
/xobjectprocs mark % <dict> -proc- -
|
|
/Image { DoImage }
|
|
/Form { DoForm }
|
|
/PS { DoPS }
|
|
.dicttomark readonly def
|
|
|
|
% Note that the keys in defaultdecodedict are resolved (PostScript, not PDF)
|
|
% color space names.
|
|
/defaultdecodedict mark
|
|
/DeviceGray { pop //01_1 } bind
|
|
/DeviceRGB { pop //01_3 } bind
|
|
/DeviceCMYK { pop //01_4 } bind
|
|
/CIEBasedA { 1 get /RangeA knownoget not { //01_1 } if } bind
|
|
/CIEBasedABC { 1 get /RangeABC knownoget not { //01_3 } if } bind
|
|
/ICCBased {
|
|
1 oget dup /Range knownoget {
|
|
exch pop
|
|
}{
|
|
/N get [ exch {0 1} repeat ] readonly
|
|
} ifelse
|
|
} bind
|
|
/Separation { pop //01_1 } bind
|
|
/DeviceN {
|
|
1 oget length [ exch {0 1} repeat ] readonly
|
|
} bind
|
|
/Indexed {
|
|
pop [ 0 1 BitsPerComponent bitshift 1 sub ]
|
|
} bind
|
|
.dicttomark readonly def
|
|
|
|
/checkaltimage { % <resdict> checkaltimage <resdict[']>
|
|
Printed {
|
|
dup /Alternates knownoget {
|
|
{
|
|
dup /DefaultForPrinting knownoget {
|
|
{
|
|
/Image oget exch pop exit
|
|
} {
|
|
pop
|
|
} ifelse
|
|
} {
|
|
pop
|
|
} ifelse
|
|
} forall
|
|
} if
|
|
} if
|
|
} bdef
|
|
|
|
/makeimagedict { % <resdict> <newdict> makeimagedict <imagemask>
|
|
% On return, newdict' is currentdict
|
|
begin
|
|
/Width 2 copy oget def
|
|
/Height 2 copy oget def
|
|
% Handle missing BitsPerComponent later.
|
|
/BitsPerComponent 2 copy knownoget { def } { pop } ifelse
|
|
/Interpolate 2 copy knownoget { def } { pop } ifelse
|
|
makeimagekeys
|
|
} bdef
|
|
/makeimagekeys { % <resdict> makeimagekeys <imagemask>
|
|
% newdict is currentdict
|
|
% Assumes Width, Height, BPC, Interpolate already copied.
|
|
/ImageType 1 def
|
|
/ImageMatrix Width 0 0
|
|
% Handle 0-height images specially.
|
|
Height dup 0 eq { pop 1 } if neg 0 1 index neg
|
|
6 array astore def
|
|
dup /ImageMask knownoget dup { and } if {
|
|
% Image mask
|
|
% Decode is required for the PostScript image operators.
|
|
% AI8 writes bogus decode array [0 1 0 0 0 0 0 0]
|
|
/Decode 2 copy knownoget { 0 2 getinterval } { //01_1 } ifelse def
|
|
% BitsPerComponent is optional for masks.
|
|
/BitsPerComponent 2 copy known { pop } { 1 def } ifelse
|
|
true
|
|
} {
|
|
% Opaque image
|
|
dup /ColorSpace oget resolvecolorspace /ColorSpace exch def
|
|
% Decode is required for the PostScript image operators.
|
|
/Decode 2 copy knownoget not {
|
|
ColorSpace //defaultdecodedict
|
|
ColorSpace dup type /arraytype eq { 0 get } if get exec
|
|
} if def
|
|
false
|
|
} ifelse
|
|
% Even though we're going to read data,
|
|
% pass false to resolvestream so that
|
|
% it doesn't try to use Length (which may not be present).
|
|
exch false resolvestream /DataSource exch def
|
|
} bdef
|
|
|
|
/DoImage {
|
|
checkaltimage dup length 6 add dict
|
|
1 index /SMask knownoget { 1 index exch /SMask exch put } if
|
|
1 index /Mask knownoget { 1 index exch /Mask exch put } if
|
|
makeimagedict doimagesmask
|
|
} bdef
|
|
/makemaskimage { % <datasource> <imagemask> <Mask> makemaskimage
|
|
% <datasource> <imagemask>, updates currentdict =
|
|
% imagedict
|
|
dup type /arraytype eq {
|
|
/ImageType 4 def
|
|
% Check that every element of the Mask is an integer.
|
|
//false 1 index {
|
|
type /integertype ne or
|
|
} forall {
|
|
(\n **** Warning: Some elements of Mask array are not integers.\n)
|
|
pdfformaterror
|
|
[ exch { 0.5 add cvi } forall ] % following AR4, 5, 6 implementation
|
|
} if
|
|
% Check elements of array are within 0::(2**BitsPerComponent)-1
|
|
% This is a PostScript error, but AR ignores Mask in that case
|
|
2 BitsPerComponent exp cvi 1 sub //false 2 index {
|
|
% stack: max_value result_bool value
|
|
dup 0 lt exch 3 index gt or or
|
|
} forall exch pop {
|
|
(\n **** Warning: Some elements of Mask array are out of range.\n)
|
|
pdfformaterror
|
|
pop /ImageType 1 def % revert to non-masked image
|
|
} {
|
|
/MaskColor exch def
|
|
} ifelse
|
|
} {
|
|
% Mask is a stream, another Image XObject.
|
|
% Stack: datasource imagemask(false) maskstreamdict
|
|
PDFfile fileposition exch
|
|
dup length dict makeimagedict pop
|
|
% In order to prevent the two data sources from being
|
|
% aliased, we need to make at least one a reusable stream.
|
|
% We pick the mask, since it's smaller (in case we need to
|
|
% read all its data now).
|
|
% Stack: datasource imagemask(false) savedpos
|
|
% maskdict is currentdict
|
|
/DataSource DataSource mark
|
|
/Intent 1
|
|
/AsyncRead true
|
|
.dicttomark .reusablestreamdecode def
|
|
PDFfile exch setfileposition
|
|
currentdict end currentdict end
|
|
5 dict begin
|
|
/ImageType 3 def
|
|
/InterleaveType 3 def
|
|
/DataDict exch def
|
|
/MaskDict exch def
|
|
/ColorSpace DataDict /ColorSpace get def
|
|
} ifelse
|
|
} bdef
|
|
/doimagesmask { % <imagemask> doimagesmask -
|
|
PDFusingtransparency { currentdict /SMask knownoget } { false } ifelse {
|
|
.begintransparencymaskimage
|
|
PDFfile fileposition exch
|
|
gsave //nodict begin
|
|
null /SoftMask gput
|
|
1 .setopacityalpha 1 .setshapealpha
|
|
0 .inittransparencymask 1 .inittransparencymask
|
|
/Compatible .setblendmode
|
|
DoImage
|
|
end grestore
|
|
PDFfile exch setfileposition
|
|
0 .endtransparencymask
|
|
<< /Subtype /Group /Isolated true >> 0 0 1 1 .begintransparencygroup
|
|
doimage
|
|
.endtransparencygroup
|
|
} {
|
|
doimage
|
|
} ifelse
|
|
} bdef
|
|
/doimage { % <imagemask> doimage -
|
|
% imagedict is currentdict, gets popped from dstack
|
|
DataSource exch
|
|
PDFusingtransparency {
|
|
currentdict /SMask knownoget
|
|
} {
|
|
false
|
|
} ifelse {
|
|
makesoftmaskimage
|
|
} {
|
|
currentdict /Mask knownoget {
|
|
makemaskimage
|
|
} if
|
|
} ifelse
|
|
% Stack: datasource imagemask
|
|
% image and imagemask can be redefined in gs_init.ps to tweak interpolation
|
|
% after device-specific files are run. Don't bind them here.
|
|
{ currentdict end setfillstate /imagemask }
|
|
{ ColorSpace setgcolorspace currentdict end setfillblend /image }
|
|
ifelse
|
|
.systemvar stopped {
|
|
pop
|
|
$error /errorname get dup /ioerror eq {
|
|
pop (\n **** Warning: File has insufficient data for an image.\n)
|
|
pdfformaterror
|
|
} {
|
|
(\n **** Warning: File encountered ')
|
|
exch 40 string cvs concatstrings
|
|
(' error while processing an image.\n) concatstrings
|
|
pdfformaterror
|
|
} ifelse
|
|
} if
|
|
% Close the input stream, unless it is PDFfile or
|
|
% PDFsource.
|
|
dup dup PDFfile eq exch PDFsource eq or { pop } { closefile } ifelse
|
|
} bdef
|
|
|
|
/.paintform { % <formdict> <resdict> <stream> .paintform -
|
|
3 -1 roll dup /Group known PDFusingtransparency and {
|
|
.paintgroupform
|
|
} {
|
|
pop pdfopdict .pdfruncontext
|
|
} ifelse
|
|
} bdef
|
|
|
|
/DoForm {
|
|
% Adobe 2nd edition of the PDF 1.3 spec makes /FormType
|
|
% and /Matrix keys optional. Cope with the missing keys.
|
|
begin <<
|
|
currentdict /FormType known not { /FormType 1 } if
|
|
currentdict /Matrix known not { /Matrix { 1 0 0 1 0 0 } cvlit } if
|
|
currentdict end { oforce } forall
|
|
>>
|
|
dup [ 2 index /Resources knownoget { oforce } { 0 dict } ifelse
|
|
3 index false /resolvestream cvx
|
|
/.paintform cvx
|
|
] cvx /PaintProc exch put
|
|
% Adjust pdfemptycount since we have an extra dictionary on the stack
|
|
pdfemptycount exch
|
|
/pdfemptycount where pop count 2 sub /pdfemptycount exch put
|
|
q execform Q % gsave / grestore around the Form
|
|
% Restore pdfemptycount
|
|
/pdfemptycount where pop exch /pdfemptycount exch put
|
|
} bdef
|
|
|
|
/_dops_save 1 array def
|
|
|
|
/DoPS {
|
|
DOPS
|
|
{
|
|
//_dops_save 0 save put
|
|
true resolvestream cvx exec
|
|
//_dops_save 0 get restore
|
|
}
|
|
{ pop }
|
|
ifelse
|
|
} bdef
|
|
|
|
currentdict /_dops_save undef
|
|
|
|
drawopdict begin
|
|
/Do {
|
|
setfillblend
|
|
PDFfile fileposition exch
|
|
dup Page /XObject rget {
|
|
exch pop dup /Subtype get xobjectprocs exch get
|
|
% Don't leave extra objects on the stack while executing
|
|
% the definition of the form.
|
|
3 -1 roll 2 .execn
|
|
} {
|
|
% This should cause an error, but Acrobat Reader can
|
|
% continue, so we do too.
|
|
( **** Undefined XObject resource: )
|
|
exch =string cvs concatstrings (\n) concatstrings
|
|
pdfformaterror
|
|
} ifelse
|
|
PDFfile exch setfileposition
|
|
} bdef
|
|
end
|
|
|
|
% ---------------- In-line images ---------------- %
|
|
|
|
% Undo the abbreviations in an in-line image dictionary.
|
|
% Note that we must look inside array values.
|
|
% /I is context-dependent.
|
|
/unabbrevkeydict mark
|
|
/BPC /BitsPerComponent /CS /ColorSpace /D /Decode /DP /DecodeParms
|
|
/F /Filter /H /Height /I /Interpolate /IM /ImageMask /W /Width
|
|
.dicttomark readonly def
|
|
/unabbrevvaluedict mark
|
|
/AHx /ASCIIHexDecode /A85 /ASCII85Decode /CC /CalCMYK
|
|
/CCF /CCITTFaxDecode /CG /CalGray /CR /CalRGB
|
|
/DCT /DCTDecode /CMYK /DeviceCMYK /Fl /FlateDecode
|
|
/G /DeviceGray /RGB /DeviceRGB
|
|
/I /Indexed /LZW /LZWDecode /RL /RunLengthDecode
|
|
.dicttomark readonly def
|
|
/unabbrevtypedict mark
|
|
/nametype {
|
|
//unabbrevvaluedict 1 index .knownget { exch pop } if
|
|
}
|
|
/arraytype {
|
|
dup 0 1 2 index length 1 sub {
|
|
2 copy get unabbrevvalue put dup
|
|
} for pop
|
|
}
|
|
.dicttomark readonly def
|
|
/unabbrevvalue { % <obj> unabbrevvalue <obj'>
|
|
oforce //unabbrevtypedict 1 index type .knownget { exec } if
|
|
} bdef
|
|
|
|
drawopdict begin
|
|
/BI { mark } bdef
|
|
/ID {
|
|
counttomark 2 idiv dup 7 add dict begin {
|
|
exch //unabbrevkeydict 1 index .knownget { exch pop } if
|
|
exch unabbrevvalue def
|
|
} repeat pop
|
|
/IDFlag true def % flag for stream processing.
|
|
/File PDFsource def
|
|
currentdict makeimagekeys doimage
|
|
% The Adobe documentation says that the data following ID
|
|
% consists of "lines", and some PDF files (specifically, some files
|
|
% produced by PCL2PDF from Visual Software) contain garbage bytes
|
|
% between the last byte of valid data and an EOL.
|
|
% Some files (PDFOUT v3.8d by GenText) have EI immediately following
|
|
% the stream. Some have no EOL and garbage bytes.
|
|
% Therefore, we skip all bytes before EI or EOL
|
|
0
|
|
{ PDFsource read not { //true exit } if
|
|
dup 10 eq 1 index 13 eq or
|
|
{ pop PDFsource token pop /EI ne exit
|
|
}
|
|
if
|
|
exch 69 eq 1 index 73 eq and { //false exit } if % 'EI'
|
|
}
|
|
loop
|
|
exch pop
|
|
{ /ID cvx /syntaxerror signalerror
|
|
}
|
|
if
|
|
} bdef
|
|
end
|
|
|
|
% ================================ Text ================================ %
|
|
|
|
drawopdict begin
|
|
% Text control
|
|
/BT { BT } def
|
|
/ET { ET } def
|
|
/Tc { Tc } def
|
|
/TL { TL } def
|
|
/Tr { Tr } def
|
|
/Ts { Ts } def
|
|
/Tw { Tw } def
|
|
/Tz { Tz } def
|
|
% Text positioning
|
|
/Td { Td } def
|
|
/TD { TD } def
|
|
/Tm { Tm } def
|
|
/T* { T* } def
|
|
% Text painting
|
|
/Tj { Tj } def
|
|
/' { ' } def
|
|
/" { " } def
|
|
/TJ { TJ } def
|
|
end
|
|
|
|
% ============================== Annotations ============================== %
|
|
|
|
|
|
|
|
% Get and normalize an annotation's rectangle.
|
|
/annotrect { % <annot> annotrect <x> <y> <w> <h>
|
|
/Rect get aload pop
|
|
exch 3 index sub dup 0 lt { dup 5 -1 roll add 4 1 roll neg } if
|
|
exch 2 index sub dup 0 lt { dup 4 -1 roll add 3 1 roll neg } if
|
|
} bdef
|
|
|
|
% Set an annotation color.
|
|
/annotsetcolor { % <annot> annotsetcolor -
|
|
/C knownoget { aload pop setrgbcolor } { 0 setgray } ifelse
|
|
} bdef
|
|
|
|
% Draw the border. Currently, we ignore requests for beveling, and we
|
|
% don't round the corners of rectangles.
|
|
/strokeborder { % <annot> <width> <dash> strokeborder -
|
|
1 index 0 ne { % do not draw if border width is 0
|
|
gsave
|
|
2 index annotsetcolor
|
|
0 setdash dup setlinewidth
|
|
exch annotrect
|
|
2 { 4 index sub 4 1 roll } repeat
|
|
2 { 4 index 0.5 mul add 4 1 roll } repeat
|
|
rectstroke pop
|
|
grestore
|
|
} {
|
|
pop pop pop
|
|
} ifelse
|
|
} bdef
|
|
|
|
% Draw an annotation border.
|
|
/drawborder { % <annot> drawborder -
|
|
gsave
|
|
dup /BS knownoget {
|
|
dup /W knownoget not { 1 } if
|
|
[] 2 index /S knownoget {
|
|
/D eq { 2 index /D knownoget not { [3] } if exch pop } if
|
|
} if 3 -1 roll pop strokeborder
|
|
} {
|
|
dup /Border knownoget {
|
|
dup 2 get
|
|
exch dup length 3 gt { 3 get } { pop [] } ifelse
|
|
strokeborder
|
|
} {
|
|
1 [] strokeborder
|
|
} ifelse
|
|
} ifelse
|
|
grestore
|
|
} bdef
|
|
|
|
%
|
|
% The PDF annotation F (flags) integer is bit encoded.
|
|
% Bit 1 (LSB) Invisible: 1 --> Do not display if no handler.
|
|
% Note: We have no handlers but we ignore this bit.
|
|
% Bit 2 Hidden: 1 --> Do not display. We will not display if this bit is set.
|
|
% Bit 3 Print: 1 --> Display if printing. We will display if this bit set
|
|
% (and not hidden) and Printed is true
|
|
% Bit 4 NoZoom: 1 --> Do not zoom annotation even if image is zoomed.
|
|
% Bit 5 NoRotate: 1 --> Do not rotate annotation even if image is rotated.
|
|
% Bit 6 NoView: 0 --> Display if this is a 'viewer'. We will display
|
|
% if this bit is not set (and not hidden) and Printed is false
|
|
% Bit 7 Read Only - 1 --> No interaction. We ignore this bit
|
|
%
|
|
/annotvisible { % <annot> annotvisible <visible>
|
|
/F knownoget not { 0 } if % Get flag value
|
|
dup 2 and 0 eq % Check hidden flag
|
|
exch dup 4 and 0 ne Printed and % Check print flag
|
|
exch 32 and 0 eq Printed not and % Check noview flag
|
|
or % Combine print and view
|
|
and % Combine with 'hidden' flag test
|
|
} bdef
|
|
|
|
/drawwidget { % <scalefactor> <annot> drawwidget -
|
|
dup /AP knownoget {
|
|
false
|
|
[/N /R /D] {
|
|
% stack: scale annot appearance false key
|
|
dup 3 index exch known {
|
|
exch pop true exit
|
|
} if
|
|
pop
|
|
} forall
|
|
% stack: scale annot appearance key true
|
|
% stack: scale annot appearance false
|
|
dup {
|
|
pop
|
|
oget
|
|
% Acrobat Distiller produces files in which this Form
|
|
% XObject lacks Type and Subtype keys. This is illegal,
|
|
% but Acrobat Reader accepts it. The only way we can
|
|
% tell whether this is a Form or a set of sub-appearances
|
|
% is by testing for the stream Length key.
|
|
dup /Length known {
|
|
% If this is a form then simply use it
|
|
true
|
|
} {
|
|
1 index /AS knownoget not {
|
|
% If we do not have AS then use any appearance
|
|
{ exch pop oforce exit } forall true
|
|
} {
|
|
% Stack: annot Ndict AS
|
|
% Get the specified appearance. If no appearance, then
|
|
% display nothing - set stack = false.
|
|
knownoget
|
|
} ifelse
|
|
} ifelse
|
|
} {
|
|
exch pop % discard useless AP dictionary
|
|
} ifelse
|
|
|
|
% Stack: scale annot appearance true
|
|
% Stack: scale annot false
|
|
{
|
|
% Draw appearance
|
|
% Initialize graphic following "7.4.4 Appearance Streams"
|
|
q graphicsbeginpage textbeginpage
|
|
1 index annotrect pop pop translate
|
|
2 index dup scale % Apply scale factor
|
|
DoForm Q
|
|
} if
|
|
} if pop pop
|
|
} bdef
|
|
|
|
% For stamp object we have to determine the size of the output rectangle
|
|
% and the size of the BBox for the stamp image. From these we calculate
|
|
% a scale factor for drawing the stamp.
|
|
/calcstampscale { % <annot> calcstampscale scale
|
|
dup /Rect known {
|
|
dup annotrect 4 -2 roll pop pop % get width height size in user space
|
|
3 -1 roll /AP knownoget {
|
|
/N knownoget {
|
|
dup /Matrix knownoget {
|
|
% transform /Annot /Rect xwidth to Form space
|
|
4 -2 roll 3 -1 roll dtransform 3 -1 roll
|
|
} if
|
|
/BBox knownoget {
|
|
exch pop % discard y height
|
|
aload pop pop exch pop sub % BBox width
|
|
dup 0 eq {
|
|
( **** Warning: /BBox has zero width which is not allowed.\n)
|
|
pdfformaterror
|
|
pop pop 1 1 % 0 width -- revert to unity scaling
|
|
} if
|
|
div % scale x widths
|
|
dup 0 lt { neg } if % get magnitude
|
|
} {
|
|
pop pop 1 % default to unity scaling
|
|
} ifelse % if we have /BBox
|
|
} {
|
|
pop pop 1
|
|
} ifelse % if we have /N
|
|
} {
|
|
pop pop 1
|
|
} ifelse % if we have /AP
|
|
} {
|
|
( **** Warning: /Annot dict is missing required /Rect entry.\n)
|
|
pdfformaterror
|
|
pop 1
|
|
} ifelse
|
|
} bdef
|
|
|
|
/drawlink { % <annot> drawlink -
|
|
dup drawborder dup calcstampscale exch drawwidget
|
|
} bdef
|
|
|
|
% Draw an annotation.
|
|
/drawannottypes mark
|
|
/Link { drawlink } bind
|
|
.dicttomark readonly def
|
|
/drawannot { % <annot> drawannot -
|
|
dup annotvisible {
|
|
gsave
|
|
dup dup /Subtype get //drawannottypes exch .knownget {
|
|
exec
|
|
} {
|
|
dup calcstampscale exch drawwidget % Use drawwidget for everything else
|
|
} ifelse % type known
|
|
grestore
|
|
} if pop % annotvisible
|
|
} bdef
|
|
currentdict /drawannottypes undef
|
|
|
|
end % pdfdict
|
|
end % GS_PDF_ProcSet
|
|
.setglobal
|