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; return;
} }
case OPS.setFillColor: case OPS.setFillColor:
if (!isNumberArray(args, null)) {
continue;
}
cs = stateManager.state.fillColorSpace; cs = stateManager.state.fillColorSpace;
args = [cs.getRgbHex(args, 0)]; args = [cs.getRgbHex(args, 0)];
fn = OPS.setFillRGBColor; fn = OPS.setFillRGBColor;
break; break;
case OPS.setStrokeColor: case OPS.setStrokeColor:
if (!isNumberArray(args, null)) {
continue;
}
cs = stateManager.state.strokeColorSpace; cs = stateManager.state.strokeColorSpace;
args = [cs.getRgbHex(args, 0)]; args = [cs.getRgbHex(args, 0)];
fn = OPS.setStrokeRGBColor; fn = OPS.setStrokeRGBColor;
break; break;
case OPS.setFillGray: case OPS.setFillGray:
if (!isNumberArray(args, null)) {
continue;
}
stateManager.state.fillColorSpace = ColorSpaceUtils.gray; stateManager.state.fillColorSpace = ColorSpaceUtils.gray;
args = [ColorSpaceUtils.gray.getRgbHex(args, 0)]; args = [ColorSpaceUtils.gray.getRgbHex(args, 0)];
fn = OPS.setFillRGBColor; fn = OPS.setFillRGBColor;
break; break;
case OPS.setStrokeGray: case OPS.setStrokeGray:
if (!isNumberArray(args, null)) {
continue;
}
stateManager.state.strokeColorSpace = ColorSpaceUtils.gray; stateManager.state.strokeColorSpace = ColorSpaceUtils.gray;
args = [ColorSpaceUtils.gray.getRgbHex(args, 0)]; args = [ColorSpaceUtils.gray.getRgbHex(args, 0)];
fn = OPS.setStrokeRGBColor; fn = OPS.setStrokeRGBColor;
break; break;
case OPS.setFillCMYKColor: case OPS.setFillCMYKColor:
if (!isNumberArray(args, null)) {
continue;
}
stateManager.state.fillColorSpace = ColorSpaceUtils.cmyk; stateManager.state.fillColorSpace = ColorSpaceUtils.cmyk;
args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)]; args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)];
fn = OPS.setFillRGBColor; fn = OPS.setFillRGBColor;
break; break;
case OPS.setStrokeCMYKColor: case OPS.setStrokeCMYKColor:
if (!isNumberArray(args, null)) {
continue;
}
stateManager.state.strokeColorSpace = ColorSpaceUtils.cmyk; stateManager.state.strokeColorSpace = ColorSpaceUtils.cmyk;
args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)]; args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)];
fn = OPS.setStrokeRGBColor; fn = OPS.setStrokeRGBColor;
break; break;
case OPS.setFillRGBColor: case OPS.setFillRGBColor:
if (!isNumberArray(args, null)) {
continue;
}
stateManager.state.fillColorSpace = ColorSpaceUtils.rgb; stateManager.state.fillColorSpace = ColorSpaceUtils.rgb;
args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)]; args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)];
break; break;
case OPS.setStrokeRGBColor: case OPS.setStrokeRGBColor:
if (!isNumberArray(args, null)) {
continue;
}
stateManager.state.strokeColorSpace = ColorSpaceUtils.rgb; stateManager.state.strokeColorSpace = ColorSpaceUtils.rgb;
args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)]; args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)];
break; break;
@ -2041,6 +2065,9 @@ class PartialEvaluator {
break; break;
} }
if (cs.name === "Pattern") { if (cs.name === "Pattern") {
if (!Array.isArray(args)) {
continue;
}
next( next(
self.handleColorN( self.handleColorN(
operatorList, operatorList,
@ -2058,6 +2085,9 @@ class PartialEvaluator {
); );
return; return;
} }
if (!isNumberArray(args, null)) {
continue;
}
args = [cs.getRgbHex(args, 0)]; args = [cs.getRgbHex(args, 0)];
fn = OPS.setFillRGBColor; fn = OPS.setFillRGBColor;
break; break;
@ -2074,6 +2104,9 @@ class PartialEvaluator {
break; break;
} }
if (cs.name === "Pattern") { if (cs.name === "Pattern") {
if (!Array.isArray(args)) {
continue;
}
next( next(
self.handleColorN( self.handleColorN(
operatorList, operatorList,
@ -2091,6 +2124,9 @@ class PartialEvaluator {
); );
return; return;
} }
if (!isNumberArray(args, null)) {
continue;
}
args = [cs.getRgbHex(args, 0)]; args = [cs.getRgbHex(args, 0)];
fn = OPS.setStrokeRGBColor; fn = OPS.setStrokeRGBColor;
break; break;

View File

@ -103,6 +103,7 @@
!issue9713.pdf !issue9713.pdf
!xfa_filled_imm1344e.pdf !xfa_filled_imm1344e.pdf
!issue8424.pdf !issue8424.pdf
!issue21570.pdf
!issue8480.pdf !issue8480.pdf
!bug1650302_reduced.pdf !bug1650302_reduced.pdf
!issue18816.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", "id": "issue2856",
"file": "pdfs/issue2856.pdf", "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 { Dict, Name } from "../../src/core/primitives.js";
import { FormatError, OPS } from "../../src/shared/util.js"; import { FormatError, OPS } from "../../src/shared/util.js";
import { Stream, StringStream } from "../../src/core/stream.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 { OperatorList } from "../../src/core/operator_list.js";
import { PartialEvaluator } from "../../src/core/evaluator.js"; import { PartialEvaluator } from "../../src/core/evaluator.js";
import { WorkerTask } from "../../src/core/worker.js"; import { WorkerTask } from "../../src/core/worker.js";
@ -57,6 +58,7 @@ describe("evaluator", function () {
handler: new HandlerMock(), handler: new HandlerMock(),
pageIndex: 0, pageIndex: 0,
idFactory: createIdFactory(/* pageIndex = */ 0), idFactory: createIdFactory(/* pageIndex = */ 0),
globalColorSpaceCache: new GlobalColorSpaceCache(),
}); });
}); });
@ -358,6 +360,32 @@ describe("evaluator", function () {
expect(result.fnArray).toEqual([]); 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 () { it("should handle invalid dash stuff", async function () {
const stream = new StringStream("[ none ] 0 d"); const stream = new StringStream("[ none ] 0 d");
const result = await runOperatorListCheck( const result = await runOperatorListCheck(