% Copyright (C) 2001-2022 Artifex Software, Inc. % All Rights Reserved. % % This software is provided AS-IS with no warranty, either express or % implied. % % This software is distributed under license and may not be copied, % modified or distributed except as expressly authorized under the terms % of the license contained in the file LICENSE in this distribution. % % Refer to licensing information at http://www.artifex.com or contact % Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, % CA 94945, U.S.A., +1(415)492-9861, for further information. % % pdf_draw.ps % PDF drawing operations (graphics, text, and images). /.setlanguagelevel where { pop 2 .setlanguagelevel } if .currentglobal //true .setglobal /GS_PDF_ProcSet load 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 } bind executeonly def /.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 } bind executeonly def /.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 } bind executeonly def /.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 signalerror } if exch token { /rangecheck signalerror } if % Use .bind to avoid idiom recognition. .bind 1 index /Function 3 -1 roll put exch PDFfile exch setfileposition } bind executeonly def /.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 } bind executeonly def /resolvefunction { % resolvefunction .resolvefn PDFDEBUG { //pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Function: ) print dup === flush } if } if } bind executeonly def /resolvefnproc { % resolvefnproc resolvefunction .buildfunction } bind executeonly def /resolveidfnproc { % resolveidfnproc dup /Identity eq { pop { } } { resolvefnproc } ifelse } bind executeonly def /resolvedefaultfnproc { % resolved'fnproc 1 index /Default eq { exch pop } { pop resolveidfnproc } ifelse } bind executeonly def %% A BBox where width or height (or both) is 0 should still paint one pixel %% See the ISO 32000-2:2017 spec, section 8.7.4.3, p228 'BBox' and 8.7.3.1 /FixPatternBBox { dup aload pop 3 index 2 index sub 0 eq { 3 index 0.000001 add 3 -1 roll pop exch } if 2 index 1 index sub 0 eq { 2 index 0.000001 add exch pop }if 5 -1 roll astore }bind executeonly def % ---------------- Shadings ---------------- % /shrdict mark /Coords { aload 5 1 roll 4 { % Bug 694542 dup type dup /integertype ne exch /realtype ne and { ( **** Error: replacing malformed number ') pdfformaterror pdfstring cvs pdfformaterror (' with 0.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror 0 } if 4 1 roll } repeat 5 -1 roll astore } bind executeonly /BBox { dup dup dup aload pop normrect_elems 5 -1 roll astore FixPatternBBox } bind executeonly /ColorSpace { resolvecolorspace } bind executeonly /Function { dup type /dicttype eq { resolvefunction } { [ exch { oforce resolvefunction } forall ] } ifelse } bind executeonly /Extend { mark exch {oforce} forall ] } bind executeonly .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 } bind executeonly def /resolvesh { % resolvesh % resolvesh Page /Shading rget { %% Horrible hacky fix, see /DoImage later in ths file for more information %% dup /ColorSpace known { dup /ColorSpace get dup type /arraytype eq { exch dup length dict copy exch dup length array copy /ColorSpace exch 2 index 3 1 roll put } {pop} ifelse } if resolveshading } { //null }ifelse } bind executeonly def % ---------------- 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 } bind executeonly /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 } bind executeonly /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 } bind executeonly /EllipseA { dup mul .9 mul exch dup mul add 1 exch sub } bind executeonly /InvertedEllipseA { dup mul .9 mul exch dup mul add 1 sub } bind executeonly /EllipseB { dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub } bind executeonly /EllipseC { dup mul .9 mul exch dup mul add 1 exch sub } bind executeonly /InvertedEllipseC { dup mul .9 mul exch dup mul add 1 sub } bind executeonly /Line { exch pop abs neg } bind executeonly /LineX { pop } bind executeonly /LineY { exch pop } bind executeonly /Square { abs exch abs 2 copy lt { exch } if pop neg } bind executeonly /Cross { abs exch abs 2 copy gt { exch } if pop neg } bind executeonly /Rhomboid { abs exch abs 0.9 mul add 2 div } bind executeonly /DoubleDot { 2 {360 mul sin 2 div exch } repeat add } bind executeonly /InvertedDoubleDot { 2 {360 mul sin 2 div exch } repeat add neg } bind executeonly /SimpleDot { dup mul exch dup mul add 1 exch sub } bind executeonly /InvertedSimpleDot { dup mul exch dup mul add 1 sub } bind executeonly /CosineDot { 180 mul cos exch 180 mul cos add 2 div } bind executeonly /Double { exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add } bind executeonly /InvertedDouble { exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add neg } bind executeonly .dicttomark readonly def /.resolveht1 { mark exch { oforce 1 index /SpotFunction eq { dup type /arraytype eq { %% check all the names in the array in turn, stop when we find %% the first one we recognise. { //spotfunctions exch .knownget { exit } if } forall dup type /nametype eq { %% If we didn't find any that we recognise, then use %% the default halftone's spot function .setdefaulthalftone currenthalftone dup /SpotFunction .knownget { exch pop }{ /GraySpotFunction .knownget not { //spotfunctions /Round get } if }ifelse } if }{ dup type /nametype eq { //spotfunctions exch get } { resolvefnproc } ifelse } ifelse } { 1 index /TransferFunction eq { resolveidfnproc } if } ifelse } forall .dicttomark } bind executeonly def /.resolveht5 { mark exch { oforce dup type /dicttype eq { resolvehalftone } if } forall .dicttomark } bind executeonly def /.resolveht6 { %% resolvestream will reposition PDFfile. If we are in the middle %% of reading a content stream from PDFfile when we execute this, %% then reading the next buffer will read from the wrong place. We %% must save and restore the position of PDFfile. See the definition %% of resolvestream. Bug #695886 PDFfile fileposition exch mark exch { oforce } forall .dicttomark dup dup //false resolvestream /ReusableStreamDecode filter /Thresholds exch put dup /TransferFunction .knownget { resolveidfnproc 1 index exch /TransferFunction exch put } if exch PDFfile exch setfileposition } bind executeonly def /htrdict mark 1 //.resolveht1 5 //.resolveht5 6 //.resolveht6 10 //.resolveht6 16 //.resolveht6 .dicttomark readonly def currentdict /.resolveht1 undef currentdict /.resolveht5 undef currentdict /.resolveht6 undef /resolvehalftone { % resolvehalftone dup /HalftoneType oget dup //htrdict exch .knownget { exch pop exec } { =string cvs ( **** Error: Incorrect halftone type ) exch concatstrings (. Using defailt.\n) concatstrings pdfformaterror ( Output may be incorrect.\n) pdfformaterror gsave .setdefaulthalftone currenthalftone grestore } ifelse } bind executeonly def % ---------------- Graphics state management ---------------- % /cmmatrix matrix def drawopdict begin % Graphics state stack /q { q } executeonly def /Q { Q } executeonly def % Graphics state setting /cm { //cmmatrix astore % If inside a BT/ET block, we need to undo the text matrix, then apply % the cm, then re-apply the text matrix :-( Of course the spec says % this isn't even legal. currentdict /TextSaveMatrix .knownget { pop unsettextmatrix } if .getpath exch concat newpath { exec } forall % If inside a BT/ET block, we need to update the TextSaveMatrix currentdict /TextSaveMatrix .knownget { settextmatrix //cmmatrix exch dup concatmatrix pop } if % And if we ha\ve done a gsave inside a text block, we need to update % that matrix instead. currentdict /qTextSaveMatrix .knownget { //cmmatrix exch dup concatmatrix pop } if } bind executeonly def /i { 1 .min setflat } bind executeonly def /J { setlinecap } bind 0 get def /d { setdash } bind 0 get def /j { setlinejoin } bind 0 get def /w { setlinewidth } bind 0 get def /M { 1 .max setmiterlimit } bind executeonly def /gs { gs } executeonly def end % Each entry in this dictionary is % -proc- /gsbg { /BGDefault load resolvedefaultfnproc setblackgeneration } bind executeonly def /gsucr { /UCRDefault load resolvedefaultfnproc setundercolorremoval } bind executeonly def /gstr { dup type /arraytype eq { { oforce /TRDefault load resolvedefaultfnproc } forall setcolortransfer } { /TRDefault load resolvedefaultfnproc settransfer } ifelse } bind executeonly def /gsparamdict mark /SA { setstrokeadjust } executeonly /OP { 1 index /op known not { dup op } if OP } executeonly % 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 } executeonly /UCR { 1 index /UCR2 known { pop } { gsucr } ifelse } executeonly /TR { 1 index /TR2 known { pop } { gstr } ifelse } executeonly % Some functions used to implement phases of HT and HTP /sethalftones { % As is so often the case, if we get an error we need to clean up the stack, but we can't % use mark/cleartomark, because the action which caused the error may have left a mark % on the stack. So we need to define our own mark. On an error we'll clean up the stack % until we reach this unique key on the stack /SethalftonesMark exch dup /Default eq { pop .setdefaulthalftone pop } { {resolvehalftone} stopped { (\n **** Error resolving halftone. Ignoring the halftone, output may be incorrect.\n) pdfformaterror % Clean up the stack by checking every entry until we find our unique key {/SethalftonesMark eq {exit} if} loop } { {sethalftone} stopped { (\n **** Error setting halftone. Ignoring the halftone, output may be incorrect.\n) pdfformaterror % Clean up the stack by checking every entry until we find our unique key {/SethalftonesMark eq {exit} if} loop } { pop }ifelse }ifelse } ifelse } bind executeonly def /sethalftonephases { {aload pop -1 2 index 2 index .setscreenphase pop pop} stopped { (\n **** Error setting halftone phase. Ignoring the phase, output may be incorrect.\n) pdfformaterror } if } bind executeonly def /HT { dup sethalftones .swapcolors sethalftones .swapcolors % 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 } executeonly /HTP { % HTP may be present even if this isn't a DPS interpreter. dup sethalftonephases .swapcolors sethalftonephases .swapcolors } executeonly % PDF 1.3 % The font is an indirect reference, not a resource name /Font { aload pop exch oforce resourcefont exch Tf } /LW { setlinewidth } executeonly /LC { setlinecap } executeonly /LJ { setlinejoin } executeonly /ML { 1 .max setmiterlimit } executeonly /D { aload pop setdash } executeonly /RI { ri } executeonly /op { op } executeonly /OPM { OPM } executeonly /BG2 { gsbg } executeonly /UCR2 { gsucr } executeonly /TR2 { gstr } executeonly /FL { 1 .min setflat } executeonly /SM { % SM may be present even if this is only a Level 2 interpreter. /setsmoothness where { pop setsmoothness } { pop } ifelse } executeonly % PDF 1.4 % All of these require the "transparency" feature in the interpreter. /ca { ca } executeonly /CA { CA } executeonly /SMask { {gssmask} PDFSTOPONERROR { exec //false } { stopped } ifelse { pop (\n **** Error in SMask during ExtGState. Ignoring the mask, output may be incorrect.\n) pdfformaterror } if } executeonly /AIS { AIS } executeonly /BM { BM } executeonly /TK { TK } executeonly /UseBlackPtComp { UseBlackPtComp } executeonly /HTO { % PDF 2.0, supposed to be 'similar' to halftone phase but using a different % co-ordiate system. Treat the same for now and fix if anyone ever complains. aload pop transform cvi exch cvi exch 2 array astore dup sethalftonephases .swapcolors sethalftonephases .swapcolors } executeonly .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 } { //pdfdict /.gs_warning_issued known not { (\n **** Error 'gs' ignored -- ExtGState missing from Resources.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror //pdfdict /.gs_warning_issued //true .forceput PDFSTOPONERROR { /gs cvx /undefined signalerror } if } executeonly if } executeonly ifelse } bind executeonly def % ------ Transparency support ------ % /gssmask { { dup type /dicttype eq { dup /G knownogetdict {pop} { ( **** Error: Ignoring invalid transparency SMask group\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror % replace the invalid SMask object pop /None } ifelse } if dup /None eq 1 index //null eq or PDFusingtransparency not or { pop //null .currentSMask //null ne { % get rid of the current SMask (Bug 695471) //false % colorspace not set << /Subtype /None >> % Special type for this purpose 0 0 0 0 % fake BBox .begintransparencymaskgroup } if exit } if % 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 1 index /G oget /Group knownoget not { ( **** Error: Ignoring a transparency group XObject without /Group attribute.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror cleartomark //null exit } if gsave //nodict begin dup /CS knownoget { exch pop resolvecolorspace dup setgcolorspace csput } { % Group attributes dictionaries are supposed to contain a /CS % entry, but Acrobat apparently also handles a /ColorSpace.... /ColorSpace knownoget { ( **** Error: A transparency group XObject has a /ColorSpace instead of /CS attribute.\n) pdfformaterror resolvecolorspace dup setgcolorspace csput } { ( **** Error: Ignoring a transparency group XObject without /CS attribute.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror cleartomark //null exit }ifelse } ifelse 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 oforce_array 1 index /Matrix knownoget { oforce_array .bbox_transform 4 array astore } if /BBox exch 4 2 roll % Because we don't execute the group form stream until we find % out whether we're actually going to draw through it, we need % to save the current gstate with the other parameters, so % we can subsequently execute it in the correct graphics state. % We need to concatenate the Matrix in this gstate as per the PDF % spec 7.5.4 (p. 552 in the PDF 1.7 Ref) (bug 694455). gsave dup /Matrix knownoget { matrix currentmatrix matrix concatmatrix setmatrix } if /GroupGState gstate currentgstate 6 2 roll grestore /GroupMat matrix currentmatrix 8 2 roll % /GroupExtGState 1 dict % 10 2 roll /.execmaskgroup cvx 2 packedarray cvx /Draw exch 3 2 roll pop .dicttomark exit } loop SMask } bind executeonly def % 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 executeonly /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 //nodict begin matrix currentmatrix 4 1 roll mark currentcolor counttomark dup 4 add exch roll pop currentcolorspace 4 1 roll .getuseciecolor 4 1 roll .swapcolors mark currentcolor counttomark dup 4 add exch roll pop currentcolorspace 4 1 roll .swapcolors currentuserparams /OverrideICC get 4 1 roll mark /OverrideICC //true .dicttomark setuserparams % We can't simply set the group's gstate here because % we can't use gsave/grestore. So we actually set it % in .execgroup. But the matrix needs set here for % .begintransparencymaskgroup to correctly work. % It might seem we should also set the colorspace % in case the group doesn't have one, *but* empirical % suggests that is not the case - fts_26_2600.pdf and % fts_26_2603.pdf render incorrectly if we set the % colrospace 1 index /GroupMat .knownget { setmatrix } if 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 } { % Group attributes dictionaries are supposed to contain a /CS % entry, but Acrobat apparently also handles a /ColorSpace.... dup /Group oget /ColorSpace knownoget { ( **** Error: A transparency group attribute dictionary has a /ColorSpace instead of /CS attribute.\n) pdfformaterror 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 } ifelse 3 -1 roll dup dup 4 1 roll /BBox get aload pop .begintransparencymaskgroup exch dup /Resources knownoget { oforce } { 2 dict } ifelse 3 -1 roll /GroupGState .knownget { 1 index /GroupGState 3 -1 roll put} if exch //false resolvestream 1 index exch %% Get the current colour space and colour values (as an array), we need to pass these to .execgroup %% as well, so that it can restore them, in case the colour space gets changed by transparency %% graphics state stuff. mark currentcolor counttomark array astore exch pop currentcolorspace 4 2 roll .execgroup % We have to remove these in case the Form XObject is subsequently used as % a form rather than a group - they remain in the paramdict for the SMask % so this will all still work if the SMask is re-evaluated. /GroupGState undef .endtransparencymask PDFfile exch setfileposition mark exch /OverrideICC exch .dicttomark setuserparams .swapcolors setcolorspace setcolor .swapcolors .setuseciecolor setcolorspace setcolor setmatrix end % restore colorspace, color and ExtGState (end) .currentSMask /Processed //true put % special setting to tell us it has been rendered } bind executeonly def % Paint a Form+Group XObject, either for a transparency mask or for a Do. /.execgroup { % [colour values] .execgroup - pdfemptycount 3 1 roll /pdfemptycount count 5 sub store gsave //nodict begin % We have to set the gstate correctly for lazy evaluation of a softmask group. % we also must restore the color(space) as setup in .execmaskgroup or paintformgroup. % This stuff must be done here, as .execmaskgroup can't use gsave/grestore to % manipulate the gstates, due to the requirements of .begintransparencymaskgroup. % We also must set the ExtGState values. % It may seem redundant to do the color(space) twice (once here and once in % .execmaskgroup) but we have to set it in .execmaskgroup for the background % color and set it here once in the correct gstate. 1 index /GroupGState .knownget { setgstate } if newpath //null SMask 1 CA 1 ca /Compatible .setblendmode % Execute the body of the Form, similar to DoForm. pdfopdict %% Restore the colour space (passed in on the stack) and current colour %% 6 -2 roll setcolorspace aload pop setcolor .pdfruncontext end grestore % check for extra garbage on the operand stack and clean it up count pdfemptycount sub dup 0 ne { ( **** Error: Transparency Group, Form XObject execution corrupted the stack.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror PDFSTOPONERROR { /.execgroup cvx /rangecheck signalerror } { dup 0 gt { { pop } repeat }{ pop } ifelse } ifelse } { pop } ifelse /pdfemptycount exch store } bind executeonly def /.beginformgroup { % groupdict bbox .beginformgroup - exch mark exch % bbox mark groupdict dup /CS knownoget { resolvecolorspace dup setgcolorspace /CS exch 3 2 roll} 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 } bind executeonly def /.beginpagegroup { % groupdict bbox .beginformgroup - currentcolorspace 3 1 roll exch mark exch % bbox mark groupdict dup /CS knownoget { resolvecolorspace dup setgcolorspace /CS exch 3 2 roll} 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 .begintransparencypagegroup setcolorspace } bind executeonly def % .paintgroupform implements the Form PaintProc in the case where the % Form XObject dictionary includes a Group key. See .paintform below. /.paintgroupform { % .paintgroupform - %% Pass the current color space, and an array with the current color vales %% as arguments to .execgroup mark currentcolor counttomark array astore exch pop currentcolorspace 5 2 roll dup /Group oget dup type /dicttype eq { exch /BBox oget dup type /arraytype eq { % Stack: resdict stream groupdict bbox .beginformgroup .execgroup .endtransparencygroup }{ ( **** Error: Form XObject has a BBox entry with an invalid type.\n) pdfformaterror ( Ignoring transparency Group, output may be incorrect.\n) pdfformaterror pop pop pop pop pop pop } ifelse } { ( **** Error: Form XObject has a Group entry with an invalid type.\n) pdfformaterror ( Ignoring transparency Group, output may be incorrect.\n) pdfformaterror pop pop pop pop pop pop } ifelse } bind executeonly def % 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} stopped {pop} if 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 .currentalphaisshape { /ShapeMaskDict } { /OpacityMaskDict } ifelse exch def /ColorSpace DataDict /ColorSpace get def } bind executeonly def % ---------------- 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 } bind executeonly def /DeviceRGB { pop 3 } bind executeonly def /DeviceCMYK { pop 4 } bind executeonly def /CIEBasedA //DeviceGray def /CIEBasedABC //DeviceRGB def /CalGray //DeviceGray def /CalRGB //DeviceRGB def /Lab //DeviceRGB def /ICCBased { 1 oget /N oget } bind executeonly def /Separation //DeviceGray def /DeviceN { 1 oget length } bind executeonly def /Indexed //DeviceGray def currentdict end readonly def % csncomp /csncomp { dup dup type /arraytype eq { 0 oget } if //csncompdict exch get exec } bind executeonly def currentdict /csncompdict undef /ICCBased-resolve { PDFfile fileposition exch dup dup 1 oget mark exch { oforce } forall .dicttomark dup dup //true resolvestream { /ReusableStreamDecode filter } stopped { pop null % ( **** Error: Failed to read ICC profile for an ICCBased colour space.\n) pdfformaterror % ( Falling back to a colour space determined by the /N value.\n) pdfformaterror }if /DataSource exch put dup /.hash 0 put % placeholder for use by seticc icc_profile_cache key % Check that the number of components (/N) defined in the ICCBased % dictionry matches the actual profile. Bug #696120 dup /N get 1 index %% If we get an error reading the profile, just assume that /N is correct %% If its genuinely faulty we will use an alternate based on /N. {.numicc_components} stopped {pop dup} if dup 3 -1 roll ne { %% /N and the actual number of components don't match. Ensure %% that we have a valid number of components from the ICC %% profile. Certain kinds of profile can't determine the numebr of components %% and in ths case we must not override the /N value. dup 0 gt { ( **** Error: ICCbased space /N value does not match the ICC profile.\n) pdfformaterror ( Using the number of channels from the profile.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror 1 index dup /N get /OrigN exch put 1 index exch /N exch put }{ pop } ifelse } { pop } ifelse 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 } bind executeonly def /csrdict 13 dict begin /DeviceGray { } bind executeonly def /DeviceRGB { } bind executeonly def /DeviceCMYK { } bind executeonly def /CalGray { 1 oget [ exch /CalGray exch ] } bind executeonly def /CalRGB { 1 oget [ exch /CalRGB exch ] } bind executeonly def /Lab { 1 oget [ exch /Lab exch ] } bind executeonly def /CalCMYK { pop /DeviceCMYK % not defined by Adobe } bind executeonly def /ICCBased { dup 1 get type /dicttype ne { % don't resolve more than once ICCBased-resolve } if } bind executeonly def /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 %% Make sure the ink name is not an indirect object.... 3 -1 roll oforce 3 1 roll 4 array astore } bind executeonly def /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 % devn_array devn_array <<..attributes..>> 1 index 4 oget /Process knownoget { dup /ColorSpace knownoget { 1 index exch resolvecolorspace /ColorSpace exch put } if % devn_array devn_array <<..attributes..>> <<..Process..>> 1 index /Process 3 -1 roll put } if 4 exch put % Put resolved or new attributes dict } if } bind executeonly def /Indexed { aload pop %% Resolve 'hival' in case it is an indirect reference. This is kind of %% dumb, it just makes the file bigger, but it *is* legal. 3 1 roll oforce 3 -1 roll 1 index -1 eq { exch pop 255 exch ( **** Error: Highest color index given as -1. Assuming this actually means 255.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } if 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 % Stack: /Indexed csp comp table 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 dup /Filter oknown not { % For Bug691941.pdf and similar lossage dup /Length knownoget not { 0 } if } { 0 } ifelse % Stack: filepos /Indexed basespace hival lookup Length 2 index 1 add % Stack: filepos /Indexed basespace hival lookup Length len 4 index csncomp mul .max string % Stack: filepos /Indexed basespace hival lookup (...) exch //true resolvestream 1 index readstring not { % The string is padded with 0s ( **** Error: Short look-up table in the Indexed color space was padded with 0's.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } if pop % Stack: filepos /Indexed basespace hival (...) PDFfile 6 -1 roll setfileposition } if 4 array astore % Stack: [filepos /Indexed basespace hival (...)] % 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 } bind executeonly def /I { % Bug 689815 ( **** Error: The name /Indexed cannot be abbreviated to /I in the color space\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror dup 0 /Indexed put //Indexed exec } bind executeonly def /Pattern { dup type /nametype ne { dup length 1 gt { 1 oget resolvecolorspace /Pattern exch 2 array astore } if } if } bind executeonly def currentdict end readonly def /cssubst { % cssubst true % cssubst false dup resolvecolorspace dup 1 index ne { exch pop //true } { pop pop //false } ifelse } bind executeonly def /csnames mark /DeviceGray dup /DeviceRGB dup /DeviceCMYK dup /Pattern dup .dicttomark readonly def /csresolve { % csresolve | dup type /nametype ne { (\n **** Error: CS/cs (setcolorspace) operand not a name: ) pdfformaterror dup stderrfile dup 3 -1 roll write==only flushfile ( ****\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror dup type /arraytype eq { % Adobe InDesign + PDF Library has array resolvecolorspace } if //true } { dup Page /ColorSpace rget { exch pop resolvecolorspace //true } { //csnames 1 index known { //true } { ( **** Error: Undefined space resource: /) exch .namestring concatstrings (\n) concatstrings pdfformaterror ( Output may be incorrect.\n) pdfformaterror //false } ifelse } ifelse } ifelse } bind executeonly def /resolvecolorspace { % resolvecolorspace dup type /dicttype eq { dup /N known { ( **** ICCBased color space is a bare stream dictionary\n) pdfformatwarning [ /ICCBased 3 -1 roll ] ICCBased-resolve exec //false } { dup /ColorSpace knownoget { ( **** Error: unrecognised color space <>\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror exch pop //true } { //true } ifelse } ifelse } { //true } ifelse { dup dup type /arraytype eq { 0 get } if dup type /packedarraytype eq {exch pop exec dup} if //csrdict exch .knownget { exec dup type /nametype ne { dup length 1 eq { 0 get } if } if } { dup type /nametype eq { csresolve not { /DeviceRGB } if % Arbitrary } { csset exch pop } ifelse } ifelse } if } bind executeonly def /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 } bind executeonly def %% Bug #696017 When we begin a text block, we switch to a special set of marking operations %% for paths, these ops don't use the current CTM, but the 'SavedTextMatrix', in order to %% correctly position marks which are illegally present inside a text block. But, if we are %% executing a PaintProc (eg for a pattern) we *don't* want to do that or the pattern will be wrong. %% So we moved the .pdfpaintproc to .actual_pdfpaintproc, and redefined .pdfpaintproc to test %% the current value of /m. We always switch to the regular marking operations, but if the definition %% of /m at the start of the PaintProc was a special text version, then we switch back to that after we %% finished running the PaintProc. /.actual_pdfpaintproc { % .pdfpaintproc - % Check the object number of the pattern, from the pattern dictionary. Somehow % there is a means to get here with no object number set, I have no idea how % but this solves the immediate problem. Hopefully good enough until we drop % this code. Fixes bug #704487 which is recursion caused by a pattern % referenced via resolving a name from a Page as it is not defined in the Form % which uses it. 1 index /.gs.pdfobj# known { 1 index /.gs.pdfobj# get } { 0 } ifelse 3 1 roll NestedPatterns 3 index known 3 index 0 ne and { PDFSTOPONERROR not { ( **** Error: Attempting to run a Pattern while already executing that Pattern.\n Ignoring this pattern, output may be incorrect.\n) pdfformaterror pop pop pop } { /PaintProc cvx /circular_reference signalerror } ifelse } { % Store the currnet object number in the dictionary just so we can find it later. NestedPatterns 3 index null put 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. % Not true since moving the ExtGState parameters into the gstate. % //null sc1 //null SC1 } ifelse % Save old values on opstack, set pdfemptycount to new value. pdfemptycount countdictstack mark %% We can't simply 'def' into the dictionary saved by 'q' above, we need to %% call gput to copy it and store inside it. Stupid or what.... /pdfemptycount count 3 sub gput 5 3 roll % % Stack: ... mark % | % New empty count points here -----------+ exch //false resolvestream pdfopdict .pdfruncontext cleartomark //false { countdictstack 2 index le { exit } if currentdict /n known not or currentdict /n known currentdict /self known or{ Q }{ (\n **** Error: File has unbalanced q/Q operators \(too many Q's\)\n Output may be incorrect.\n) //pdfdict /.Qqwarning_issued .knownget { { pop } { currentglobal //pdfdict gcheck .setglobal //pdfdict /.Qqwarning_issued //true .forceput .setglobal pdfformaterror } executeonly ifelse } executeonly { currentglobal //pdfdict gcheck .setglobal //pdfdict /.Qqwarning_issued //true .forceput .setglobal pdfformaterror } executeonly ifelse end } executeonly ifelse } executeonly loop { (\n **** Error: File has unbalanced q/Q operators \(too many q's\)\n Output may be incorrect.\n) //pdfdict /.Qqwarning_issued .knownget { { pop } { currentglobal //pdfdict gcheck .setglobal //pdfdict /.Qqwarning_issued //true .forceput .setglobal pdfformaterror } executeonly ifelse } executeonly { currentglobal //pdfdict gcheck .setglobal //pdfdict /.Qqwarning_issued //true .forceput .setglobal pdfformaterror } executeonly ifelse } executeonly if pop % restore pdfemptycount /pdfemptycount exch def Q PDFDEBUG { //pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%End PaintProc) print dup === flush } if } if PDFfile exch setfileposition NestedPatterns exch undef }ifelse } bind executeonly odef /.pdfpaintproc { % Copy the pattern dictionary, we need it to rewind the /File if it is a file % rather than a string, after we've run .actual_pdfpaintproc. If we don't reset % the file position then if we try to run the PaintProc again we will already be % at EOF and nothing will be executed. 1 index 3 1 roll %% Get the /m from pdfopdict (must be present) %% and check its a packedarray pdfopdict /m get dup type /packedarraytype eq { %% The non-text version of /m is executeonly, so if we can't read it, its not a text block. dup rcheck { %% get the initial element of the packedarray %% and check its a name 0 get dup type /nametype eq { %% If the name is inside_text_m then we are in a text block /inside_text_m eq }{ pop //false } ifelse }{ pop //false } ifelse }{ pop //false } ifelse %% rearrange the operands, move the boolean to the back 3 1 roll %% Unconditionally use the normal marking ops switch_to_normal_marking_ops .actual_pdfpaintproc %% If we were in a text block, restore the text marking ops. { switch_to_text_marking_ops } if % If the pattern dictionary has a /File (it should always but let's be safe) % *and* the /File is a file object, not a string, then we need to set the % position of that file (it's a subfiledecode filter) back to 0 so we can % run the PaintProc again, should we need to. % cf bug #704388 /File .knownget { dup type /filetype eq { 0 setfileposition } { pop } ifelse } if }bind executeonly odef /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 /BBox 2 copy knownoget { normrect FixPatternBBox put } { pop pop } ifelse dup /.pattern_uses_transparency 1 index patternusestransparency put % Regardless of whether we are using transparency, if we are doing Overprint % simulation we still need to have the pattern code push the pdf14 compositor. % We consider we are doing overprint simulation if: % The current page device has /Overprint set to /simulate % The current page device does NOT contain PageSpotColors (spot-capable devices can overprint) % The current page device has a /PageUsesOverprint key (set by the interpreter) and it is set to true % If all these conditions are true then we set /.pattern_uses_transparency, otherwise we leave it % untouched as set above. % currentpagedevice dup /Overprint get /simulate eq 1 index /PageSpotColors known not and exch /PageUsesOverprint .knownget not { //false } if and { dup /.pattern_uses_transparency //true put } if PDFDEBUG { //pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Pattern: ) print dup === flush } if } if } bind executeonly def /ignore_color_op ( **** Error: Ignoring a color operation in a cached context.\n Output may be incorrect.\n) readonly def drawopdict begin /g { .incachedevice { % Bug 689302 pop //ignore_color_op pdfformaterror } { /DeviceGray cssubst { cs sc1 } { g } ifelse } ifelse } bind executeonly def /rg { .incachedevice { pop pop pop //ignore_color_op pdfformaterror } { /DeviceRGB cssubst { cs sc* } { rg } ifelse } ifelse } bind executeonly def /k { .incachedevice { pop pop pop pop //ignore_color_op pdfformaterror } { k } ifelse } bind executeonly def /cs { .incachedevice { pop //ignore_color_op pdfformaterror } { csresolve { cs } if } ifelse } bind executeonly def /sc { .incachedevice { .pdfcount { pop } repeat //ignore_color_op pdfformaterror } { scresolve 1 index //null eq { pop pop //ignore_color_op pdfformaterror } { { sc*_and_set } { sc1_and_set } ifelse } ifelse } ifelse } bind executeonly def /scn /sc load def /G { .incachedevice { pop //ignore_color_op pdfformaterror } { /DeviceGray cssubst { CS SC1 } { G } ifelse } ifelse } bind executeonly def /RG { .incachedevice { pop pop pop //ignore_color_op pdfformaterror } { /DeviceRGB cssubst { CS SC* } { RG } ifelse } ifelse } bind executeonly def /K { .incachedevice { pop pop pop pop //ignore_color_op pdfformaterror } { K } ifelse } bind executeonly def /CS { .incachedevice { pop //ignore_color_op pdfformaterror } { csresolve { CS } if } ifelse } bind executeonly def /ri { .incachedevice { pop //ignore_color_op pdfformaterror } { ri } ifelse } bind executeonly def /SC { .incachedevice { .pdfcount { pop } repeat //ignore_color_op pdfformaterror } { scresolve 1 index //null eq { pop pop //ignore_color_op pdfformaterror }{ { SC*_and_set } { SC1_and_set } ifelse }ifelse } ifelse } bind executeonly def /SCN /SC load def end currentdict /ignore_color_op undef % ---------------- Paths ---------------- % drawopdict begin % Path construction /m { { moveto } stopped { count pdfemptycount sub 2 .min { pop } repeat 0 0 moveto } if } bind executeonly def /l { { lineto } stopped { count pdfemptycount sub 2 .min { pop } repeat } if } bind executeonly def /c { { curveto } stopped { count pdfemptycount sub 6 .min { pop } repeat } if } bind executeonly def /v { count pdfemptycount sub 4 ge { { currentpoint 6 2 roll curveto } stopped { count pdfemptycount sub 6 .min { pop } repeat } if } { count pdfemptycount sub { pop } repeat } ifelse } bind executeonly def /y { { 2 copy curveto } stopped { count pdfemptycount sub 6 .min { pop } repeat } if } bind executeonly def /re { 4 2 roll moveto exch dup 0 rlineto 0 3 -1 roll rlineto neg 0 rlineto closepath } bind executeonly def /h { closepath } bind 0 get def % Path painting and clipping /n { n } executeonly def /S { S } executeonly def /s { s } executeonly def /f { f } executeonly def /f* { f* } executeonly def /B { B } executeonly def /b { b } executeonly def /B* { B* } executeonly def /b* { b* } executeonly def /W { W } executeonly def /W* { W* } executeonly def /sh_save 1 array def /do_shade { 0 .setoverprintmode { dup /.shading .knownget { exch pop } { .buildshading_and_shfill } ifelse } stopped { pop ( **** Error: Ignoring invalid smooth shading object, output may be incorrect.\n) pdfformaterror } if } bind executeonly def /sh { OFFlevels length 0 eq { setsmaskstate resolvesh //sh_save 0 save put PDFusingtransparency { gsave dup /BBox knownoget { { oforce } forall 4 2 roll moveto exch 0 lineto 0 exch lineto closepath } { clippath } ifelse % If we get an error, just emit an empty box { pathbbox } stopped { 0 0 0 0 } if 4 array astore grestore //null setup_trans //do_shade exec teardown_trans } { //do_shade exec } ifelse //sh_save 0 get restore } { pop } ifelse } bind executeonly def currentdict dup /sh_save undef /sh_group undef end % ---------------- XObjects ---------------- % /xobjectprocs mark % -proc- - /Image { DoImage } executeonly /Form { DoForm } executeonly /PS { DoPS } executeonly .dicttomark readonly def % Note that the keys in defaultdecodedict are resolved (PostScript, not PDF) % color space names. /defaultdecodedict mark /DeviceGray { pop //01_1 } bind executeonly /DeviceRGB { pop //01_3 } bind executeonly /DeviceCMYK { pop //01_4 } bind executeonly /CIEBasedA { 1 get /RangeA knownoget not { //01_1 } if } bind executeonly /CIEBasedABC { 1 get /RangeABC knownoget not { //01_3 } if } bind executeonly /CalGray { pop //01_1 } bind executeonly /CalRGB { pop //01_3 } bind executeonly /Lab { 1 get /Range knownoget not { [-100 100 -100 100] } {aload pop 0 100 6 2 roll 6 array astore}ifelse } bind executeonly /ICCBased { 1 oget dup /Range knownoget { exch pop }{ /N get [ exch {0 1} repeat ] readonly } ifelse } bind executeonly /Separation { pop //01_1 } bind executeonly /DeviceN { 1 oget length [ exch {0 1} repeat ] readonly } bind executeonly /Indexed { pop [ 0 1 BitsPerComponent bitshift 1 sub ] } bind executeonly .dicttomark readonly def /checkaltimage { % checkaltimage Printed { dup /Alternates knownoget { { dup /DefaultForPrinting knownoget { { /Image oget exch pop exit } { pop } ifelse } { pop } ifelse } forall } if } if } bind executeonly def % getu16 /getu16 { 2 copy get 8 bitshift 3 1 roll 1 add get add } bind executeonly def % getu32 /getu32 { 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add } bind executeonly def /jp2_csp_dict mark 12 { /DeviceCMYK } % CMYK 14 { [ /Lab << /WhitePoint [ 0.9505 1 1.0890 ] readonly >> ] } % LAB, WhitePoint == D65 16 { /sRGBICC /ColorSpace findresource } bind executeonly 17 { /sGrayICC /ColorSpace findresource } bind executeonly 18 3 index % YCC is converted to RGB % 19 % CIEJab not supportec by PDF 1.7 20 { /esRGBICC /ColorSpace findresource } bind executeonly % e-sRGB 21 { /rommRGBICC /ColorSpace findresource} bind executeonly % ROMMRGB 24 { /esRGBICC /ColorSpace findresource } bind executeonly % e-sYCC .dicttomark readonly def % Process jp2 blocks (aka boxes). All procedures have the signature % -> ... /jp2_tag_dict 10 dict begin /jp2h { % descend into a sub-stream, don't return. () /SubFileDecode filter 0 } bind executeonly def /ihdr { 14 sub % file len-14 1 index (1234567890abcd) readstring pop % file len-14 (14) /JPXComponents 1 index 8 getu16 % file len-14 (14) /JPXComponents NC def % file len-14 (14) 10 get %% If the BPC is 255 then each component has variable depth %% we can't handle this, but JasPer is known to produce %% images whcih declare this, but are actually all equal, we cater %% for that in the bpcc box below. dup 16#FF eq not { 16#7F and 1 add dup 12 eq { pop 16 } if /BitsPerComponent exch def % file len-14 } {pop} ifelse } bind executeonly def %% if the ihdr has a BPC of 255 then we get a bpcc box which %% gives the bpc for each component individually. We cannot %% actually deal with differing component depths, but it %% seems JasPer produces images with this box where all the %% component depths are in fact the same. /bpcc { JPXComponents sub 1 index JPXComponents string readstring pop dup 0 get /BitsPerComponent exch def 1 1 JPXComponents 1 sub { 1 index exch get BitsPerComponent eq not { ( **** Error: JPX image colour channels do not all have the same colour depth\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } if } for pop /BitsPerComponent BitsPerComponent 1 add def } bind executeonly def /colr { currentdict /ColorSpace known not { 3 sub 1 index (123) readstring pop % file len-3 (3) 0 get dup 1 eq { pop 4 sub % file len-7 1 index (1234) readstring pop % file len-16 (4) 0 getu32 % file len-16 enum //jp2_csp_dict exch .knownget { exec /ColorSpace exch def % file len-7 } { ( **** Error: Unknown enumerated color space in JPX stream.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } { dup 2 eq exch 3 eq or { 1 index exch () /SubFileDecode filter /ReusableStreamDecode filter /JPXICC exch def 0 % file 0 } { ( **** Error: Unknown color space method in JPX stream.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } ifelse } if } bind executeonly def % Palette colors are decoded by the library. /pclr { 4 sub 1 index (1234) readstring pop 3 get 16#7F and 1 add /BitsPerComponent exch def } bind executeonly def /cdef { pop dup (12) readstring pop 0 getu16 { dup (123456) readstring pop 2 getu16 dup 3 lt { { /JPXColors /JPXOpacity /JPXPremult } exch get currentdict 1 index .knownget { 1 add } { 1 } ifelse def } { pop } ifelse } repeat 0 } bind executeonly def currentdict end 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 //== exec % 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 executeonly def currentdict /jp2_tag_dict .undef currentdict /jp2_csp_dict .undef % Add a key-value pair to the last /DecodeParms dictionary % Copy the objects to avoid spoiling shared ones. % -> /add-to-last-param { 2 index /DecodeParms knownoget { dup type /dicttype ne 1 index type /arrratype ne and 1 index length 1 lt or { pop //false } { //true } ifelse } { //false } ifelse { dup type /arraytype eq { [ exch { oforce } forall dup //null eq { pop 1 dict } if ] dup dup length 1 sub get % [] <<>> } { dup length 1 add dict copy dup % <<>> <<>> } ifelse 4 2 roll put % obj } { % mark 3 1 roll .dicttomark % obj 1 index /Filter knownoget { dup type /arraytype eq { length array % obj [...] dup dup length 1 sub % obj [...] [...] len-1 4 -1 roll put % [... obj] } { pop } ifelse } if } ifelse 1 index exch /DecodeParms exch put % } bind executeonly def % Add a key-value pair to the all the /DecodeParms % dictionaries (i.e. handle the array) % Copy the objects to avoid spoiling shared ones. % -> /add-to-all-params { 1 index % /Filter knownoget { % dup type /arraytype eq { length % dup 0 gt { 2 index /DecodeParms knownoget { oforce_recursive % resolve indirect references exch pop % [array] [ exch { dup type /dicttype eq { mark exch {} forall .dicttomark } { pop 1 dict } ifelse } forall ] % [array] } { % % create an array of dictionaries [ 0 1 4 -1 roll 1 sub { pop 1 dict } for ] % [array] } ifelse dup % [array] [array] { % [array] [dict] 2 index % [array] [dict] { % [array] [dict] 2 index % [array] [dict] [dict] 3 1 roll put } forall pop } forall % [array] exch pop % [dict/array] 1 index exch /DecodeParms exch put } { pop pop } ifelse } { % pop 1 index /DecodeParms knownoget { oforce_recursive dup type /dicttype eq { mark exch {} forall .dicttomark } { pop 1 dict } ifelse } { 1 dict } ifelse % [dict] 1 index % [dict] { % [dict] 2 index 3 1 roll put } forall exch pop % [dict/array] 1 index exch /DecodeParms exch put } ifelse } {pop} ifelse } bind def /last-ditch-bpc-csp { currentdict /BitsPerComponent oknown not { ( **** Error: image has no /BitsPerComponent key; assuming 8 bit.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror /BitsPerComponent 8 def } if currentdict /ColorSpace knownoget not { dup /ColorSpace knownoget not { ( **** Error: image has no /ColorSpace key; assuming /DeviceRGB.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror /DeviceRGB } if } if resolvecolorspace %% This section is to deal with the horrible pair of files in Bug #696690 and Bug #696120 %% These files have ICCBased spaces where the value of /N and the number of components %% in the profile differ. In addition the profile in Bug #696690 is invalid. In the %% case of Bug #696690 the /N value is correct, and the profile is wrong, in the case %% of Bug #696120 the /N value is incorrect and the profile is correct. %% We 'suspect' that Acrobat uses the fact that Bug #696120 is a pure image to detect %% that the /N is incorrect, we can't be sure whether it uses the profile or just uses %% the /N to decide on a device space. What we now do is; If the /N and device profile %% number of components don't match, we assume the device profile is correct and patch %% /N to be the same as the profile (see /ICCBased-resolve), but we save the original %% value of /N in /OrigN. In setcolor, if the space is a genuine ICCBased space %% (not a replacement for a device profile) we call set_dev_color which will actually %% exercise the profile. If that fails we return an error. Here we run setcolor in a %% stopped context, and if it fails we check to see if there is a /OrigN (ths occurs %% only if the /N was different to the number of components in the profile). If there %% is a /OrigN then prefer that to the profile, otherwise they agreed, so just use %% /N and select a device space. If we can't select a device space with the correct %% number of components, give up and throw an error. See also 'Cdict' in pdf_ops.ps. dup type /arraytype eq { dup 0 get /ICCBased eq { gsave dup setcolorspace dup 1 get /N get 1 sub mark exch 0 1 3 -1 roll {pop 0} for {setcolor} stopped grestore { cleartomark 1 get dup /OrigN .knownget {exch pop}{/N get} ifelse [//null /DeviceGray //null /DeviceRGB /DeviceCMYK] exch {get} stopped { ( **** Error: Unable to set an ICCBased colour space, and cannot set an alternate from the number of components.\n) print /setcolorspace cvx /undefined signalerror } { dup //null eq { ( **** Error: Unable to set an ICCBased colour space, and cannot set an alternate from the number of components.\n) print /setcolorspace cvx /undefined signalerror }{ ICCProfileNError not { ( **** Warning : Error setting an ICCBased colour space, using /N to set an alternate device space.\n) print ( Output may be incorrect.\n) print } if } ifelse }ifelse /ICCProfileNError //true def }{cleartomark}ifelse } if } if /ColorSpace exch def } bind executeonly def /get-smask-in-data { % -> /SMaskInData knownoget { dup dup 1 ne exch 2 ne and { pop 0 } if } { 0 } ifelse } bind executeonly def /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 { cvi def } { pop } ifelse /Interpolate 2 copy knownoget { def } { pop } ifelse makeimagekeys } bind executeonly def /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 %% If the image has a rendering intent, get its numeric equivalent %% from renderingintentdict, and save it in the dictionary we pass %% on to render images. dup /Intent knownoget { //.renderingintentdict exch .knownget { /Intent exch def } if } if 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). % Bug 701083: We add a /ErrsAsEOD key to the DecodeParms here too. <> //add-to-all-params exec //false resolvestream /DataSource exch def //true } { % Opaque image dup /Filter knownoget { dup type /arraytype eq { dup length dup 0 gt { 1 sub get oforce } { pop } ifelse } if /JPXDecode eq } { //false } ifelse { % /JPXDecode tricks % Previously we only ran the code to extract the Color Space and Bits Per Component % from the JOX stream if the image dict had either BPC or ColorSpace undefined. % However, while this is correct for the ColorSpace, its *not* correct for the BPC. % According to the spec we should ignore any BPC in the image dicitonary and % always use the BPC from the JPX stream. % Now the code in get_jp2_csp always overwrites the ColorSpace (in the image resource dict) % which technically is fine, because the image dictionary entry must be either not present or the % same as the JPX stream. However, this doesn't work, so instead we just save the existing % color space (if any). Then after extracting the color space and BPC from the JPX stream % we put back the saved color space, but only if there was one previously. dup /ColorSpace oknown { dup dup /ColorSpace get /ImageDictColorSpace exch put } if dup /IDFlag known { ( **** Warning: PDF spec bans inline JPX images.\n) pdfformatwarning % 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 /DecodeParms knownoget { dup type /arraytype eq { dup length 1 gt { dup length 1 sub 0 exch getinterval 1 index exch /DecodeParms exch put } { pop dup /DecodeParms undef } ifelse } { pop dup /DecodeParms undef } ifelse } if } { pop dup /Filter undef dup /DecodeParms undef } ifelse } { pop dup /Filter undef dup /DecodeParms undef } ifelse //false resolvestream get_jp2_csp currentdict /ColorSpace oknown not { currentdict /JPXICC .knownget { [ /ICCBased mark /DataSource 5 -1 roll /N currentdict /JPXColors .knownget not { currentdict /JPXComponents get } if .dicttomark ] /ColorSpace exch def } if } if { /JPXICC /JPXColors /JPXComponents /JPXOpacity /JPXPremult } { currentdict exch undef } forall } ifelse % If we had a Color Space in the image dictionary before we read the JPX % stream, put it back now. We mujst do this before last-ditch-bpc-csp % because that resolves any indirect references to the color space. dup /ImageDictColorSpace known { dup /ImageDictColorSpace get currentdict /ColorSpace 3 -1 roll put } if //last-ditch-bpc-csp exec dup /ColorSpace oknown { % Propagate known color space to the filter /ColorSpace currentdict /ColorSpace get //add-to-last-param exec } if /Decode 2 copy knownoget not { ColorSpace //defaultdecodedict ColorSpace dup type /arraytype eq { 0 get } if get exec } if def dup get-smask-in-data dup 0 ne { PDFusingtransparency { currentdict dup length dict copy begin {/Mask/SMask/SMaskInData/Name} { currentdict exch undef } forall 2 eq { /Matte [ Decode length 2 idiv { 0 } repeat ] def } if /Decode //01_1 def /ColorSpace /DeviceGray def {/File /FilePosition /Filter /Length /DecodeParms /FFilter /FDecodeParms } { 2 copy knownoget { def } { pop } ifelse } forall currentdict /Alpha //true //add-to-last-param exec pop /SMask currentdict end def } { pop } ifelse } { pop } ifelse } { % not JPX image //last-ditch-bpc-csp exec /Decode 2 copy knownoget not { ColorSpace //defaultdecodedict ColorSpace dup type /arraytype eq { 0 get } if get exec } if def } ifelse % fi JPX tricks % Add a /Height key containing the image height to the DecodeParms % for any Filters we will apply. If there are no DecodeParms for any % filter, create one and add a /Height key. This is to solve the problem % in Bug #695116 where a JPEG image has a bad height, which is later % fixed up using a DNL marker. By placing the image height from the % PDF in the DecodeParms we can use it in the DCTDecode filter to % work around this. % Bug 701083: We add a /ErrsAsEOD key to the DecodeParms here too. << /Height 2 index /Height oget round cvi /ErrsAsEOD //true >> //add-to-all-params exec % 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 } bind executeonly def currentdict /add-to-last-param undef currentdict /add-to-all-params undef currentdict /last-ditch-bpc-csp undef /DoImage { %% Bug #696439. This is incredibly icky. When we find indirect obects we resolve them %% and store the resolved object in the containing object. This means that we retain %% the image dicionary here until the end of job. Potentially wasteful. Even worse though %% is the case where the image has a ColorSpace which is not an indirect object, but *is* %% an ICCBased colour space. In ths case we end up resolving the colour space and storing it %% here. Unfortunately, we use a ReusableStreamDecode filter on the ICC profile, which means %% we end up retaining the memory for that too. ICC profiles can be large, and if there are a %% lot of places where they get used, we can exhaust memory. %% Here we check if the ColorSpace is an array object, if it is we *copy* the image dictionary %% and use the copy instead. The copy is (eventually) discarded so we don't retain the ICC profile %% and don't exhaust memory. Note that we have to copy the actual colour space array too, copying %% the dictionary just copies the opriginal array as well. %% 1 dict begin /.ImageDictStackDepth countdictstack def /.ImageOpStackDepth count 2 sub def { dup /ColorSpace known { dup /ColorSpace get dup type /arraytype eq { exch dup length dict copy exch dup length array copy /ColorSpace exch 2 index 3 1 roll put } {pop} ifelse } if checkaltimage dup length 6 add dict % <> <<>> 1 index /SMask knownoget { % <> <<>> <> dup 3 index ne { % <> <<>> <> <> 1 index exch /SMask exch put } { pop ( **** Error: ignoring recursive /SMask attribute.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } if 1 index /Mask knownoget { dup type dup /dicttype eq exch /arraytype eq or { % Bug #703681 1 index exch /Mask exch put } { pop ( **** Error: Ignoring Mask attribute that is not an array or a dictionary.\n) pdfformaterror } ifelse } if makeimagedict doimagesmask } PDFSTOPONERROR {exec false}{stopped} ifelse { (\n **** Error: File encountered ') $error /errorname get dup length string cvs concatstrings (' error while processing an image.\n) concatstrings ( Output may be incorrect.\n) concatstrings pdfformaterror } if count .ImageOpStackDepth sub {pop} repeat countdictstack .ImageDictStackDepth sub {end} repeat end } bind executeonly def /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 { oforce_array //false 1 index { type /integertype ne or } forall { (\n **** Error: Some elements of Mask array are not integers.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror [ exch { 0.5 add cvi } forall ] % following AR4, 5, 6 implementation } if } if % Check elements of array are within 0::(2**BitsPerComponent)-1 % This is a PostScript error, but AR tries to fix the Mask. 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 { ( **** Error: Some elements of Mask array are out of range.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror ColorSpace dup type /arraytype eq { 0 oget } if /Indexed eq BitsPerComponent 1 eq and { % AR9 treats Indexed 1 bpc images specially. Bug 692852 see also 697919 and 689717. dup 0 oget dup 0 lt exch 1 BitsPerComponent bitshift ge or { % First component is invalid - AR9 ignores the mask pop //null } { % Second component is invalid; AR9 replaces it with 1. [ exch 0 oget 1 ] } ifelse } { BitsPerComponent 1 eq { dup length 2 gt { % There are too many Mask entries, discard the Mask array pop //null }{ % Bug 701468 and 689717, the latter requires us to set the Mask values % so that the value is calculated from the BPC, the other requires us % to ignore the Mask. The only difference between the two files is the % actual range of the Mask values. This may yet need more work. % Note! Both files are technically invalid.... aload 3 1 roll eq { % There's only one Mask value, but its illegal, substitute with the % calculated maximum. [ exch { 1 BitsPerComponent bitshift 1 sub and } forall ] } { % The Mask values are not the same. This is a 2 colour image, if % we mask off any range then the result will be blank, so ignore the Mask pop //null } ifelse } ifelse } { % We think AR5, AR9 do this for most other cases. Originally Bug 690786, % but that is actually handled in the /Indexed case above. [ exch { 1 BitsPerComponent bitshift 1 sub and } forall ] } ifelse } ifelse } if dup //null ne { /MaskColor exch def } { pop /ImageType 1 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} stopped {pop} if 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 } bind executeonly def /doimagesmask { % doimagesmask - PDFusingtransparency not /PreserveSMask /GetDeviceParam .special_op { exch pop } { //false } ifelse or { % not using transparency OR the device supports SMask (e.g. pdfwrite) doimage } { currentdict /SMask knownoget { % We are doing transparency and SMask is present in the image % stack: % Normalize /Matte attribute for .begintransparencymaskimage dup /Matte .knownget { oforce dup //null eq { pop dup /Matte undef } { 1 index /Matte [ 4 -1 roll { oforce } forall ] put } ifelse } if .begintransparencymaskimage PDFfile fileposition exch gsave //nodict begin //null .setSMask 1 CA 1 ca /Compatible .setblendmode DoImage end grestore PDFfile exch setfileposition 0 .endtransparencymask << /Subtype /Group /Isolated //true /.image_with_SMask //true % pdfwrite needs : see gs/src/ztrans.c, gs/src/gdevpdft.c % Code to deal with a Matte in the SMask. We know the image dictionary must have an SMask % entry if we get here, so we don't need to check its existence. Just pull it out and see if % the SMask has a Matte entry. If it does, get the ColorSpace from the parent image and % put a /CS key with that colour space in the Group that we manufacture. Bug #700686 % We also need to actually set the current colour space to be the same as the group % code only picks up the current colour space, not the space from the dictionary. currentdict /SMask get /Matte known {/CS currentdict /ColorSpace get dup pdfopdict /cs get exec } if >> 0 0 1 1 gsave 1 1 moveto 0 0 lineto % If we get an error, just emit an empty box { pathbbox } stopped { 0 0 0 0 } if 4 array astore grestore /image setup_trans .begintransparencygroup .currentstrokeconstantalpha .currentfillconstantalpha 3 -1 roll 1 .setfillconstantalpha 1 .setstrokeconstantalpha doimage .setfillconstantalpha .setstrokeconstantalpha .endtransparencygroup % tell the compositor we're done with the SMask. % Note that any SMask in the ExtGState should be reapplied % by the next call to setfill(stroke)state AND this relies % on our lazy evaulation of SMask groups //false << /Subtype /None >> 0 0 0 0 .begintransparencymaskgroup } { % We don't have an SMask in the image but there might be an SMask in the ExtGState .currentSMask //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 .currentstrokeconstantalpha .currentfillconstantalpha 3 -1 roll 1 .setfillconstantalpha 1 .setstrokeconstantalpha doimage .setfillconstantalpha .setstrokeconstantalpha .endtransparencygroup } { doimage } ifelse } ifelse } ifelse } bind executeonly 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 { /doimagesmask { % doimagesmask - doimage } bind executeonly def } if /ValidateDecode { % <> -imagemask- ValidateDecode <> exch dup /Decode .knownget { dup length % -imagemask- <> [Decode] length 4 -1 roll % <> [Decode] length -imagemask- { 1 % ImageMask Decode arrays must be [0 1] or [1 0] } { mark currentcolor counttomark % <> [Decode] length [ ... component_count dup 2 add 1 roll % <> [Decode] length component_count [ .... cleartomark % <> [Decode] length component_count } ifelse 2 mul dup % <> [Decode] length comp_count*2 comp_count*2 3 1 roll % <> [Decode] comp_count*2 length comp_count*2 eq { % <> length of Decode matches colour space requirement pop pop % <> remove [Decode] and comp_count*2 }{ % <> Decode array incorrect dup 2 index length % <> [Decode] comp_count*2 comp_count*2 length exch sub 0 gt { % Decode is too long (\n **** Warning: Decode array for an image is too long\n) pdfformatwarning ( Output may be incorrect.\n) pdfformatwarning 0 exch % <> [Decode] 0 comp_count*2 getinterval % <> [subarray of Decode] 1 index exch /Decode exch % <> <> /Decode [subarray] put % <> }{ % Decode is too short, Acrobat throws errors on this (\n **** ERROR: Decode array for an image is too short\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror pop pop % remove [Decode] and comp_count*2 } ifelse } ifelse } { exch pop }ifelse }bind executeonly def /doimage { % doimage - % imagedict is currentdict, gets popped from dstack %% We must save the colour space, in case it gets changed. I did try doing this %% at a higher level (/Do) but that caused numerous problems with pdfwrite. currentcolorspace exch %% save the current rendering intent .currentrenderintent exch %% Check the image dictionary to see if there is a /Intent currentdict /Intent known { %% and set the current rendering intent to match if so Intent .setrenderingintent } if DataSource exch currentdict /SMask known PDFusingtransparency and { /PreserveSMask /GetDeviceParam .special_op { pop pop currentdict /SMask oget makesoftmaskimage } if } if currentdict /Mask knownoget { makemaskimage } if % Stack: datasource imagemask { currentdict end setsmaskstate //true ValidateDecode { imagemask } } { ColorSpace setgcolorspace currentdict end setsmaskstate //false ValidateDecode { image } } ifelse PDFSTOPONERROR { exec //false } { stopped } ifelse { dup type /dicttype eq { pop } if % Sometimes image fails to restore the stack $error /errorname get dup /ioerror eq { pop (\n **** Error: File has insufficient data for an image.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } { (\n **** Error: File encountered ') exch 40 string cvs concatstrings (' error while processing an image.\n) concatstrings pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } if % Close the input stream, unless it is PDFfile or % PDFsource. dup dup PDFfile eq exch PDFsource eq or { pop } { closefile } ifelse %% restore the rendering intent .setrenderingintent %% and restore the colour space. We need to do this in a stopped context because %% if we are rendering a glyph, the cache device will throw an error if we try %% to change colour space (even when the new space is the same as the old space) %% We can't tell if we are rendering a bitmap for a glyph, and its hard to compare %% colour spaces, so just ignore errors for now. {setcolorspace} stopped {pop} if teardown_trans } bind executeonly def /.paintform { % .paintform - 1 index /FormResDict gput % For broken forms that inherit resources from the context. 3 -1 roll dup /Group oknown PDFusingtransparency and { .paintgroupform } { pop pdfopdict .pdfruncontext } ifelse } bind executeonly def /IncrementAppearanceNumber { //pdfdict /AppearanceNumber .knownget { 1 add //pdfdict /AppearanceNumber 3 -1 roll .forceput } executeonly { //pdfdict /AppearanceNumber 0 .forceput } executeonly ifelse }bind executeonly odef /MakeAppearanceName { //pdfdict /AppearanceNumber get 10 string cvs dup length 10 add string dup 0 (\{FormName) putinterval dup 3 -1 roll 9 exch putinterval dup dup length 1 sub (\}) putinterval } bind executeonly def /MakeNewAppearanceName { IncrementAppearanceNumber MakeAppearanceName }bind executeonly def /DoAppearance { %% Might need to rethink this. The problem is that if the page has a CropBox, we apply %% that as an initial clip. When we run the form, we don't apply the /Rect from the %% annotation, which means that the form could be out of the clip, which results in %% content going missing. Resetting the clip prevents this. gsave initclip MakeNewAppearanceName .pdfFormName //pdfdict /.PreservePDFForm known {//pdfdict /.PreservePDFForm get} {//false}ifelse exch //pdfdict /.PreservePDFForm //true .forceput DoForm //pdfdict /.PreservePDFForm 3 -1 roll .forceput grestore } bind executeonly odef %% We don't want to do any high level forms stuff if the source %% is PDF because : %% 1) Transparent forms are handled separately and we don't want to ge confused %% 2) PDF forms are too llikely to trip over the limitations in our support %% 3) Its highly unusual to find a PDF file which uses forms sensibly. %% %% So we have a special PDF version of execform which doesn't do high level forms. pdfdict /.PDFexecform { % This is a separate operator so that the stacks will be restored % properly if an error occurs. dup /Matrix get concat dup /BBox get aload pop exch 3 index sub exch 2 index sub rectclip dup /PaintProc get 1 index /Implementation known not { 1 index dup /Implementation //null .forceput readonly pop } executeonly if exec } .bind executeonly put pdfdict /PDFexecform { gsave { //.PDFexecform exec } stopped grestore {stop} if } .bind executeonly put /DoForm { %% save the current value, if its true we will set it to false later, in order %% to prevent us preserving Forms which are used *from* an annotation /Appearance. //pdfdict /.PreservePDFForm known {//pdfdict /.PreservePDFForm get} {//false}ifelse exch %% We may alter the Default* colour spaces, if the Resources %% ColorSpace entry contains one of them. But we don't want that %% to become the new default, we want to revert to any existing %% definition, or the Device space. The Default* spaces are defined %% as ColorSpace resources, so the only way to handle them is to %% save and restore round the definitions 3 dict dup begin /saved_DG /DefaultGray /ColorSpace findresource def /saved_DRGB /DefaultRGB /ColorSpace findresource def /saved_DCMYK /DefaultCMYK /ColorSpace findresource def end exch % 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 } { 0 1 Matrix length 1 sub { dup Matrix exch get type dup /integertype eq exch /realtype eq or not { (\n **** Error: Invalid element in /Form XObject matrix.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror Matrix exch 0.00 put } { pop } ifelse } for } ifelse currentdict /BBox known not { (\n **** Error: Required entry /BBox not present in Form.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror /BBox [0 1 0 1] } if currentdict end { oforce } forall >> dup [ 2 index /Resources knownoget { oforce } { 0 dict } ifelse %% Ugly hackery for Default* colour spaces in forms %% dup /ColorSpace knownoget { oforce { //false 3 1 roll exch dup /DefaultGray eq { pop exec resolvecolorspace dup csncomp 1 eq { dup type /nametype eq { 1 array astore } if /DefaultGray exch /ColorSpace defineresource pop pop //true }{ pop ( **** Error: ignoring invalid /DefaultGray color space.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse }{ dup /DefaultRGB eq { pop exec resolvecolorspace dup csncomp 3 eq { dup type /nametype eq { 1 array astore } if /DefaultRGB exch /ColorSpace defineresource pop pop //true }{ pop ( **** Error: ignoring invalid /DefaultRGB color space in Form Resources.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse }{ /DefaultCMYK eq { exec resolvecolorspace dup csncomp 4 eq { dup type /nametype eq { 1 array astore } if /DefaultCMYK exch /ColorSpace defineresource pop pop //true }{ pop ( **** Error: ignoring invalid /DefaultCMYK color space in Form Resources.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse }{ pop } ifelse } ifelse }ifelse { % if using color space substitution, "transition" the current color space currentcolorspace dup length 1 eq { % always an array 0 get dup /DeviceGray eq 1 index /DeviceRGB eq or 1 index /DeviceCMYK eq or { /Pattern setcolorspace setcolorspace } { pop } ifelse } { pop } ifelse } if } forall } if 3 index % /Contents for the stream is not per the spec, but Acrobat handles it dup /Contents knownoget { % We want to make it's a dictionary, and represents a stream dup type /dicttype eq { dup /FilePosition known { PDFSTOPONERROR { /DoForm cvx /undefinedresource signalerror } if ( **** Error: Invalid Form definition. Output may be incorrect.\n) pdfformaterror exch pop } {pop} ifelse } { pop } ifelse }if //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 4 sub store //pdfdict /.PreservePDFForm known {//pdfdict /.PreservePDFForm get}{//false} ifelse { %% We must *not* preserve any subsidiary forms (curently at least) as PDF %% form preservation doesn't really work. This is used just for Annotation %% Appearances currently, and if they should happen to use a form, we do not %% want to preserve it. //pdfdict /.PreservePDFForm //false .forceput /q cvx /execform cvx 5 -2 roll } executeonly { /q cvx /PDFexecform cvx 5 -2 roll } ifelse 4 .execn % Restore pdfemptycount 0 { countdictstack 2 index le { exit } if currentdict /n known not { 1 add } if countdictstack Q countdictstack eq {end} if } loop 1 gt { ( **** Error: Form stream has unbalanced q/Q operators \(too many q's\)\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } if pop /pdfemptycount exch store % We've now seen Form XObjects leaving junk on the stack, so we % can't assume that when we finish the form the stack will be restored % nor can we assume that the junk won't include a 'mark' so we an't % simply do a cleartomark. Instead clear the stack until we get back % to a dictionary which contains /saved_DG. We can still get errors; % if the stream removes too many objects from the stack we will end % up with a stackunderflow, but there's nothing we can do about that. dup type /dicttype eq not { //true } { dup /saved_DG known { //false } { //true } ifelse } ifelse { ( **** Error: Form stream left garbage on the stack, attempting to recover.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror { dup type /dicttype eq not { pop } { dup /saved_DG known { exit } { pop } ifelse } ifelse } loop } if %% Put back pre-existing Default* ColorSpace definitions. dup type /dicttype eq { begin saved_DG /DefaultGray exch /ColorSpace defineresource pop saved_DRGB /DefaultRGB exch /ColorSpace defineresource pop saved_DCMYK /DefaultCMYK exch /ColorSpace defineresource pop end } if //pdfdict /.PreservePDFForm 3 -1 roll .forceput } bind executeonly odef /_dops_save 1 array def /DoPS { DOPS { //_dops_save 0 save put //true resolvestream cvx exec //_dops_save 0 get restore } { pop } ifelse } bind executeonly def currentdict /_dops_save undef /ocg_pocs 4 dict begin /AllOn { //true exch { oforce dup type /dicttype eq { /OFF known not and } { pop } ifelse } forall } bind executeonly def /AnyOn { //false exch { oforce dup type /dicttype eq { /OFF known not or } { pop } ifelse } forall } bind executeonly def /AnyOff { //AllOn exec not } bind executeonly def /AllOff { //AnyOn exec not } bind executeonly def 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 } { dup /OFF known not % OFF is inserted by process_trailer_attrs { %% /OC is not in the OCProperties /OFF array, so we need to %% test its usage. We may eventually have to add a /ON to the dictionary %% if the OCProperties /ON array defines the /OC, I think that should override % the Usage, but I don't have an example to test. /Usage .knownget { oforce /Printed where { /Printed get } { //false }ifelse { %% We are behaving as a printer, check the Print state /Print .knownget { oforce /PrintState .knownget { oforce /OFF eq { //false }{ //true } ifelse }{ //true } ifelse }{ %% If we don't know, assume its visible //true } ifelse }{ %% We are behaving as a viewer, check the View state /View .knownget { oforce /ViewState .knownget { oforce /OFF eq { //false }{ //true } ifelse }{ //true } ifelse }{ %% If we don't know, assume its visible //true } ifelse } ifelse }{ %% If we don't know, assume its visible //true } ifelse }{ pop //false }ifelse } ifelse } { /OFF known not % OFF is inserted by process_trailer_attrs } ifelse } bind executeonly def drawopdict begin /Do { % /Name %% Bug 695897 This file has nested text blocks and also a Do image inside %% a text block. Here we attempt to detect and recover from this by setting the %% CTM to the matrix we saved before the text block. NB we update the 'TextSaveMatrix' %% or 'qTextSaveMatrix' whenever a 'cm' is issued, even if we are in a text block, so %% these matrices 'ought' to be correct. %% Of course, the file is badly broken, but 'Acrobat can open it....' currentdict /TextSaveMatrix known { gsave ( **** Error: Executing Do inside a text block, attempting to recover\n) pdfformaterror currentdict /TextSaveMatrix get setmatrix ( Output may be incorrect.\n) pdfformaterror } if currentdict /qTextSaveMatrix known { gsave ( **** Error: Executing Do inside a text block, attempting to recover\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror currentdict /qTextSaveMatrix get setmatrix } if setsmaskstate PDFfile fileposition exch % pos /Name % Bug #698226, Acrobat signals an error for recursive XObjects in a PDF file % but continues. This is true even if the XObject is not a simple self-reference % (eg /Fm1 -> /Fm2 -> /Fm3 -> /Fm1). % Normally when dealing with recursion we would put a dictionary on the stack, store the % object numbers encoutnered in it, and check each new object number to see if we've % already seen it. This doesn't work well for XObjects, because the operand stack can be % in any state when we run a Do. So we make a new dictionary in pdfdict to hold the % object numbers. % We also don't usually know the object number of a Form, we just get given its name % so we need a new routine to return the object number. This is because the parent XObject % might reference teh object by one name, while the child references it by another, we % can't permit clashes. % % Start by getting the object number for a Form XObject dup Page /XObject obj_get dup 0 eq not { % Now get the recording dictionary and see if that object number has been seen //pdfdict /Recursive_XObject_D get 1 index known { ( **** Error: Recursive XObject detected, ignoring ") print 1 index 256 string cvs print (", object number ) print 256 string cvs print (\n) print ( Output may be incorrect.\n) pdfformaterror //false }{ % We haven't seen it yet, so record it. //pdfdict /Recursive_XObject_D get 1 index //null put 3 1 roll //true }ifelse } { % I don't think this should be possible, but just in case ( **** Error: Unable to determine object number for ) print exch 256 string cvs print ( so ignoring it) print ( Output may be incorrect.\n) pdfformaterror //false } ifelse % If we could get the object number, and we haven't already seen it, then execute it. { dup Page /XObject rget { exch pop % pos obj OFFlevels length 0 eq { dup /OC knownoget { ocg-is-visible } { //true } ifelse } { //false } ifelse { dup /Subtype oget //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. ( **** Error: Undefined XObject resource: ) exch =string cvs concatstrings (\n) concatstrings pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse PDFfile exch setfileposition //pdfdict /Recursive_XObject_D get exch undef }{ % Otherwise ignore it and tidy up the stacks pop pop } ifelse } bind executeonly def 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 } bind executeonly def /is_space_dict << 0 0 9 9 10 10 12 12 13 13 32 32 >> readonly def drawopdict begin /BI { mark } bind executeonly def /ID { gsave %% Bug 696547, related to Bug 695897 (see /Do above) This file has an inline image inside %% a text block. Here we attempt to detect and recover from this by setting the %% CTM to the matrix we saved before the text block. NB we update the 'TextSaveMatrix' %% or 'qTextSaveMatrix' whenever a 'cm' is issued, even if we are in a text block, so %% these matrices 'ought' to be correct. %% Of course, the file is badly broken, but 'Acrobat can open it....' currentdict /TextSaveMatrix known { ( **** Error: Executing ID inside a text block, attempting to recover\n) pdfformaterror currentdict /TextSaveMatrix get setmatrix ( Output may be incorrect.\n) pdfformaterror } if currentdict /qTextSaveMatrix known { ( **** Error: Executing ID inside a text block, attempting to recover\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror currentdict /qTextSaveMatrix get setmatrix } if 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 { gsave 1 1 moveto 0 0 lineto % If we get an error, just emit an empty box { pathbbox } stopped { 0 0 0 0 } if 4 array astore grestore /image setup_trans doimage } { pop Width currentdict /ImageMask knownoget dup { and } if not { ColorSpace oforce csncomp mul 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 grestore } bind executeonly def end currentdict /is_space_dict undef % ================================ Text ================================ % drawopdict begin % Text control /BT { BT } executeonly def /ET { ET } executeonly def /Tc { Tc } executeonly def /TL { TL } executeonly def /Tr { Tr } executeonly def /Ts { Ts } executeonly def /Tw { Tw } executeonly def /Tz { Tz } executeonly def % Text positioning /Td { Td } executeonly def /TD { TD } executeonly def /Tm { Tm } executeonly def /T* { T* } executeonly def % Text painting /Tj { Tj } executeonly def /' { ' } executeonly def /" { " } executeonly def /TJ { TJ } executeonly def /Tform { Tform } executeonly def % Text formatting and painting for AcroForm % without appearance streams. end % ======================= Invalid operators ============================ % drawopdict begin /QBT { Q BT ( **** Error: invalid operator QBT processed as Q BT .\n) pdfformaterror % Bug 690089 ( Output may be incorrect.\n) pdfformaterror } executeonly def /. { 0. ( **** Error: invalid operator . processed as number 0. .\n) pdfformaterror % Bug 690730 ( Output may be incorrect.\n) pdfformaterror } executeonly def end % ============================== Annotations ============================== % % Create links from separate widget annotations to the parent field nodes. % Surprisingly, separate widget annotations don't have a link to the parent % from which they inherit some data. /link_widget_annots { % <> <> -> <> <> dup /Kids knownoget { { oforce dup type /dicttype eq { link_widget_annots } if pop } forall } if dup /Parent oknown not { 2 copy exch /ParentField exch put } if } bind executeonly def % Get and normalize an annotation's rectangle. /annotrect { % annotrect /Rect oget oforce_recursive 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 } bind executeonly def % Set an annotation color. % If the /C array is empty we don't want to draw the annotation % /annotsetcolor { % annotsetcolor bool /C knownoget { dup length 4 eq { aload pop setcmykcolor //true }{ dup length 3 eq { aload pop setrgbcolor //true }{ dup length 1 eq { aload pop setgray //true } { dup length 0 eq { pop //false }{ ( **** Error: invalid color specified for annotation /C entry) pdfformaterror //false ( Output may be incorrect.\n) pdfformaterror } ifelse } ifelse } ifelse } ifelse } { 0 setgray //true} ifelse } bind executeonly def % Set an annotation color. % If the /C array is empty we don't want to draw the annotation % /annotsetinteriorcolor { % annotsetcolor bool /IC knownoget { dup length 4 eq { aload pop setcmykcolor //true }{ dup length 3 eq { aload pop setrgbcolor //true }{ dup length 1 eq { aload pop setgray //true } { dup length 0 eq { pop //false }{ ( **** Error: invalid color specified for annotation /C entry) pdfformaterror //false ( Output may be incorrect.\n) pdfformaterror } ifelse } ifelse } ifelse } ifelse } { //false } ifelse } bind executeonly def % 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 dup annotrect 5 -1 roll /RD knownoget { applyRD } if 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 } { pop pop pop }ifelse } bind executeonly def % 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 { ( **** Error: Invalid annotation border object, border has not been drawn.\n) pdfformaterror ( Output may be incorrect.\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 % Don't apply USerUnit if we are passing it to the device /PassUserUnit /GetDeviceParam .special_op {exch pop} {//false} ifelse 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 } bind executeonly def % stroke the path of an annotation border. /strokeborderpath { % strokeborderpath - 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 { ( **** Error: Invalid annotation border object, border has not been drawn.\n) pdfformaterror ( Output may be incorrect.\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 % Don't apply USerUnit if we are passing it to the device /PassUserUnit /GetDeviceParam .special_op {exch pop} {//false} ifelse 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 index /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if 3 -1 roll pop % 2 index annotsetcolor { 0 setdash setlinewidth stroke % } if } { dup 2 get % If element 3 of the /Border array is 0, then don't draw the border dup 0 ne { exch dup length 3 gt { 3 get } { pop {} } ifelse 3 index /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if % 2 index annotsetcolor { 0 setdash setlinewidth stroke % } if }{ pop pop } ifelse } ifelse } { dup /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if 1 {} % 2 index annotsetcolor { 0 setdash setlinewidth stroke % } if } ifelse pop grestore } bind executeonly def /fillborderpath { % fillborderpath - gsave dup /ca knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if annotsetinteriorcolor {fill} if grestore }bind executeonly def % % 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 % % AR8 and AR9 print 3D annotations even if Print flag is off. Bug 691486. % /annotvisible { % annotvisible dup /Subtype knownoget { /3D eq } { //false } ifelse % 3D annot exch /F knownoget not { 0 } if % Get flag value dup 2 and 0 eq { /Printed load { 4 and 4 eq or % Printed or 3D } { 32 and 0 eq exch pop % not NoView } ifelse } { pop pop //false % Hidden } ifelse } bind executeonly def /set_bc_color << 1 { 0 get oforce setgray } bind executeonly 3 { { oforce } forall setrgbcolor } bind executeonly 4 { { oforce } forall setcmykcolor } bind executeonly >> readonly def % Get an inherited attribute from a node through /Parent and /ParentField % links. The latter is set at start-up to access parents of annotations and % defaults at AcroForm. /fget % fget -true- { % fget -false- { 2 copy knownoget { exch pop exch pop //true exit } { exch dup /Parent knownoget { exch pop exch } { /ParentField knownoget { exch } { pop //false exit } ifelse } ifelse } ifelse } loop } bind executeonly def % foo /make_tx_da { 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 1 index /DR fget not { 0 dict } if def /File 1 index /V fget not { () } if length 2 index /DA fget not { () } if length add 500 add 65535 .min string dup 3 1 roll def /NullEncode filter % file dup (BT ) writestring 1 index /DA fget not { 1 index /V fget { anchorsearch { pop /Helvetica findfont 12 scalefont setfont } { anchorsearch { pop pop /FallBackFont /Identity-UTF16-H [/CIDFallBack] composefont 12 scalefont setfont } { pop /Helvetica findfont % re-encode the font to PDFDocEncoding dup length dict begin { 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse } forall /Encoding /PDFDocEncoding /Encoding findresource def /FontName /Helvetica-PDFDocEncoding def currentdict end /Helvetica-PDFDocEncoding exch definefont 12 scalefont setfont }ifelse }ifelse } if () }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 2 index /MaxLen fget not { 0 } if write= dup 2 index /V fget not { () } if write== dup 2 index /Ff fget not { 0 } if write= dup 2 index /Q fget not { 0 } if write= dup (Tform ET) write= dup .fileposition /Length exch def /File File 0 Length getinterval def closefile % end } bind executeonly def /can-regenerate-ap { % -> //false exch NeedAppearances { dup /FT fget { dup /Tx eq { pop dup /V oknown { pop not 1 } if } { /Ch eq { dup /V oknown { pop not 1 } if } if } ifelse } if } if pop } bind executeonly def /drawwidget { % drawwidget - %% This code checks to see if we can geenrate an appearance stream for the %% given widget, and if we can it ignores the given Appearance stream, so that %% we generate one instead. This seems wrong to me, if we've been given an %% appearance stream we should use it, no synthesize something else. Several %% files in our regression test suite render 'incorrectly' when compared to %% Acrobat with this removed, clearly Acrobat always ignores appearances. However %% several other files are rendered better when we *don't* ignore the Appearance %% So on balance I'm choosing to honour the appearance. %% % dup /UpdatedAP known not { % dup can-regenerate-ap { % dup /AP undef % } if % } if % Acrobat doesn't draw Widget annotations unles they have both /FT % (which is defined as required) and /T keys present. Annoyingly % these can either be inherited from the Form Definition Field % dictionary (via the AcroForm tree) or present directly in the % annotation, so we need to check the annotation to make sure its % a Widget, then follow any /Parent key up to the root node % extracting and storing any FT or T keys as we go (we only care if % these are present, their value is immaterial). If after all that % both keys are not present, then we don't draw the annotation. dup /Subtype get /Widget eq { dup /FT known 1 index /T known and not { dup { dup /FT knownoget { /FT exch 3 index 3 1 roll put } if dup /T knownoget { /T exch 3 index 3 1 roll put } if /Parent knownoget not { exit } if } loop } if dup /FT known 1 index /T known and { //true } { ( **** Warning: A Widget annotation dictionary lacks either the FT or T key.\n) pdfformaterror ( Acrobat ignores such annotations, annotation will not be rendered.\n) pdfformaterror ( Output may not be as expected.\n) pdfformaterror //false } ifelse } { //true }ifelse { dup /AP knownoget { dup /N known not { ( **** Error: Appearance dictionary (AP) lacks the mandatory normal (N) appearance.\n) pdfformaterror ( Output may be incorrect.\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 knownoget { type /integertype eq } { //false } ifelse 1 index /File knownoget { type /filetype eq or } if { % 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 { dup type /dicttype eq { % 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 } { ( **** Error: Annotation's appearance is not a dictionary.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } if } { dup /MK knownoget { % mk dup /BG knownoget { % mk bg dup length % mk bg len //set_bc_color exch .knownget { gsave exec 3 index 3 index scale 1 index annotrect rectfill grestore } { pop } ifelse } if dup /BC knownoget { dup length //set_bc_color exch .knownget { gsave exec 1 setlinewidth 3 index 3 index scale 1 index annotrect rectstroke grestore } { pop } ifelse } if pop } if dup can-regenerate-ap { make_tx_da dup /UpdatedAP //true put 3 copy drawwidget } if } ifelse } if pop pop pop } bind executeonly def currentdict /set_bc_color undef % 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 2 index /AP knownoget { /N knownogetdict { % <> x y <> dup 4 index /AS knownoget { knownoget { exch pop } if } { pop } ifelse 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 { ( **** Error: /BBox has zero width or height, which is not allowed.\n) pdfformaterror ( Output may be incorrect.\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 3 -1 roll pop } { ( **** Error: /Annot dict is missing required /Rect entry.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror pop 1 1 } ifelse } bind executeonly def /applyRD { % x y w h [l t r b] dup 0 get % x y w h [] l 6 -1 roll add 5 1 roll %x+l y w h [] dup 1 get %x+l y w h [] b 5 -1 roll add %x+l w h [] b+y 4 1 roll %x+l y+b w h [] aload pop %x+l y+b w h l t r b exch %x+l y+b w h l t b r 4 -1 roll add %x+l y+b w h t b r+l 3 1 roll add %x+l y+b w h r+l t+b 3 -1 roll exch sub %x+l y+b w r+l h-(t+b) 3 1 roll sub %x+l y+b h-(t+b) w-(r+l) exch } bind executeonly def % Draw an annotation. /drawannottypes 20 dict begin /startannottransparency { PDFusingtransparency { dup /BM known { dup /BM get << exch /BM exch >> } { << >> }ifelse %% We should be able to use the Rect to create the group, but it seems %% Acrobat ignores this, or at least doesn't clip the annotation to it :-( % 1 index /Rect known { % 1 index annotrect exch % llx lly h w % 3 index add exch % x y urx h % 2 index add % }{ clippath pathbbox newpath % } ifelse .begintransparencygroup } if }bind executeonly def /endannottransparency { PDFusingtransparency { .endtransparencygroup } if }bind executeonly def /ValidateAP { dup /AP oknown { dup /AP oget /N oknown not { //false } { //true } ifelse } { //false }ifelse } bind executeonly def % x0 y0 x1 y1 x2 y2 x3 y3 -> x0 y0 x1-x0 y1-y0 x2-x0 y2-y0 /quadpoints2basis { 8 { oforce 8 1 roll } repeat % The text is oriented with respect to the vertex with the smallest % y value (or the leftmost of those, if there are two such vertices) % (x0, y0) and the next vertex in a counterclockwise direction % (x1, y1), regardless of whether these are the first two points in % the QuadPoints array. 2 { 2 index 1 index eq { 3 index 2 index gt { 4 2 roll } if } { 2 index 1 index gt { 4 2 roll } if } ifelse 8 4 roll } repeat 6 index 3 index gt { 8 4 roll } if % ^ % | % * (x2,y2) * (x3,y3) % | % | % *------------*-> % (x0,y0) (x1,y1) pop pop % x0 y0 x1 y1 x2 y2 4 index sub exch % x0 y0 x1 y1 y2-y0 x2 5 index sub exch % x0 y0 x1 y1 x2-x0 y2-y0 4 2 roll 4 index sub exch % x0 y0 x2-x0 y2-y0 y1-y0 x1 5 index sub exch % x0 y0 x2-x0 y2-y0 x1-x0 y1-y0 4 2 roll % x0 y0 x1-x0 y1-y0 x2-x0 y2-y0 } bind executeonly def /Square { //ValidateAP exec { //true } { gsave //startannottransparency exec dup annotsetinteriorcolor { gsave dup /ca knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if dup annotrect 5 index /RD knownoget { applyRD } if rectfill grestore dup /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if dup annotsetcolor { drawborder } if //false }{ dup annotrect 5 index /RD knownoget { applyRD } if drawopdict /re get exec dup annotsetcolor { strokeborderpath } if } ifelse //endannottransparency exec grestore //false }ifelse } bind executeonly def %% Width Height drawellipse - /drawellipse { %% Don Lancaster's code for drawing an ellipse 0.55228475 0.00045 sub % improved magic value 3 1 roll % magic width height 2 div exch 2 div % magic y-radius x-radius dup 3 index mul % magic y-radius x-radius x-magic 2 index % magic y-radius x-radius x-magic y-radius 5 -1 roll mul % magic y-radius x-radius x-magic y-magic 2 index neg 0 moveto % xrad neg 0 moveto 2 index neg 1 index 3 index neg 6 index 0 8 index curveto % xrad neg ymag xmag neg yrad 0 yrad curveto 1 index 4 index 4 index 3 index 1 index 0 curveto % xmag yrad xrad ymag xrad 0 curveto 2 index 1 index neg 3 index 6 index neg 0 1 index curveto % xrad ymag neg xmag yrad neg 0 yrad neg curveto % Stack: yrad xrad xmag ymag exch neg 4 1 roll 3 -1 roll neg 3 1 roll exch neg exch neg 1 index 0 curveto % xmag neg yrad neg xrad neg ymag neg 0 curveto }bind executeonly def /Circle { //ValidateAP exec { //true } { gsave //startannottransparency exec dup annotrect 5 index /RD knownoget { applyRD } if 4 2 roll exch 3 index 2 div add exch 2 index 2 div add translate //drawellipse exec dup fillborderpath dup annotsetcolor { strokeborderpath } if //endannottransparency exec grestore //false } ifelse } bind executeonly def /Polygon { //ValidateAP exec { //true } { gsave //startannottransparency exec dup /Vertices knownoget { dup length 2 div 1 sub cvi 0 1 3 -1 roll { 2 mul dup 2 index exch 2 getinterval aload pop 3 -1 roll 0 eq { moveto }{ lineto } ifelse } for pop closepath //true } { ( **** Error: Invalid Vertices for Polygon, annotation has not been drawn.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror //false } ifelse 1 index annotsetinteriorcolor { //true }{ //false }ifelse and { gsave dup /ca knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if fill grestore dup /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if dup annotsetcolor { strokeborderpath } if } { dup annotsetcolor { strokeborderpath } if } ifelse //endannottransparency exec //false grestore } ifelse } bind executeonly def /LineEnd_dict 10 dict begin %% Stack contains %% CTM rotated so line segment is vertical, translated so line endpoint at 0,0 /Square { dup /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse dup 2.5 mul gsave dup neg 1 index neg exch moveto dup neg 1 index lineto dup 1 index exch lineto dup neg lineto closepath 1 index /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if 1 index fillborderpath grestore 3 mul dup neg 1 index neg exch moveto dup neg 1 index lineto dup 1 index exch lineto dup neg lineto closepath strokeborderpath } bind executeonly def /Circle { dup /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse dup gsave 2.5 mul dup 0 moveto 0 0 3 -1 roll 0 360 arc 1 index /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if 1 index fillborderpath grestore 3 mul dup 0 moveto 0 0 3 -1 roll 0 360 arc strokeborderpath } bind executeonly def /Diamond { dup /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse dup 2.5 mul gsave dup neg 0 exch moveto dup neg 0 lineto dup 0 exch lineto 0 lineto closepath 1 index /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if 1 index fillborderpath grestore 3 mul dup neg 0 exch moveto dup neg 0 lineto dup 0 exch lineto 0 lineto closepath strokeborderpath } bind executeonly def /OpenArrow { dup gsave /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse 0 setlinejoin dup 6 mul neg 1 index 4 mul neg moveto dup 1.2 div neg 0 lineto dup 6 mul neg exch 4 mul lineto strokeborderpath grestore } bind executeonly def /ClosedArrow { dup gsave /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse dup gsave 0 setlinejoin dup 6 mul neg 1 index 4 mul neg moveto dup 1.2 div neg 0 lineto dup 6 mul neg exch 4 mul lineto closepath 1 index strokeborderpath grestore dup 1.3 mul neg 0 translate dup 2 div sub dup 8.4 mul neg 1 index 5.9 mul neg moveto dup 1.2 div neg 0 lineto dup 8.4 mul neg exch 5.9 mul lineto closepath dup /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if fillborderpath grestore } bind executeonly def /None {pop} bind executeonly def /Butt { dup /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse 3 mul dup neg 0 exch moveto 0 exch lineto strokeborderpath } bind executeonly def /ROpenArrow { gsave dup /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse 180 rotate 0 setlinejoin dup 6 mul neg 1 index 4 mul neg moveto dup 1.2 div neg 0 lineto dup 6 mul neg exch 4 mul lineto strokeborderpath grestore } bind executeonly def /RClosedArrow { gsave dup /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse 180 rotate dup gsave 0 setlinejoin dup 6 mul neg 1 index 4 mul neg moveto dup 1.2 div neg 0 lineto dup 6 mul neg exch 4 mul lineto closepath 1 index strokeborderpath grestore dup 1.3 mul neg 0 translate dup 2 div sub dup 8.4 mul neg 1 index 5.9 mul neg moveto dup 1.2 div neg 0 lineto dup 8.4 mul neg exch 5.9 mul lineto closepath dup /CA knownoget {dup .setstrokeconstantalpha .setfillconstantalpha} if fillborderpath grestore } bind executeonly def /Slash { gsave dup /BS knownoget { /W knownoget { }{ 1 }ifelse }{ 1 }ifelse 330 rotate 3 mul dup neg 0 exch moveto 0 exch lineto strokeborderpath grestore } bind executeonly def currentdict end readonly def /Line { //ValidateAP exec { //true } { gsave //startannottransparency exec dup annotsetcolor { dup /L knownoget { 1 index /LE knownoget { % [x1 y1 x2 y2] [LE1 LE2] gsave 1 index aload pop % [x1 y1 x2 y2] [LE1 LE2] x1 y1 x2 y2 3 -1 roll sub % [x1 y1 x2 y2] [LE1 LE2] x1 x2 dy 3 1 roll exch sub % [x1 y1 x2 y2] [LE1 LE2] dy dx 3 index aload pop 4 2 roll pop pop translate 0 0 moveto {atan} stopped {pop pop 0} if % [x1 y1 x2 y2] [LE1 LE2] rotate dup 1 get % [x1 y1 x2 y2] [LE1 LE2] LE1 dup //LineEnd_dict exch known not { pop /None } if //LineEnd_dict exch % [x1 y1 x2 y2] [LE1 LE2] LE1 get % [x1 y1 x2 y2] [LE1 LE2] {} 3 index exch % [x1 y1 x2 y2] [LE1 LE2] {} exec grestore gsave 1 index aload pop % x1 y1 x2 y2 3 -1 roll sub % x1 x2 dy 3 1 roll exch sub % dy dx 3 index aload pop pop pop translate 0 0 moveto {atan} stopped {pop pop 0} if 180 add rotate 0 get dup //LineEnd_dict exch known not {pop /None} if //LineEnd_dict exch get 3 index exch exec grestore }if aload pop 4 2 roll moveto lineto strokeborderpath }{ ( **** Error: Invalid L array for Line, annotation has not been drawn.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror pop } ifelse } if //endannottransparency exec //false grestore } ifelse } bind executeonly def /PolyLine { //ValidateAP exec { //true } { gsave //startannottransparency exec dup annotsetcolor pop dup /Vertices knownoget { 1 index /LE knownoget { gsave 1 index 0 4 getinterval aload pop 4 2 roll 2 copy translate 4 2 roll 3 -1 roll exch sub % x1 x2 dy 3 1 roll sub % dy dx {atan} stopped {pop pop 0} if rotate dup 0 get dup //LineEnd_dict exch known not {pop /None} if //LineEnd_dict exch get 3 index exch exec grestore gsave 1 index dup length 4 sub 4 getinterval aload pop 2 copy translate 3 -1 roll sub % x1 x2 dy 3 1 roll exch sub % dy dx {atan} stopped {pop pop 0} if rotate 1 get dup //LineEnd_dict exch known not {pop /None} if //LineEnd_dict exch get 3 index exch exec grestore } if dup length 2 div 1 sub cvi 0 1 3 -1 roll { 2 mul dup 2 index exch 2 getinterval aload pop 3 -1 roll 0 eq { moveto }{ lineto } ifelse } for pop //true } { ( **** Error: Invalid Vertices for Polygon, annotation has not been drawn.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror //false } ifelse { strokeborderpath } if //endannottransparency exec //false grestore } ifelse } bind executeonly def /Link { % -> //startannottransparency exec dup annotsetcolor { dup drawborder dup calc_annot_scale 2 copy mul 0 ne {3 -1 roll drawwidget} { pop pop ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror }ifelse } if //endannottransparency exec //false } bind executeonly def /Ink { % -> % -> //ValidateAP exec { //true } { //startannottransparency exec 1 setlinewidth 1 setlinecap 1 setlinejoin dup annotsetcolor { dup calc_annot_scale 2 copy mul 0 ne { scale dup /InkList knownoget { { oforce [ exch { oforce } forall ] .pdfinkpath stroke } forall pop } { /Path knownoget { oforce dup length 1 sub 0 1 3 -1 roll { dup 0 eq { 1 index exch get aload pop moveto } { 1 index exch get dup length 2 eq { aload pop lineto }{ aload pop curveto } ifelse }ifelse } for pop dup strokeborderpath } if }ifelse } { pop pop ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } if //endannottransparency exec //false } ifelse } bind executeonly def /Underline { //ValidateAP exec { //true } { 0 setlinecap dup annotsetcolor { dup calc_annot_scale 2 copy mul 0 ne { scale /QuadPoints knownoget { aload length 8 idiv { //quadpoints2basis exec % Acrobat draws the line at 1/7 of the box width from the bottom % of the box and 1/16 thick of the box width. /Rect is ignored. 2 copy dup mul exch dup mul add sqrt 16 div setlinewidth 7 div 4 index add exch % x0 y0 x1-x0 y1-y0 (y2-y0)/7+y0 x2-x0 7 div 5 index add exch % x0 y0 x1-x0 y1-y0 (x2-x0)/7+x0 (y2-y0)/7+y0 2 copy moveto 2 index add exch 3 index add exch lineto % x0 y0 x1-x0 y1-y0 pop pop pop pop stroke } repeat } if } { pop pop ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } if //false } ifelse } bind executeonly def /StrikeOut { //ValidateAP exec { //true } { 0 setlinecap dup annotsetcolor { dup calc_annot_scale 2 copy mul 0 ne { scale /QuadPoints knownoget { aload length 8 idiv { //quadpoints2basis exec % Acrobat draws the line at 3/7 of the box width from the bottom % of the box and 1/16 thick of the box width. /Rect is ignored. 2 copy dup mul exch dup mul add sqrt 16 div setlinewidth 0.4285714 mul 4 index add exch % x0 y0 x1-x0 y1-y0 (y2-y0)*3/7+y0 x2-x0 0.4285714 mul 5 index add exch % x0 y0 x1-x0 y1-y0 (x2-x0)*3/7+x0 (y2-y0)*3/7+y0 2 copy moveto 2 index add exch 3 index add exch lineto % x0 y0 x1-x0 y1-y0 pop pop pop pop stroke } repeat } if } { pop pop ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } if //false } ifelse } bind executeonly def % Connect 2 points with an arc that has max distance from the line % segment to the ark equal 1/4 of the radius. /highlight-arc { % x1 y1 x0 y0 -> - 4 2 roll % x0 y0 x1 y1 dup 3 index add 2 div % x0 y0 x1 y1 (y1+y0)/2 2 index 5 index sub .9375 mul sub % x0 y0 x1 y1 (y1+y0)/2-15/16*dx=yc 4 index 3 index add 2 div % x0 y0 x1 y1 yc (x0+x1)/2 2 index 5 index sub .9375 mul add % x0 y0 x1 y1 yc xc exch % x0 y0 x1 y1 xc yc dup 3 index exch sub % x0 y0 x1 y1 xc yc y1-yc 4 index 3 index sub % x0 y0 x1 y1 xc yc y1-yc x1-xc dup dup mul 2 index dup mul add sqrt %x0 y0 x1 y1 xc yc y1-yc x1-xc r 3 1 roll atan % x0 y0 x1 y1 xc yc r a1 6 index 3 index sub % x0 y0 x1 y1 xc yc r a1 y0-yc 8 index 5 index sub % x0 y0 x1 y1 xc yc r a1 y0-yc x0-xc atan % x0 y0 x1 y1 xc yc r a1 a2 exch arcn % x0 y0 x1 y1 pop pop pop pop } bind executeonly def /emptydict 0 dict readonly def /Highlight { //ValidateAP exec { //true } { 0 setlinecap dup annotsetcolor { /QuadPoints knownoget { aload length 8 idiv { 6 -2 roll 2 copy moveto //highlight-arc exec 2 copy lineto //highlight-arc exec closepath } repeat PDFusingtransparency { //emptydict % If we get an error, just emit an empty box { pathbbox } stopped { 0 0 0 0 } if 2 index add exch 3 index add exch .begintransparencygroup /Multiply .setblendmode fill .endtransparencygroup } { % for -dNOTRANSPARENCY stroke newpath } ifelse } if } if //false } ifelse } bind executeonly def currentdict /emptydict undef currentdict /highlight-arc undef /Squiggly { //ValidateAP exec { //true } { //startannottransparency exec dup annotsetcolor { dup calc_annot_scale 2 copy mul 0 ne { scale /QuadPoints knownoget { aload length 8 idiv { gsave 8 copy moveto lineto 4 2 roll lineto lineto closepath clip newpath //quadpoints2basis exec 6 -2 roll translate % adjust for x0 y0 % x1-x0 y1-y0 x2-x0 y2-y0 1 index 56 div 1 index 56 div translate % zigzag box is 1/56 up 1 index 72 div 1 index 72 div translate % the line in the box is 1/72 up 2 copy dup mul exch dup mul add sqrt % x1-x0 y1-y0 x2-x0 y2-y0 |p2| 4 index dup mul 4 index dup mul add sqrt % x1-x0 y1-y0 x2-x0 y2-y0 |p2| |p1| dup 0 gt 2 index 0 gt and { div % x1-x0 y1-y0 x2-x0 y2-y0 |p2|/|p1|=p12 dup 1 exch div 4 mul 1 add cvi exch 6 2 roll % cnt p12 x1-x0 y1-y0 x2-x0 y2-y0 4 2 roll % cnt p12 x2-x0 y2-y0 x1-x0 y1-y0 4 index mul exch 4 index mul exch % cnt p12 x2-x0 y2-y0 (x1-x0)*p12 (y1-y0)*p12 4 2 roll 0 0 6 array astore concat % cnt p12 1 40 div 1 72 div scale pop % cnt 0 0 moveto 1 setlinecap 1 setlinejoin 1 setlinewidth { 5 10 lineto 10 0 lineto 10 0 translate } repeat stroke } { 6 { pop } repeat } ifelse grestore } repeat } if } { pop pop ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } if //endannottransparency exec //false } ifelse } bind executeonly def /Text { //ValidateAP exec { //true } { //startannottransparency exec dup calc_annot_scale 2 copy mul 0 ne { scale annotrect 4 2 roll translate exch pop % Draw a page icon 0.5 exch 18.5 sub translate 1 setlinewidth 0.75 setgray 0.5 -1 moveto 10 -1 lineto 15 4 lineto 15 17.5 lineto stroke 0 0 moveto 9 0 lineto 14 5 lineto 14 18 lineto 0 18 lineto closepath gsave .5 setgray fill grestore 0 setgray stroke 3 8 moveto 7.5 8 lineto 3 11 moveto 10 11 lineto 3 14 moveto 10 14 lineto 9 0 moveto 9 5 lineto 14 5 lineto stroke } { pop pop ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse //endannottransparency exec //false } ifelse } bind executeonly def /FreeText { //ValidateAP exec { //true } %% We either have no appearance, or its invalid, make one up. { gsave //startannottransparency exec dup annotrect rectclip dup /CA knownoget { dup .setstrokeconstantalpha .setfillconstantalpha } if dup /ca knownoget { dup .setstrokeconstantalpha .setfillconstantalpha } if dup /C knownoget { dup length 4 eq { aload pop setcmykcolor //true }{ dup length 3 eq { aload pop setrgbcolor //true }{ dup length 1 eq { aload pop setgray //true } { dup length 0 eq { pop //false }{ ( **** Error: invalid color specified for FreeText annotation /C entry) pdfformaterror ( Output may be incorrect.\n) pdfformaterror //false } ifelse } ifelse } ifelse } ifelse }{ //false } ifelse { dup annotrect 5 index /RD knownoget { applyRD } if rectfill } if %% get and process the default appearance string, if we don't have one, use a default /DA_Action_Dict << /Tf { exch dup /Helv eq { pop /Helvetica dup findfont } {dup findfont}ifelse % re-encode the font to PDFDocEncoding dup length dict begin { 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse } forall /Encoding /PDFDocEncoding /Encoding findresource def /FontName /Helvetica-PDFDocEncoding def currentdict end definefont exch scalefont setfont } /r {aload pop setrgbcolor} % Can't find this actually defined anywhere, but Acrobat seems to honour it :-( /rg {setrgbcolor} /RG {setrgbcolor} /G {setgray} /g {setgray} /k {setcmykcolor} /K {setcmykcolor} >> def % Set some sane defaults, in case the /DA does not. 0 setgray /Helvetica findfont % re-encode the font to PDFDocEncoding dup length dict begin { 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse } forall /Encoding /PDFDocEncoding /Encoding findresource def /FontName /Helvetica-PDFDocEncoding def currentdict end /Helvetica-PDFDocEncoding exch definefont 12 scalefont setfont dup /DA knownoget { length string /tempstr exch def dup /DA get tempstr copy pop gstate mark { { %% This is kind of ugly, we use token to process the string %% and process each token separately. tempstr token { exch /tempstr exch def %% If the token is a name %% dup type /nametype eq { %% Is it a name we want to take actionon dup DA_Action_Dict exch known { DA_Action_Dict exch get exec }{ %% Its not a name we know, is it executable dup xcheck {exec} if } ifelse }{ %% Not a name, just make it executable and execute it cvx exec }ifelse }{ exit }ifelse } loop } stopped {cleartomark setgstate} {cleartomark pop} ifelse } if %% draw the border, if we don't have a border style dictionary, draw a default one. dup /BS knownoget { pop dup drawborder }{ newpath 0 setgray 1 setlinewidth dup annotrect 5 index /RD knownoget { applyRD 4 -1 roll 4 -1 roll 4 -1 roll 4 -1 roll 4 2 roll } { 4 -1 roll 1 add 4 -1 roll 1 add 4 -1 roll 2 sub 4 -1 roll 2 sub 4 2 roll }ifelse moveto currentpoint exch 3 index add exch lineto currentpoint 2 index add lineto exch currentpoint 3 1 roll exch sub exch lineto currentpoint 3 -1 roll sub lineto stroke }ifelse gsave % in case we rotate the contents %% Start the current point at the top left of the annotation Rect %% dup /Rotate knownoget % x y w h - x' w' x' y' { dup 90 eq { pop dup annotrect 5 index /RD knownoget { applyRD } if exch pop 3 -1 roll 2 index moveto 90 rotate 1 index add } { dup 180 eq { pop dup annotrect 5 index /RD knownoget { applyRD } if pop 3 -1 roll 1 index add -1 mul exch 1 index -1 mul 4 -1 roll moveto 180 rotate 1 index add }{ 270 eq { dup annotrect 5 index /RD knownoget { applyRD } if dup 4 -1 roll add 3 -1 roll 3 index add exch moveto 270 rotate exch pop currentpoint pop dup 3 -1 roll add }{ dup annotrect 5 index /RD knownoget { applyRD 3 -1 roll add 2 index exch moveto 1 index add }{ 4 -1 roll 2 add 4 -1 roll 2 add 4 -1 roll 4 sub 4 -1 roll 4 sub 3 -1 roll add 2 index exch moveto 1 index add } ifelse } ifelse } ifelse } ifelse }{ dup annotrect 5 index /RD knownoget { applyRD 3 -1 roll add 2 index exch moveto 1 index add }{ 4 -1 roll 2 add 4 -1 roll 2 add 4 -1 roll 4 sub 4 -1 roll 4 sub 3 -1 roll add 2 index exch moveto 1 index add } ifelse } ifelse %% Get the Contents string, if we don't have one, we're done %% 2 index /Contents knownoget { dup length 0 gt { PDFusingtransparency { .begintransparencytextgroup } if %% Check for UTF16-BE, we probably don't work properly with this yet. %% (If the string is less than 4 bytes its either not UTF16-BE or it is %% but has no actual content) dup length 4 ge { dup 0 get 254 eq 1 index 1 get 255 eq and }{ //false } ifelse { /FallBackFont /Identity-UTF16-H [/CIDFallBack] composefont 12 scalefont setfont dup length 2 div 1 sub 0 1 3 -1 roll { %% llx urx (string) index 1 index exch 2 mul 2 getinterval %% llx urx (string) (substring) dup stringwidth pop currentpoint pop add 3 index gt { currentpoint exch pop 4 index exch 12 sub moveto } if show } for pop } { %% Heuristic to determine the height (ascender to descender) of the text %% for when we move down a line. gsave /..TextHeight (Hy) //false charpath pathbbox exch pop exch sub exch pop def grestore %% and use it immediatley to start the text one line down %% currentpoint ..TextHeight sub moveto %% Now we process each character code in the string. If we find %% a /r/ or /n then we drop a line. If the character would end up %% outside the Annot Rect, then we drop a line before showing it. %% dup length 1 sub 0 1 3 -1 roll { %% llx urx (string) index 1 index exch get %% llx urx (string) int dup 10 eq 1 index 13 eq or { pop currentpoint exch pop 3 index exch ..TextHeight sub moveto } { 1 string dup 0 4 -1 roll put dup %% llx urx (string) (int) (int) stringwidth pop currentpoint pop add 3 index gt { currentpoint exch pop 4 index exch ..TextHeight sub moveto } if show } ifelse } for pop }ifelse PDFusingtransparency { .endtransparencytextgroup } if } { pop } ifelse } if pop pop grestore % in case the contents were rotated dup /CL knownoget { dup length 6 eq { dup aload pop pop pop } { dup length 4 eq { dup aload pop } { pop 0 } ifelse } ifelse 4 2 roll exch 4 -1 roll sub 3 1 roll exch sub atan exch aload pop moveto lineto lineto currentpoint % stroke % 0 1 0 setrgbcolor moveto currentpoint translate 0 0 moveto 360 exch sub rotate currentpoint -5 -8 rlineto moveto 5 -8 rlineto stroke } if //endannottransparency exec //false grestore } ifelse } bind executeonly def /frame { { 255 div } forall setrgbcolor -95 -25 translate 2 190 atan rotate { 6 0 moveto 190 0 190 6 6 arct 190 47 184 47 6 arct 0 47 0 41 6 arct 0 0 6 0 6 arct closepath 10 4 moveto 185 4 185 9 5 arct 185 43 180 43 5 arct 5 43 5 38 5 arct 5 4 9 4 5 arct closepath eofill } gsave 1 -1 translate 0.75 setgray dup exec grestore exec } bind executeonly def % (text) y h -> - /text { PDFusingtransparency { .begintransparencytextgroup } if /Times-Bold findfont % re-encode the font to PDFDocEncoding dup length dict begin { 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse } forall /Encoding /PDFDocEncoding /Encoding findresource def /FontName /Times-Bold-PDFDocEncoding def currentdict end /Times-Bold-PDFDocEncoding exch definefont exch scalefont setfont % (text) y gsave 0 0 moveto 1 index //false charpath flattenpath pathbbox pop exch pop sub 2 div grestore 95 add exch moveto gsave 1 -1 rmoveto 0.75 setgray dup show grestore show PDFusingtransparency { .endtransparencytextgroup } if } bind executeonly def /red readonly def /green <3fae49> readonly def /blue <0072bc> readonly def /stamp_dict 14 dict begin /Approved { //green //frame exec (APPROVED) 13 30 //text exec } bind executeonly def /AsIs { //red //frame exec (AS IS) 13 30 //text exec } bind executeonly def /Confidential { //red //frame exec (CONFIDENTIAL) 17 20 //text exec } bind executeonly def /Departmental { //blue //frame exec (DEPARTMENTAL) 17 20 //text exec } bind executeonly def /Draft { //red //frame exec (DRAFT) 13 30 //text exec } bind executeonly def /Experimental { //blue //frame exec (EXPERIMENTAL) 17 20 //text exec } bind executeonly def /Expired { //red //frame exec (EXPIRED) 13 30 //text exec } bind executeonly def /Final { //red //frame exec (FINAL) 13 30 //text exec } bind executeonly def /ForComment { //green //frame exec (FOR COMMENT) 17 20 //text exec } bind executeonly def /ForPublicRelease { //green //frame exec (FOR PUBLIC) 26 18 //text exec (RELEASE) 8.5 18 //text exec } bind executeonly def /NotApproved { //red //frame exec (NOT APPROVED) 17 20 //text exec } bdef /NotForPublicRelease { //red //frame exec (NOT FOR) 26 18 //text exec (PUBLIC RELEASE) 8.5 18 //text exec } bind executeonly def /Sold { //blue //frame exec (SOLD) 13 30 //text exec } bind executeonly def /TopSecret { //red //frame exec (TOP SECRET) 14 26 //text exec } bind executeonly def currentdict end readonly def {/text/frame/red/green/blue} {currentdict exch undef} forall /Stamp { //ValidateAP exec { //true } { //startannottransparency exec dup calc_annot_scale 2 copy mul 0 ne { scale % translate to the center of Rect dup annotrect 4 2 roll % dx dy x0 y0 2 index 2 div add exch 3 index 2 div add exch translate % dx dy 50 div exch 190 div .min dup 0.0 eq {pop 1.0} if dup scale /Name knownoget not { /Draft } if //stamp_dict 1 index known not { exch pop /Draft exch } if //stamp_dict exch get exec } { pop pop ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse //endannottransparency exec //false } ifelse } bind executeonly def /Popup { dup /Open oknown { dup /Open get { //ValidateAP exec { //true } { gsave //startannottransparency exec newpath 0.05 setlinewidth dup /Parent .knownget { oforce } { dup /P .knownget { oforce } { dup } ifelse } ifelse /C .knownget { aload pop }{ 1 1 0 }ifelse setrgbcolor dup /Rect get dup aload pop 2 index sub exch 3 index sub exch 4 copy gsave 1 setgray rectfill grestore gsave 0 setgray rectstroke grestore 1 index /Parent .knownget { oforce }{ 1 index /P .knownget { oforce }{ 1 index } ifelse }ifelse dup /Contents .knownget { gsave PDFusingtransparency { .begintransparencytextgroup } if 0 setgray /Helvetica findfont % re-encode the font to PDFDocEncoding dup length dict begin { 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse } forall /Encoding /PDFDocEncoding /Encoding findresource def /FontName /Helvetica-PDFDocEncoding def currentdict end /Helvetica-PDFDocEncoding exch definefont 9 scalefont setfont 2 index aload pop 3 1 roll pop pop 30 sub exch 5 add exch moveto show PDFusingtransparency { .endtransparencytextgroup } if grestore } if exch dup aload pop 3 -1 roll pop exch 2 index sub -15 4 copy rectfill 0 setgray rectstroke exch /T .knownget { gsave PDFusingtransparency { .begintransparencytextgroup } if 0 setgray /Helvetica findfont % re-encode the font to PDFDocEncoding dup length dict begin { 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse } forall /Encoding /PDFDocEncoding /Encoding findresource def /FontName /Helvetica-PDFDocEncoding def currentdict end /Helvetica-PDFDocEncoding exch definefont 9 scalefont setfont dup stringwidth pop 2 index aload pop pop exch pop exch sub exch sub 2 div 2 index aload pop 3 1 roll pop pop 11 sub 3 1 roll add exch moveto show PDFusingtransparency { .endtransparencytextgroup } if grestore } if grestore //endannottransparency exec //false } ifelse } { pop //false }ifelse } { pop //false }ifelse } bind executeonly def /Redact { %% Redact annotations are part of a process, a Redact annotation is only present %% until the content is removed, before that the content should be present and %% I beleive we should print it. So take no action for Redact annotations if they %% have no appearance. //ValidateAP exec { //true } { //false } ifelse } bind executeonly def currentdict /startannottransparency undef currentdict /endannottransparency undef currentdict /ValidateAP undef currentdict /quadpoints2basis undef currentdict /drawellipse undef currentdict end readonly def /.PDFDrawAnnotType? { //false exch /ShowAnnotTypes where { /ShowAnnotTypes get { dup /* eq exch 2 index eq or { pop //true exch exit } if } forall pop } {pop pop //true} ifelse } bind executeonly def /.PDFPreserveAnnotType? { //false exch /PreserveAnnotTypes where { /PreserveAnnotTypes get { dup /* eq exch 2 index eq or { pop //true exch exit } if } forall pop } {pop pop //true} ifelse } bind executeonly def /drawannot { % drawannot - dup annotvisible { gsave dup dup /Subtype knownoget { dup //.PDFDrawAnnotType? exec { //drawannottypes exch .knownget { exec } { //true } ifelse { dup calc_annot_scale 2 copy mul 0 ne { 3 -1 roll drawwidget } { ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror }ifelse % Draw rejected annots as widgets } if % type known } { pop }ifelse } { pop ( **** Error: Ignoring /Annot dict without required /Subtype entry.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse grestore } if pop % annotvisible } bind executeonly def currentdict /drawannottypes undef % Draw an annotation. /loadannot { dup /AP .knownget { % <> <> true | false oforce dup { % <> <> /Key <> oforce % <> <> /Key <> %% %% Check to see if the apperance key has a simple stream or a dictionary of states %% dup /Subtype known % <> <> /Key <> bool { %% Simple appearance stream DoAppearance % <> <> /Key 2 index % <> <> /Key <> /AP << % <> <> /Key <> /AP << 4 -1 roll MakeAppearanceName cvx cvn >> put % <> <> } { %% dictionary of states <> <> /Key <> dup % <> <> /Key <> <> { % <> <> /Key <> /StateKey <> oforce % <> <> /Key <> /StateKey <> DoAppearance % <> <> /Key <> /StateKey 1 index exch % <> <> /Key <> <> /StateKey MakeAppearanceName cvx cvn % <> <> /Key <> <> /StateKey {} put % <> <> /Key <> } forall put % <> <> /Key dup }ifelse } forall pop % <> } if %% Parent (or /P) references will be incorrect. Remove them %% for now as they are optional. dup /Popup known {dup /Popup undef} if dup /IRT known {dup /IRT undef} if dup /RT known {dup /RT undef} if dup /P known {dup /P undef} if dup /Parent known {dup /Parent undef} if %% Resolve any indirect references. May need further work :-( { %% We know /AP doesn't need processing, we handled that above... 1 index /AP eq not { dup {oforce} stopped not {exch pop} if dup type /dicttype eq{ dup { dup {oforce} stopped not {exch pop} if 2 index 3 1 roll put } forall Removepdfobj# } if dup type /arraytype eq { 0 1 2 index length 1 sub{ dup 2 index exch get dup {oforce} stopped not {exch pop} if 2 index 3 1 roll put } for } if } if } forall } bind executeonly def /ApplyCTMToQuadPoints { %% Nasty hackery here really. We need to undo the HWResolution scaling which %% is done by pdfwrite. Default is 720 dpi, so 0.1. We also need to make %% sure that any translation of the page (because its been rotated for example) %% is also modified by the requisite amount. SO we ned to calculate a matrix %% which does the scaling and concatenate it with the current matrix. %% Do this inside a gsave/grestore pair to avoid side effects! gsave currentpagedevice /HWResolution get aload pop exch 72 exch div exch 72 exch div matrix 3 1 roll 2 index 3 3 -1 roll put 1 index 0 3 -1 roll put matrix currentmatrix exch matrix concatmatrix setmatrix oforce %% QuadPoints are given as 'n' sequences of 8 numbers. mark exch aload counttomark 1 roll counttomark 1 sub 2 div cvi { transform counttomark 1 sub 2 roll } repeat counttomark -1 roll astore exch pop % the mark grestore } bind executeonly def /preserveannottypes 20 dict begin /Circle {mark exch loadannot /ANN pdfmark //false} bind executeonly def /FileAttachment {mark exch loadannot /ANN pdfmark //false} bind executeonly def /FreeText {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Highlight { mark exch dup /QuadPoints .knownget { 1 index /QuadPoints 3 -1 roll ApplyCTMToQuadPoints put } if loadannot /ANN pdfmark //false } bind executeonly def /Ink {mark exch loadannot /ANN pdfmark //false} bind executeonly def /PolyLine {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Line {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Link { /NO_PDFMARK_DESTS where {pop NO_PDFMARK_DESTS not}{//true}ifelse { mark exch dup /BS knownoget { << exch { oforce } forall >> /BS exch 3 -1 roll } if dup /F knownoget { /F exch 3 -1 roll } if dup /C knownoget { /Color exch 3 -1 roll } if dup /Rect knownoget { /Rect exch 3 -1 roll } if dup /Border knownoget { dup type /arraytype eq { dup length 3 lt } { //true } ifelse { pop [ 0 0 0 ] % Following AR5 use invisible border. } if /Border exch 3 -1 roll } if dup /A knownoget { dup /URI known { /A mark 3 2 roll % <<>> /A [ <> { oforce } forall .dicttomark 3 2 roll } { dup /S knownoget { %% Because we process GoTo Destinations into absolute references in the PDF file %% we need to resolve the /D or /Dest. However, we must *not* do this for %% GoToR Destinations because (obviously) those are in a different file and %% we cannot resolve them into absolute references. We don't need to anyway %% because that file must already have a named destination. dup /GoTo eq { pop dup /D knownoget { exch pop exch dup length dict copy dup /Dest 4 -1 roll put } if }{ dup /GoToR eq { pop /A mark % <<..action dict..>> /A [ 3 2 roll % /A [ <<..action dict..>> { oforce } forall .dicttomark 3 2 roll }{ dup /Launch eq { pop /A mark % <<..action dict..>> /A [ 3 2 roll % /A [ <<..action dict..>> { oforce } forall .dicttomark 3 2 roll }{ /Named eq { /N knownoget { namedactions exch .knownget { exec { pop ( **** Warning: Ignoring a named action pointing out of the document page range.\n) pdfformatwarning } { /Page exch 3 -1 roll } ifelse } if } if } if }ifelse } ifelse } ifelse } if } ifelse } if { linkdest } stopped { cleartomark ( **** Warning: Link annotation points out of the document page range.\n) pdfformatwarning } { pop { %% Need to remove any '/.gs.pdfobj# key/value pairs from any dictionaries counttomark array astore dup length 1 sub 0 1 3 -1 roll { dup 2 index exch get Removepdfobj# 2 index 3 1 roll put } for aload pop /LNK pdfmark } stopped {cleartomark} if } ifelse }{pop} ifelse //false } bind executeonly def %% We don't handle movies correctly, so don't try to preserve them %/Movie {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Popup {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Sound {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Square {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Stamp {mark exch loadannot /ANN pdfmark //false} bind executeonly def /StrikeOut { mark exch dup /QuadPoints .knownget { 1 index /QuadPoints 3 -1 roll ApplyCTMToQuadPoints put } if loadannot /ANN pdfmark //false } bind executeonly def /Squiggly { mark exch dup /QuadPoints .knownget { 1 index /QuadPoints 3 -1 roll ApplyCTMToQuadPoints put } if loadannot /ANN pdfmark //false } bind executeonly def /Text {mark exch loadannot /ANN pdfmark //false} bind executeonly def /TrapNet {mark exch loadannot /ANN pdfmark //false} bind executeonly def /Underline { mark exch dup /QuadPoints .knownget { 1 index /QuadPoints 3 -1 roll ApplyCTMToQuadPoints put } if loadannot /ANN pdfmark //false } bind executeonly def %% Widget annotations are only used with AcroForms, and since we don't preserve AcroForms %% we don't want to preserve widget annotations either, because the consumer of the new %% PDF won't know what values they should take. So we draw widget annotations instead. If we %% ever preserve AcroForms then we should alter this to preserve Widgets as well. %% simply chane "drawannot" to "mark exch loadannot /ANN pdfmark" /Widget {mark exch {drawannot} PDFSTOPONERROR {exec}{stopped {(Error: Ignoring invalid annotation, output may be incorrect.\n) pdfformaterror} if} ifelse cleartomark //false} bind executeonly def currentdict end readonly def /preserveannot { % preserveannot - dup /.gs.pdfobj# known { dup /.gs.pdfobj# undef } if gsave dup dup /Subtype knownoget { dup //.PDFPreserveAnnotType? exec { //preserveannottypes exch .knownget { exec } { //true } ifelse { dup annotvisible { dup calc_annot_scale 2 copy mul 0 ne { 3 -1 roll drawwidget } { ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror }ifelse % Draw rejected annots as widgets } { pop }ifelse } if } { % Not preserving this type of annotation % discard teh Subtype pop % copy the Annot dictionary and try drawing it instead dup drawannot } ifelse % type known } { pop ( **** Error: Ignoring /Annot dict without required /Subtype entry.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse grestore } bind executeonly def currentdict /preserveannottypes undef currentdict /.PDFDrawAnnotType? 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 } bind executeonly def % 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 } bind executeonly def /Tx { dup /AP known { dup 1 1 3 -1 roll drawwidget } { %% If we don't have a NeedApperances, treat as true, because Acrobat %% always regenerates Appearances anyway. 2 index /NeedAppearances knownoget not { //true } 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 1000 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 { 3 index /DV pget not { () } if } 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 } bind executeonly def /Ch { dup /AP known 3 index /NeedAppearances knownoget not { //true } if not and { dup 1 1 3 -1 roll drawwidget } { %% If we don't have a NeedApperances, treat as true, because Acrobat %% always regenerates Appearances anyway. 2 index /NeedAppearances knownoget not { //true } 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 1000 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 { 3 index /DV pget not { () } if } 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 } bind executeonly def /Sig { (Sig is not yet implemened ) //== exec } bind executeonly def 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 } bind executeonly def % 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 type /dicttyype eq { % File for Bug692447 has 'null' Fields entries % This matches what pdf_main process_trailer_attrs dup /Kids knownoget { % field [] dup length 0 gt { 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 } { ( **** Error: Ignoring empty /Kids array in Form field.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } { draw_terminal_field % merged annotation % - } ifelse } if } bind executeonly def /draw_acro_form { %
draw_acro_form - dup /Fields knownoget { { oforce draw_form_field } forall } if pop } bind executeonly def currentdict /draw_terminal_field_dict undef end % pdfdict end % GS_PDF_ProcSet .setglobal