diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 6d1d1fe32..1257a02eb 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -3602,7 +3602,7 @@ class TranslatedFont { var charProcOperatorList = Object.create(null); for (const key of charProcs.getKeys()) { - loadCharProcsPromise = loadCharProcsPromise.then(function () { + loadCharProcsPromise = loadCharProcsPromise.then(() => { var glyphStream = charProcs.get(key); var operatorList = new OperatorList(); return type3Evaluator @@ -3612,7 +3612,16 @@ class TranslatedFont { resources: fontResources, operatorList, }) - .then(function () { + .then(() => { + // According to the PDF specification, section "9.6.5 Type 3 Fonts" + // and "Table 113": + // "A glyph description that begins with the d1 operator should + // not execute any operators that set the colour (or other + // colour-related parameters) in the graphics state; + // any use of such operators shall be ignored." + if (operatorList.fnArray[0] === OPS.setCharWidthAndBounds) { + this._removeType3ColorOperators(operatorList); + } charProcOperatorList[key] = operatorList.getIR(); for (const dependency of operatorList.dependencies) { @@ -3631,6 +3640,68 @@ class TranslatedFont { }); return this.type3Loaded; } + + /** + * @private + */ + _removeType3ColorOperators(operatorList) { + if ( + typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING") + ) { + assert( + operatorList.fnArray[0] === OPS.setCharWidthAndBounds, + "Type3 glyph shall start with the d1 operator." + ); + } + let i = 1, + ii = operatorList.length; + while (i < ii) { + switch (operatorList.fnArray[i]) { + case OPS.setStrokeColorSpace: + case OPS.setFillColorSpace: + case OPS.setStrokeColor: + case OPS.setStrokeColorN: + case OPS.setFillColor: + case OPS.setFillColorN: + case OPS.setStrokeGray: + case OPS.setFillGray: + case OPS.setStrokeRGBColor: + case OPS.setFillRGBColor: + case OPS.setStrokeCMYKColor: + case OPS.setFillCMYKColor: + case OPS.shadingFill: + case OPS.setRenderingIntent: + operatorList.fnArray.splice(i, 1); + operatorList.argsArray.splice(i, 1); + ii--; + continue; + + case OPS.setGState: + const gStateObj = operatorList.argsArray[i]; + let j = 0, + jj = gStateObj.length; + while (j < jj) { + const [gStateKey] = gStateObj[j]; + switch (gStateKey) { + case "TR": + case "TR2": + case "HT": + case "BG": + case "BG2": + case "UCR": + case "UCR2": + gStateObj.splice(j, 1); + jj--; + continue; + } + j++; + } + break; + } + i++; + } + } } class StateManager { diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 6b7ae9e9a..9bedc1ad8 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -222,6 +222,7 @@ !issue5734.pdf !issue4875.pdf !issue11740_reduced.pdf +!issue12705.pdf !issue4881.pdf !issue5994.pdf !issue6151.pdf diff --git a/test/pdfs/issue12705.pdf b/test/pdfs/issue12705.pdf new file mode 100644 index 000000000..74a0143d1 Binary files /dev/null and b/test/pdfs/issue12705.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 19a428235..e1578916f 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -4531,6 +4531,12 @@ "annotations": true, "type": "eq" }, + { "id": "issue12705", + "file": "pdfs/issue12705.pdf", + "md5": "d8725b9dcfef72fd4fa4a39cab711624", + "rounds": 1, + "type": "eq" + }, { "id": "annotation-strikeout", "file": "pdfs/annotation-strikeout.pdf", "md5": "6624e6b5bedd2f2855b6ab12bbf93c57", @@ -4894,5 +4900,5 @@ "rounds": 1, "type": "eq", "annotations": true - } + } ]