1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-28 23:28:16 +02:00

Improve parseAppearanceStream to handle more "complex" ColorSpaces

The existing code is unable to *correctly* extract the color from the appearance-stream when the ColorSpace-data is "complex". To reproduce this:
 - Open `freetexts.pdf` in the viewer.
 - Note the purple color of the "Hello World from Preview" annotation.
 - Enable any of the Editors.
 - Note how the relevant annotation is now black.
This commit is contained in:
Jonas Jenwald 2023-07-06 13:03:11 +02:00
parent 8281bb8858
commit 6442a6cc4e
4 changed files with 201 additions and 42 deletions

View file

@ -20,9 +20,17 @@ import {
numberToString,
stringToUTF16HexString,
} from "./core_utils.js";
import { LINE_DESCENT_FACTOR, LINE_FACTOR, OPS, warn } from "../shared/util.js";
import {
LINE_DESCENT_FACTOR,
LINE_FACTOR,
OPS,
shadow,
warn,
} from "../shared/util.js";
import { ColorSpace } from "./colorspace.js";
import { EvaluatorPreprocessor } from "./evaluator.js";
import { LocalColorSpaceCache } from "./image_utils.js";
import { PDFFunctionFactory } from "./function.js";
import { StringStream } from "./stream.js";
class DefaultAppearanceEvaluator extends EvaluatorPreprocessor {
@ -88,9 +96,13 @@ function parseDefaultAppearance(str) {
}
class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
constructor(stream) {
constructor(stream, evaluatorOptions, xref) {
super(stream);
this.stream = stream;
this.evaluatorOptions = evaluatorOptions;
this.xref = xref;
this.resources = stream.dict?.get("Resources");
}
parse() {
@ -103,6 +115,7 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
fontSize: 0,
fontName: "",
fontColor: /* black = */ new Uint8ClampedArray(3),
fillColorSpace: ColorSpace.singletons.gray,
};
let breakLoop = false;
const stack = [];
@ -123,6 +136,7 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
fontSize: result.fontSize,
fontName: result.fontName,
fontColor: result.fontColor.slice(),
fillColorSpace: result.fillColorSpace,
});
break;
case OPS.restore:
@ -140,6 +154,19 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
result.fontSize = fontSize * result.scaleFactor;
}
break;
case OPS.setFillColorSpace:
result.fillColorSpace = ColorSpace.parse({
cs: args[0],
xref: this.xref,
resources: this.resources,
pdfFunctionFactory: this._pdfFunctionFactory,
localColorSpaceCache: this._localColorSpaceCache,
});
break;
case OPS.setFillColor:
const cs = result.fillColorSpace;
cs.getRgbItem(args, 0, result.fontColor, 0);
break;
case OPS.setFillRGBColor:
ColorSpace.singletons.rgb.getRgbItem(args, 0, result.fontColor, 0);
break;
@ -162,15 +189,28 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
}
this.stream.reset();
delete result.scaleFactor;
delete result.fillColorSpace;
return result;
}
get _localColorSpaceCache() {
return shadow(this, "_localColorSpaceCache", new LocalColorSpaceCache());
}
get _pdfFunctionFactory() {
const pdfFunctionFactory = new PDFFunctionFactory({
xref: this.xref,
isEvalSupported: this.evaluatorOptions.isEvalSupported,
});
return shadow(this, "_pdfFunctionFactory", pdfFunctionFactory);
}
}
// Parse appearance stream to extract font and color information.
// It returns the font properties used to render the first text object.
function parseAppearanceStream(stream) {
return new AppearanceStreamEvaluator(stream).parse();
function parseAppearanceStream(stream, evaluatorOptions, xref) {
return new AppearanceStreamEvaluator(stream, evaluatorOptions, xref).parse();
}
function getPdfColor(color, isFill) {