diff --git a/src/core/evaluator.js b/src/core/evaluator.js index e0cb73d01..41a83644c 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -1991,40 +1991,64 @@ class PartialEvaluator { return; } case OPS.setFillColor: + if (!isNumberArray(args, null)) { + continue; + } cs = stateManager.state.fillColorSpace; args = [cs.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; case OPS.setStrokeColor: + if (!isNumberArray(args, null)) { + continue; + } cs = stateManager.state.strokeColorSpace; args = [cs.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; case OPS.setFillGray: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.fillColorSpace = ColorSpaceUtils.gray; args = [ColorSpaceUtils.gray.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; case OPS.setStrokeGray: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.strokeColorSpace = ColorSpaceUtils.gray; args = [ColorSpaceUtils.gray.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; case OPS.setFillCMYKColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.fillColorSpace = ColorSpaceUtils.cmyk; args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; case OPS.setStrokeCMYKColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.strokeColorSpace = ColorSpaceUtils.cmyk; args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; case OPS.setFillRGBColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.fillColorSpace = ColorSpaceUtils.rgb; args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)]; break; case OPS.setStrokeRGBColor: + if (!isNumberArray(args, null)) { + continue; + } stateManager.state.strokeColorSpace = ColorSpaceUtils.rgb; args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)]; break; @@ -2041,6 +2065,9 @@ class PartialEvaluator { break; } if (cs.name === "Pattern") { + if (!Array.isArray(args)) { + continue; + } next( self.handleColorN( operatorList, @@ -2058,6 +2085,9 @@ class PartialEvaluator { ); return; } + if (!isNumberArray(args, null)) { + continue; + } args = [cs.getRgbHex(args, 0)]; fn = OPS.setFillRGBColor; break; @@ -2074,6 +2104,9 @@ class PartialEvaluator { break; } if (cs.name === "Pattern") { + if (!Array.isArray(args)) { + continue; + } next( self.handleColorN( operatorList, @@ -2091,6 +2124,9 @@ class PartialEvaluator { ); return; } + if (!isNumberArray(args, null)) { + continue; + } args = [cs.getRgbHex(args, 0)]; fn = OPS.setStrokeRGBColor; break; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 54d04c8cf..7cd2904ed 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -103,6 +103,7 @@ !issue9713.pdf !xfa_filled_imm1344e.pdf !issue8424.pdf +!issue21570.pdf !issue8480.pdf !bug1650302_reduced.pdf !issue18816.pdf diff --git a/test/pdfs/issue21570.pdf b/test/pdfs/issue21570.pdf new file mode 100644 index 000000000..6c1179975 Binary files /dev/null and b/test/pdfs/issue21570.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index b64418498..02eb0efd2 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -13059,6 +13059,13 @@ } } }, + { + "id": "issue21570", + "file": "pdfs/issue21570.pdf", + "md5": "3065e65224901203e708e3dacad2d99a", + "rounds": 1, + "type": "eq" + }, { "id": "issue2856", "file": "pdfs/issue2856.pdf", diff --git a/test/unit/evaluator_spec.js b/test/unit/evaluator_spec.js index fa2c0c202..90ad3ec00 100644 --- a/test/unit/evaluator_spec.js +++ b/test/unit/evaluator_spec.js @@ -17,6 +17,7 @@ import { createIdFactory, XRefMock } from "./test_utils.js"; import { Dict, Name } from "../../src/core/primitives.js"; import { FormatError, OPS } from "../../src/shared/util.js"; import { Stream, StringStream } from "../../src/core/stream.js"; +import { GlobalColorSpaceCache } from "../../src/core/image_utils.js"; import { OperatorList } from "../../src/core/operator_list.js"; import { PartialEvaluator } from "../../src/core/evaluator.js"; import { WorkerTask } from "../../src/core/worker.js"; @@ -57,6 +58,7 @@ describe("evaluator", function () { handler: new HandlerMock(), pageIndex: 0, idFactory: createIdFactory(/* pageIndex = */ 0), + globalColorSpaceCache: new GlobalColorSpaceCache(), }); }); @@ -358,6 +360,32 @@ describe("evaluator", function () { expect(result.fnArray).toEqual([]); }); + it("should skip empty set fill/stroke color operators", async function () { + const colorOps = [ + "SC", + "SCN", + "sc", + "scn", + "G", + "g", + "RG", + "rg", + "K", + "k", + ]; + + for (const op of colorOps) { + const stream = new StringStream(`/DeviceRGB CS /DeviceRGB cs ${op}`); + const result = await runOperatorListCheck( + partialEvaluator, + stream, + new ResourcesMock() + ); + expect(result.argsArray).toEqual([]); + expect(result.fnArray).toEqual([]); + } + }); + it("should handle invalid dash stuff", async function () { const stream = new StringStream("[ none ] 0 d"); const result = await runOperatorListCheck(