% 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 10687 2010-02-02 07:23:57Z alexcher $ % 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 dup 65535 le { string 1 index exch readstring pop } { 1 index exch () /SubFileDecode filter /ReusableStreamDecode filter } ifelse 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 { % .resolvefn 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 { % resolvefunction .resolvefn PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { true } ifelse { (%Function: ) print dup === flush } if } if } bdef /resolvefnproc { % resolvefnproc resolvefunction .buildfunction } bdef /resolveidfnproc { % resolveidfnproc dup /Identity eq { pop { } } { resolvefnproc } ifelse } bdef /resolvedefaultfnproc { % resolved'fnproc 1 index /Default eq { exch pop } { pop resolveidfnproc } ifelse } bdef % ---------------- Shadings ---------------- % /shrdict mark /BBox { dup dup dup aload pop normrect_elems 5 -1 roll astore } bind /ColorSpace { resolvecolorspace } bind /Function { dup type /dicttype eq { resolvefunction } { [ exch { oforce resolvefunction } forall ] } ifelse } bind .dicttomark readonly def /resolveshading { % resolveshading dup /.shading_dict .knownget { exch pop dup /ShadingType get 4 ge { dup /DataSource get 0 setfileposition } if } { dup 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 dup 3 1 roll /.shading_dict exch put } ifelse } bdef /resolvesh { % resolvesh % resolvesh 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 { % resolvehalftone dup /HalftoneType oget 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 { //cmmatrix astore .getpath exch concat newpath { exec } forall % If inside a BT/ET block, we need to update the TextSaveMatrix currentdict /TextSaveMatrix .knownget { //cmmatrix exch dup concatmatrix pop } if } bdef /i { 1 .min setflat } bdef /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 % -proc- /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 { % 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 1 index //null eq or 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 //nodict begin 1 index /G oget /Group oget /CS knownoget { resolvecolorspace dup setgcolorspace csput } if aload pop setcolor [ currentgray ] end grestore /GrayBackground exch 3 2 roll } if dup /TR knownoget { dup /Identity eq { pop } { resolvefnproc /TransferFunction exch 3 2 roll } ifelse } 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 % Functions specific to the Device* colorspaces to force the switch to % the Device* colorspace so that the SMask will not get a CIEBased* colorspace % in the case when UseCIEColor changes the Device* colorspace to something else. % Also see the logic in pdf_main.ps:pdfopen that similarly defines these resources. /forceDefaultCS << { currentcolorspace setcolorspace % this will switch to Device colorspace } bind /DeviceGray exch /DeviceRGB 1 index /DeviceCMYK 1 index >> def % This procedure is called to actually render the soft mask. /.execmaskgroup { % .execmaskgroup - % Save our place in PDFfile. Do not use gsave-grestore when creating % a soft mask with .begintransparencygroup because high level devices % need to modify the graphic state by storing the soft mask ID. % Save the ExtGState (//nodict begin) BEFORE changing the colorspace mark currentcolor counttomark dup 4 add exch roll pop currentcolorspace 4 1 roll .getuseciecolor 4 1 roll //nodict begin PDFfile fileposition 4 1 roll % We have to select the group's color space so that the % background color will be interpreted correctly. % [save/restore]DefaultCS make sure that the SMask logic sees % the Device* spaces, not CIEBased* that UseCIEColor may have % established. false .setuseciecolor % SMask gets processed without UseCIEColor dup /Group oget /CS knownoget { resolvecolorspace dup setgcolorspace csput //true % use currentcolorspace } { % inheriting the colorspace -- make sure Device* spaces are not CIEBased forceDefaultCS currentcolorspace 0 get .knownget { exec } if //false % no defined colorspace } ifelse 3 -1 roll 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 .setuseciecolor setcolorspace setcolor end % restore colorspace, color and ExtGState (end) } bdef % Paint a Form+Group XObject, either for a transparency mask or for a Do. /.execgroup { % .execgroup - gsave //nodict begin newpath null SMask 1 .setopacityalpha 1 .setshapealpha 1 CA 1 ca /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 { resolvecolorspace 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 { % .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 { % makesoftmaskimage % , 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 9 dict begin /DeviceGray { pop 1 } bdef /DeviceRGB { pop 3 } bdef /DeviceCMYK { pop 4 } bdef /CIEBasedA //DeviceGray def /CIEBasedABC //DeviceRGB def /ICCBased { 1 oget /N oget } bdef /Separation //DeviceGray def /DeviceN { 1 oget length } bdef /Indexed //DeviceGray def currentdict end readonly def /csrdict 13 dict begin /DeviceGray { } bdef /DeviceRGB { } bdef /DeviceCMYK { } bdef /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 ] } bdef /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 ] } bdef /CalCMYK { pop /DeviceCMYK % not defined by Adobe } bdef /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 ] } bdef /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 } bdef /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 } bdef /DeviceN { [ exch aload pop ] % Copy into a new array dup dup 1 oget % Resolve Names array [ exch { oforce } forall ] % resolve each of the names 1 exch put dup dup 2 oget resolvecolorspace 2 exch put dup dup 3 oget resolvefnproc 3 exch put dup length 4 gt { % Check for attributes dict dup dup 4 oget % devn_array devn_array attr_dict dup /Colorants knownoget % Check for Colorants Dict { % Create a new attribute dict with only a Colorants dict entry. % Resolve all of the Colorant dict entries. This is needed % to prevent a conflict if we attempt to resolve the tint % transform functions of the Colorant color spaces multiple % times. exch pop % Remove old attributes dict << exch % Start new attributes dict % Build new Colorants dict with resolved entries << exch { oforce resolvecolorspace } forall >> /Colorants exch >> % Finish new attributes dict } if 4 exch put % Put resolved or new attributes dict } if } bdef /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 dup 3 1 roll readstring pop % the string is padded with 0s length 1 index length lt { ( **** Warning: Short look-up table in the Indexed color space was padded with 0's.\n) pdfformaterror } if % Stack: filepos /Indexed basespace hival table 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 } bdef /I { % Bug 689815 ( **** Warning: The name /Indexed cannot be abbreviated to /I in the color space\n) pdfformaterror dup 0 /Indexed put //Indexed exec } bdef /Pattern { dup type /nametype ne { dup length 1 gt { 1 oget resolvecolorspace /Pattern exch 2 array astore } if } if } bdef currentdict end readonly def /cssubst { % cssubst true % 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 { % csresolve 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 { % resolvecolorspace 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 { % ... scresolve % 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 { % .pdfpaintproc - PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { true } ifelse { (%Begin PaintProc) print dup === flush } if } if PDFfile fileposition 3 1 roll q 1 index /PaintType oget 1 eq { % For colored patterns, set default fill and stroke colors. 0 g 0 G } { % For uncolored patterns, we have to unbind the current % color and color space before running the PaintProc. //null sc1 //null SC1 } ifelse % Save old values on opstack, set pdfemptycount to new value. pdfemptycount countdictstack /pdfemptycount count 3 sub def 4 2 roll % % Stack: ... % | % New empty count points here -----+ exch //false resolvestream pdfopdict .pdfruncontext countdictstack exch sub dup 0 gt { ( **** Warning: Pattern stream has unbalanced q/Q operators \(too many q's\)\n) pdfformaterror { Q } repeat } { pop } ifelse % 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 { % resolvepattern % 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 knownoget { dup 65535 le { dup 0 eq { pop pop () } { string readstring pop } ifelse } { () /SubFileDecode filter /ReusableStreamDecode filter } ifelse } { 0 (endstream) /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 dup /.pattern_uses_transparency 1 index patternusestransparency put PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { true } ifelse { (%Pattern: ) print dup === flush } if } if } bdef /ignore_color_op ( **** Warning: Ignoring a color operation in a cached context.\n) readonly def drawopdict begin /g { .incachedevice { % Bug 689302 pop //ignore_color_op pdfformaterror } { /DeviceGray cssubst { cs sc1 } { g } ifelse } ifelse } bdef /rg { .incachedevice { pop pop pop //ignore_color_op pdfformaterror } { /DeviceRGB cssubst { cs sc* } { rg } ifelse } ifelse } bdef /k { .incachedevice { pop pop pop pop //ignore_color_op pdfformaterror } { k } ifelse } bdef /cs { .incachedevice { pop //ignore_color_op pdfformaterror } { csresolve cs } ifelse } bdef /sc { .incachedevice { .pdfcount { pop } repeat //ignore_color_op pdfformaterror } { scresolve { sc* } { sc1 } ifelse } ifelse } bdef /scn /sc load def /G { .incachedevice { pop //ignore_color_op pdfformaterror } { /DeviceGray cssubst { CS SC1 } { G } ifelse } ifelse } bdef /RG { .incachedevice { pop pop pop //ignore_color_op pdfformaterror } { /DeviceRGB cssubst { CS SC* } { RG } ifelse } ifelse } bdef /K { .incachedevice { pop pop pop pop //ignore_color_op pdfformaterror } { K } ifelse } bdef /CS { .incachedevice { pop //ignore_color_op pdfformaterror } { csresolve CS } ifelse } bdef /ri { .incachedevice { pop //ignore_color_op pdfformaterror } { ri } ifelse } bdef /SC { .incachedevice { .pdfcount { pop } repeat //ignore_color_op pdfformaterror } { scresolve { SC* } { SC1 } ifelse } ifelse } bdef /SCN /SC load def end currentdict /ignore_color_op undef % ---------------- Paths ---------------- % drawopdict begin % Path construction /m /moveto load def /l /lineto load def /c /curveto load def /v { currentpoint 6 2 roll curveto } bdef /y { 2 copy curveto } bdef /re { 4 2 roll moveto exch dup 0 rlineto 0 3 -1 roll rlineto neg 0 rlineto closepath } bdef /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 { OFFlevels length 0 eq { setfillstate resolvesh gsave 0 .setoverprintmode dup /.shading .knownget { exch pop } { dup .buildshading dup 3 1 roll /.shading exch put } ifelse .shfill grestore } { pop } ifelse } bdef end % ---------------- XObjects ---------------- % /xobjectprocs mark % -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 { % checkaltimage Printed { dup /Alternates knownoget { { dup /DefaultForPrinting knownoget { { /Image oget exch pop exit } { pop } ifelse } { pop } ifelse } forall } if } if } bdef % getu16 /getu16 { 2 copy get 8 bitshift 3 1 roll 1 add get add } bind def % getu32 /getu32 { 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add } bind def /jp2_csp_dict << 16 { /sRGB /ColorSpace findresource } bind 18 1 index % YCC is convertrd to RGB 17 { /sGray /ColorSpace findresource } bind >> readonly def % Process jp2 blocks (aka boxes). All procedures have the signature % -> ... /jp2_tag_dict << /jp2h { % descend into a sub-stream, don't return. () /SubFileDecode filter 0 } bind /ihdr { 14 sub % file len-14 1 index 14 string readstring pop % file len-14 (14) /Components 1 index 8 getu16 % file len-14 (14) /Components NC def % file len-14 (14) 10 get 16#7F and 1 add 8 .min % color depth is reduced in the library /BitsPerComponent exch def % file len-14 } bind /colr { currentdict /ColorSpace known not { 3 sub 1 index 3 string readstring pop % file len-3 (3) 0 get dup 1 eq { pop 4 sub % file len-7 1 index 4 string readstring pop % file len-16 (4) 0 getu32 % file len-16 enum //jp2_csp_dict exch .knownget { exec /ColorSpace exch def % file len-7 } { ( **** Warning: Unknown enumerated color space in JPX stream.\n) pdfformaterror } ifelse } { 2 eq { 3 dict begin /N /Components load def string 1 index exch readstring pop % file () /ReusableStreamDecode filter /DataSource exch def currentdict end /ICCBased exch 2 array astore /ColorSpace exch % file /ColorSpace [...] def 0 % file 0 } { ( **** Warning: Unknown color space method in JPX stream.\n) pdfformaterror } ifelse } ifelse } if } bind % Palette colors are decoded by the library. % For now, ignore 'pclr' table. /pclr { } >> readonly def % Parse jp2 file format to get color space and image depth info. % get_jp2_csp - /get_jp2_csp { { dup (01234567) readstring pop % f (LBoxTBox) dup length 8 lt { pop exit } if dup 4 4 getinterval exch % f (TBox) (LBoxTBox) 0 getu32 % f (TBox) LBox dup 0 eq { pop pop exit % cannot happen } { dup 1 eq { pop 1 index (01234567) readstring pop 4 getu32 % f (TBox) LBox 16 sub } { 8 sub } ifelse } ifelse % f (TBox) LBox-8..16 PDFDEBUG { 2 copy 2 packedarray == % f (TBox) LBox-8..16 } if //jp2_tag_dict 3 -1 roll .knownget { exec } if % f flush dup 0 ne { 1 index exch % f f flush () /SubFileDecode filter flushfile % skip unwanted blocks } { pop } ifelse } loop pop } bind def currentdict /jp2_tag_dict .undef currentdict /jp2_csp_dict .undef /makeimagedict { % makeimagedict % 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 { % makeimagekeys % 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 % 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). //false resolvestream /DataSource exch def //true } { % Opaque image dup /ColorSpace oknown 1 index /BitsPerComponent oknown and not { dup /Filter knownoget { dup type /arraytype eq { dup length dup 0 gt { 1 sub get oforce } { pop } ifelse } if /JPXDecode eq { % JPXDecode filters can omit the /ColorSpace and /BitsPerComponent % keys, in which case the interpreter must retrieve this information % from inside the compressed stream. Here we substitute the most % likely values as a work-around. dup /IDFlag known { ( **** Warning: PDF spec bans inline JPX images.\n) pdfformaterror % Inline stream is not positionable. Cannot get ColorSpace. } { % Drop the last filter (JPXDecode) from the pipeline dup dup length dict copy dup /Filter oget dup type /arraytype eq { dup length 1 gt { dup length 1 sub 0 exch getinterval 1 index exch /Filter exch put dup /Params knownoget { dup type /arraytype eq { dup length 1 gt { dup length 1 sub 0 exch getinterval 1 index exch /Params exch put } { pop dup /Params undef } ifelse } { pop dup /Params undef } ifelse } if } { pop dup /Filter undef dup /Params undef } ifelse } { pop dup /Filter undef dup /Params undef } ifelse //false resolvestream get_jp2_csp } ifelse } if } if currentdict /BitsPerComponent oknown not { ( **** Warning: image has no /BitsPerComponent key; assuming 8 bit.\n) pdfformaterror /BitsPerComponent 8 def } if } if currentdict /ColorSpace knownoget not { dup /ColorSpace knownoget not { ( **** Warning: image has no /ColorSpace key; assuming /DeviceRGB.\n) pdfformaterror /DeviceRGB } if } if 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 % 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). //false resolvestream /DataSource exch def //false } ifelse } 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 { % makemaskimage % , 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 1 BitsPerComponent bitshift 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 [ exch { 1 BitsPerComponent bitshift 1 sub and } forall ] % AR5 does this } if /MaskColor exch def } { % 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 { % doimagesmask - PDFusingtransparency { currentdict /SMask knownoget } { false } ifelse { % We are doing transparency and SMask is present in the image % stack: currentdevice .devicename /pdfwrite eq { pop % pdfwrite will process SMask directly during 'doimage' } { .begintransparencymaskimage PDFfile fileposition exch gsave //nodict begin null /SoftMask gput 1 .setopacityalpha 1 .setshapealpha 1 CA 1 ca /Compatible .setblendmode DoImage end grestore PDFfile exch setfileposition 0 .endtransparencymask } ifelse << /Subtype /Group /Isolated true /.image_with_SMask true % pdfwrite needs : see gs/src/ztrans.c, gs/src/gdevpdft.c >> 0 0 1 1 .begintransparencygroup doimage .endtransparencygroup } { SoftMask //null ne { % the image doesn't have an SMask, but the ExtGState does, force a group. << /Subtype /Group /Isolated true >> 0 0 1 1 .begintransparencygroup doimage .endtransparencygroup } { doimage } ifelse } ifelse } bdef % For development needs we define a special option for running with a new handler % for images with a soft mask. //systemdict /NEW_IMAGE3X .knownget not { //false } if { /doimagesmask { % doimagesmask - doimage } bdef } if /is_big_mask { % - is_big_mask 1 0 dtransform dup mul exch dup mul sqrt add 0 1 dtransform dup mul exch dup mul sqrt add mul currentdevice getdeviceprops .dicttomark /BufferSpace .knownget not { 4000000 % hack: Can't get the real default value from C source. } if 2 % arbitrary div gt } bind def % For development needs we define a special option for running with a new handler % for images with a soft mask. //systemdict /NEW_IMAGE3X .knownget not { //false } if { /is_big_mask { % - is_big_mask //false } bdef } if /doimage { % doimage - % imagedict is currentdict, gets popped from dstack DataSource exch PDFusingtransparency currentdevice .devicename /pdfwrite ne { % This is a temporary workaround for the bug 689080, % which is done under a rush of 8.63 release. % The purpose is to disable a conversion of an image with soft mask % into a Type 103 image, which currently allocates a full mask buffer % before writing clist. % With this workaround the Matte color is not working (ignored). is_big_mask not } { true % pdfwrite doesn't need the workaround explained above, % and cannot work with it. } ifelse and { currentdict /SMask knownoget } { false } ifelse { makesoftmaskimage } { currentdict /Mask knownoget { makemaskimage } if } ifelse % Stack: datasource imagemask { currentdict end setfillstate { imagemask } } { ColorSpace setgcolorspace currentdict end setfillblend { image } } ifelse stopped { dup type /dicttype eq { pop } if % Sometimes image fails to restore the stack $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 { % .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 countdictstack 3 -1 roll /pdfemptycount count 2 sub store q execform % gsave / grestore around the Form % Restore pdfemptycount countdictstack exch sub dup 1 gt { ( **** Warning: Pattern stream has unbalanced q/Q operators \(too many q's\)\n) pdfformaterror } if { Q } repeat /pdfemptycount exch store } 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 /ocg_pocs 4 dict begin /AllOn { //true exch { oforce dup type /dicttype eq { /OFF known not and } { pop } ifelse } forall } bdef /AnyOn { //false exch { oforce dup type /dicttype eq { /OFF known not or } { pop } ifelse } forall } bdef /AnyOff { //AllOn exec not } bdef /AllOff { //AnyOn exec not } bdef currentdict end readonly def % Check whether OCG or OCMD is visible % oc-is-visible /ocg-is-visible { dup /Type knownoget { /OCMD eq { dup /OCGs knownoget not { {} } if % OC OCGs dup type /dicttype eq { 1 array astore } if //true 1 index { //null eq and } forall { pop pop //true % all nulls => show } { exch /P knownoget not { /AnyOn } if % OCGs P //ocg_pocs exch get exec % bool } ifelse } { /OFF known not % OFF is inserted by process_trailer_attrs } ifelse } { /OFF known not % OFF is inserted by process_trailer_attrs } ifelse } bdef drawopdict begin /Do { % /Name setfillblend PDFfile fileposition exch % pos /Name dup Page /XObject rget { exch pop % pos obj OFFlevels length 0 eq { dup /OC knownoget { ocg-is-visible } { //true } ifelse } { //false } ifelse { dup /Subtype get //xobjectprocs exch get % pos obj {proc} % Don't leave extra objects on the stack while executing % the definition of the form. 3 -1 roll % obj {proc} pos 2 .execn % pos } { pop % pos } ifelse } { % 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 currentdict /xobjectprocs .undef currentdict /ocg_pocs .undef % ---------------- 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 { % unabbrevvalue oforce //unabbrevtypedict 1 index type .knownget { exec } if } bdef /is_space_dict << 0 0 9 9 10 10 12 12 13 13 32 32 >> readonly def 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 OFFlevels length 0 eq { doimage } { Width 1 index /ImageMask knownoget dup { and } if not { 1 index /ColorSpace oget dup type /arraytype eq { 0 oget } if //csncompdict exch get exec BitsPerComponent mul } if 7 add 8 idiv Height mul DataSource exch () /SubFileDecode filter flushfile end } ifelse % 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. % Sometimes (bug 690300) CCITTDecode filter consumes 'E' in 'EI'. % Therefore, we search for I or EI PDFsource read not { /ID cvx /syntaxerror signalerror } if dup 73 eq { pop 10 69 73 % Seed to: EI } { 10 10 3 -1 roll % Seed to: } ifelse { PDFsource read not dup { 10 exch } if //is_space_dict 2 index known 3 index 73 eq and 4 index 69 eq and //is_space_dict 6 index known and { pop pop pop pop pop exit } { { pop pop pop /ID cvx /syntaxerror signalerror } { 4 -1 roll pop } ifelse } ifelse } loop } bdef end currentdict /is_space_dict undef % ================================ 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 /Tform { Tform } def % Text formatting and painting for AcroForm % without appearance streams. end % ======================= Invalid operators ============================ % drawopdict begin /QBT { Q BT ( **** Warning: invalid operator QBT processed as Q BT .\n) pdfformaterror % Bug 690089 } def /. { 0. ( **** Warning: invalid operator . processed as number 0. .\n) pdfformaterror % Bug 690730 } def end % ============================== Annotations ============================== % % Get and normalize an annotation's rectangle. /annotrect { % annotrect /Rect oget 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 { % 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 { % 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 { % drawborder - gsave dup /BS known 1 index /Border known or { dup /BS knownoget { dup type /dicttype ne % } { dup /Border oget dup type /arraytype eq { dup length 3 lt } { //true } ifelse % [border] } ifelse { ( **** Warning: Wrong annotation border object, no border is drawn.\n) pdfformaterror pop { 0 0 0 } } if dup type /dicttype eq { dup /W knownoget not { 1 } if % Per PDF1.6 Reference table 8.13, /W in the border style dictionary is % expressed in points (an absolute unit), so compensate here for any % scaling of the PostScript user space done due to /UserUnit. % Scaling due to -dPDFFitPage is not undone, to keep the correct border width % compared to the size of the surrounding marks. //systemdict /NoUserUnit .knownget not { //false } if not //systemdict /PDFFitPage known not and { % UserUnit is ignored if -dPDFFitPage Page /UserUnit knownoget { div } if } if {} 2 index /S knownoget { /D eq { 2 index /D knownoget not { {3} } if exch pop } if } if 3 -1 roll pop strokeborder } { dup 2 get exch dup length 3 gt { 3 get } { pop {} } ifelse strokeborder } ifelse } { 1 {} strokeborder } 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 { % annotvisible /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 { % drawwidget - dup /AP knownoget { dup /N known not { ( **** Appearance dictionary (AP) lacks the mandatory normal (N) appearance.\n) pdfformaterror } if //false [/N /R /D] { % stack: scalex scaley annot appearance false key 2 index exch knownogetdict { exch not exit } if } forall % stack: scalex scaley annot appearance value true % stack: scalex scaley annot appearance false dup { pop exch pop % 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 or File key. % If the stream lacks Length key, try File key. dup /Length known 1 index /File known or { % 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: scalex scaley annot appearance true % Stack: scalex scaley annot false { % Draw appearance % Initialize graphic following "7.4.4 Appearance Streams" q graphicsbeginpage textbeginpage 1 index annotrect pop pop translate 3 index 3 index scale % Apply scale factors dup /BBox knownoget { 1 index /Matrix knownoget not { {1 0 0 1 0 0} } if .bbox_transform pop pop % Compensate for non-zero origin of BBox neg exch neg exch translate } if DoForm Q } if } { dup /FT knownoget { /Tx eq { % Stack: scalex scaley annot dup /DA known 1 index /V known and { dup /DA oget q graphicsbeginpage textbeginpage 1 index annotrect pop pop translate 3 index 3 index scale % Apply scale factors cvx exec dup /V oget 0 0 moveto dup false charpath pathbbox newpath 3 -1 roll sub abs 3 1 roll sub abs 3 index annotrect 4 2 roll pop pop 6 index mul exch 6 index mul % stack: scale annot V vsize hsize vrect hrect % Calculate horizontal justification first % horizontal can be left (Q=0), center (Q=1), or right (Q=2) justification 3 -1 roll % stack: scalex scaley annot V vsize vrect hrect hsize 5 index /Q knownoget not { 0 } if % default 0 == left dup 0 eq { pop pop pop 0 % left justified } { 1 eq { 2 div exch 2 div exch sub % centered } { sub % right justified (hrect - hsize) } ifelse } ifelse % stack: scalex scaley annot V vsize vrect hoffset % Center the text vertically in the rect (Acrobat Reader seems to do this) 3 1 roll 2 div exch 2 div sub abs % stack: scalex scaley annot V hoffset voffset moveto show Q } if } if } if } ifelse pop pop pop } bdef % For annotation object we have to determine the size of the output rectangle % and the size of the BBox for the form XObject. From these we calculate % a scale factors for drawing it. /calc_annot_scale { % calc_annot_scale dup /Rect knownoget { pop dup annotrect 4 2 roll pop pop % get width height size in user space 3 -1 roll /AP knownoget { /N knownogetdict { dup /Matrix knownoget not { {1 0 0 1 0 0} } if exch /BBox knownoget { % x y {matrix} [box] exch .bbox_transform % x y x0 y0 x1 y1 3 -1 roll sub % x y x0 x1 y1-y0 3 1 roll exch sub % x y y1-y0 x1-x0 2 copy mul 0 eq { ( **** Warning: /BBox has zero width or height, which is not allowed.\n) pdfformaterror pop pop pop pop 1 1 % zero size -- revert to unity scaling } { 3 1 roll div % x x1-x0 y/(y1-y0) 3 1 roll div % y/(y1-y0) x/(x1-x0) exch % x/(x1-x0) y/(y1-y0) } ifelse } { pop pop pop 1 1 % default to unity scaling } ifelse % if we have /BBox } { pop pop 1 1 } ifelse % if we have /N } { pop pop 1 1 } ifelse % if we have /AP } { ( **** Warning: /Annot dict is missing required /Rect entry.\n) pdfformaterror pop 1 1 } ifelse } bdef % Draw an annotation. /drawannottypes mark /Link { % -> dup drawborder dup calc_annot_scale 3 -1 roll drawwidget //false } bind /Ink { % -> % -> dup /AP oknown { //true } { 1 setlinewidth 1 setlinecap 1 setlinejoin dup annotsetcolor dup calc_annot_scale 3 index annotrect pop pop translate scale /InkList knownoget { { oforce mark exch { oforce } forall .pdfinkpath stroke } forall } if //false } ifelse } bind .dicttomark readonly def /drawannot { % drawannot - dup annotvisible { gsave dup dup /Subtype knownoget { //drawannottypes exch .knownget { exec } { //true } ifelse { dup calc_annot_scale 3 -1 roll drawwidget % Draw rejected annots as widgets } if % type known } { pop ( **** Warning: /Annot dict without required /Subtype entry is ignored.\n) pdfformaterror } ifelse grestore } if pop % annotvisible } bdef currentdict /drawannottypes undef % ============================ AcroForm fields ============================ % % Get an attribure of the 0th annotation of a node /annot_oget { % /Name annot_oget 1 index /Kids knownoget { 0 oget exch oget exch pop } { oget } ifelse } bdef % All procedures have the signature: % foo /draw_terminal_field_dict 4 dict begin /Btn { 1 index /Tf pget not { 0 } if dup 16#20000 and 0 ne { pop % Push button dup /AP known { 1 1 2 index drawwidget } { (Push button without appearance stream is not yet implemented) = } ifelse } { 16#10000 and 0 ne { % Radio button dup /AP known { 1 index /Kids oget { 1 1 3 -1 roll drawwidget } forall } { (Radio button without appearance stream is not yet implemented) = } ifelse } { % Checkbox dup /AP known { dup 1 1 3 -1 roll drawwidget } { (CkeckBox without appearance stream is not yet implemented) = } ifelse } ifelse } ifelse } bdef /Tx { dup /AP known { dup 1 1 3 -1 roll drawwidget } { 2 index /NeedAppearances knownoget not { //false } if { dup /AP << /N 10 dict dup cvx begin >> put /Subtype /Form def /BBox [ 0 0 4 index /Rect oget { oforce } forall 3 -1 roll sub abs 3 1 roll sub abs exch ] def /Resources 3 index /DR pget not { 0 dict } if def /File 1000 string dup 3 1 roll def /Length 0 def % (string) /NullEncode filter % file dup (BT ) writestring 2 index /DA pget not { () } if [ exch { token { dup /Tf eq { 2 index 0 eq { /BBox load 3 get 0.75 mul % empirical constant 4 -1 roll pop 3 1 roll } if } if exch } { exit } ifelse } loop ] { 1 index exch write== } forall dup 3 index /MaxLen pget not { 0 } if write= dup 3 index /V pget not { () } if write== dup 3 index /Ff pget not { 0 } if write= dup 3 index /Q pget not { 0 } if write= dup (Tform ET) write= end closefile % dup 1 1 3 -1 roll drawwidget } if } ifelse } bdef /Ch { (Ch is not yet implemened) == } bdef /Sig { (Sig is not yet implemened ) == } bdef currentdict end def /draw_terminal_field { % draw_terminal_field - dup /Kids knownoget { 0 oget } { dup } ifelse dup /P knownoget { /Page load eq { //draw_terminal_field_dict 2 index /FT pget not { 0 } if .knownget { exec } if } if } if pop pop } bdef % We distinguish 4 types of nodes on the form field tree: % - non-terminal field - has a kid that refers to the parent (or anywhere else) % - terminal field with separate widget annotations - has a kid that doesn't have a parent % - terminal field with a merged widget annotation - has no kids % - widget annotation - has /Subtype and /Rect % % The recursive enumeration of the form fields doesn't descend into widget annotations. /draw_form_field { % draw_form_field - dup /Kids knownoget { % field [] dup 0 oget /Parent knownoget { % field [] kid pop % mon-terminal field % field [] exch pop % [] { oforce draw_form_field } forall } { pop draw_terminal_field % separate annots % - } ifelse } { draw_terminal_field % merged annotation % - } ifelse } bdef /draw_acro_form { %
draw_acro_form - dup /Fields knownoget { { oforce draw_form_field } forall } if pop } bdef currentdict /draw_terminal_field_dict undef end % pdfdict end % GS_PDF_ProcSet .setglobal