From 26121177ab80029e21715b09ca41176f58bbfd6b Mon Sep 17 00:00:00 2001 From: Jani Pehkonen Date: Tue, 22 Jan 2019 19:59:36 +0200 Subject: [PATCH] Implement Decode entry in Indexed images --- src/core/colorspace.js | 29 ++++++++++++++++++++--------- src/core/evaluator.js | 4 +++- src/core/image.js | 9 ++++++--- test/pdfs/.gitignore | 1 + test/pdfs/issue10339_reduced.pdf | Bin 0 -> 1819 bytes test/test_manifest.json | 6 ++++++ test/unit/colorspace_spec.js | 2 +- 7 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 test/pdfs/issue10339_reduced.pdf diff --git a/src/core/colorspace.js b/src/core/colorspace.js index 081d489db..7b60a0348 100644 --- a/src/core/colorspace.js +++ b/src/core/colorspace.js @@ -492,7 +492,7 @@ class AlternateCS extends ColorSpace { alpha01); } - isDefaultDecode(decodeMap) { + isDefaultDecode(decodeMap, bpc) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } } @@ -565,8 +565,19 @@ class IndexedCS extends ColorSpace { return this.base.getOutputLength(inputLength * this.base.numComps, alpha01); } - isDefaultDecode(decodeMap) { - return true; // Indexed color maps shouldn't be changed. + isDefaultDecode(decodeMap, bpc) { + if (!Array.isArray(decodeMap)) { + return true; + } + if (decodeMap.length !== 2) { + warn('Decode map length is not correct'); + return true; + } + if (!Number.isInteger(bpc) || bpc < 1) { + warn('Bits per component is not correct'); + return true; + } + return decodeMap[0] === 0 && decodeMap[1] === (1 << bpc) - 1; } } @@ -609,7 +620,7 @@ class DeviceGrayCS extends ColorSpace { return inputLength * (3 + alpha01); } - isDefaultDecode(decodeMap) { + isDefaultDecode(decodeMap, bpc) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } } @@ -661,7 +672,7 @@ class DeviceRgbCS extends ColorSpace { return bits === 8; } - isDefaultDecode(decodeMap) { + isDefaultDecode(decodeMap, bpc) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } } @@ -744,7 +755,7 @@ const DeviceCmykCS = (function DeviceCmykCSClosure() { return (inputLength / 4 * (3 + alpha01)) | 0; } - isDefaultDecode(decodeMap) { + isDefaultDecode(decodeMap, bpc) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } } @@ -847,7 +858,7 @@ const CalGrayCS = (function CalGrayCSClosure() { return inputLength * (3 + alpha01); } - isDefaultDecode(decodeMap) { + isDefaultDecode(decodeMap, bpc) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } } @@ -1129,7 +1140,7 @@ const CalRGBCS = (function CalRGBCSClosure() { return (inputLength * (3 + alpha01) / 3) | 0; } - isDefaultDecode(decodeMap) { + isDefaultDecode(decodeMap, bpc) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } } @@ -1280,7 +1291,7 @@ const LabCS = (function LabCSClosure() { return (inputLength * (3 + alpha01) / 3) | 0; } - isDefaultDecode(decodeMap) { + isDefaultDecode(decodeMap, bpc) { // XXX: Decoding is handled with the lab conversion because of the strange // ranges that are used. return true; diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 24942512d..7599c1c40 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -100,6 +100,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { } var cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res, pdfFunctionFactory); + // isDefaultDecode() of DeviceGray and DeviceRGB needs no `bpc` argument. return (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB') && cs.isDefaultDecode(dict.getArray('Decode', 'D')); }; @@ -114,8 +115,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { } var cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res, pdfFunctionFactory); + const bpc = dict.get('BitsPerComponent', 'BPC') || 1; return (cs.numComps === 1 || cs.numComps === 3) && - cs.isDefaultDecode(dict.getArray('Decode', 'D')); + cs.isDefaultDecode(dict.getArray('Decode', 'D'), bpc); }; function PartialEvaluator({ pdfManager, xref, handler, pageIndex, idFactory, diff --git a/src/core/image.js b/src/core/image.js index c402a5208..b9029235a 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -169,18 +169,21 @@ var PDFImage = (function PDFImageClosure() { this.decode = dict.getArray('Decode', 'D'); this.needsDecode = false; if (this.decode && - ((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) || + ((this.colorSpace && + !this.colorSpace.isDefaultDecode(this.decode, bitsPerComponent)) || (isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) { this.needsDecode = true; // Do some preprocessing to avoid more math. var max = (1 << bitsPerComponent) - 1; this.decodeCoefficients = []; this.decodeAddends = []; + const isIndexed = this.colorSpace && this.colorSpace.name === 'Indexed'; for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) { var dmin = this.decode[i]; var dmax = this.decode[i + 1]; - this.decodeCoefficients[j] = dmax - dmin; - this.decodeAddends[j] = max * dmin; + this.decodeCoefficients[j] = isIndexed ? ((dmax - dmin) / max) : + (dmax - dmin); + this.decodeAddends[j] = isIndexed ? dmin : (max * dmin); } } diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index ad6cec7f2..a6bbdc3b5 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -251,6 +251,7 @@ !bug878026.pdf !issue1045.pdf !issue5010.pdf +!issue10339_reduced.pdf !issue4934.pdf !issue4650.pdf !issue6721_reduced.pdf diff --git a/test/pdfs/issue10339_reduced.pdf b/test/pdfs/issue10339_reduced.pdf new file mode 100644 index 0000000000000000000000000000000000000000..438779f5a7608534b148a64a5da08d809f30c361 GIT binary patch literal 1819 zcmd5-ZA?>V6h^?X-4Vl-=*-M`BNiuy-jDXSWgrLz29u9cWDqNLm-eMp%DvED0(Oi= z5!4Dl%ouKwz?KC+kdaJgkipynbHgQ*Wn(|KxbU?iiw-DkGIVBp-_mLklO_ALo7|hc z=RGIqoaa2xxe`rMN)#<+3CYCd@b`oYP(Ua=Na)CPt`Nk=5~P;nO;8s_Gb$+sXhw;? zzJ~&W%qupFP$QUmQAbIm6>^4>0UEhcQWYbQrdZ^XXyFVcUKf1hehY}WxB>$5Mx2rL zWX3tuA#W0kfm}t9DQ1fZtz?RY6JZiG2u6s42%BhyTq#l2vhx?GRzt}djbB1YX)%#_ zy%&_fF}z>B_H?zrYq!2DF}N<`d}JetT$59<&V_S%LOod-pR9Y#Mw?EC3|dt2-a}=O z)Nm$fBS^JS!Ha;#i9KP_K4G3>Wh&-hs!cs%95|-S;I;(Ky}8#Y{>)dlxmp)nDz}_r zK9Pr9TGap8*EEz`bbP4!*;krIXHVW5cO8nGERU^^pNr}F;G+li;i`rMhWppF3!9I1 zE*%YX1zhd1hm4NvE{=|sbm_h2IKo{bED5OZCD@$II%Pqnq{(3~;fb8`sVMwdQ8n)MDDzys5im{7s21 z1~$)p{u|R5_1?Q5CKNrxf0>bB59goy?)KUP+dHQBW&hAnlH};xcp-Nri*GS!>#&GziN?3qPM>B?I&?e6}#!SUI>zyJ6%kX#sU^AGkr0?q`l zp1s0ni0*OcXB8fV2JsR9=qFAT@xdZkbILda1WHU7f?Q^%j$v6Zv&mFwHWiCNP7!1p zFG5})o2 zIkX8Cs5~2xFL$IC+(p{})+Opt!&z}PSTE?50gYxZQK-@(9Ro&%76VIRHGB0zWBZCU z{~g=^DUf*bxI-NpuMt*3Bfz^;3lIkYUJq!Ac$Ni5)Qg1&282EUXyi1&B-Ab+7~qCY zi*fXU(kI%zkGwN*PfyK>oJBDC_!CuDSVW+S&;<4H0ScCtv7iWeY_wcX1NSZ9y*3J0 z{+NxXDAW~x9{JHSCF*abjY7s%Hl+fQZKWSAdx9TDugXiwFcgo)(!Ms)%9$gI7; zlI}%CARYhCsa^5vzHJXWziPU(1FSZowXPKew8`C=lR0KP#4sVOZ6aqC-N4c4k3~o% I$yq7HKLGb-*8l(j literal 0 HcmV?d00001 diff --git a/test/test_manifest.json b/test/test_manifest.json index 60c981d2b..f9bb996cc 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -2643,6 +2643,12 @@ "link": false, "type": "eq" }, + { "id": "issue10339", + "file": "pdfs/issue10339_reduced.pdf", + "md5": "e34ef74f188080f8194c7d8e8b68c562", + "rounds": 1, + "type": "eq" + }, { "id": "issue1721", "file": "pdfs/issue1721.pdf", "md5": "b47177f9e5197a76ec498733ecab60e6", diff --git a/test/unit/colorspace_spec.js b/test/unit/colorspace_spec.js index c3c6f9488..43845430b 100644 --- a/test/unit/colorspace_spec.js +++ b/test/unit/colorspace_spec.js @@ -496,7 +496,7 @@ describe('colorspace', function () { expect(colorSpace.getRgb([2], 0)).toEqual( new Uint8ClampedArray([255, 109, 70])); expect(colorSpace.isPassthrough(8)).toBeFalsy(); - expect(colorSpace.isDefaultDecode([0, 1])).toBeTruthy(); + expect(colorSpace.isDefaultDecode([0, 1], 1)).toBeTruthy(); expect(testDest).toEqual(expectedDest); }); });