Merge pull request #21574 from Snuffleupagus/issue-21570

Skip setFillColorN/setStrokeColorN operators without valid arguments (issue 21570)
This commit is contained in:
Tim van der Meij 2026-07-14 19:39:55 +02:00 committed by GitHub
commit f62702068a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 72 additions and 0 deletions

View File

@ -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;

View File

@ -103,6 +103,7 @@
!issue9713.pdf
!xfa_filled_imm1344e.pdf
!issue8424.pdf
!issue21570.pdf
!issue8480.pdf
!bug1650302_reduced.pdf
!issue18816.pdf

BIN
test/pdfs/issue21570.pdf Normal file

Binary file not shown.

View File

@ -13059,6 +13059,13 @@
}
}
},
{
"id": "issue21570",
"file": "pdfs/issue21570.pdf",
"md5": "3065e65224901203e708e3dacad2d99a",
"rounds": 1,
"type": "eq"
},
{
"id": "issue2856",
"file": "pdfs/issue2856.pdf",

View File

@ -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(