diff --git a/src/core/colorspace.js b/src/core/colorspace.js index dbd63a26c5028..d1597a730ac21 100644 --- a/src/core/colorspace.js +++ b/src/core/colorspace.js @@ -22,7 +22,8 @@ import { unreachable, warn, } 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. @@ -259,9 +260,109 @@ class ColorSpace { return shadow(this, "usesZeroToOneRange", true); } - static parse(cs, xref, res, pdfFunctionFactory) { - const IR = this.parseToIR(cs, xref, res, pdfFunctionFactory); - return this.fromIR(IR); + /** + * @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 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) { @@ -312,7 +413,7 @@ class ColorSpace { } } - static parseToIR(cs, xref, res = null, pdfFunctionFactory) { + static parseToIR(cs, xref, resources = null, pdfFunctionFactory) { cs = xref.fetchIfRef(cs); if (isName(cs)) { switch (cs.name) { @@ -328,15 +429,20 @@ class ColorSpace { case "Pattern": return ["PatternCS", null]; default: - if (isDict(res)) { - const colorSpaces = res.get("ColorSpace"); + if (isDict(resources)) { + const colorSpaces = resources.get("ColorSpace"); if (isDict(colorSpaces)) { - const resCS = colorSpaces.get(cs.name); - if (resCS) { - if (isName(resCS)) { - return this.parseToIR(resCS, xref, res, pdfFunctionFactory); + const resourcesCS = colorSpaces.get(cs.name); + if (resourcesCS) { + if (isName(resourcesCS)) { + return this.parseToIR( + resourcesCS, + xref, + resources, + pdfFunctionFactory + ); } - cs = resCS; + cs = resourcesCS; break; } } @@ -377,10 +483,15 @@ class ColorSpace { numComps = dict.get("N"); alt = dict.get("Alternate"); if (alt) { - const altIR = this.parseToIR(alt, xref, res, pdfFunctionFactory); + const altIR = this.parseToIR( + alt, + xref, + resources, + pdfFunctionFactory + ); // Parse the /Alternate CS to ensure that the number of components // are correct, and also (indirectly) that it is not a PatternCS. - const altCS = this.fromIR(altIR, pdfFunctionFactory); + const altCS = this.fromIR(altIR); if (altCS.numComps === numComps) { return altIR; } @@ -400,7 +511,7 @@ class ColorSpace { basePatternCS = this.parseToIR( basePatternCS, xref, - res, + resources, pdfFunctionFactory ); } @@ -410,7 +521,7 @@ class ColorSpace { const baseIndexedCS = this.parseToIR( cs[1], xref, - res, + resources, pdfFunctionFactory ); const hiVal = xref.fetchIfRef(cs[2]) + 1; @@ -423,7 +534,7 @@ class ColorSpace { case "DeviceN": const name = xref.fetchIfRef(cs[1]); numComps = Array.isArray(name) ? name.length : 1; - alt = this.parseToIR(cs[2], xref, res, pdfFunctionFactory); + alt = this.parseToIR(cs[2], xref, resources, pdfFunctionFactory); const tintFn = pdfFunctionFactory.create(xref.fetchIfRef(cs[3])); return ["AlternateCS", numComps, alt, tintFn]; case "Lab": diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 4d873ec064f81..d11804ba7747d 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -73,13 +73,13 @@ import { } from "./standard_fonts.js"; import { getTilingPatternIR, Pattern } from "./pattern.js"; import { Lexer, Parser } from "./parser.js"; +import { LocalColorSpaceCache, LocalImageCache } from "./image_utils.js"; import { bidi } from "./bidi.js"; import { ColorSpace } from "./colorspace.js"; import { DecodeStream } from "./stream.js"; import { getGlyphsUnicode } from "./glyphlist.js"; import { getMetrics } from "./metrics.js"; import { isPDFFunction } from "./function.js"; -import { LocalImageCache } from "./image_utils.js"; import { MurmurHash3_64 } from "./murmurhash3.js"; import { OperatorList } from "./operator_list.js"; import { PDFImage } from "./image.js"; @@ -411,12 +411,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { groupOptions.isolated = group.get("I") || false; groupOptions.knockout = group.get("K") || false; if (group.has("CS")) { - const cs = group.get("CS"); + const cs = group.getRaw("CS"); - const localColorSpace = - cs instanceof Name && localColorSpaceCache.getByName(cs.name); - if (localColorSpace) { - colorSpace = localColorSpace; + const cachedColorSpace = ColorSpace.getCached( + cs, + this.xref, + localColorSpaceCache + ); + if (cachedColorSpace) { + colorSpace = cachedColorSpace; } else { colorSpace = await this.parseColorSpace({ cs, @@ -483,6 +486,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { operatorList, cacheKey, localImageCache, + localColorSpaceCache, }) { var dict = image.dict; const imageRef = dict.objId; @@ -549,6 +553,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { image, isInline, pdfFunctionFactory: this.pdfFunctionFactory, + localColorSpaceCache, }); // We force the use of RGBA_32BPP images here, because we can't handle // any other kind. @@ -585,6 +590,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { image, isInline, pdfFunctionFactory: this.pdfFunctionFactory, + localColorSpaceCache, }) .then(imageObj => { imgData = imageObj.createImageData(/* forceRGBA = */ false); @@ -1135,19 +1141,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { }, parseColorSpace({ cs, resources, localColorSpaceCache }) { - return new Promise(resolve => { - const parsedColorSpace = ColorSpace.parse( - cs, - this.xref, - resources, - this.pdfFunctionFactory - ); - - const csName = cs instanceof Name ? cs.name : null; - if (csName) { - localColorSpaceCache.set(csName, /* ref = */ null, parsedColorSpace); - } - resolve(parsedColorSpace); + return ColorSpace.parseAsync({ + cs, + xref: this.xref, + resources, + pdfFunctionFactory: this.pdfFunctionFactory, + localColorSpaceCache, }).catch(reason => { if (reason instanceof AbortException) { 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 var patternName = args[args.length - 1]; // SCN/scn applies patterns along with normal colors @@ -1194,7 +1202,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { this.xref, resources, this.handler, - this.pdfFunctionFactory + this.pdfFunctionFactory, + localColorSpaceCache ); operatorList.addOp(fn, pattern.getIR()); return undefined; @@ -1224,7 +1233,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var xref = this.xref; let parsingText = false; const localImageCache = new LocalImageCache(); - const localColorSpaceCache = new LocalImageCache(); + const localColorSpaceCache = new LocalColorSpaceCache(); var xobjs = resources.get("XObject") || Dict.empty; var patterns = resources.get("Pattern") || Dict.empty; @@ -1352,6 +1361,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { operatorList, cacheKey: name, localImageCache, + localColorSpaceCache, }) .then(resolveXObject, rejectXObject); return; @@ -1425,6 +1435,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { operatorList, cacheKey, localImageCache, + localColorSpaceCache, }) ); return; @@ -1483,11 +1494,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { break; case OPS.setFillColorSpace: { - const localColorSpace = - args[0] instanceof Name && - localColorSpaceCache.getByName(args[0].name); - if (localColorSpace) { - stateManager.state.fillColorSpace = localColorSpace; + const cachedColorSpace = ColorSpace.getCached( + args[0], + xref, + localColorSpaceCache + ); + if (cachedColorSpace) { + stateManager.state.fillColorSpace = cachedColorSpace; continue; } @@ -1507,11 +1520,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { return; } case OPS.setStrokeColorSpace: { - const localColorSpace = - args[0] instanceof Name && - localColorSpaceCache.getByName(args[0].name); - if (localColorSpace) { - stateManager.state.strokeColorSpace = localColorSpace; + const cachedColorSpace = ColorSpace.getCached( + args[0], + xref, + localColorSpaceCache + ); + if (cachedColorSpace) { + stateManager.state.strokeColorSpace = cachedColorSpace; continue; } @@ -1579,7 +1594,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { cs, patterns, resources, - task + task, + localColorSpaceCache ) ); return; @@ -1598,7 +1614,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { cs, patterns, resources, - task + task, + localColorSpaceCache ) ); return; @@ -1624,7 +1641,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { xref, resources, self.handler, - self.pdfFunctionFactory + self.pdfFunctionFactory, + localColorSpaceCache ); var patternIR = shadingFill.getIR(); args = [patternIR]; diff --git a/src/core/image.js b/src/core/image.js index 5c5bc15bc4586..f41a1991aab5d 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -89,6 +89,7 @@ var PDFImage = (function PDFImageClosure() { mask = null, isMask = false, pdfFunctionFactory, + localColorSpaceCache, }) { this.image = image; var dict = image.dict; @@ -159,7 +160,7 @@ var PDFImage = (function PDFImageClosure() { this.bpc = bitsPerComponent; if (!this.imageMask) { - var colorSpace = dict.get("ColorSpace", "CS"); + let colorSpace = dict.getRaw("ColorSpace") || dict.getRaw("CS"); if (!colorSpace) { info("JPX images (which do not require color spaces)"); switch (image.numComps) { @@ -179,13 +180,13 @@ var PDFImage = (function PDFImageClosure() { ); } } - const resources = isInline ? res : null; - this.colorSpace = ColorSpace.parse( - colorSpace, + this.colorSpace = ColorSpace.parse({ + cs: colorSpace, xref, - resources, - pdfFunctionFactory - ); + resources: isInline ? res : null, + pdfFunctionFactory, + localColorSpaceCache, + }); this.numComps = this.colorSpace.numComps; } @@ -221,6 +222,7 @@ var PDFImage = (function PDFImageClosure() { image: smask, isInline, pdfFunctionFactory, + localColorSpaceCache, }); } else if (mask) { if (isStream(mask)) { @@ -236,6 +238,7 @@ var PDFImage = (function PDFImageClosure() { isInline, isMask: true, pdfFunctionFactory, + localColorSpaceCache, }); } } else { @@ -254,6 +257,7 @@ var PDFImage = (function PDFImageClosure() { image, isInline = false, pdfFunctionFactory, + localColorSpaceCache, }) { const imageData = image; let smaskData = null; @@ -280,6 +284,7 @@ var PDFImage = (function PDFImageClosure() { smask: smaskData, mask: maskData, pdfFunctionFactory, + localColorSpaceCache, }); }; diff --git a/src/core/image_utils.js b/src/core/image_utils.js index 2fbb93eb0e619..d255cc09855da 100644 --- a/src/core/image_utils.js +++ b/src/core/image_utils.js @@ -14,11 +14,14 @@ */ /* eslint no-var: error */ -import { assert, info, shadow } from "../shared/util.js"; +import { assert, info, shadow, unreachable } from "../shared/util.js"; import { RefSetCache } from "./primitives.js"; -class LocalImageCache { +class BaseLocalCache { constructor() { + if (this.constructor === BaseLocalCache) { + unreachable("Cannot initialize BaseLocalCache."); + } this._nameRefMap = new Map(); this._imageMap = new Map(); this._imageCache = new RefSetCache(); @@ -36,6 +39,12 @@ class LocalImageCache { return this._imageCache.get(ref) || null; } + set(name, ref, data) { + unreachable("Abstract method `set` called."); + } +} + +class LocalImageCache extends BaseLocalCache { set(name, ref = null, data) { if (!name) { throw new Error('LocalImageCache.set - expected "name" argument.'); @@ -56,6 +65,32 @@ class LocalImageCache { } } +class LocalColorSpaceCache extends BaseLocalCache { + set(name = null, ref = null, data) { + if (!name && !ref) { + throw new Error( + 'LocalColorSpaceCache.set - expected "name" and/or "ref" argument.' + ); + } + if (ref) { + if (this._imageCache.has(ref)) { + return; + } + if (name) { + // Optional when `ref` is defined. + this._nameRefMap.set(name, ref); + } + this._imageCache.put(ref, data); + return; + } + // name + if (this._imageMap.has(name)) { + return; + } + this._imageMap.set(name, data); + } +} + class GlobalImageCache { static get NUM_PAGES_THRESHOLD() { return shadow(this, "NUM_PAGES_THRESHOLD", 2); @@ -149,4 +184,4 @@ class GlobalImageCache { } } -export { LocalImageCache, GlobalImageCache }; +export { LocalImageCache, LocalColorSpaceCache, GlobalImageCache }; diff --git a/src/core/pattern.js b/src/core/pattern.js index c380adf0b0c80..e1f63b513ed16 100644 --- a/src/core/pattern.js +++ b/src/core/pattern.js @@ -57,7 +57,8 @@ var Pattern = (function PatternClosure() { xref, res, handler, - pdfFunctionFactory + pdfFunctionFactory, + localColorSpaceCache ) { var dict = isStream(shading) ? shading.dict : shading; var type = dict.get("ShadingType"); @@ -72,7 +73,8 @@ var Pattern = (function PatternClosure() { matrix, xref, res, - pdfFunctionFactory + pdfFunctionFactory, + localColorSpaceCache ); case ShadingType.FREE_FORM_MESH: case ShadingType.LATTICE_FORM_MESH: @@ -83,7 +85,8 @@ var Pattern = (function PatternClosure() { matrix, xref, res, - pdfFunctionFactory + pdfFunctionFactory, + localColorSpaceCache ); default: throw new FormatError("Unsupported ShadingType: " + type); @@ -111,13 +114,25 @@ Shadings.SMALL_NUMBER = 1e-6; // Radial and axial shading have very similar implementations // If needed, the implementations can be broken into two classes Shadings.RadialAxial = (function RadialAxialClosure() { - function RadialAxial(dict, matrix, xref, res, pdfFunctionFactory) { + function RadialAxial( + dict, + matrix, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache + ) { this.matrix = matrix; this.coordsArr = dict.getArray("Coords"); this.shadingType = dict.get("ShadingType"); this.type = "Pattern"; - var cs = dict.get("ColorSpace", "CS"); - cs = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const cs = ColorSpace.parse({ + cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"), + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache, + }); this.cs = cs; const bbox = dict.getArray("BBox"); if (Array.isArray(bbox) && bbox.length === 4) { @@ -830,7 +845,14 @@ Shadings.Mesh = (function MeshClosure() { } } - function Mesh(stream, matrix, xref, res, pdfFunctionFactory) { + function Mesh( + stream, + matrix, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache + ) { if (!isStream(stream)) { throw new FormatError("Mesh data is not a stream"); } @@ -844,8 +866,13 @@ Shadings.Mesh = (function MeshClosure() { } else { this.bbox = null; } - var cs = dict.get("ColorSpace", "CS"); - cs = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const cs = ColorSpace.parse({ + cs: dict.getRaw("ColorSpace") || dict.getRaw("CS"), + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache, + }); this.cs = cs; this.background = dict.has("Background") ? cs.getRgb(dict.get("Background"), 0) diff --git a/test/unit/colorspace_spec.js b/test/unit/colorspace_spec.js index 47fd40659da9f..eeb381e33c752 100644 --- a/test/unit/colorspace_spec.js +++ b/test/unit/colorspace_spec.js @@ -16,18 +16,21 @@ import { Dict, Name, Ref } from "../../src/core/primitives.js"; import { Stream, StringStream } from "../../src/core/stream.js"; import { ColorSpace } from "../../src/core/colorspace.js"; +import { LocalColorSpaceCache } from "../../src/core/image_utils.js"; import { PDFFunctionFactory } from "../../src/core/function.js"; import { XRefMock } from "./test_utils.js"; describe("colorspace", function () { - describe("ColorSpace", function () { + describe("ColorSpace.isDefaultDecode", function () { it("should be true if decode is not an array", function () { expect(ColorSpace.isDefaultDecode("string", 0)).toBeTruthy(); }); + it("should be true if length of decode array is not correct", function () { expect(ColorSpace.isDefaultDecode([0], 1)).toBeTruthy(); expect(ColorSpace.isDefaultDecode([0, 1, 0], 1)).toBeTruthy(); }); + it("should be true if decode map matches the default decode map", function () { 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 () { it("should handle the case when cs is a Name object", function () { const cs = Name.get("DeviceGray"); @@ -55,12 +190,18 @@ describe("colorspace", function () { data: new Dict(), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); const testSrc = new Uint8Array([27, 125, 250, 131]); const testDest = new Uint8ClampedArray(4 * 4 * 3); @@ -100,12 +241,18 @@ describe("colorspace", function () { data: Name.get("DeviceGray"), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); const testSrc = new Uint8Array([27, 125, 250, 131]); const testDest = new Uint8ClampedArray(3 * 3 * 3); @@ -141,12 +288,18 @@ describe("colorspace", function () { data: new Dict(), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); // prettier-ignore const testSrc = new Uint8Array([ @@ -192,12 +345,18 @@ describe("colorspace", function () { data: Name.get("DeviceRGB"), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); // prettier-ignore const testSrc = new Uint8Array([ @@ -239,12 +398,18 @@ describe("colorspace", function () { data: new Dict(), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); // prettier-ignore const testSrc = new Uint8Array([ @@ -290,12 +455,18 @@ describe("colorspace", function () { data: Name.get("DeviceCMYK"), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); // prettier-ignore const testSrc = new Uint8Array([ @@ -342,12 +513,18 @@ describe("colorspace", function () { data: new Dict(), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); const testSrc = new Uint8Array([27, 125, 250, 131]); const testDest = new Uint8ClampedArray(4 * 4 * 3); @@ -396,12 +573,18 @@ describe("colorspace", function () { data: new Dict(), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); // prettier-ignore const testSrc = new Uint8Array([ @@ -448,12 +631,18 @@ describe("colorspace", function () { data: new Dict(), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); // prettier-ignore const testSrc = new Uint8Array([ @@ -502,12 +691,18 @@ describe("colorspace", function () { data: new Dict(), }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); const testSrc = new Uint8Array([2, 2, 0, 1]); const testDest = new Uint8ClampedArray(3 * 3 * 3); @@ -564,12 +759,18 @@ describe("colorspace", function () { data: fn, }, ]); - const res = new Dict(); + const resources = new Dict(); const pdfFunctionFactory = new PDFFunctionFactory({ xref, }); - const colorSpace = ColorSpace.parse(cs, xref, res, pdfFunctionFactory); + const colorSpace = ColorSpace.parse({ + cs, + xref, + resources, + pdfFunctionFactory, + localColorSpaceCache: new LocalColorSpaceCache(), + }); const testSrc = new Uint8Array([27, 25, 50, 31]); const testDest = new Uint8ClampedArray(3 * 3 * 3);