diff options
Diffstat (limited to 'Master/tlpkg/tlgs/Resource/Init/pdf_draw.ps')
-rw-r--r-- | Master/tlpkg/tlgs/Resource/Init/pdf_draw.ps | 4088 |
1 files changed, 4088 insertions, 0 deletions
diff --git a/Master/tlpkg/tlgs/Resource/Init/pdf_draw.ps b/Master/tlpkg/tlgs/Resource/Init/pdf_draw.ps new file mode 100644 index 00000000000..88da2de7485 --- /dev/null +++ b/Master/tlpkg/tlgs/Resource/Init/pdf_draw.ps @@ -0,0 +1,4088 @@ +% Copyright (C) 2001-2012 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., 7 Mt. Lassen Drive - Suite A-134, San Rafael, +% CA 94903, 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 +/pdfdict where { pop } { /pdfdict 100 dict def } ifelse +GS_PDF_ProcSet begin +pdfdict begin + +% For simplicity, we use a single interpretation dictionary for all +% PDF graphics operations, even though this is too liberal. +/drawopdict 100 dict def + +/SetGroupExtGStateDict +<< + /AlphaIsShape //AIS + /FillConstantAlpha //ca + % We don't have to worry about the enumeration order, even + % with the color/space settings, since we only store, not + % not set them. + /FillColor //sc1 + /FillColorSpace { /FillColorSpace gput } bind + /FillOverprint //op + /SoftMask //SMask + /StrokeConstantAlpha //CA + /StrokeColor //SC1 + /StrokeColorSpace { /StrokeColorSpace gput } bind + /StrokeOverprint //OP + /TextSpacing //Tc + % We can't use //Tz as we've stored the value we actually use, + % not value * 100 (see /Tz in pdf_ops.ps) + /TextHScaling { /TextHScaling gput } bind + /Leading //TD + /TextFont { /TextFont gput} bind + /TextLineMatrix { /TextLineMatrix gput } bind + /TextMatrix { /TextMatrix gput } bind + /TextRise { /TextRise gput } bind + /TextRenderingMode { /TextRenderingMode gput } bind + /WordSpacing //Tw +>> def + +% ================================ Graphics ================================ % + +% ---------------- Functions ---------------- % + +% Note that resolvefunction converts a PDF Function to a PostScript Function; +% resolve*fnproc converts a PDF function to a PostScript procedure. +% We need to process all required and optional parameters to resolve any +% use of indirect references. + +/fnrdict mark + 0 { .resolvefn0 } + 2 { .resolvefn2 } + 3 { .resolvefn3 } + 4 { .resolvefn4 } +.dicttomark readonly def + +/.resolvefn0 { + dup length 1 add dict .copydict % make room for DataSource + % now resolve any indirect references + dup /Size 2 copy knownoget { put } { pop pop } ifelse + dup /BitsPerSample 2 copy knownoget { put } { pop pop } ifelse + dup /Order 2 copy knownoget { put } { pop pop } ifelse + dup /Encode 2 copy knownoget { put } { pop pop } ifelse + dup /Decode 2 copy knownoget { put } { pop pop } ifelse + + % Don't lose our place in PDFfile. + PDFfile fileposition exch + dup //true resolvestream + % The stream isn't positionable, so read all the data now. + % Stack: filepos fndict stream + 1 index /Range get length 2 idiv 2 index /BitsPerSample get mul + 2 index /Size get { mul } forall + 7 add 8 idiv + dup 65535 le { + string 1 index exch readstring pop + } { + 1 index exch () /SubFileDecode filter /ReusableStreamDecode filter + } ifelse + exch closefile + % Stack: filepos fndict data + exch dup /DataSource 4 -1 roll put + exch PDFfile exch setfileposition +} bdef + +/.resolvefn2 { + dup length dict .copydict + dup /C0 2 copy knownoget { put } { pop pop } ifelse + dup /C1 2 copy knownoget { put } { pop pop } ifelse + dup /N 2 copy knownoget { put } { pop pop } ifelse +} bdef + +/.resolvefn3 { + dup length dict .copydict + dup /Bounds 2 copy knownoget { put } { pop pop } ifelse + dup /Encode 2 copy knownoget { put } { pop pop } ifelse + dup /Functions 2 copy oget mark exch dup { + oforce .resolvefn + } forall + counttomark -1 roll astore exch pop put +} bdef + +/.resolvefn4 { + PDFfile fileposition exch % filepos fndict + dup //true resolvestream % filepos fndict stream + exch dup length dict copy % filepos stream fndict2 + dup /Function undef % filepos stream fndict2 + exch dup token not { + () /rangecheck cvx signalerror + } if + exch token { + /rangecheck cvx signalerror + } if + % Use .bind to avoid idiom recognition. + .bind + 1 index /Function 3 -1 roll put + exch PDFfile exch setfileposition +} bdef + +/.resolvefn { % <fndict> .resolvefn <fndict'> + dup length dict .copydict + dup /Domain 2 copy knownoget { put } { pop pop } ifelse + dup /Range 2 copy knownoget { put } { pop pop } ifelse + dup /FunctionType oget //fnrdict exch get exec +} bdef + +/resolvefunction { % <fndict> resolvefunction <function> + .resolvefn + PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Function: ) print dup === flush } if } if +} bdef + +/resolvefnproc { % <fndict> resolvefnproc <proc> + resolvefunction .buildfunction +} bdef + +/resolveidfnproc { % <fndict> resolveidfnproc <proc> + dup /Identity eq { pop { } } { resolvefnproc } ifelse +} bdef + +/resolvedefaultfnproc { % <fndict> <default> resolved'fnproc <proc> + 1 index /Default eq { exch pop } { pop resolveidfnproc } ifelse +} bdef + +% ---------------- Shadings ---------------- % + +/shrdict mark + /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 + /BBox { + dup dup dup aload pop normrect_elems + 5 -1 roll astore + } bind + /ColorSpace { + resolvecolorspace + } bind + /Function { + dup type /dicttype eq { + resolvefunction + } { + [ exch { oforce resolvefunction } forall ] + } ifelse + } bind + /Extend { + mark exch {oforce} forall ] + } bind +.dicttomark readonly def + +/resolveshading { % <shadingstream> resolveshading <shading> + dup /.shading_dict .knownget { + exch pop + dup /ShadingType get 4 ge { + dup /DataSource get 0 setfileposition + } if + } { + dup + PDFfile fileposition exch + mark exch { + oforce //shrdict 2 index .knownget { exec } if + } forall .dicttomark + dup /ShadingType get 4 ge { + dup dup //true resolvestream + % Make a reusable stream so that the shading doesn't + % reposition PDFfile at unexpected times. + /ReusableStreamDecode filter /DataSource exch put + } if + exch PDFfile exch setfileposition + dup 3 1 roll /.shading_dict exch put + } ifelse +} bdef +/resolvesh { % <shname> resolvesh <shading> + % <shname> resolvesh <null> + 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 +} bdef + +% ---------------- Halftones ---------------- % + +/spotfunctions mark + /Round { + abs exch abs 2 copy add 1 le { + dup mul exch dup mul add 1 exch sub + } { + 1 sub dup mul exch 1 sub dup mul add 1 sub + } ifelse + } bind + /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 + /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 + /EllipseA { dup mul .9 mul exch dup mul add 1 exch sub } bind + /InvertedEllipseA { dup mul .9 mul exch dup mul add 1 sub } bind + /EllipseB { dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub } bind + /EllipseC { dup mul .9 mul exch dup mul add 1 exch sub } bind + /InvertedEllipseC { dup mul .9 mul exch dup mul add 1 sub } bind + /Line { exch pop abs neg } bind + /LineX { pop } bind + /LineY { exch pop } bind + /Square { abs exch abs 2 copy lt { exch } if pop neg } bind + /Cross { abs exch abs 2 copy gt { exch } if pop neg } bind + /Rhomboid { abs exch abs 0.9 mul add 2 div } bind + /DoubleDot { 2 {360 mul sin 2 div exch } repeat add } bind + /InvertedDoubleDot { 2 {360 mul sin 2 div exch } repeat add neg } bind + /SimpleDot { dup mul exch dup mul add 1 exch sub } bind + /InvertedSimpleDot { dup mul exch dup mul add 1 sub } bind + /CosineDot { 180 mul cos exch 180 mul cos add 2 div } bind + /Double { exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add } bind + /InvertedDouble { + exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add neg + } bind +.dicttomark readonly def + +/.resolveht1 { + mark exch { + oforce + 1 index /SpotFunction eq { + dup type /nametype eq + { //spotfunctions exch get } { resolvefnproc } + ifelse + } { + 1 index /TransferFunction eq { + resolveidfnproc + } if + } ifelse + } forall .dicttomark +} bdef + +/.resolveht5 { + mark exch { + oforce dup type /dicttype eq { resolvehalftone } if + } forall .dicttomark +} bdef + +/.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 +} bdef + +/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 { % <dict> resolvehalftone <halftone> + 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 +} bdef + +% ---------------- Graphics state management ---------------- % + +/cmmatrix matrix def +drawopdict begin + % Graphics state stack + /q { q } def + /Q { Q } def + % Graphics state setting + /cm { //cmmatrix astore + .getpath + exch concat + newpath { exec } forall + % If inside a BT/ET block, we need to update the TextSaveMatrix + currentdict /TextSaveMatrix .knownget { + //cmmatrix exch dup concatmatrix pop + } if + % 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 + } bdef + + /i { 1 .min setflat } bdef + /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 } bdef + /gs { gs } def +end + +% Each entry in this dictionary is +% <gsres> <value> -proc- <gsres> +/gsbg { + /BGDefault load resolvedefaultfnproc setblackgeneration +} bdef +/gsucr { + /UCRDefault load resolvedefaultfnproc setundercolorremoval +} bdef +/gstr { + dup type /arraytype eq { + { oforce /TRDefault load resolvedefaultfnproc } forall + setcolortransfer + } { + /TRDefault load resolvedefaultfnproc settransfer + } ifelse +} bdef +/gsparamdict mark + /SA { setstrokeadjust } + /OP { 1 index /op known not { dup op } if OP } + % The PDF 1.3 specification says that the name /Default is only + % recognized for {BG,UCR,TR}2. However, PDF 1.3 files produced + % by Adobe Acrobat Distiller 4.0 for Windows use the name /Default + % with the older keys, so we have to implement this. + /BG { 1 index /BG2 known { pop } { gsbg } ifelse } + /UCR { 1 index /UCR2 known { pop } { gsucr } ifelse } + /TR { 1 index /TR2 known { pop } { gstr } ifelse } + + % Some functions used to implement phases of HT and HTP + /sethalftones { + dup /Default eq { + pop .setdefaulthalftone + } { + resolvehalftone sethalftone + } ifelse + } bdef + /sethalftonephases { + /sethalftonephase where { pop aload pop sethalftonephase } { pop } ifelse + } bdef + + /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 + } + /HTP { + % HTP may be present even if this isn't a DPS interpreter. + dup sethalftonephases .swapcolors sethalftonephases .swapcolors + } + % PDF 1.3 + % The font is an indirect reference, not a resource name + /Font { aload pop exch oforce resourcefont exch Tf } + /LW { setlinewidth } + /LC { setlinecap } + /LJ { setlinejoin } + /ML { 1 .max setmiterlimit } + /D { aload pop setdash } + /RI { ri } + /op { op } + /OPM { OPM } + /BG2 { gsbg } + /UCR2 { gsucr } + /TR2 { gstr } + /FL { 1 .min setflat } + /SM { + % SM may be present even if this is only a Level 2 interpreter. + /setsmoothness where { pop setsmoothness } { pop } ifelse + } + % PDF 1.4 + % All of these require the "transparency" feature in the interpreter. + /ca { ca } + /CA { CA } + /SMask { + {gssmask} PDFSTOPONERROR { exec //false } { stopped } ifelse + { + pop (\n **** Error in SMask during ExtGState. Ignoring the mask, output may be incorrect.\n) + pdfformaterror + } if + } + /AIS { AIS } + /BM { BM } + /TK { TK } +.dicttomark readonly def +/gs { % <gsres> gs - + Page /ExtGState rget { + % We keep the dictionary on the stack during the forall so that + % keys that interact with each other have access to it. + dup { + oforce exch gsparamdict exch .knownget { exec } { pop } ifelse + } forall pop + } if +} bdef + +% ------ Transparency support ------ % + +/gssmask { + { + dup 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 + SoftMask //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 + /CS knownoget { + resolvecolorspace dup setgcolorspace csput + } if + aload pop setcolor [ currentgray ] + end grestore + /GrayBackground exch 3 2 roll + } if + dup /TR knownoget { + dup /Identity eq { + pop + } { + resolvefnproc /TransferFunction exch 3 2 roll + } ifelse + } if + dup /G oget + dup /BBox oget 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 + //SetGroupExtGStateDict + { + exch dup where + { + exch get 2 index 3 1 roll put + } + { + pop pop + } ifelse + } forall + 10 2 roll + /.execmaskgroup cvx 2 packedarray cvx /Draw exch 3 2 roll + pop + .dicttomark + exit + } loop + SMask +} bdef + +% Functions specific to the Device* colorspaces to force the switch to +% the Device* colorspace so that the SMask will not get a CIEBased* colorspace +% in the case when UseCIEColor changes the Device* colorspace to something else. +% Also see the logic in pdf_main.ps:pdfopen that similarly defines these resources. +/forceDefaultCS << + { + currentcolorspace setcolorspace % this will switch to Device colorspace + } bind + /DeviceGray exch + /DeviceRGB 1 index + /DeviceCMYK 1 index +>> +def + +% This procedure is called to actually render the soft mask. +/.execmaskgroup { % <masknum> <paramdict> <formdict> .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 + 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 + } { + % inheriting the colorspace -- make sure Device* spaces are not CIEBased + forceDefaultCS currentcolorspace 0 get .knownget { exec } if + //false % no defined colorspace + } ifelse + 3 -1 roll dup + dup 4 1 roll /BBox get aload pop .begintransparencymaskgroup + exch dup /Resources knownoget { oforce } { 2 dict } ifelse + 3 -1 roll dup /GroupGState .knownget { 2 index /GroupGState 3 -1 roll put} if + /GroupExtGState .knownget { 1 index /GroupExtGState 3 -1 roll put} if + exch //false resolvestream + 1 index exch .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. + dup /GroupGState undef + /GroupExtGState undef + .endtransparencymask + PDFfile exch setfileposition + mark exch /OverrideICC exch .dicttomark setuserparams + .setuseciecolor setcolorspace setcolor + setmatrix + end % restore colorspace, color and ExtGState (end) + /SoftMask where pop /SoftMask //true put % special setting to tell us it has been rendered +} bdef + +% Paint a Form+Group XObject, either for a transparency mask or for a Do. +/.execgroup { % <resdict> <stream> .execgroup - + pdfemptycount 3 1 roll + /pdfemptycount count 3 sub store + gsave //nodict begin + + % We have to set the gstate correctly for lazy evaluation of a softmask group. + % we also must preserve the color(space) as setup in .execmaskgroup. + % 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. + mark currentcolor currentcolorspace counttomark 2 add index dup + /GroupGState .knownget { setgstate } if + /GroupExtGState .knownget { { exch exec } forall } if + setcolorspace setcolor pop + newpath //null SMask + 1 .setopacityalpha 1 .setshapealpha + 1 CA 1 ca + /Compatible .setblendmode + % Execute the body of the Form, similar to DoForm. + pdfopdict .pdfruncontext + end grestore + /pdfemptycount exch store +} bdef + +/.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 +} bdef + +% .paintgroupform implements the Form PaintProc in the case where the +% Form XObject dictionary includes a Group key. See .paintform below. +/.paintgroupform { % <resdict> <stream> <formdict> .paintgroupform - + dup /Group oget exch /BBox oget + % Stack: resdict stream groupdict bbox + .beginformgroup + .execgroup + .endtransparencygroup +} bdef + +% Make an ImageType 103 (soft-masked) image. +/makesoftmaskimage { % <datasource> <imagemask> <SMask> makesoftmaskimage + % <datasource> <imagemask>, updates currentdict = + % imagedict + % See the ImageType 3 case of makemaskimage below. + % SMask is a stream, another Image XObject. + % Stack: datasource imagemask(false) smaskstreamdict + PDFfile fileposition exch + dup /Matte knownoget { /Matte exch def } if + dup length dict makeimagedict pop + % In order to prevent the two data sources from being + % aliased, we need to make at least one a reusable stream. + % We pick the mask, since it's smaller (in case we need to + % read all its data now). + % Stack: datasource imagemask(false) savedpos + % maskdict is currentdict + /DataSource DataSource mark + /Intent 1 + /AsyncRead //true + .dicttomark {.reusablestreamdecode} 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 + AlphaIsShape { /ShapeMaskDict } { /OpacityMaskDict } ifelse exch def + /ColorSpace DataDict /ColorSpace get def +} bdef + +% ---------------- Color setting ---------------- % + +/01_1 [0 1] readonly def +/01_3 [0 1 0 1 0 1] readonly def +/01_4 [0 1 0 1 0 1 0 1] readonly def + +% The keys here are resolved (PostScript, not PDF) color space names. +/csncompdict 9 dict begin + /DeviceGray { pop 1 } bdef + /DeviceRGB { pop 3 } bdef + /DeviceCMYK { pop 4 } bdef + /CIEBasedA //DeviceGray def + /CIEBasedABC //DeviceRGB def + /CalGray //DeviceGray def + /CalRGB //DeviceRGB def + /Lab //DeviceRGB def + /ICCBased { 1 oget /N oget } bdef + /Separation //DeviceGray def + /DeviceN { 1 oget length } bdef + /Indexed //DeviceGray def +currentdict end readonly def + +% <colorspace> csncomp <n> +/csncomp { + dup dup type /arraytype eq { 0 oget } if + //csncompdict exch get exec +} bdef + +currentdict /csncompdict undef + +/ICCBased-resolve { + PDFfile fileposition exch + dup dup 1 oget + mark exch { oforce } forall .dicttomark + dup dup //true resolvestream + /ReusableStreamDecode filter /DataSource exch put + + % 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 +} bdef + +/csrdict 13 dict begin + /DeviceGray { } bdef + /DeviceRGB { } bdef + /DeviceCMYK { } bdef + + /CalGray { 1 oget [ exch /CalGray exch ] } bdef + /CalRGB { 1 oget [ exch /CalRGB exch ] } bdef + /Lab { 1 oget [ exch /Lab exch ] } bdef + + /CalCMYK { + pop /DeviceCMYK % not defined by Adobe + } bdef + + /ICCBased { + dup 1 get type /dicttype ne { % don't resolve more than once + ICCBased-resolve + } if + } bdef + + /Separation { + aload pop exch oforce resolvecolorspace + % Contrary to PDF manuals up to v.1.5, Acrobat Distiller 3.01 + % can use /Identity name here instead of a function. + exch oforce resolveidfnproc + + %% Make sure the ink name is not an indirect object.... + 3 -1 roll oforce 3 1 roll + + 4 array astore + } bdef + + /DeviceN { + [ exch aload pop ] % Copy into a new array + dup dup 1 oget % Resolve Names array + [ exch { oforce } forall ] % resolve each of the names + 1 exch put + dup dup 2 oget resolvecolorspace + 2 exch put + dup dup 3 oget resolvefnproc + 3 exch put + dup length 4 gt { % Check for attributes dict + dup dup 4 oget % devn_array devn_array attr_dict + dup /Colorants knownoget % Check for Colorants Dict + { % Create a new attribute dict with only a Colorants dict entry. + % Resolve all of the Colorant dict entries. This is needed + % to prevent a conflict if we attempt to resolve the tint + % transform functions of the Colorant color spaces multiple + % times. + exch pop % Remove old attributes dict + << exch % Start new attributes dict + % Build new Colorants dict with resolved entries + << exch { oforce resolvecolorspace } forall >> + /Colorants exch >> % Finish new attributes dict + } if + 4 exch put % Put resolved or new attributes dict + } if + } bdef + + /Indexed { + aload pop + %% 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 + } bdef + + /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 + } bdef + + /Pattern { + dup type /nametype ne { + dup length 1 gt { + 1 oget resolvecolorspace + /Pattern exch 2 array astore + } if + } if + } bdef + +currentdict end readonly def + +/cssubst { % <csname> cssubst <cspace'> true + % <csname> cssubst false + dup resolvecolorspace + dup 1 index ne { exch pop //true } { pop pop //false } ifelse +} bdef + +/csnames mark + /DeviceGray dup /DeviceRGB dup /DeviceCMYK dup /Pattern dup +.dicttomark readonly def +/csresolve { % <csresourcename> csresolve <cspace> <true> | <false> + 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 +} bdef + +/resolvecolorspace { % <cspace> resolvecolorspace <cspace'> + 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 <</ColorSpace /Device...>>\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + exch pop //true + } { + //true + } ifelse + } ifelse + } { + //true + } ifelse { + dup dup type /arraytype eq { 0 get } if + //csrdict exch .knownget { + exec dup type /nametype ne { dup length 1 eq { 0 get } if } if + } { + dup type /nametype eq { + csresolve not { /DeviceRGB } if % Arbitrary + } { + csset exch pop + } ifelse + } ifelse + } if +} bdef + +/scresolve { % <c0> ... scresolve <multi> + % We can't really make sc[n] and SC[N] work, because + % the color space information isn't available at + % conversion time; so we hack it by assuming that + % all the operands on the stack are used, and that + % if the top operand is a name, it's a Pattern resource. + dup type /nametype eq + { Page /Pattern rget { resolvepattern } { //null } ifelse } + if + dup type /dicttype eq { + % Check the PaintType, if any (shading patterns don't + % have one). + dup /PaintType knownoget { 2 eq } { //false } ifelse + } { + .pdfcount 1 gt + } ifelse +} bdef + +%% 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 { % <patdict> <resdict> .pdfpaintproc - + PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Begin PaintProc) print dup === flush } if } if + PDFfile fileposition 3 1 roll + q + 1 index /PaintType oget 1 eq { + % For colored patterns, set default fill and stroke colors. + 0 g 0 G + } { + % For uncolored patterns, we have to unbind the current + % color and color space before running the PaintProc. + //null sc1 //null SC1 + } ifelse + + % Save old values on opstack, set pdfemptycount to new value. + pdfemptycount countdictstack mark + + /pdfemptycount count 3 sub def 5 3 roll + % + % Stack: ... <old emptycount> <dictcount> mark <patdict> <resdict> + % | + % New empty count points here -----------+ + + exch //false resolvestream pdfopdict .pdfruncontext + cleartomark + + //false + { countdictstack + 2 index le { exit } if + currentdict /n known not or + Q + } loop { + ( **** Error: Pattern stream has unbalanced q/Q operators \(too many q's\)\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + } 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 +} bdef + +/.pdfpaintproc { + %% Get the /m from pdfopdict (must be present) + %% and check its a packedarray + pdfopdict /m get dup type /packedarraytype eq { + %% 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 + %% rearrange the operands, move the boolean to the back + 3 1 roll + %% Uncopnditionally 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 +}bdef + +/resolvepattern { % <patternstreamdict> resolvepattern <patterndict> + % Don't do the resolvestream now: just capture the data + % from the file if necessary. + dup length dict copy + dup /FilePosition .knownget { + 1 index /File get dup fileposition 3 1 roll + % Stack: dict savepos pos file + dup 3 -1 roll setfileposition + dup 3 index /Length 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 put } { pop pop } ifelse + dup /.pattern_uses_transparency 1 index patternusestransparency put + PDFDEBUG { pdfdict /PDFSTEPcount .knownget { 1 le } { //true } ifelse { (%Pattern: ) print dup === flush } if } if +} bdef + +/ignore_color_op ( **** 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 + } bdef + + /rg { .incachedevice { + pop pop pop //ignore_color_op pdfformaterror + } { + /DeviceRGB cssubst { cs sc* } { rg } ifelse + } ifelse + } bdef + + /k { .incachedevice { + pop pop pop pop //ignore_color_op pdfformaterror + } { + k + } ifelse + } bdef + + /cs { .incachedevice { + pop //ignore_color_op pdfformaterror + } { + csresolve { cs } if + } ifelse + } bdef + + /sc { .incachedevice { + .pdfcount { pop } repeat //ignore_color_op pdfformaterror + } { + scresolve { sc*_and_set } { sc1_and_set } ifelse + } ifelse + } bdef + + /scn /sc load def + + /G { .incachedevice { + pop //ignore_color_op pdfformaterror + } { + /DeviceGray cssubst { CS SC1 } { G } ifelse + } ifelse + } bdef + + /RG { .incachedevice { + pop pop pop //ignore_color_op pdfformaterror + } { + /DeviceRGB cssubst { CS SC* } { RG } ifelse + } ifelse + } bdef + + /K { .incachedevice { + pop pop pop pop //ignore_color_op pdfformaterror + } { + K + } ifelse + } bdef + + /CS { .incachedevice { + pop //ignore_color_op pdfformaterror + } { + csresolve { CS } if + } ifelse + } bdef + + /ri { .incachedevice { + pop //ignore_color_op pdfformaterror + } { + ri + } ifelse + } bdef + + /SC { .incachedevice { + .pdfcount { pop } repeat //ignore_color_op pdfformaterror + } { + scresolve { SC*_and_set } { SC1_and_set } ifelse + } ifelse + } bdef + + /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 } bdef + /l { { lineto } stopped { count pdfemptycount sub 2 .min { pop } repeat } if } bdef + /c { { curveto } stopped { count pdfemptycount sub 6 .min { pop } repeat } if } bdef + + /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 + } bdef + /y { { 2 copy curveto } stopped { count pdfemptycount sub 6 .min { pop } repeat } if } bdef + + /re { + 4 2 roll moveto exch dup 0 rlineto 0 3 -1 roll rlineto neg 0 rlineto + closepath + } bdef + + /h { closepath } bind 0 get def + % Path painting and clipping + /n { n } def + /S { S } def + /s { s } def + /f { f } def + /f* { f* } def + /B { B } def + /b { b } def + /B* { B* } def + /b* { b* } def + /W { W } def + /W* { W* } def + + /sh_save 1 array def + /sh_group << /Subtype /Group /Isolated //true >> readonly def + + /do_shade { + 0 .setoverprintmode + { dup /.shading .knownget { + exch pop + } { + .buildshading + } ifelse + .shfill + } stopped { + pop + ( **** Error: Ignoring invalid smooth shading object, output may be incorrect.\n) + pdfformaterror + } if + } bdef + + /sh { + OFFlevels length 0 eq { + setfillstate resolvesh + //sh_save 0 save put + PDFusingtransparency { + SoftMask //null ne { + //sh_group + 1 index /BBox knownoget { + { oforce } forall + } { + gsave clippath pathbbox grestore + } ifelse + .begintransparencygroup + } if + dup checkOPtrans exch 1 index { + % We need to push a non-isolated, non-knockout transparency group and + % perform the operation in CompatibleOverprint mode, then end the + % transparency group. Do the begintransparencygroup step here. + mark /Subtype /Group /Isolated //false .dicttomark + 1 index /BBox knownoget { + { oforce } forall + } { + gsave clippath pathbbox grestore + } ifelse + .begintransparencygroup + exch .currentblendmode exch .currentopacityalpha exch 4 -1 roll % save current values + /CompatibleOverprint .setblendmode 1 .setopacityalpha + } if + //do_shade exec + { + .endtransparencygroup .setopacityalpha .setblendmode % end the CompatibleOverprint group + } if + SoftMask //null ne { + .endtransparencygroup + } if + } { + //do_shade exec + } ifelse + //sh_save 0 get restore + } { + pop + } ifelse + } bdef + currentdict dup /sh_save undef /sh_group undef +end + +% ---------------- XObjects ---------------- % + +/xobjectprocs mark % <dict> -proc- - + /Image { DoImage } + /Form { DoForm } + /PS { DoPS } +.dicttomark readonly def + +% Note that the keys in defaultdecodedict are resolved (PostScript, not PDF) +% color space names. +/defaultdecodedict mark + /DeviceGray { pop //01_1 } bind + /DeviceRGB { pop //01_3 } bind + /DeviceCMYK { pop //01_4 } bind + /CIEBasedA { 1 get /RangeA knownoget not { //01_1 } if } bind + /CIEBasedABC { 1 get /RangeABC knownoget not { //01_3 } if } bind + /CalGray { pop //01_1 } bind + /CalRGB { pop //01_3 } bind + /Lab { 1 get /Range knownoget not { [-100 100 -100 100] } if } bind + /ICCBased { + 1 oget dup /Range knownoget { + exch pop + }{ + /N get [ exch {0 1} repeat ] readonly + } ifelse + } bind + /Separation { pop //01_1 } bind + /DeviceN { + 1 oget length [ exch {0 1} repeat ] readonly + } bind + /Indexed { + pop [ 0 1 BitsPerComponent bitshift 1 sub ] + } bind +.dicttomark readonly def + +/checkaltimage { % <resdict> checkaltimage <resdict[']> + Printed { + dup /Alternates knownoget { + { + dup /DefaultForPrinting knownoget { + { + /Image oget exch pop exit + } { + pop + } ifelse + } { + pop + } ifelse + } forall + } if + } if +} bdef + +% <string> <index> getu16 <integer> +/getu16 { + 2 copy get 8 bitshift 3 1 roll 1 add get add +} bind def + +% <string> <index> getu32 <integer> +/getu32 { + 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add +} bind 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 + 17 { /sGrayICC /ColorSpace findresource } bind + 18 3 index % YCC is converted to RGB +% 19 % CIEJab not supportec by PDF 1.7 +% 20 % e-sRGB +% 21 % ROMMRGB +% 24 % e-sYCC +.dicttomark readonly def + +% Process jp2 blocks (aka boxes). All procedures have the signature +% <file> <length> -> ... <file> <flush_length> +/jp2_tag_dict 10 dict begin + + /jp2h { % descend into a sub-stream, don't return. + () /SubFileDecode filter 0 + } bdef + + /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 + } bdef + + %% 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 + } bdef + + /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 + } bdef + + % 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 + } bdef + + /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 + } bdef + +currentdict end readonly def + +% Parse jp2 file format to get color space and image depth info. +% <file> 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 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. +% <resdict> <key> <value> -> <resdict> +/add-to-last-param { + 2 index /DecodeParms knownoget { + dup {} eq { + 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 % <resdict> <key> <value> [] <<>> + } { + dup length 1 add dict copy dup % <resdict> <key> <value> <<>> <<>> + } ifelse + 4 2 roll put % <resdict> obj + } { + % <resdict> <key> <value> + mark 3 1 roll .dicttomark % <resdict> obj + 1 index /Filter knownoget { + dup type /arraytype eq { + length array % <resdict> obj [...] + dup dup length 1 sub % <resdict> obj [...] [...] len-1 + 4 -1 roll put % <resdict> [... obj] + } { + pop + } ifelse + } if + } ifelse + 1 index exch + /DecodeParms exch put % <resdict> +} bdef + +/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 +} bdef + +/get-smask-in-data { % <dict> -> <int> + /SMaskInData knownoget { + dup dup 1 ne exch 2 ne and { + pop 0 + } if + } { + 0 + } ifelse +} bdef + +/makeimagedict { % <resdict> <newdict> makeimagedict <imagemask?> + % On return, newdict' is currentdict + begin + /Width 2 copy oget def + /Height 2 copy oget def + % Handle missing BitsPerComponent later. + /BitsPerComponent 2 copy knownoget { cvi def } { pop } ifelse + /Interpolate 2 copy knownoget { def } { pop } ifelse + makeimagekeys +} bdef + +/makeimagekeys { % <resdict> makeimagekeys <imagemask> + % newdict is currentdict + % Assumes Width, Height, BPC, Interpolate already copied. + /ImageType 1 def + /ImageMatrix Width 0 0 + % Handle 0-height images specially. + Height dup 0 eq { pop 1 } if neg 0 1 index neg + 6 array astore def + + %% 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). + //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 DeoceParms we cna use it in the DCTDecode filter to + % work around this. + dup /Filter knownoget { % <<stream dict>> /name or [array] + dup type /arraytype eq { + % <<stream dict>> [array of names] + length % <<stream dict>> number of filters + 1 index /DecodeParms knownoget { + exch pop % drop length of Filter array, the DecodeParams has 1 entry per filter + % <<stream dict>> [array of decodeparams] + } { + % No deocde params, we must make an array of them + % <<stream dict>> number of filters + array % <<stream dict>> [] + dup % <<stream dict>> [] [] + 2 index /DecodeParms exch % <<stream dict>> [] [] /DecodeParms <<stream dict>> + 3 1 roll % <<stream dict>> <<stream dict>> [] /DecodeParms + exch put % <<stream dict>> [] + } ifelse + dup length 1 sub % <<stream dict>> [] arraylength-1 + 0 1 3 -1 roll % <<stream dict>> [] 0 1 arraylength-1 + { % <<stream dict>> [] loopcount + 1 index % <<stream dict>> [] loopcount [] + 2 copy % <<stream dict>> [] loopcount [] loopcount [] + exch + get % <<stream dict>> [] loopcount [] <<>> or -null- + dup null eq { + pop exch % <<stream dict>> [] [] loopcount + <</Height + 5 index /Height oget % <<stream dict>> [] [] loopcount << /Height Height + round cvi + >> + put % <<stream dict>> [] + }{ % + oforce_recursive % resolve any indirect references + dup type /dicttype eq { + % <<stream dict>> [] loopcount [] <<>> + /Height % <<stream dict>> [] loopcount [] <<>> /Height + 5 index /Height oget % <<stream dict>> [] loopcount [] <<>> /Height Height + round + cvi + put pop pop % <<stream dict>> [] + }{ + %% bogus entry, throw it away and create a new one + pop exch % <<stream dict>> [] loopcount [] + <</Height + 5 index /Height oget % <<stream dict>> [] [] loopcount << /Height Height + round cvi + >> + put % <<stream dict>> [] + } ifelse + }ifelse + } for + pop % <<stream dict>> + }{ + pop % <<stream dict>> + dup /DecodeParms knownoget { + oforce_recursive % resolve any indirect references + dup type /dicttype eq { + % <<stream dict>> <<decode parms dict>> + /Height 2 index % <<stream dict>> <<decode parms dict>> /Height <<stream dict>> + /Height oget % <<stream dict>> <<decode parms dict>> /Height ImageHeight + round cvi + put % <<stream dict>> + }{ + %% bogus entry, throw it away and create a new one + pop % <<image dict>> <<stream dict>> [] + <</Height % <<stream dict>> <<image dict>> << /Height + 2 index /Height oget % <<stream dict>> <<image dict>> << /Height Height + round cvi + >> + 1 index exch /DecodeParms exch put % <<stream dict> <<image dict>> + } ifelse + }{ + dup % <<stream dict>> <<stream dict>> + /DecodeParms <</Height % <<stream dict>> <<stream dict>> /DecodeParms << /Height + 3 index % <<stream dict>> <<stream dict>> /DecodeParms << /Height <<stream dict>> + /Height oget + round cvi + >> % <<stream dict>> <<stream dict>> /DecodeParms << /Height ImageHeight>> + put % <<stream dict>> + }ifelse + }ifelse + } if + + % Even though we're going to read data, + % pass false to resolvestream so that + % it doesn't try to use Length (which may not be present). + //false resolvestream /DataSource exch def + //false + } ifelse +} bdef + +currentdict /add-to-last-param 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. + %% + 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 % <<image>> <<>> + 1 index /SMask knownoget { % <<image>> <<>> <<sm>> + dup 3 index ne { % <<image>> <<>> <<sm>> <<sm>> + 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 { 1 index exch /Mask exch put } if + makeimagedict doimagesmask +} bdef +/makemaskimage { % <datasource> <imagemask> <Mask> makemaskimage + % <datasource> <imagemask>, updates currentdict = + % imagedict + dup type /arraytype eq { + /ImageType 4 def + % Check that every element of the Mask is an integer. + //false 1 index { + type /integertype ne or + } forall { + 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. + 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 + } { + % AR5, AR9 do this for most cases. Bug 690786. + [ exch { 1 BitsPerComponent bitshift 1 sub and } forall ] + } 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 +} bdef + +/doimagesmask { % <imagemask> doimagesmask - + PDFusingtransparency { + currentdict /SMask knownoget + } { + //false + } ifelse + { % We are doing transparency and SMask is present in the image + % stack: <imagemask> <SMask> + /PreserveSMask /GetDeviceParam .special_op { + exch pop + }{ + //false + }ifelse + { + pop % pdfwrite will process SMask directly during 'doimage' + } { + .begintransparencymaskimage + PDFfile fileposition exch + gsave //nodict begin + //null /SoftMask gput + 1 .setopacityalpha 1 .setshapealpha + 1 CA 1 ca + /Compatible .setblendmode + DoImage + end grestore + PDFfile exch setfileposition + 0 .endtransparencymask + } ifelse + << /Subtype /Group /Isolated //true + /.image_with_SMask //true % pdfwrite needs : see gs/src/ztrans.c, gs/src/gdevpdft.c + >> 0 0 1 1 .begintransparencygroup + doimage + .endtransparencygroup + % 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 + } { + SoftMask //null ne { + % the image doesn't have an SMask, but the ExtGState does, force a group. + << /Subtype /Group /Isolated //true >> 0 0 1 1 .begintransparencygroup + doimage + .endtransparencygroup + } + { doimage } + ifelse + } ifelse +} bdef + +% For development needs we define a special option for running with a new handler +% for images with a soft mask. +//systemdict /NEW_IMAGE3X .knownget not { //false } if { + /doimagesmask { % <imagemask> doimagesmask - + doimage + } bdef +} if + +/doimage { % <imagemask> doimage - + % imagedict is currentdict, gets popped from dstack + //null checkOPtrans { + % We need to push a non-isolated, non-knockout transparency group and + % perform the operation in CompatibleOverprint mode, then end the + % transparency group. Do the begintransparencygroup step here. + mark /Subtype /Group /Isolated //false .dicttomark 0 0 1 1 .begintransparencygroup + OPsavedict dup /saveBM .currentblendmode put /saveOA .currentopacityalpha put % save current values + /CompatibleOverprint .setblendmode 1 .setopacityalpha + } if + + %% 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 setfillstate { imagemask } } + { ColorSpace setgcolorspace currentdict end setfillblend { 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 + + .currentblendmode /CompatibleOverprint eq { + .endtransparencygroup + OPsavedict dup /saveOA get .setopacityalpha /saveBM get .setblendmode + } if +} bdef + +/.paintform { % <formdict> <resdict> <stream> .paintform - + 1 index /FormResDict gput % For broken forms that inherit resources from the context. + 3 -1 roll dup /Group known PDFusingtransparency and { + .paintgroupform + } { + pop pdfopdict .pdfruncontext + } ifelse +} bdef + +/IncrementAppearanceNumber { + pdfdict /AppearanceNumber .knownget { + 1 add pdfdict /AppearanceNumber 3 -1 roll .forceput + }{ + pdfdict /AppearanceNumber 0 .forceput + } ifelse +}bdef + +/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 +} bdef + +/MakeNewAppearanceName { + IncrementAppearanceNumber + MakeAppearanceName +}bdef + +/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 +} bdef + +/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 //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 + }{ + /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 + + %% 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 +} bdef + +/_dops_save 1 array def + +/DoPS { + DOPS + { + //_dops_save 0 save put + //true resolvestream cvx exec + //_dops_save 0 get restore + } + { pop } + ifelse +} bdef + +currentdict /_dops_save undef + +/ocg_pocs 4 dict begin + /AllOn { + //true exch { + oforce dup type /dicttype eq { + /OFF known not and + } { + pop + } ifelse + } forall + } bdef + /AnyOn { + //false exch { + oforce dup type /dicttype eq { + /OFF known not or + } { + pop + } ifelse + } forall + } bdef + /AnyOff { + //AllOn exec not + } bdef + /AllOff { + //AnyOn exec not + } bdef +currentdict end readonly def + +% Check whether OCG or OCMD is visible +% <dict> oc-is-visible <bool> +/ocg-is-visible { + dup /Type knownoget { + /OCMD eq { + dup /OCGs knownoget not { {} } if % OC OCGs + dup type /dicttype eq { 1 array astore } if + //true 1 index { //null eq and } forall { + pop pop //true % all nulls => show + } { + exch /P knownoget not { /AnyOn } if % OCGs P + //ocg_pocs exch get exec % bool + } ifelse + } { + /OFF known not % OFF is inserted by process_trailer_attrs + } ifelse + } { + /OFF known not % OFF is inserted by process_trailer_attrs + } ifelse +} bdef + +drawopdict begin + /Do { % /Name + %% 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 + setfillblend + PDFfile fileposition exch % pos /Name + dup Page /XObject rget { + exch pop % pos obj + OFFlevels length 0 eq { + dup /OC knownoget { ocg-is-visible } { //true } ifelse + } { + //false + } ifelse { + dup /Subtype 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 + } bdef +end + +currentdict /xobjectprocs .undef +currentdict /ocg_pocs .undef + +% ---------------- In-line images ---------------- % + +% Undo the abbreviations in an in-line image dictionary. +% Note that we must look inside array values. +% /I is context-dependent. +/unabbrevkeydict mark + /BPC /BitsPerComponent /CS /ColorSpace /D /Decode /DP /DecodeParms + /F /Filter /H /Height /I /Interpolate /IM /ImageMask /W /Width +.dicttomark readonly def +/unabbrevvaluedict mark + /AHx /ASCIIHexDecode /A85 /ASCII85Decode /CC /CalCMYK + /CCF /CCITTFaxDecode /CG /CalGray /CR /CalRGB + /DCT /DCTDecode /CMYK /DeviceCMYK /Fl /FlateDecode + /G /DeviceGray /RGB /DeviceRGB + /I /Indexed /LZW /LZWDecode /RL /RunLengthDecode +.dicttomark readonly def +/unabbrevtypedict mark + /nametype { + //unabbrevvaluedict 1 index .knownget { exch pop } if + } + /arraytype { + dup 0 1 2 index length 1 sub { + 2 copy get unabbrevvalue put dup + } for pop + } +.dicttomark readonly def +/unabbrevvalue { % <obj> unabbrevvalue <obj'> + oforce //unabbrevtypedict 1 index type .knownget { exec } if +} bdef + +/is_space_dict << 0 0 9 9 10 10 12 12 13 13 32 32 >> readonly def + +drawopdict begin + /BI { mark } bdef + /ID { + 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 { + 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 <start>I<sp|end> or <start|sp>EI<sp|end> + PDFsource read not { + /ID cvx /syntaxerror signalerror + } if + dup 73 eq { + pop 10 69 73 % Seed to: <sp>EI + } { + 10 10 3 -1 roll % Seed to: <sp><sp><any> + } 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 + } bdef +end + +currentdict /is_space_dict undef + +% ================================ Text ================================ % + +drawopdict begin + % Text control + /BT { BT } def + /ET { ET } def + /Tc { Tc } def + /TL { TL } def + /Tr { Tr } def + /Ts { Ts } def + /Tw { Tw } def + /Tz { Tz } def + % Text positioning + /Td { Td } def + /TD { TD } def + /Tm { Tm } def + /T* { T* } def + % Text painting + /Tj { Tj } def + /' { ' } def + /" { " } def + /TJ { TJ } def + + /Tform { Tform } def % Text formatting and painting for AcroForm + % without appearance streams. +end + +% ======================= Invalid operators ============================ % + +drawopdict begin + /QBT { + Q BT + ( **** Error: invalid operator QBT processed as Q BT .\n) + pdfformaterror % Bug 690089 + ( Output may be incorrect.\n) pdfformaterror + } def + + /. { + 0. + ( **** Error: invalid operator . processed as number 0. .\n) + pdfformaterror % Bug 690730 + ( Output may be incorrect.\n) pdfformaterror + } 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 { % <<parent>> <<kid>> -> <<parent>> <<kid>> + 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 +} bdef + +% Get and normalize an annotation's rectangle. +/annotrect { % <annot> annotrect <x> <y> <w> <h> + /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 +} bdef + +% Set an annotation color. +% If the /C array is empty we don't want to draw the annotation +% +/annotsetcolor { % <annot> 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 +} bdef + +% Draw the border. Currently, we ignore requests for beveling, and we +% don't round the corners of rectangles. +/strokeborder { % <annot> <width> <dash> strokeborder - + 1 index 0 ne { % do not draw if border width is 0 + gsave + 2 index annotsetcolor + { + 0 setdash dup setlinewidth + exch annotrect + 2 { 4 index sub 4 1 roll } repeat + 2 { 4 index 0.5 mul add 4 1 roll } repeat + rectstroke pop + grestore + } { + pop pop pop + } ifelse + } { + pop pop pop + }ifelse +} bdef + +% Draw an annotation border. +/drawborder { % <annot> drawborder - + gsave + dup /BS known 1 index /Border known or { + dup /BS knownoget { + dup type /dicttype ne % <annot> <border> <bad?> + } { + dup /Border oget + dup type /arraytype eq { + dup length 3 lt + } { + //true + } ifelse % <annot> [border] <bad?> + } ifelse { + ( **** Error: Invalids 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 { % UserUnit is ignored if -dPDFFitPage + Page /UserUnit knownoget { div } if + } if + {} 2 index /S knownoget { + /D eq { 2 index /D knownoget not { {3} } if exch pop } if + } if 3 -1 roll pop strokeborder + } { + dup 2 get + exch dup length 3 gt { 3 get } { pop {} } ifelse + strokeborder + } ifelse + } { + 1 {} strokeborder + } ifelse + grestore +} bdef + +% +% The PDF annotation F (flags) integer is bit encoded. +% Bit 1 (LSB) Invisible: 1 --> Do not display if no handler. +% Note: We have no handlers but we ignore this bit. +% Bit 2 Hidden: 1 --> Do not display. We will not display if this bit is set. +% Bit 3 Print: 1 --> Display if printing. We will display if this bit set +% (and not hidden) and Printed is true +% Bit 4 NoZoom: 1 --> Do not zoom annotation even if image is zoomed. +% Bit 5 NoRotate: 1 --> Do not rotate annotation even if image is rotated. +% Bit 6 NoView: 0 --> Display if this is a 'viewer'. We will display +% if this bit is not set (and not hidden) and Printed is false +% Bit 7 Read Only - 1 --> No interaction. We ignore this bit +% +% AR8 and AR9 print 3D annotations even if Print flag is off. Bug 691486. +% +/annotvisible { % <annot> annotvisible <visible> + 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 +} bdef + +/set_bc_color << + 1 { 0 get oforce setgray } bind + 3 { { oforce } forall setrgbcolor } bind + 4 { { oforce } forall setcmykcolor } bind +>> 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 % <field> <key> fget <value> -true- + { % <field> <key> 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 def + +% <annot> foo <annot> +/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 % <annot> file + + dup (BT ) writestring + 1 index /DA fget not { + 1 index /V fget { + <FEFF> anchorsearch{ + pop pop /FallBackFont /Identity-UTF16-H [/CIDFallBack] composefont 12 scalefont setfont + }{ + pop /Helvetica findfont 12 scalefont setfont + } 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 % <annot> + end +} bdef + +/can-regenerate-ap { % <annot> -> <bool> + //false exch + NeedAppearances { + dup /FT fget { + /Tx eq { + dup /V oknown { + pop not 1 + } if + } if + } if + } if + pop +} bdef + +/drawwidget { % <scalefactor_x> <scalefactor_y> <annot> 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 + 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 + pop pop pop +} bdef + +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 { % <annot> calc_annot_scale <x_scale> <y_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 { % <<Annot>> x y <<N>> + 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 +} bdef + +% Draw an annotation. +/drawannottypes 20 dict begin + + % 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 + } bdef + + /Link { % <annot> -> <false> + dup drawborder dup calc_annot_scale + 2 copy mul 0 ne + {3 -1 roll drawwidget //false} + { + pop pop + ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + }ifelse + } bdef + + /Ink { % <annot> -> <annot> <true> + % <annot> -> <false> + dup /AP oknown { + //true + } { + 1 setlinewidth + 1 setlinecap + 1 setlinejoin + dup annotsetcolor { + dup calc_annot_scale + 2 copy mul 0 ne + { + 3 index annotrect pop pop translate + scale + /InkList knownoget { + { oforce + mark exch { oforce } forall + .pdfinkpath + stroke + } forall + } if + } + { + pop pop + ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + } + ifelse + } if + //false + } ifelse + } bdef + + /Underline { + dup /AP oknown { + //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 + } bdef + + /StrikeOut { + dup /AP oknown { + //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 + } bdef + + % 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 def + + /emptydict 0 dict readonly def + + /Highlight { + 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 + pathbbox 2 index add exch 3 index add exch .begintransparencygroup + /Multiply .setblendmode + fill + .endtransparencygroup + } { % for -dNOTRANSPARENCY + stroke newpath + } ifelse + } if + } if + //false + } bdef + currentdict /emptydict undef + currentdict /highlight-arc undef + + /Squiggly { + dup /AP oknown { + //true + } { + 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 + //false + } ifelse + } bdef + + /Text { + dup /AP oknown { + //true + } { + 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 + //false + } ifelse + } bdef + + /FreeText { + dup /AP knownoget { + %% Check minimal entriy in /AP dictionary + /N known not { + //true + }{ + //false + }ifelse + } { + //true + }ifelse + %% We either have no appearance, or its invalid, make one up. + { + gsave + + dup annotrect (rectclip from freetext annotation) == flush rectclip + + dup /CA knownoget { + .setopacityalpha + } if + + dup /ca knownoget { + .setopacityalpha + } 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 + %% Somewhat horrifyingly, rectfill maps directly to the device fill_rectangle + %% method, which bypasses transparency (!!) So we construct the rectangle, + %% and fill it, manually instead.... + gsave 4 2 roll moveto 1 index 0 rlineto + 0 exch rlineto neg 0 rlineto closepath fill grestore + } 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 findfont exch scalefont setfont}{findfont exch scalefont setfont}ifelse} + /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 + dup /DA knownoget { + length string /tempstr exch def + dup /DA get tempstr copy pop + { + %% 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 + } { + 0 setgray + /Helvetica findfont 12 scalefont setfont + }ifelse + %% 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 4 -1 roll 1 add 4 -1 roll 1 add 4 -1 roll 2 sub 4 -1 roll 2 sub + 4 2 roll 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 + + %% Start the current point at the top left of the annotation Rect + %% + dup annotrect 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 + + %% Get the Contents string, if we don't have one, we're done + %% + 2 index /Contents knownoget { + %% Check for UTF16-BE, we probably don't work properly with this yet. + %% + dup 0 get 254 eq 1 index 1 get 255 eq and + { + /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 + } if + pop pop + //false + grestore + } + { + //true + } ifelse + } bdef + + /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 + } bdef + + % (text) y h -> - + /text { + /Times-Bold findfont 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 + } bdef + + /red <ef4023> readonly def + /green <3fae49> readonly def + /blue <0072bc> readonly def + + /stamp_dict 14 dict begin + /Approved { + //green //frame exec + (APPROVED) 13 30 //text exec + } bdef + /AsIs { + //red //frame exec + (AS IS) 13 30 //text exec + } bdef + /Confidential { + //red //frame exec + (CONFIDENTIAL) 17 20 //text exec + } bdef + /Departmental { + //blue //frame exec + (DEPARTMENTAL) 17 20 //text exec + } bdef + /Draft { + //red //frame exec + (DRAFT) 13 30 //text exec + } bdef + /Experimental { + //blue //frame exec + (EXPERIMENTAL) 17 20 //text exec + } bdef + /Expired { + //red //frame exec + (EXPIRED) 13 30 //text exec + } bdef + /Final { + //red //frame exec + (FINAL) 13 30 //text exec + } bdef + /ForComment { + //green //frame exec + (FOR COMMENT) 17 20 //text exec + } bdef + /ForPublicRelease { + //green //frame exec + (FOR PUBLIC) 26 18 //text exec + (RELEASE) 8.5 18 //text exec + } bdef + /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 + } bdef + /Sold { + //blue //frame exec + (SOLD) 13 30 //text exec + } bdef + /TopSecret { + //red //frame exec + (TOP SECRET) 14 26 //text exec + } bdef + currentdict end readonly def + + {/text/frame/red/green/blue} {currentdict exch undef} forall + + /Stamp { + dup /AP oknown { + //true + } { + 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 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 + //false + } ifelse + } bdef + + currentdict /quadpoints2basis undef +currentdict end readonly def + +/drawannot { % <annot> drawannot - + dup annotvisible { + gsave + dup dup /Subtype knownoget { + //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 + ( **** Error: Ignoring /Annot dict without required /Subtype entry.\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + } ifelse + grestore + } if pop % annotvisible +} bdef +currentdict /drawannottypes undef + +% Draw an annotation. + +/loadannot { + dup /AP .knownget { % <<Annot dict>> <<Appearance dictionary>> true | false + oforce + + dup { % <<Annot dict>> <<Appearance dict>> /Key <</Key dict>> + oforce % <<Annot dict>> <<Appearance dict>> /Key <<resolved /Key dict>> + + %% + %% Check to see if the apperance key has a simple stream or a dictionary of states + %% + dup /Subtype known % <<Annot dict>> <<Appearance dict>> /Key <<resolved /Key dict>> bool + { + %% Simple appearance stream + DoAppearance % <<Annot dict>> <<Appearance dict>> /Key + 2 index % <<Annot dict>> <<Appearance dict>> /Key <<Annot dict>> + /AP << % <<Annot dict>> <<Appearance dict>> /Key <<Annot dict>> /AP << + 4 -1 roll MakeAppearanceName cvx cvn >> put % <<Annot dict>> <<Appearance dict>> + } { + %% dictionary of states <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> + dup % <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> <<appearance states dict>> + { % <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> /StateKey <<State dictionary>> + oforce % <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> /StateKey <<resolved State dictionary>> + DoAppearance % <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> /StateKey + 1 index exch % <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> <<appearance states dict>> /StateKey + MakeAppearanceName cvx cvn % <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> <<appearance states dict>> /StateKey {} + put % <<Annot dict>> <<Appearance dict>> /Key <<appearance states dict>> + } forall + put % <<Annot dict>> <<Appearance dict>> /Key + dup + }ifelse + } forall + pop % <<Annot dict>> + } 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 + } 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 +} bdef + + +/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 +} bdef + +/preserveannottypes 20 dict begin + +/Circle {mark exch loadannot /ANN pdfmark false} bdef +/FileAttachment {mark exch loadannot /ANN pdfmark false} bdef +/FreeText {mark exch loadannot /ANN pdfmark false} bdef + +/Highlight { + mark exch + dup /QuadPoints .knownget { + 1 index /QuadPoints 3 -1 roll + ApplyCTMToQuadPoints + put + } if + loadannot /ANN pdfmark false +} bdef + +/Ink {mark exch loadannot /ANN pdfmark false} bdef + +/Line { + mark exch dup /L .knownget { + aload 5 1 roll transform 4 -2 roll transform 4 2 roll + 5 -1 roll astore + 1 index /L 3 -1 roll put + } if + loadannot /ANN pdfmark false +} bdef + +/Link {mark exch {drawannot} PDFSTOPONERROR {exec}{stopped {(Error: Ignoring invalid annotation, output may be incorrect.\n) pdfformaterror} if} ifelse cleartomark false} bdef + +/Movie {mark exch loadannot /ANN pdfmark false} bdef +/Popup {mark exch loadannot /ANN pdfmark false} bdef +/Sound {mark exch loadannot /ANN pdfmark false} bdef +/Square {mark exch loadannot /ANN pdfmark false} bdef +/Stamp {mark exch loadannot /ANN pdfmark false} bdef + +/StrikeOut { + mark exch + dup /QuadPoints .knownget { + 1 index /QuadPoints 3 -1 roll + ApplyCTMToQuadPoints + put + } if + loadannot /ANN pdfmark false +} bdef + +/Squiggly { + mark exch + dup /QuadPoints .knownget { + 1 index /QuadPoints 3 -1 roll + ApplyCTMToQuadPoints + put + } if + loadannot /ANN pdfmark false +} bdef + +/Text {mark exch loadannot /ANN pdfmark false} bdef +/TrapNet {mark exch loadannot /ANN pdfmark false} bdef + +/Underline { + mark exch + dup /QuadPoints .knownget { + 1 index /QuadPoints 3 -1 roll + ApplyCTMToQuadPoints + put + } if + loadannot /ANN pdfmark false +} bdef + +%% 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} bdef + +currentdict end readonly def + +/preserveannot { % <annot> preserveannot - + dup annotvisible { + gsave + dup dup /Subtype knownoget { + //preserveannottypes 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 + ( **** Error: Ignoring /Annot dict without required /Subtype entry.\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + } ifelse + grestore + } if pop % annotvisible +} bdef + +currentdict /preserveannottypes undef + +% ============================ AcroForm fields ============================ % + +% Get an attribure of the 0th annotation of a node +/annot_oget { % <annot> /Name annot_oget <value> + 1 index /Kids knownoget { + 0 oget exch oget exch pop + } { + oget + } ifelse +} bdef + +% All procedures have the signature: +% <acroform> <field> <annot|field> foo <acroform> <field> <annot|field> +/draw_terminal_field_dict 4 dict begin + +/Btn { + 1 index /Tf pget not { 0 } if + dup 16#20000 and 0 ne { + pop % Push button + dup /AP known { + 1 1 2 index drawwidget + } { + (Push button without appearance stream is not yet implemented) = + } ifelse + } { + 16#10000 and 0 ne { + % Radio button + dup /AP known { + 1 index /Kids oget { + 1 1 3 -1 roll drawwidget + } forall + } { + (Radio button without appearance stream is not yet implemented) = + } ifelse + } { + % Checkbox + dup /AP known { + dup 1 1 3 -1 roll drawwidget + } { + (CkeckBox without appearance stream is not yet implemented) = + } ifelse + } ifelse + } ifelse +} bdef + +/Tx { + dup /AP known { + dup 1 1 3 -1 roll drawwidget + } { + %% 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 + % <acroform> <field> <annot> (string) + /NullEncode filter % <acroform> <field> <annot> 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 write== + } if + dup 3 index /Ff pget not { 0 } if write= + dup 3 index /Q pget not { 0 } if write= + dup (Tform ET) write= + end + closefile % <acroform> <field> <annot> + dup 1 1 3 -1 roll drawwidget + } if + } ifelse +} bdef + +/Ch { + (Ch is not yet implemened) //== exec +} bdef + +/Sig { + (Sig is not yet implemened ) //== exec +} bdef + +currentdict end def + +/draw_terminal_field { % <field> draw_terminal_field - + dup /Kids knownoget { 0 oget } { dup } ifelse + dup /P knownoget { + /Page load eq { + //draw_terminal_field_dict 2 index /FT pget not { 0 } if .knownget { + exec + } if + } if + } if + pop pop +} bdef + +% We distinguish 4 types of nodes on the form field tree: +% - non-terminal field - has a kid that refers to the parent (or anywhere else) +% - terminal field with separate widget annotations - has a kid that doesn't have a parent +% - terminal field with a merged widget annotation - has no kids +% - widget annotation - has /Subtype and /Rect +% +% The recursive enumeration of the form fields doesn't descend into widget annotations. + +/draw_form_field { % <field> draw_form_field - + 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 +} bdef + +/draw_acro_form { % <form> draw_acro_form - + dup /Fields knownoget { + { oforce draw_form_field } forall + } if + pop +} bdef + +currentdict /draw_terminal_field_dict undef + +end % pdfdict +end % GS_PDF_ProcSet +.setglobal |