Improve (local) caching of parsed ColorSpace
s (PR 12001 follow-up)
This patch contains the following *notable* improvements: - Changes the `ColorSpace.parse` call-sites to, where possible, pass in a reference rather than actual ColorSpace data (necessary for the next point). - Adds (local) caching of `ColorSpace`s by `Ref`, when applicable, in addition the caching by name. This (generally) improves `ColorSpace` caching for e.g. the SMask code-paths. - Extends the (local) `ColorSpace` caching to also apply when handling Images and Patterns, thus further reducing unneeded re-parsing. - Adds a new `ColorSpace.parseAsync` method, almost identical to the existing `ColorSpace.parse` one, but returning a Promise instead (this simplifies some code in the `PartialEvaluator`).
This commit is contained in:
parent
51e87b9248
commit
19d7976483
@ -22,7 +22,8 @@ import {
|
|||||||
unreachable,
|
unreachable,
|
||||||
warn,
|
warn,
|
||||||
} from "../shared/util.js";
|
} from "../shared/util.js";
|
||||||
import { isDict, isName, isStream } from "./primitives.js";
|
import { isDict, isName, isStream, Name, Ref } from "./primitives.js";
|
||||||
|
import { MissingDataException } from "./core_utils.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes an RGB image with 3 components.
|
* Resizes an RGB image with 3 components.
|
||||||
@ -259,9 +260,109 @@ class ColorSpace {
|
|||||||
return shadow(this, "usesZeroToOneRange", true);
|
return shadow(this, "usesZeroToOneRange", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static parse({ cs, xref, resources = null, pdfFunctionFactory }) {
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _cache(cacheKey, xref, localColorSpaceCache, parsedColorSpace) {
|
||||||
|
if (!localColorSpaceCache) {
|
||||||
|
throw new Error(
|
||||||
|
'ColorSpace._cache - expected "localColorSpaceCache" argument.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!parsedColorSpace) {
|
||||||
|
throw new Error(
|
||||||
|
'ColorSpace._cache - expected "parsedColorSpace" argument.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let csName, csRef;
|
||||||
|
if (cacheKey instanceof Ref) {
|
||||||
|
csRef = cacheKey;
|
||||||
|
|
||||||
|
// If parsing succeeded, we know that this call cannot throw.
|
||||||
|
cacheKey = xref.fetch(cacheKey);
|
||||||
|
}
|
||||||
|
if (cacheKey instanceof Name) {
|
||||||
|
csName = cacheKey.name;
|
||||||
|
}
|
||||||
|
if (csName || csRef) {
|
||||||
|
localColorSpaceCache.set(csName, csRef, parsedColorSpace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getCached(cacheKey, xref, localColorSpaceCache) {
|
||||||
|
if (!localColorSpaceCache) {
|
||||||
|
throw new Error(
|
||||||
|
'ColorSpace.getCached - expected "localColorSpaceCache" argument.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (cacheKey instanceof Ref) {
|
||||||
|
const localColorSpace = localColorSpaceCache.getByRef(cacheKey);
|
||||||
|
if (localColorSpace) {
|
||||||
|
return localColorSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
cacheKey = xref.fetch(cacheKey);
|
||||||
|
} catch (ex) {
|
||||||
|
if (ex instanceof MissingDataException) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
// Any errors should be handled during parsing, rather than here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cacheKey instanceof Name) {
|
||||||
|
const localColorSpace = localColorSpaceCache.getByName(cacheKey.name);
|
||||||
|
if (localColorSpace) {
|
||||||
|
return localColorSpace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async parseAsync({
|
||||||
|
cs,
|
||||||
|
xref,
|
||||||
|
resources = null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
}) {
|
||||||
|
if (
|
||||||
|
typeof PDFJSDev === "undefined" ||
|
||||||
|
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||||
|
) {
|
||||||
|
assert(
|
||||||
|
!this.getCached(cs, xref, localColorSpaceCache),
|
||||||
|
"Expected `ColorSpace.getCached` to have been manually checked " +
|
||||||
|
"before calling `ColorSpace.parseAsync`."
|
||||||
|
);
|
||||||
|
}
|
||||||
const IR = this.parseToIR(cs, xref, resources, pdfFunctionFactory);
|
const IR = this.parseToIR(cs, xref, resources, pdfFunctionFactory);
|
||||||
return this.fromIR(IR);
|
const parsedColorSpace = this.fromIR(IR);
|
||||||
|
|
||||||
|
// Attempt to cache the parsed ColorSpace, by name and/or reference.
|
||||||
|
this._cache(cs, xref, localColorSpaceCache, parsedColorSpace);
|
||||||
|
|
||||||
|
return parsedColorSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse({
|
||||||
|
cs,
|
||||||
|
xref,
|
||||||
|
resources = null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
}) {
|
||||||
|
const cachedColorSpace = this.getCached(cs, xref, localColorSpaceCache);
|
||||||
|
if (cachedColorSpace) {
|
||||||
|
return cachedColorSpace;
|
||||||
|
}
|
||||||
|
const IR = this.parseToIR(cs, xref, resources, pdfFunctionFactory);
|
||||||
|
const parsedColorSpace = this.fromIR(IR);
|
||||||
|
|
||||||
|
// Attempt to cache the parsed ColorSpace, by name and/or reference.
|
||||||
|
this._cache(cs, xref, localColorSpaceCache, parsedColorSpace);
|
||||||
|
|
||||||
|
return parsedColorSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromIR(IR) {
|
static fromIR(IR) {
|
||||||
|
@ -411,12 +411,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
groupOptions.isolated = group.get("I") || false;
|
groupOptions.isolated = group.get("I") || false;
|
||||||
groupOptions.knockout = group.get("K") || false;
|
groupOptions.knockout = group.get("K") || false;
|
||||||
if (group.has("CS")) {
|
if (group.has("CS")) {
|
||||||
const cs = group.get("CS");
|
const cs = group.getRaw("CS");
|
||||||
|
|
||||||
const localColorSpace =
|
const cachedColorSpace = ColorSpace.getCached(
|
||||||
cs instanceof Name && localColorSpaceCache.getByName(cs.name);
|
cs,
|
||||||
if (localColorSpace) {
|
this.xref,
|
||||||
colorSpace = localColorSpace;
|
localColorSpaceCache
|
||||||
|
);
|
||||||
|
if (cachedColorSpace) {
|
||||||
|
colorSpace = cachedColorSpace;
|
||||||
} else {
|
} else {
|
||||||
colorSpace = await this.parseColorSpace({
|
colorSpace = await this.parseColorSpace({
|
||||||
cs,
|
cs,
|
||||||
@ -483,6 +486,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
operatorList,
|
operatorList,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
localImageCache,
|
localImageCache,
|
||||||
|
localColorSpaceCache,
|
||||||
}) {
|
}) {
|
||||||
var dict = image.dict;
|
var dict = image.dict;
|
||||||
const imageRef = dict.objId;
|
const imageRef = dict.objId;
|
||||||
@ -549,6 +553,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
image,
|
image,
|
||||||
isInline,
|
isInline,
|
||||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
});
|
});
|
||||||
// We force the use of RGBA_32BPP images here, because we can't handle
|
// We force the use of RGBA_32BPP images here, because we can't handle
|
||||||
// any other kind.
|
// any other kind.
|
||||||
@ -585,6 +590,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
image,
|
image,
|
||||||
isInline,
|
isInline,
|
||||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
})
|
})
|
||||||
.then(imageObj => {
|
.then(imageObj => {
|
||||||
imgData = imageObj.createImageData(/* forceRGBA = */ false);
|
imgData = imageObj.createImageData(/* forceRGBA = */ false);
|
||||||
@ -1135,19 +1141,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
parseColorSpace({ cs, resources, localColorSpaceCache }) {
|
parseColorSpace({ cs, resources, localColorSpaceCache }) {
|
||||||
return new Promise(resolve => {
|
return ColorSpace.parseAsync({
|
||||||
const parsedColorSpace = ColorSpace.parse({
|
|
||||||
cs,
|
cs,
|
||||||
xref: this.xref,
|
xref: this.xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||||
});
|
localColorSpaceCache,
|
||||||
|
|
||||||
const csName = cs instanceof Name ? cs.name : null;
|
|
||||||
if (csName) {
|
|
||||||
localColorSpaceCache.set(csName, /* ref = */ null, parsedColorSpace);
|
|
||||||
}
|
|
||||||
resolve(parsedColorSpace);
|
|
||||||
}).catch(reason => {
|
}).catch(reason => {
|
||||||
if (reason instanceof AbortException) {
|
if (reason instanceof AbortException) {
|
||||||
return null;
|
return null;
|
||||||
@ -1165,7 +1164,16 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleColorN(operatorList, fn, args, cs, patterns, resources, task) {
|
async handleColorN(
|
||||||
|
operatorList,
|
||||||
|
fn,
|
||||||
|
args,
|
||||||
|
cs,
|
||||||
|
patterns,
|
||||||
|
resources,
|
||||||
|
task,
|
||||||
|
localColorSpaceCache
|
||||||
|
) {
|
||||||
// compile tiling patterns
|
// compile tiling patterns
|
||||||
var patternName = args[args.length - 1];
|
var patternName = args[args.length - 1];
|
||||||
// SCN/scn applies patterns along with normal colors
|
// SCN/scn applies patterns along with normal colors
|
||||||
@ -1194,7 +1202,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
this.xref,
|
this.xref,
|
||||||
resources,
|
resources,
|
||||||
this.handler,
|
this.handler,
|
||||||
this.pdfFunctionFactory
|
this.pdfFunctionFactory,
|
||||||
|
localColorSpaceCache
|
||||||
);
|
);
|
||||||
operatorList.addOp(fn, pattern.getIR());
|
operatorList.addOp(fn, pattern.getIR());
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -1352,6 +1361,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
operatorList,
|
operatorList,
|
||||||
cacheKey: name,
|
cacheKey: name,
|
||||||
localImageCache,
|
localImageCache,
|
||||||
|
localColorSpaceCache,
|
||||||
})
|
})
|
||||||
.then(resolveXObject, rejectXObject);
|
.then(resolveXObject, rejectXObject);
|
||||||
return;
|
return;
|
||||||
@ -1425,6 +1435,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
operatorList,
|
operatorList,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
localImageCache,
|
localImageCache,
|
||||||
|
localColorSpaceCache,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -1483,11 +1494,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OPS.setFillColorSpace: {
|
case OPS.setFillColorSpace: {
|
||||||
const localColorSpace =
|
const cachedColorSpace = ColorSpace.getCached(
|
||||||
args[0] instanceof Name &&
|
args[0],
|
||||||
localColorSpaceCache.getByName(args[0].name);
|
xref,
|
||||||
if (localColorSpace) {
|
localColorSpaceCache
|
||||||
stateManager.state.fillColorSpace = localColorSpace;
|
);
|
||||||
|
if (cachedColorSpace) {
|
||||||
|
stateManager.state.fillColorSpace = cachedColorSpace;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1507,11 +1520,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case OPS.setStrokeColorSpace: {
|
case OPS.setStrokeColorSpace: {
|
||||||
const localColorSpace =
|
const cachedColorSpace = ColorSpace.getCached(
|
||||||
args[0] instanceof Name &&
|
args[0],
|
||||||
localColorSpaceCache.getByName(args[0].name);
|
xref,
|
||||||
if (localColorSpace) {
|
localColorSpaceCache
|
||||||
stateManager.state.strokeColorSpace = localColorSpace;
|
);
|
||||||
|
if (cachedColorSpace) {
|
||||||
|
stateManager.state.strokeColorSpace = cachedColorSpace;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1579,7 +1594,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
cs,
|
cs,
|
||||||
patterns,
|
patterns,
|
||||||
resources,
|
resources,
|
||||||
task
|
task,
|
||||||
|
localColorSpaceCache
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -1598,7 +1614,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
cs,
|
cs,
|
||||||
patterns,
|
patterns,
|
||||||
resources,
|
resources,
|
||||||
task
|
task,
|
||||||
|
localColorSpaceCache
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -1624,7 +1641,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
self.handler,
|
self.handler,
|
||||||
self.pdfFunctionFactory
|
self.pdfFunctionFactory,
|
||||||
|
localColorSpaceCache
|
||||||
);
|
);
|
||||||
var patternIR = shadingFill.getIR();
|
var patternIR = shadingFill.getIR();
|
||||||
args = [patternIR];
|
args = [patternIR];
|
||||||
|
@ -89,6 +89,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
mask = null,
|
mask = null,
|
||||||
isMask = false,
|
isMask = false,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
}) {
|
}) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
var dict = image.dict;
|
var dict = image.dict;
|
||||||
@ -159,7 +160,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
this.bpc = bitsPerComponent;
|
this.bpc = bitsPerComponent;
|
||||||
|
|
||||||
if (!this.imageMask) {
|
if (!this.imageMask) {
|
||||||
var colorSpace = dict.get("ColorSpace", "CS");
|
let colorSpace = dict.getRaw("ColorSpace") || dict.getRaw("CS");
|
||||||
if (!colorSpace) {
|
if (!colorSpace) {
|
||||||
info("JPX images (which do not require color spaces)");
|
info("JPX images (which do not require color spaces)");
|
||||||
switch (image.numComps) {
|
switch (image.numComps) {
|
||||||
@ -184,6 +185,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
xref,
|
xref,
|
||||||
resources: isInline ? res : null,
|
resources: isInline ? res : null,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
});
|
});
|
||||||
this.numComps = this.colorSpace.numComps;
|
this.numComps = this.colorSpace.numComps;
|
||||||
}
|
}
|
||||||
@ -220,6 +222,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
image: smask,
|
image: smask,
|
||||||
isInline,
|
isInline,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
});
|
});
|
||||||
} else if (mask) {
|
} else if (mask) {
|
||||||
if (isStream(mask)) {
|
if (isStream(mask)) {
|
||||||
@ -235,6 +238,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
isInline,
|
isInline,
|
||||||
isMask: true,
|
isMask: true,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -253,6 +257,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
image,
|
image,
|
||||||
isInline = false,
|
isInline = false,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
}) {
|
}) {
|
||||||
const imageData = image;
|
const imageData = image;
|
||||||
let smaskData = null;
|
let smaskData = null;
|
||||||
@ -279,6 +284,7 @@ var PDFImage = (function PDFImageClosure() {
|
|||||||
smask: smaskData,
|
smask: smaskData,
|
||||||
mask: maskData,
|
mask: maskData,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,7 +57,8 @@ var Pattern = (function PatternClosure() {
|
|||||||
xref,
|
xref,
|
||||||
res,
|
res,
|
||||||
handler,
|
handler,
|
||||||
pdfFunctionFactory
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache
|
||||||
) {
|
) {
|
||||||
var dict = isStream(shading) ? shading.dict : shading;
|
var dict = isStream(shading) ? shading.dict : shading;
|
||||||
var type = dict.get("ShadingType");
|
var type = dict.get("ShadingType");
|
||||||
@ -72,7 +73,8 @@ var Pattern = (function PatternClosure() {
|
|||||||
matrix,
|
matrix,
|
||||||
xref,
|
xref,
|
||||||
res,
|
res,
|
||||||
pdfFunctionFactory
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache
|
||||||
);
|
);
|
||||||
case ShadingType.FREE_FORM_MESH:
|
case ShadingType.FREE_FORM_MESH:
|
||||||
case ShadingType.LATTICE_FORM_MESH:
|
case ShadingType.LATTICE_FORM_MESH:
|
||||||
@ -83,7 +85,8 @@ var Pattern = (function PatternClosure() {
|
|||||||
matrix,
|
matrix,
|
||||||
xref,
|
xref,
|
||||||
res,
|
res,
|
||||||
pdfFunctionFactory
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
throw new FormatError("Unsupported ShadingType: " + type);
|
throw new FormatError("Unsupported ShadingType: " + type);
|
||||||
@ -111,16 +114,24 @@ Shadings.SMALL_NUMBER = 1e-6;
|
|||||||
// Radial and axial shading have very similar implementations
|
// Radial and axial shading have very similar implementations
|
||||||
// If needed, the implementations can be broken into two classes
|
// If needed, the implementations can be broken into two classes
|
||||||
Shadings.RadialAxial = (function RadialAxialClosure() {
|
Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||||
function RadialAxial(dict, matrix, xref, resources, pdfFunctionFactory) {
|
function RadialAxial(
|
||||||
|
dict,
|
||||||
|
matrix,
|
||||||
|
xref,
|
||||||
|
resources,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache
|
||||||
|
) {
|
||||||
this.matrix = matrix;
|
this.matrix = matrix;
|
||||||
this.coordsArr = dict.getArray("Coords");
|
this.coordsArr = dict.getArray("Coords");
|
||||||
this.shadingType = dict.get("ShadingType");
|
this.shadingType = dict.get("ShadingType");
|
||||||
this.type = "Pattern";
|
this.type = "Pattern";
|
||||||
const cs = ColorSpace.parse({
|
const cs = ColorSpace.parse({
|
||||||
cs: dict.get("ColorSpace", "CS"),
|
cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"),
|
||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
});
|
});
|
||||||
this.cs = cs;
|
this.cs = cs;
|
||||||
const bbox = dict.getArray("BBox");
|
const bbox = dict.getArray("BBox");
|
||||||
@ -834,7 +845,14 @@ Shadings.Mesh = (function MeshClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Mesh(stream, matrix, xref, resources, pdfFunctionFactory) {
|
function Mesh(
|
||||||
|
stream,
|
||||||
|
matrix,
|
||||||
|
xref,
|
||||||
|
resources,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache
|
||||||
|
) {
|
||||||
if (!isStream(stream)) {
|
if (!isStream(stream)) {
|
||||||
throw new FormatError("Mesh data is not a stream");
|
throw new FormatError("Mesh data is not a stream");
|
||||||
}
|
}
|
||||||
@ -849,10 +867,11 @@ Shadings.Mesh = (function MeshClosure() {
|
|||||||
this.bbox = null;
|
this.bbox = null;
|
||||||
}
|
}
|
||||||
const cs = ColorSpace.parse({
|
const cs = ColorSpace.parse({
|
||||||
cs: dict.get("ColorSpace", "CS"),
|
cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"),
|
||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
});
|
});
|
||||||
this.cs = cs;
|
this.cs = cs;
|
||||||
this.background = dict.has("Background")
|
this.background = dict.has("Background")
|
||||||
|
@ -16,18 +16,21 @@
|
|||||||
import { Dict, Name, Ref } from "../../src/core/primitives.js";
|
import { Dict, Name, Ref } from "../../src/core/primitives.js";
|
||||||
import { Stream, StringStream } from "../../src/core/stream.js";
|
import { Stream, StringStream } from "../../src/core/stream.js";
|
||||||
import { ColorSpace } from "../../src/core/colorspace.js";
|
import { ColorSpace } from "../../src/core/colorspace.js";
|
||||||
|
import { LocalColorSpaceCache } from "../../src/core/image_utils.js";
|
||||||
import { PDFFunctionFactory } from "../../src/core/function.js";
|
import { PDFFunctionFactory } from "../../src/core/function.js";
|
||||||
import { XRefMock } from "./test_utils.js";
|
import { XRefMock } from "./test_utils.js";
|
||||||
|
|
||||||
describe("colorspace", function () {
|
describe("colorspace", function () {
|
||||||
describe("ColorSpace", function () {
|
describe("ColorSpace.isDefaultDecode", function () {
|
||||||
it("should be true if decode is not an array", function () {
|
it("should be true if decode is not an array", function () {
|
||||||
expect(ColorSpace.isDefaultDecode("string", 0)).toBeTruthy();
|
expect(ColorSpace.isDefaultDecode("string", 0)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be true if length of decode array is not correct", function () {
|
it("should be true if length of decode array is not correct", function () {
|
||||||
expect(ColorSpace.isDefaultDecode([0], 1)).toBeTruthy();
|
expect(ColorSpace.isDefaultDecode([0], 1)).toBeTruthy();
|
||||||
expect(ColorSpace.isDefaultDecode([0, 1, 0], 1)).toBeTruthy();
|
expect(ColorSpace.isDefaultDecode([0, 1, 0], 1)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be true if decode map matches the default decode map", function () {
|
it("should be true if decode map matches the default decode map", function () {
|
||||||
expect(ColorSpace.isDefaultDecode([], 0)).toBeTruthy();
|
expect(ColorSpace.isDefaultDecode([], 0)).toBeTruthy();
|
||||||
|
|
||||||
@ -46,6 +49,138 @@ describe("colorspace", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("ColorSpace caching", function () {
|
||||||
|
let localColorSpaceCache = null;
|
||||||
|
|
||||||
|
beforeAll(function (done) {
|
||||||
|
localColorSpaceCache = new LocalColorSpaceCache();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(function (done) {
|
||||||
|
localColorSpaceCache = null;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("caching by Name", function () {
|
||||||
|
const xref = new XRefMock();
|
||||||
|
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||||
|
xref,
|
||||||
|
});
|
||||||
|
|
||||||
|
const colorSpace1 = ColorSpace.parse({
|
||||||
|
cs: Name.get("Pattern"),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
});
|
||||||
|
expect(colorSpace1.name).toEqual("Pattern");
|
||||||
|
|
||||||
|
const colorSpace2 = ColorSpace.parse({
|
||||||
|
cs: Name.get("Pattern"),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
});
|
||||||
|
expect(colorSpace2.name).toEqual("Pattern");
|
||||||
|
|
||||||
|
const colorSpaceNonCached = ColorSpace.parse({
|
||||||
|
cs: Name.get("Pattern"),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
|
});
|
||||||
|
expect(colorSpaceNonCached.name).toEqual("Pattern");
|
||||||
|
|
||||||
|
const colorSpaceOther = ColorSpace.parse({
|
||||||
|
cs: Name.get("RGB"),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
});
|
||||||
|
expect(colorSpaceOther.name).toEqual("DeviceRGB");
|
||||||
|
|
||||||
|
// These two must be *identical* if caching worked as intended.
|
||||||
|
expect(colorSpace1).toBe(colorSpace2);
|
||||||
|
|
||||||
|
expect(colorSpace1).not.toBe(colorSpaceNonCached);
|
||||||
|
expect(colorSpace1).not.toBe(colorSpaceOther);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("caching by Ref", function () {
|
||||||
|
const paramsCalGray = new Dict();
|
||||||
|
paramsCalGray.set("WhitePoint", [1, 1, 1]);
|
||||||
|
paramsCalGray.set("BlackPoint", [0, 0, 0]);
|
||||||
|
paramsCalGray.set("Gamma", 2.0);
|
||||||
|
|
||||||
|
const paramsCalRGB = new Dict();
|
||||||
|
paramsCalRGB.set("WhitePoint", [1, 1, 1]);
|
||||||
|
paramsCalRGB.set("BlackPoint", [0, 0, 0]);
|
||||||
|
paramsCalRGB.set("Gamma", [1, 1, 1]);
|
||||||
|
paramsCalRGB.set("Matrix", [1, 0, 0, 0, 1, 0, 0, 0, 1]);
|
||||||
|
|
||||||
|
const xref = new XRefMock([
|
||||||
|
{
|
||||||
|
ref: Ref.get(50, 0),
|
||||||
|
data: [Name.get("CalGray"), paramsCalGray],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ref: Ref.get(100, 0),
|
||||||
|
data: [Name.get("CalRGB"), paramsCalRGB],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||||
|
xref,
|
||||||
|
});
|
||||||
|
|
||||||
|
const colorSpace1 = ColorSpace.parse({
|
||||||
|
cs: Ref.get(50, 0),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
});
|
||||||
|
expect(colorSpace1.name).toEqual("CalGray");
|
||||||
|
|
||||||
|
const colorSpace2 = ColorSpace.parse({
|
||||||
|
cs: Ref.get(50, 0),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
});
|
||||||
|
expect(colorSpace2.name).toEqual("CalGray");
|
||||||
|
|
||||||
|
const colorSpaceNonCached = ColorSpace.parse({
|
||||||
|
cs: Ref.get(50, 0),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
|
});
|
||||||
|
expect(colorSpaceNonCached.name).toEqual("CalGray");
|
||||||
|
|
||||||
|
const colorSpaceOther = ColorSpace.parse({
|
||||||
|
cs: Ref.get(100, 0),
|
||||||
|
xref,
|
||||||
|
resources: null,
|
||||||
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache,
|
||||||
|
});
|
||||||
|
expect(colorSpaceOther.name).toEqual("CalRGB");
|
||||||
|
|
||||||
|
// These two must be *identical* if caching worked as intended.
|
||||||
|
expect(colorSpace1).toBe(colorSpace2);
|
||||||
|
|
||||||
|
expect(colorSpace1).not.toBe(colorSpaceNonCached);
|
||||||
|
expect(colorSpace1).not.toBe(colorSpaceOther);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("DeviceGrayCS", function () {
|
describe("DeviceGrayCS", function () {
|
||||||
it("should handle the case when cs is a Name object", function () {
|
it("should handle the case when cs is a Name object", function () {
|
||||||
const cs = Name.get("DeviceGray");
|
const cs = Name.get("DeviceGray");
|
||||||
@ -65,6 +200,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testSrc = new Uint8Array([27, 125, 250, 131]);
|
const testSrc = new Uint8Array([27, 125, 250, 131]);
|
||||||
@ -115,6 +251,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testSrc = new Uint8Array([27, 125, 250, 131]);
|
const testSrc = new Uint8Array([27, 125, 250, 131]);
|
||||||
@ -161,6 +298,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@ -217,6 +355,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@ -269,6 +408,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@ -325,6 +465,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@ -382,6 +523,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testSrc = new Uint8Array([27, 125, 250, 131]);
|
const testSrc = new Uint8Array([27, 125, 250, 131]);
|
||||||
@ -441,6 +583,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@ -498,6 +641,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@ -557,6 +701,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testSrc = new Uint8Array([2, 2, 0, 1]);
|
const testSrc = new Uint8Array([2, 2, 0, 1]);
|
||||||
@ -624,6 +769,7 @@ describe("colorspace", function () {
|
|||||||
xref,
|
xref,
|
||||||
resources,
|
resources,
|
||||||
pdfFunctionFactory,
|
pdfFunctionFactory,
|
||||||
|
localColorSpaceCache: new LocalColorSpaceCache(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testSrc = new Uint8Array([27, 25, 50, 31]);
|
const testSrc = new Uint8Array([27, 25, 50, 31]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user