From ea1c348c670611bc318669cb912ff87379182b22 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 9 Nov 2021 22:39:21 +0100 Subject: [PATCH] Always prefer abbreviated keys, over full ones, when doing any dictionary lookups (issue 14256) Note that issue 14256 was specifically about *inline* images, please refer to: - https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf#G7.1852045 - https://www.pdfa.org/safedocs-unearths-pdf-inline-image-issue/ - https://pdf-issues.pdfa.org/32000-2-2020/clause08.html#H8.9.7 However, during review of the initial PR in https://github.com/mozilla/pdf.js/pull/14257#issuecomment-964469710, it was suggested that we instead do this *unconditionally for all* dictionary lookups. In addition to re-ordering the existing call-sites in the `src/core`-code, and adding non-PRODUCTION/TESTING asserts to catch future errors, for consistency a number of existing `if`/`switch`-blocks were re-factored to also check the abbreviated keys first. --- src/core/colorspace.js | 14 +- src/core/evaluator.js | 23 +- src/core/image.js | 21 +- src/core/jpeg_stream.js | 4 +- src/core/parser.js | 139 +++++---- src/core/pattern.js | 4 +- src/core/predictor_stream.js | 2 +- src/core/primitives.js | 42 +++ test/pdfs/.gitignore | 1 + test/pdfs/issue14256.pdf | 576 +++++++++++++++++++++++++++++++++++ test/test_manifest.json | 6 + test/unit/primitives_spec.js | 2 +- 12 files changed, 730 insertions(+), 104 deletions(-) create mode 100644 test/pdfs/issue14256.pdf diff --git a/src/core/colorspace.js b/src/core/colorspace.js index 5f3fe01b0..b07be2a8f 100644 --- a/src/core/colorspace.js +++ b/src/core/colorspace.js @@ -379,14 +379,14 @@ class ColorSpace { cs = xref.fetchIfRef(cs); if (isName(cs)) { switch (cs.name) { - case "DeviceGray": case "G": + case "DeviceGray": return this.singletons.gray; - case "DeviceRGB": case "RGB": + case "DeviceRGB": return this.singletons.rgb; - case "DeviceCMYK": case "CMYK": + case "DeviceCMYK": return this.singletons.cmyk; case "Pattern": return new PatternCS(/* baseCS = */ null); @@ -417,14 +417,14 @@ class ColorSpace { let params, numComps, baseCS, whitePoint, blackPoint, gamma; switch (mode) { - case "DeviceGray": case "G": + case "DeviceGray": return this.singletons.gray; - case "DeviceRGB": case "RGB": + case "DeviceRGB": return this.singletons.rgb; - case "DeviceCMYK": case "CMYK": + case "DeviceCMYK": return this.singletons.cmyk; case "CalGray": params = xref.fetchIfRef(cs[1]); @@ -467,8 +467,8 @@ class ColorSpace { baseCS = this._parse(baseCS, xref, resources, pdfFunctionFactory); } return new PatternCS(baseCS); - case "Indexed": case "I": + case "Indexed": baseCS = this._parse(cs[1], xref, resources, pdfFunctionFactory); const hiVal = xref.fetchIfRef(cs[2]) + 1; const lookup = xref.fetchIfRef(cs[3]); diff --git a/src/core/evaluator.js b/src/core/evaluator.js index face5b2e7..cf859793f 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -580,8 +580,8 @@ class PartialEvaluator { }) { const dict = image.dict; const imageRef = dict.objId; - const w = dict.get("Width", "W"); - const h = dict.get("Height", "H"); + const w = dict.get("W", "Width"); + const h = dict.get("H", "Height"); if (!(w && isNum(w)) || !(h && isNum(h))) { warn("Image dimensions are missing, or not numbers."); @@ -604,8 +604,8 @@ class PartialEvaluator { operatorList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]); } - const imageMask = dict.get("ImageMask", "IM") || false; - const interpolate = dict.get("Interpolate", "I"); + const imageMask = dict.get("IM", "ImageMask") || false; + const interpolate = dict.get("I", "Interpolate"); let imgData, args; if (imageMask) { // This depends on a tmpCanvas being filled with the @@ -613,20 +613,17 @@ class PartialEvaluator { // data can't be done here. Instead of creating a // complete PDFImage, only read the information needed // for later. - - const width = dict.get("Width", "W"); - const height = dict.get("Height", "H"); - const bitStrideLength = (width + 7) >> 3; + const bitStrideLength = (w + 7) >> 3; const imgArray = image.getBytes( - bitStrideLength * height, + bitStrideLength * h, /* forceClamped = */ true ); - const decode = dict.getArray("Decode", "D"); + const decode = dict.getArray("D", "Decode"); imgData = PDFImage.createMask({ imgArray, - width, - height, + width: w, + height: h, imageIsFromDecodeStream: image instanceof DecodeStream, inverseDecode: !!decode && decode[0] > 0, interpolate, @@ -648,7 +645,7 @@ class PartialEvaluator { return; } - const softMask = dict.get("SMask", "SM") || false; + const softMask = dict.get("SM", "SMask") || false; const mask = dict.get("Mask") || false; const SMALL_IMAGE_DIMENSIONS = 200; diff --git a/src/core/image.js b/src/core/image.js index e1b55057a..8477f491a 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -93,7 +93,7 @@ class PDFImage { this.image = image; const dict = image.dict; - const filter = dict.get("Filter"); + const filter = dict.get("F", "Filter"); if (isName(filter)) { switch (filter.name) { case "JPXDecode": @@ -114,8 +114,8 @@ class PDFImage { } // TODO cache rendered images? - let width = dict.get("Width", "W"); - let height = dict.get("Height", "H"); + let width = dict.get("W", "Width"); + let height = dict.get("H", "Height"); if ( Number.isInteger(image.width) && @@ -139,13 +139,13 @@ class PDFImage { this.width = width; this.height = height; - this.interpolate = dict.get("Interpolate", "I"); - this.imageMask = dict.get("ImageMask", "IM") || false; + this.interpolate = dict.get("I", "Interpolate"); + this.imageMask = dict.get("IM", "ImageMask") || false; this.matte = dict.get("Matte") || false; let bitsPerComponent = image.bitsPerComponent; if (!bitsPerComponent) { - bitsPerComponent = dict.get("BitsPerComponent", "BPC"); + bitsPerComponent = dict.get("BPC", "BitsPerComponent"); if (!bitsPerComponent) { if (this.imageMask) { bitsPerComponent = 1; @@ -159,7 +159,7 @@ class PDFImage { this.bpc = bitsPerComponent; if (!this.imageMask) { - let colorSpace = dict.getRaw("ColorSpace") || dict.getRaw("CS"); + let colorSpace = dict.getRaw("CS") || dict.getRaw("ColorSpace"); if (!colorSpace) { info("JPX images (which do not require color spaces)"); switch (image.numComps) { @@ -174,8 +174,7 @@ class PDFImage { break; default: throw new Error( - `JPX images with ${image.numComps} ` + - "color components not supported." + `JPX images with ${image.numComps} color components not supported.` ); } } @@ -189,7 +188,7 @@ class PDFImage { this.numComps = this.colorSpace.numComps; } - this.decode = dict.getArray("Decode", "D"); + this.decode = dict.getArray("D", "Decode"); this.needsDecode = false; if ( this.decode && @@ -226,7 +225,7 @@ class PDFImage { } else if (mask) { if (isStream(mask)) { const maskDict = mask.dict, - imageMask = maskDict.get("ImageMask", "IM"); + imageMask = maskDict.get("IM", "ImageMask"); if (!imageMask) { warn("Ignoring /Mask in image without /ImageMask."); } else { diff --git a/src/core/jpeg_stream.js b/src/core/jpeg_stream.js index e8a0be588..7cd822ec7 100644 --- a/src/core/jpeg_stream.js +++ b/src/core/jpeg_stream.js @@ -62,9 +62,9 @@ class JpegStream extends DecodeStream { }; // Checking if values need to be transformed before conversion. - const decodeArr = this.dict.getArray("Decode", "D"); + const decodeArr = this.dict.getArray("D", "Decode"); if (this.forceRGB && Array.isArray(decodeArr)) { - const bitsPerComponent = this.dict.get("BitsPerComponent") || 8; + const bitsPerComponent = this.dict.get("BPC", "BitsPerComponent") || 8; const decodeArrLength = decodeArr.length; const transform = new Int32Array(decodeArrLength); let transformNeeded = false; diff --git a/src/core/parser.js b/src/core/parser.js index ad5f958e0..12eb59eb6 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -513,7 +513,7 @@ class Parser { } // Extract the name of the first (i.e. the current) image filter. - const filter = dict.get("Filter", "F"); + const filter = dict.get("F", "Filter"); let filterName; if (isName(filter)) { filterName = filter.name; @@ -527,14 +527,21 @@ class Parser { // Parse image stream. const startPos = stream.pos; let length; - if (filterName === "DCTDecode" || filterName === "DCT") { - length = this.findDCTDecodeInlineStreamEnd(stream); - } else if (filterName === "ASCII85Decode" || filterName === "A85") { - length = this.findASCII85DecodeInlineStreamEnd(stream); - } else if (filterName === "ASCIIHexDecode" || filterName === "AHx") { - length = this.findASCIIHexDecodeInlineStreamEnd(stream); - } else { - length = this.findDefaultInlineStreamEnd(stream); + switch (filterName) { + case "DCT": + case "DCTDecode": + length = this.findDCTDecodeInlineStreamEnd(stream); + break; + case "A85": + case "ASCII85Decode": + length = this.findASCII85DecodeInlineStreamEnd(stream); + break; + case "AHx": + case "ASCIIHexDecode": + length = this.findASCIIHexDecodeInlineStreamEnd(stream); + break; + default: + length = this.findDefaultInlineStreamEnd(stream); } let imageStream = stream.makeSubStream(startPos, length, dict); @@ -694,15 +701,12 @@ class Parser { } filter(stream, dict, length) { - let filter = dict.get("Filter", "F"); - let params = dict.get("DecodeParms", "DP"); + let filter = dict.get("F", "Filter"); + let params = dict.get("DP", "DecodeParms"); if (isName(filter)) { if (Array.isArray(params)) { - warn( - "/DecodeParms should not contain an Array, " + - "when /Filter contains a Name." - ); + warn("/DecodeParms should not be an Array, when /Filter is a Name."); } return this.makeFilter(stream, filter.name, length, params); } @@ -740,59 +744,60 @@ class Parser { try { const xrefStreamStats = this.xref.stats.streamTypes; - if (name === "FlateDecode" || name === "Fl") { - xrefStreamStats[StreamType.FLATE] = true; - if (params) { - return new PredictorStream( - new FlateStream(stream, maybeLength), - maybeLength, - params - ); - } - return new FlateStream(stream, maybeLength); - } - if (name === "LZWDecode" || name === "LZW") { - xrefStreamStats[StreamType.LZW] = true; - let earlyChange = 1; - if (params) { - if (params.has("EarlyChange")) { - earlyChange = params.get("EarlyChange"); + switch (name) { + case "Fl": + case "FlateDecode": + xrefStreamStats[StreamType.FLATE] = true; + if (params) { + return new PredictorStream( + new FlateStream(stream, maybeLength), + maybeLength, + params + ); } - return new PredictorStream( - new LZWStream(stream, maybeLength, earlyChange), - maybeLength, - params - ); - } - return new LZWStream(stream, maybeLength, earlyChange); - } - if (name === "DCTDecode" || name === "DCT") { - xrefStreamStats[StreamType.DCT] = true; - return new JpegStream(stream, maybeLength, params); - } - if (name === "JPXDecode" || name === "JPX") { - xrefStreamStats[StreamType.JPX] = true; - return new JpxStream(stream, maybeLength, params); - } - if (name === "ASCII85Decode" || name === "A85") { - xrefStreamStats[StreamType.A85] = true; - return new Ascii85Stream(stream, maybeLength); - } - if (name === "ASCIIHexDecode" || name === "AHx") { - xrefStreamStats[StreamType.AHX] = true; - return new AsciiHexStream(stream, maybeLength); - } - if (name === "CCITTFaxDecode" || name === "CCF") { - xrefStreamStats[StreamType.CCF] = true; - return new CCITTFaxStream(stream, maybeLength, params); - } - if (name === "RunLengthDecode" || name === "RL") { - xrefStreamStats[StreamType.RLX] = true; - return new RunLengthStream(stream, maybeLength); - } - if (name === "JBIG2Decode") { - xrefStreamStats[StreamType.JBIG] = true; - return new Jbig2Stream(stream, maybeLength, params); + return new FlateStream(stream, maybeLength); + case "LZW": + case "LZWDecode": + xrefStreamStats[StreamType.LZW] = true; + let earlyChange = 1; + if (params) { + if (params.has("EarlyChange")) { + earlyChange = params.get("EarlyChange"); + } + return new PredictorStream( + new LZWStream(stream, maybeLength, earlyChange), + maybeLength, + params + ); + } + return new LZWStream(stream, maybeLength, earlyChange); + case "DCT": + case "DCTDecode": + xrefStreamStats[StreamType.DCT] = true; + return new JpegStream(stream, maybeLength, params); + case "JPX": + case "JPXDecode": + xrefStreamStats[StreamType.JPX] = true; + return new JpxStream(stream, maybeLength, params); + case "A85": + case "ASCII85Decode": + xrefStreamStats[StreamType.A85] = true; + return new Ascii85Stream(stream, maybeLength); + case "AHx": + case "ASCIIHexDecode": + xrefStreamStats[StreamType.AHX] = true; + return new AsciiHexStream(stream, maybeLength); + case "CCF": + case "CCITTFaxDecode": + xrefStreamStats[StreamType.CCF] = true; + return new CCITTFaxStream(stream, maybeLength, params); + case "RL": + case "RunLengthDecode": + xrefStreamStats[StreamType.RLX] = true; + return new RunLengthStream(stream, maybeLength); + case "JBIG2Decode": + xrefStreamStats[StreamType.JBIG] = true; + return new Jbig2Stream(stream, maybeLength, params); } warn(`Filter "${name}" is not supported.`); return stream; diff --git a/src/core/pattern.js b/src/core/pattern.js index 113f402e4..fb744142c 100644 --- a/src/core/pattern.js +++ b/src/core/pattern.js @@ -117,7 +117,7 @@ class RadialAxialShading extends BaseShading { this.coordsArr = dict.getArray("Coords"); this.shadingType = dict.get("ShadingType"); const cs = ColorSpace.parse({ - cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"), + cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"), xref, resources, pdfFunctionFactory, @@ -415,7 +415,7 @@ class MeshShading extends BaseShading { this.bbox = null; } const cs = ColorSpace.parse({ - cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"), + cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"), xref, resources, pdfFunctionFactory, diff --git a/src/core/predictor_stream.js b/src/core/predictor_stream.js index b04765ff5..afeec2adb 100644 --- a/src/core/predictor_stream.js +++ b/src/core/predictor_stream.js @@ -43,7 +43,7 @@ class PredictorStream extends DecodeStream { this.dict = str.dict; const colors = (this.colors = params.get("Colors") || 1); - const bits = (this.bits = params.get("BitsPerComponent") || 8); + const bits = (this.bits = params.get("BPC", "BitsPerComponent") || 8); const columns = (this.columns = params.get("Columns") || 1); this.pixBytes = (colors * bits + 7) >> 3; diff --git a/src/core/primitives.js b/src/core/primitives.js index 334af49b7..cc37a5f68 100644 --- a/src/core/primitives.js +++ b/src/core/primitives.js @@ -90,8 +90,22 @@ class Dict { get(key1, key2, key3) { let value = this._map[key1]; if (value === undefined && key2 !== undefined) { + if ( + (typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING")) && + key2.length < key1.length + ) { + unreachable("Dict.get: Expected keys to be ordered by length."); + } value = this._map[key2]; if (value === undefined && key3 !== undefined) { + if ( + (typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING")) && + key3.length < key2.length + ) { + unreachable("Dict.get: Expected keys to be ordered by length."); + } value = this._map[key3]; } } @@ -105,8 +119,22 @@ class Dict { async getAsync(key1, key2, key3) { let value = this._map[key1]; if (value === undefined && key2 !== undefined) { + if ( + (typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING")) && + key2.length < key1.length + ) { + unreachable("Dict.getAsync: Expected keys to be ordered by length."); + } value = this._map[key2]; if (value === undefined && key3 !== undefined) { + if ( + (typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING")) && + key3.length < key2.length + ) { + unreachable("Dict.getAsync: Expected keys to be ordered by length."); + } value = this._map[key3]; } } @@ -120,8 +148,22 @@ class Dict { getArray(key1, key2, key3) { let value = this._map[key1]; if (value === undefined && key2 !== undefined) { + if ( + (typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING")) && + key2.length < key1.length + ) { + unreachable("Dict.getArray: Expected keys to be ordered by length."); + } value = this._map[key2]; if (value === undefined && key3 !== undefined) { + if ( + (typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING")) && + key3.length < key2.length + ) { + unreachable("Dict.getArray: Expected keys to be ordered by length."); + } value = this._map[key3]; } } diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 407e9e101..2b4476710 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -437,6 +437,7 @@ !annotation-strikeout.pdf !annotation-strikeout-without-appearance.pdf !annotation-squiggly.pdf +!issue14256.pdf !annotation-squiggly-without-appearance.pdf !annotation-highlight.pdf !annotation-highlight-without-appearance.pdf diff --git a/test/pdfs/issue14256.pdf b/test/pdfs/issue14256.pdf new file mode 100644 index 000000000..2f20d465c --- /dev/null +++ b/test/pdfs/issue14256.pdf @@ -0,0 +1,576 @@ +%PDF-1.7 +% Copyright 2021, PDF Association. + +1 0 obj +<< /Type /Catalog + /Outlines 2 0 R + /Pages 3 0 R +>> +endobj + +2 0 obj +<< /Type /Outlines + /Count 0 +>> +endobj + +3 0 obj +<< /Type /Pages + /Kids [4 0 R] + /Count 1 +>> +endobj + +4 0 obj +<< /Type /Page + /Parent 3 0 R + /MediaBox [0 0 900 900] + /Contents 5 0 R + /Resources + << /ColorSpace + << /3chanRGB [ /CalRGB + << /WhitePoint [0.9505 1.0 1.0890] + /Gamma [0.5 1.2 1.9] + /Matrix [0.4497 0.2446 0.0252 + 0.3163 0.4920 0.1412 + 0.3845 0.0833 0.9227] + >> ] + >> + /Font << /F1 6 0 R >> + >> +>> +endobj + +5 0 obj +<< /Length 13569 >> +stream +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #1: Only full key names --> all PDF parsers should support! +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 45 520 Tm + (1) Tj +ET +Q +q +0 1 0 rg % Green fill +10 400 200 100 re f % Paint green rectangle below image +200 0 0 100 10 400 cm +BI + /Width 20 + /Height 10 + /BitsPerComponent 8 + /ColorSpace /DeviceRGB + /Filter [/ASCIIHexDecode] + /Length 1240 +ID +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ff +ff00ffff00ff0000ff0000ffff000000 +ff0000ff0000ffffff000000ffffff00 +ffff00ffff000000ffffff00ffff00ff +ff000000ff0000ffffff00ffff00ffff +00ff0000ff0000ffff00ffff000000ff +ffff00ffff000000ff0000ffffff0000 +00ff0000ffffff00ffff000000ffffff +00ffff000000ffffff00ffff00ff0000 +ff0000ffff00ffff000000ffffff00ff +ff000000ffffff000000ffffff000000 +ffffff000000ffffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +ff00ffff000000ffffff00ffff000000 +ffffff000000ffffff000000ffffff00 +0000ffffff00ffff000000ff0000ffff +ff00ffff00ff0000ff0000ffff00ffff +000000ffffff00ffff000000ffffff00 +ffff00ffff000000ffffff00ffff0000 +00ffffff00ffff000000ffffff00ffff +00ff0000ff0000ffff000000ff0000ff +0000ffffff000000ffffff00ffff00ff +ff000000ffffff00ffff00ffff000000 +ff0000ff0000ffffff00ffff00ff0000 +ff0000ffff00ffff00ffff00ffff00ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000 > +EI +Q + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #2: Only abbreviated key names --> all PDF parsers should support! +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 255 520 Tm + (2) Tj +ET +Q +q +0 1 0 rg % Green fill +220 400 200 100 re f % Paint green rectangle below image +200 0 0 100 220 400 cm +BI + /W 20 + /H 10 + /BPC 8 + /CS /RGB + /F [/AHx] + /L 1240 +ID +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ff +ff00ffff00ff0000ff0000ffff000000 +ff0000ff0000ffffff000000ffffff00 +ffff00ffff000000ffffff00ffff00ff +ff000000ff0000ffffff00ffff00ffff +00ff0000ff0000ffff00ffff000000ff +ffff00ffff000000ff0000ffffff0000 +00ff0000ffffff00ffff000000ffffff +00ffff000000ffffff00ffff00ff0000 +ff0000ffff00ffff000000ffffff00ff +ff000000ffffff000000ffffff000000 +ffffff000000ffffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +ff00ffff000000ffffff00ffff000000 +ffffff000000ffffff000000ffffff00 +0000ffffff00ffff000000ff0000ffff +ff00ffff00ff0000ff0000ffff00ffff +000000ffffff00ffff000000ffffff00 +ffff00ffff000000ffffff00ffff0000 +00ffffff00ffff000000ffffff00ffff +00ff0000ff0000ffff000000ff0000ff +0000ffffff000000ffffff00ffff00ff +ff000000ffffff00ffff00ffff000000 +ff0000ff0000ffffff00ffff00ff0000 +ff0000ffff00ffff00ffff00ffff00ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000 > +EI +Q + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #3: CORRECT abbreviated key names, INCORRECT full keys +% (width x height = constant). +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 465 520 Tm + (3) Tj +ET +Q +q +0 1 0 rg % Green fill +430 400 200 100 re f % Paint green rectangle below image +200 0 0 100 430 400 cm +BI + /W 20 %% COMMENT OUT THIS LINE (and below) TO SEE EFFECT! + /Width 10 + /H 10 %% COMMENT OUT THIS LINE (and above) TO SEE EFFECT! + /Height 40 + /BPC 8 + /BitsPerComponent 4 + /CS /RGB + /F [/AHx] + /L 1240 +ID +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ff +ff00ffff00ff0000ff0000ffff000000 +ff0000ff0000ffffff000000ffffff00 +ffff00ffff000000ffffff00ffff00ff +ff000000ff0000ffffff00ffff00ffff +00ff0000ff0000ffff00ffff000000ff +ffff00ffff000000ff0000ffffff0000 +00ff0000ffffff00ffff000000ffffff +00ffff000000ffffff00ffff00ff0000 +ff0000ffff00ffff000000ffffff00ff +ff000000ffffff000000ffffff000000 +ffffff000000ffffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +ff00ffff000000ffffff00ffff000000 +ffffff000000ffffff000000ffffff00 +0000ffffff00ffff000000ff0000ffff +ff00ffff00ff0000ff0000ffff00ffff +000000ffffff00ffff000000ffffff00 +ffff00ffff000000ffffff00ffff0000 +00ffffff00ffff000000ffffff00ffff +00ff0000ff0000ffff000000ff0000ff +0000ffffff000000ffffff00ffff00ff +ff000000ffffff00ffff00ffff000000 +ff0000ff0000ffffff00ffff00ff0000 +ff0000ffff00ffff00ffff00ffff00ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000 > +EI +Q + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #4: CORRECT abbreviated key names, INCORRECT full keys +% for Filter +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 675 520 Tm + (4) Tj +ET +Q +q +0 1 0 rg % Green fill +640 400 200 100 re f % Paint green rectangle below image +200 0 0 100 640 400 cm +BI + /W 20 + /H 10 + /BPC 8 + /CS /RGB + /F [/AHx] + /Filter [/A85] + /Length 1240 +ID +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ff +ff00ffff00ff0000ff0000ffff000000 +ff0000ff0000ffffff000000ffffff00 +ffff00ffff000000ffffff00ffff00ff +ff000000ff0000ffffff00ffff00ffff +00ff0000ff0000ffff00ffff000000ff +ffff00ffff000000ff0000ffffff0000 +00ff0000ffffff00ffff000000ffffff +00ffff000000ffffff00ffff00ff0000 +ff0000ffff00ffff000000ffffff00ff +ff000000ffffff000000ffffff000000 +ffffff000000ffffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +ff00ffff000000ffffff00ffff000000 +ffffff000000ffffff000000ffffff00 +0000ffffff00ffff000000ff0000ffff +ff00ffff00ff0000ff0000ffff00ffff +000000ffffff00ffff000000ffffff00 +ffff00ffff000000ffffff00ffff0000 +00ffffff00ffff000000ffffff00ffff +00ff0000ff0000ffff000000ff0000ff +0000ffffff000000ffffff00ffff00ff +ff000000ffffff00ffff00ffff000000 +ff0000ff0000ffffff00ffff00ff0000 +ff0000ffff00ffff00ffff00ffff00ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000 > +EI +Q + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #5: CORRECT abbreviated key names, INCORRECT full keys +% for ColorSpace. Visual colour shift if INCORRECT (compared +% to other images) +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 45 220 Tm + (5) Tj +ET +Q +q +0 1 0 rg % Green fill +10 100 200 100 re f % Paint green rectangle below image +200 0 0 100 10 100 cm +BI + /W 20 + /H 10 + /BPC 8 + /CS /RGB %% COMMENT OUT THIS LINE TO SEE EFFECT! + /ColorSpace /3chanRGB + /F [/AHx] + /Length 1240 +ID +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ff +ff00ffff00ff0000ff0000ffff000000 +ff0000ff0000ffffff000000ffffff00 +ffff00ffff000000ffffff00ffff00ff +ff000000ff0000ffffff00ffff00ffff +00ff0000ff0000ffff00ffff000000ff +ffff00ffff000000ff0000ffffff0000 +00ff0000ffffff00ffff000000ffffff +00ffff000000ffffff00ffff00ff0000 +ff0000ffff00ffff000000ffffff00ff +ff000000ffffff000000ffffff000000 +ffffff000000ffffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +ff00ffff000000ffffff00ffff000000 +ffffff000000ffffff000000ffffff00 +0000ffffff00ffff000000ff0000ffff +ff00ffff00ff0000ff0000ffff00ffff +000000ffffff00ffff000000ffffff00 +ffff00ffff000000ffffff00ffff0000 +00ffffff00ffff000000ffffff00ffff +00ff0000ff0000ffff000000ff0000ff +0000ffffff000000ffffff00ffff00ff +ff000000ffffff00ffff00ffff000000 +ff0000ff0000ffffff00ffff00ff0000 +ff0000ffff00ffff00ffff00ffff00ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000 > +EI +Q + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #6: CORRECT abbreviated key names, INCORRECT full keys +% for Decode. Colours will be inverted if PDF parser is wrong! +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 255 220 Tm + (6) Tj +ET +Q +q +0 1 0 rg % Green fill +220 100 200 100 re f % Paint green rectangle below image +200 0 0 100 220 100 cm +BI + /W 20 + /H 10 + /BPC 8 + /CS /RGB + /D [ 0 1 0 1 0 1 ] %% COMMENT OUT THIS LINE TO SEE EFFECT! + /Decode [ 1 0 1 0 1 0 ] + /F [/AHx] + /Length 1240 +ID +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ff +ff00ffff00ff0000ff0000ffff000000 +ff0000ff0000ffffff000000ffffff00 +ffff00ffff000000ffffff00ffff00ff +ff000000ff0000ffffff00ffff00ffff +00ff0000ff0000ffff00ffff000000ff +ffff00ffff000000ff0000ffffff0000 +00ff0000ffffff00ffff000000ffffff +00ffff000000ffffff00ffff00ff0000 +ff0000ffff00ffff000000ffffff00ff +ff000000ffffff000000ffffff000000 +ffffff000000ffffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +ff00ffff000000ffffff00ffff000000 +ffffff000000ffffff000000ffffff00 +0000ffffff00ffff000000ff0000ffff +ff00ffff00ff0000ff0000ffff00ffff +000000ffffff00ffff000000ffffff00 +ffff00ffff000000ffffff00ffff0000 +00ffffff00ffff000000ffffff00ffff +00ff0000ff0000ffff000000ff0000ff +0000ffffff000000ffffff00ffff00ff +ff000000ffffff00ffff00ffff000000 +ff0000ff0000ffffff00ffff00ff0000 +ff0000ffff00ffff00ffff00ffff00ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000 > +EI +Q + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #7: CORRECT abbreviated key names, INCORRECT full keys +% for Interpolate. If appearance is different to the other +% images then the PDF parser is incorrect! +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 465 220 Tm + (7) Tj +ET +Q +q +0 1 0 rg % Green fill +430 100 200 100 re f % Paint green rectangle below image +200 0 0 100 430 100 cm +BI + /W 20 + /H 10 + /BPC 8 + /CS /RGB + /I false %% COMMENT OUT THIS LINE TO SEE EFFECT! + /Interpolate true + /F [/AHx] + /Length 1240 +ID +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ffff00ffff00ff +ff00ffff00ff0000ff0000ffff000000 +ff0000ff0000ffffff000000ffffff00 +ffff00ffff000000ffffff00ffff00ff +ff000000ff0000ffffff00ffff00ffff +00ff0000ff0000ffff00ffff000000ff +ffff00ffff000000ff0000ffffff0000 +00ff0000ffffff00ffff000000ffffff +00ffff000000ffffff00ffff00ff0000 +ff0000ffff00ffff000000ffffff00ff +ff000000ffffff000000ffffff000000 +ffffff000000ffffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +ff00ffff000000ffffff00ffff000000 +ffffff000000ffffff000000ffffff00 +0000ffffff00ffff000000ff0000ffff +ff00ffff00ff0000ff0000ffff00ffff +000000ffffff00ffff000000ffffff00 +ffff00ffff000000ffffff00ffff0000 +00ffffff00ffff000000ffffff00ffff +00ff0000ff0000ffff000000ff0000ff +0000ffffff000000ffffff00ffff00ff +ff000000ffffff00ffff00ffff000000 +ff0000ff0000ffffff00ffff00ff0000 +ff0000ffff00ffff00ffff00ffff00ff +ff00ffff00ffff00ffff00ffff00ffff +00ffff00ffff00ffff00ffff00ffff00 +ffff00ffff00ffff00ff0000ff0000ff +0000ff0000ff0000ff0000ff0000ff00 +00ff0000ff0000ff0000ff0000ff0000 +ff0000ff0000ff0000ff0000ff0000ff +0000ff0000ff0000 > +EI +Q + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% #8: CORRECT abbreviated key names, INCORRECT full keys +% for DecodeParams. If appearance is different to the other +% images then the PDF parser is incorrect! +q +BT + 0 0 0 rg % Black text + /F1 8 Tf + 10 0 0 10 675 220 Tm + (8) Tj +ET +Q +q +0 1 0 rg % Green fill +640 100 200 100 re f % Paint green rectangle below image +200 0 0 100 640 100 cm +BI + /W 20 + /H 10 + /BPC 8 + /CS /RGB + /F [ /AHx /Fl ] + /DP [ null << /Predictor 15 /Colors 3 /BitsPerComponent 8 /Columns 20 >> ] %% THIS IS REQUIRED TO VIEW IMAGE CORRECTLY + /DecodeParms [ null null ] + /Length 197 +ID +28919d90510e80200c435be2fdaf5c3f +a6653297280b2165e175050afb7500c0 +9e01312e41c50a3d2f3c753e02372cd1 +bb998594283137c76ba2b894bdac2d5a +b8ab25790be7094e9b9b13ae8fac5ef5 +c3c2f05776a3e8677da81323233119> +EI + +endstream +endobj + +6 0 obj +<< /Type /Font + /Subtype /Type1 + /BaseFont /Helvetica +>> +endobj + +7 0 obj +<< /CreationDate (D:20210529) + /Producer (Manual) + /Creator (Peter Wyatt for SafeDocs) + /Author (Peter Wyatt) + /Subject (Inline Image Test for abbreviated and full key names) + /Title (Inline Image Test for abbreviated and full key names) + /Keywords (image, inline, abbreviation, ambiguous) +>> +endobj + +xref +0 8 +0000000000 65536 f +0000000048 00000 n +0000000137 00000 n +0000000194 00000 n +0000000267 00000 n +0000000791 00000 n +0000014420 00000 n +0000014509 00000 n +trailer +<< /Size 8 + /Root 1 0 R + /Info 7 0 R +>> +startxref +14872 +%%EOF diff --git a/test/test_manifest.json b/test/test_manifest.json index 303b770bc..a1e0f449b 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -85,6 +85,12 @@ "lastPage": 2, "type": "eq" }, + { "id": "issue14256", + "file": "pdfs/issue14256.pdf", + "md5": "15938b7562146dbea7ed8aa15b172fe6", + "rounds": 1, + "type": "eq" + }, { "id": "issue11549", "file": "pdfs/issue11549_reduced.pdf", "md5": "a1ea636f413e02e10dbdf379ab4a99ae", diff --git a/test/unit/primitives_spec.js b/test/unit/primitives_spec.js index 5ca1a75ba..347f12db5 100644 --- a/test/unit/primitives_spec.js +++ b/test/unit/primitives_spec.js @@ -87,7 +87,7 @@ describe("primitives", function () { const checkInvalidKeyValues = function (dict) { expect(dict.get()).toBeUndefined(); expect(dict.get("Prev")).toBeUndefined(); - expect(dict.get("Decode", "D")).toBeUndefined(); + expect(dict.get("D", "Decode")).toBeUndefined(); expect(dict.get("FontFile", "FontFile2", "FontFile3")).toBeUndefined(); };