mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-20 15:18:08 +02:00
Support using ICC profiles in using qcms (bug 860023)
This commit is contained in:
parent
4693b7ad2f
commit
971be48b60
22 changed files with 999 additions and 362 deletions
|
@ -64,7 +64,7 @@ import { Stream, StringStream } from "./stream.js";
|
|||
import { BaseStream } from "./base_stream.js";
|
||||
import { bidi } from "./bidi.js";
|
||||
import { Catalog } from "./catalog.js";
|
||||
import { ColorSpace } from "./colorspace.js";
|
||||
import { ColorSpaceUtils } from "./colorspace_utils.js";
|
||||
import { FileSpec } from "./file_spec.js";
|
||||
import { JpegStream } from "./jpeg_stream.js";
|
||||
import { ObjectLoader } from "./object_loader.js";
|
||||
|
@ -552,15 +552,15 @@ function getRgbColor(color, defaultColor = new Uint8ClampedArray(3)) {
|
|||
return null;
|
||||
|
||||
case 1: // Convert grayscale to RGB
|
||||
ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
|
||||
ColorSpaceUtils.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
|
||||
return rgbColor;
|
||||
|
||||
case 3: // Convert RGB percentages to RGB
|
||||
ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
|
||||
ColorSpaceUtils.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
|
||||
return rgbColor;
|
||||
|
||||
case 4: // Convert CMYK to RGB
|
||||
ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
|
||||
ColorSpaceUtils.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
|
||||
return rgbColor;
|
||||
|
||||
default:
|
||||
|
|
|
@ -49,7 +49,7 @@ import { GlobalColorSpaceCache, GlobalImageCache } from "./image_utils.js";
|
|||
import { NameTree, NumberTree } from "./name_number_tree.js";
|
||||
import { BaseStream } from "./base_stream.js";
|
||||
import { clearGlobalCaches } from "./cleanup_helper.js";
|
||||
import { ColorSpace } from "./colorspace.js";
|
||||
import { ColorSpaceUtils } from "./colorspace_utils.js";
|
||||
import { FileSpec } from "./file_spec.js";
|
||||
import { MetadataParser } from "./metadata_parser.js";
|
||||
import { StructTreeRoot } from "./struct_tree.js";
|
||||
|
@ -357,7 +357,7 @@ class Catalog {
|
|||
isNumberArray(color, 3) &&
|
||||
(color[0] !== 0 || color[1] !== 0 || color[2] !== 0)
|
||||
) {
|
||||
rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
|
||||
rgbColor = ColorSpaceUtils.singletons.rgb.getRgb(color, 0);
|
||||
}
|
||||
|
||||
const outlineItem = {
|
||||
|
|
|
@ -22,9 +22,7 @@ import {
|
|||
unreachable,
|
||||
warn,
|
||||
} from "../shared/util.js";
|
||||
import { Dict, Name, Ref } from "./primitives.js";
|
||||
import { BaseStream } from "./base_stream.js";
|
||||
import { MissingDataException } from "./core_utils.js";
|
||||
|
||||
/**
|
||||
* Resizes an RGB image with 3 components.
|
||||
|
@ -306,283 +304,6 @@ class ColorSpace {
|
|||
return shadow(this, "usesZeroToOneRange", true);
|
||||
}
|
||||
|
||||
static #cache(
|
||||
cacheKey,
|
||||
parsedCS,
|
||||
{ xref, globalColorSpaceCache, localColorSpaceCache }
|
||||
) {
|
||||
if (!globalColorSpaceCache || !localColorSpaceCache) {
|
||||
throw new Error(
|
||||
'ColorSpace.#cache - expected "globalColorSpaceCache"/"localColorSpaceCache" argument.'
|
||||
);
|
||||
}
|
||||
if (!parsedCS) {
|
||||
throw new Error('ColorSpace.#cache - expected "parsedCS" 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, parsedCS);
|
||||
|
||||
if (csRef) {
|
||||
globalColorSpaceCache.set(/* name = */ null, csRef, parsedCS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static getCached(
|
||||
cacheKey,
|
||||
xref,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache
|
||||
) {
|
||||
if (!globalColorSpaceCache || !localColorSpaceCache) {
|
||||
throw new Error(
|
||||
'ColorSpace.getCached - expected "globalColorSpaceCache"/"localColorSpaceCache" argument.'
|
||||
);
|
||||
}
|
||||
if (cacheKey instanceof Ref) {
|
||||
const cachedCS =
|
||||
globalColorSpaceCache.getByRef(cacheKey) ||
|
||||
localColorSpaceCache.getByRef(cacheKey);
|
||||
if (cachedCS) {
|
||||
return cachedCS;
|
||||
}
|
||||
|
||||
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) {
|
||||
return localColorSpaceCache.getByName(cacheKey.name) || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static async parseAsync({
|
||||
cs,
|
||||
xref,
|
||||
resources = null,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
}) {
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||
assert(
|
||||
!this.getCached(cs, xref, globalColorSpaceCache, localColorSpaceCache),
|
||||
"Expected `ColorSpace.getCached` to have been manually checked " +
|
||||
"before calling `ColorSpace.parseAsync`."
|
||||
);
|
||||
}
|
||||
|
||||
const options = {
|
||||
xref,
|
||||
resources,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
};
|
||||
const parsedCS = this.#parse(cs, options);
|
||||
|
||||
// Attempt to cache the parsed ColorSpace, by name and/or reference.
|
||||
this.#cache(cs, parsedCS, options);
|
||||
|
||||
return parsedCS;
|
||||
}
|
||||
|
||||
static parse({
|
||||
cs,
|
||||
xref,
|
||||
resources = null,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
}) {
|
||||
const cachedCS = this.getCached(
|
||||
cs,
|
||||
xref,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache
|
||||
);
|
||||
if (cachedCS) {
|
||||
return cachedCS;
|
||||
}
|
||||
|
||||
const options = {
|
||||
xref,
|
||||
resources,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
};
|
||||
const parsedCS = this.#parse(cs, options);
|
||||
|
||||
// Attempt to cache the parsed ColorSpace, by name and/or reference.
|
||||
this.#cache(cs, parsedCS, options);
|
||||
|
||||
return parsedCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: This method should *only* be invoked from `this.#parse`,
|
||||
* when parsing "sub" ColorSpaces.
|
||||
*/
|
||||
static #subParse(cs, options) {
|
||||
const { globalColorSpaceCache } = options;
|
||||
|
||||
let csRef;
|
||||
if (cs instanceof Ref) {
|
||||
const cachedCS = globalColorSpaceCache.getByRef(cs);
|
||||
if (cachedCS) {
|
||||
return cachedCS;
|
||||
}
|
||||
csRef = cs;
|
||||
}
|
||||
const parsedCS = this.#parse(cs, options);
|
||||
|
||||
// Only cache the parsed ColorSpace globally, by reference.
|
||||
if (csRef) {
|
||||
globalColorSpaceCache.set(/* name = */ null, csRef, parsedCS);
|
||||
}
|
||||
return parsedCS;
|
||||
}
|
||||
|
||||
static #parse(cs, options) {
|
||||
const { xref, resources, pdfFunctionFactory } = options;
|
||||
|
||||
cs = xref.fetchIfRef(cs);
|
||||
if (cs instanceof Name) {
|
||||
switch (cs.name) {
|
||||
case "G":
|
||||
case "DeviceGray":
|
||||
return this.singletons.gray;
|
||||
case "RGB":
|
||||
case "DeviceRGB":
|
||||
return this.singletons.rgb;
|
||||
case "DeviceRGBA":
|
||||
return this.singletons.rgba;
|
||||
case "CMYK":
|
||||
case "DeviceCMYK":
|
||||
return this.singletons.cmyk;
|
||||
case "Pattern":
|
||||
return new PatternCS(/* baseCS = */ null);
|
||||
default:
|
||||
if (resources instanceof Dict) {
|
||||
const colorSpaces = resources.get("ColorSpace");
|
||||
if (colorSpaces instanceof Dict) {
|
||||
const resourcesCS = colorSpaces.get(cs.name);
|
||||
if (resourcesCS) {
|
||||
if (resourcesCS instanceof Name) {
|
||||
return this.#parse(resourcesCS, options);
|
||||
}
|
||||
cs = resourcesCS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback to the default gray color space.
|
||||
warn(`Unrecognized ColorSpace: ${cs.name}`);
|
||||
return this.singletons.gray;
|
||||
}
|
||||
}
|
||||
if (Array.isArray(cs)) {
|
||||
const mode = xref.fetchIfRef(cs[0]).name;
|
||||
let params, numComps, baseCS, whitePoint, blackPoint, gamma;
|
||||
|
||||
switch (mode) {
|
||||
case "G":
|
||||
case "DeviceGray":
|
||||
return this.singletons.gray;
|
||||
case "RGB":
|
||||
case "DeviceRGB":
|
||||
return this.singletons.rgb;
|
||||
case "CMYK":
|
||||
case "DeviceCMYK":
|
||||
return this.singletons.cmyk;
|
||||
case "CalGray":
|
||||
params = xref.fetchIfRef(cs[1]);
|
||||
whitePoint = params.getArray("WhitePoint");
|
||||
blackPoint = params.getArray("BlackPoint");
|
||||
gamma = params.get("Gamma");
|
||||
return new CalGrayCS(whitePoint, blackPoint, gamma);
|
||||
case "CalRGB":
|
||||
params = xref.fetchIfRef(cs[1]);
|
||||
whitePoint = params.getArray("WhitePoint");
|
||||
blackPoint = params.getArray("BlackPoint");
|
||||
gamma = params.getArray("Gamma");
|
||||
const matrix = params.getArray("Matrix");
|
||||
return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
|
||||
case "ICCBased":
|
||||
const stream = xref.fetchIfRef(cs[1]);
|
||||
const dict = stream.dict;
|
||||
numComps = dict.get("N");
|
||||
const altRaw = dict.getRaw("Alternate");
|
||||
if (altRaw) {
|
||||
const altCS = this.#subParse(altRaw, options);
|
||||
// Ensure that the number of components are correct,
|
||||
// and also (indirectly) that it is not a PatternCS.
|
||||
if (altCS.numComps === numComps) {
|
||||
return altCS;
|
||||
}
|
||||
warn("ICCBased color space: Ignoring incorrect /Alternate entry.");
|
||||
}
|
||||
if (numComps === 1) {
|
||||
return this.singletons.gray;
|
||||
} else if (numComps === 3) {
|
||||
return this.singletons.rgb;
|
||||
} else if (numComps === 4) {
|
||||
return this.singletons.cmyk;
|
||||
}
|
||||
break;
|
||||
case "Pattern":
|
||||
baseCS = cs[1] || null;
|
||||
if (baseCS) {
|
||||
baseCS = this.#subParse(baseCS, options);
|
||||
}
|
||||
return new PatternCS(baseCS);
|
||||
case "I":
|
||||
case "Indexed":
|
||||
baseCS = this.#subParse(cs[1], options);
|
||||
const hiVal = Math.max(0, Math.min(xref.fetchIfRef(cs[2]), 255));
|
||||
const lookup = xref.fetchIfRef(cs[3]);
|
||||
return new IndexedCS(baseCS, hiVal, lookup);
|
||||
case "Separation":
|
||||
case "DeviceN":
|
||||
const name = xref.fetchIfRef(cs[1]);
|
||||
numComps = Array.isArray(name) ? name.length : 1;
|
||||
baseCS = this.#subParse(cs[2], options);
|
||||
const tintFn = pdfFunctionFactory.create(cs[3]);
|
||||
return new AlternateCS(numComps, baseCS, tintFn);
|
||||
case "Lab":
|
||||
params = xref.fetchIfRef(cs[1]);
|
||||
whitePoint = params.getArray("WhitePoint");
|
||||
blackPoint = params.getArray("BlackPoint");
|
||||
const range = params.getArray("Range");
|
||||
return new LabCS(whitePoint, blackPoint, range);
|
||||
default:
|
||||
// Fallback to the default gray color space.
|
||||
warn(`Unimplemented ColorSpace object: ${mode}`);
|
||||
return this.singletons.gray;
|
||||
}
|
||||
}
|
||||
// Fallback to the default gray color space.
|
||||
warn(`Unrecognized ColorSpace object: ${cs}`);
|
||||
return this.singletons.gray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a decode map matches the default decode map for a color space.
|
||||
* This handles the general decode maps where there are two values per
|
||||
|
@ -607,23 +328,6 @@ class ColorSpace {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static get singletons() {
|
||||
return shadow(this, "singletons", {
|
||||
get gray() {
|
||||
return shadow(this, "gray", new DeviceGrayCS());
|
||||
},
|
||||
get rgb() {
|
||||
return shadow(this, "rgb", new DeviceRgbCS());
|
||||
},
|
||||
get rgba() {
|
||||
return shadow(this, "rgba", new DeviceRgbaCS());
|
||||
},
|
||||
get cmyk() {
|
||||
return shadow(this, "cmyk", new DeviceCmykCS());
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1583,4 +1287,16 @@ class LabCS extends ColorSpace {
|
|||
}
|
||||
}
|
||||
|
||||
export { ColorSpace };
|
||||
export {
|
||||
AlternateCS,
|
||||
CalGrayCS,
|
||||
CalRGBCS,
|
||||
ColorSpace,
|
||||
DeviceCmykCS,
|
||||
DeviceGrayCS,
|
||||
DeviceRgbaCS,
|
||||
DeviceRgbCS,
|
||||
IndexedCS,
|
||||
LabCS,
|
||||
PatternCS,
|
||||
};
|
||||
|
|
357
src/core/colorspace_utils.js
Normal file
357
src/core/colorspace_utils.js
Normal file
|
@ -0,0 +1,357 @@
|
|||
/* Copyright 2024 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AlternateCS,
|
||||
CalGrayCS,
|
||||
CalRGBCS,
|
||||
DeviceCmykCS,
|
||||
DeviceGrayCS,
|
||||
DeviceRgbaCS,
|
||||
DeviceRgbCS,
|
||||
IndexedCS,
|
||||
LabCS,
|
||||
PatternCS,
|
||||
} from "./colorspace.js";
|
||||
import { assert, shadow, warn } from "../shared/util.js";
|
||||
import { Dict, Name, Ref } from "./primitives.js";
|
||||
import { IccColorSpace } from "./icc_colorspace.js";
|
||||
import { MissingDataException } from "./core_utils.js";
|
||||
|
||||
class ColorSpaceUtils {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static #cache(
|
||||
cacheKey,
|
||||
parsedCS,
|
||||
{ xref, globalColorSpaceCache, localColorSpaceCache }
|
||||
) {
|
||||
if (!globalColorSpaceCache || !localColorSpaceCache) {
|
||||
throw new Error(
|
||||
'ColorSpace.#cache - expected "globalColorSpaceCache"/"localColorSpaceCache" argument.'
|
||||
);
|
||||
}
|
||||
if (!parsedCS) {
|
||||
throw new Error('ColorSpace.#cache - expected "parsedCS" 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, parsedCS);
|
||||
|
||||
if (csRef) {
|
||||
globalColorSpaceCache.set(/* name = */ null, csRef, parsedCS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static getCached(
|
||||
cacheKey,
|
||||
xref,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache
|
||||
) {
|
||||
if (!globalColorSpaceCache || !localColorSpaceCache) {
|
||||
throw new Error(
|
||||
'ColorSpace.getCached - expected "globalColorSpaceCache"/"localColorSpaceCache" argument.'
|
||||
);
|
||||
}
|
||||
if (cacheKey instanceof Ref) {
|
||||
const cachedCS =
|
||||
globalColorSpaceCache.getByRef(cacheKey) ||
|
||||
localColorSpaceCache.getByRef(cacheKey);
|
||||
if (cachedCS) {
|
||||
return cachedCS;
|
||||
}
|
||||
|
||||
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) {
|
||||
return localColorSpaceCache.getByName(cacheKey.name) || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static async parseAsync({
|
||||
cs,
|
||||
xref,
|
||||
resources = null,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
}) {
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||
assert(
|
||||
!this.getCached(cs, xref, globalColorSpaceCache, localColorSpaceCache),
|
||||
"Expected `ColorSpace.getCached` to have been manually checked " +
|
||||
"before calling `ColorSpace.parseAsync`."
|
||||
);
|
||||
}
|
||||
|
||||
const options = {
|
||||
xref,
|
||||
resources,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
};
|
||||
const parsedCS = this.#parse(cs, options);
|
||||
|
||||
// Attempt to cache the parsed ColorSpace, by name and/or reference.
|
||||
this.#cache(cs, parsedCS, options);
|
||||
|
||||
return parsedCS;
|
||||
}
|
||||
|
||||
static parse({
|
||||
cs,
|
||||
xref,
|
||||
resources = null,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
}) {
|
||||
const cachedCS = this.getCached(
|
||||
cs,
|
||||
xref,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache
|
||||
);
|
||||
if (cachedCS) {
|
||||
return cachedCS;
|
||||
}
|
||||
|
||||
const options = {
|
||||
xref,
|
||||
resources,
|
||||
pdfFunctionFactory,
|
||||
globalColorSpaceCache,
|
||||
localColorSpaceCache,
|
||||
};
|
||||
const parsedCS = this.#parse(cs, options);
|
||||
|
||||
// Attempt to cache the parsed ColorSpace, by name and/or reference.
|
||||
this.#cache(cs, parsedCS, options);
|
||||
|
||||
return parsedCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: This method should *only* be invoked from `this.#parse`,
|
||||
* when parsing "sub" ColorSpaces.
|
||||
*/
|
||||
static #subParse(cs, options) {
|
||||
const { globalColorSpaceCache } = options;
|
||||
|
||||
let csRef;
|
||||
if (cs instanceof Ref) {
|
||||
const cachedCS = globalColorSpaceCache.getByRef(cs);
|
||||
if (cachedCS) {
|
||||
return cachedCS;
|
||||
}
|
||||
csRef = cs;
|
||||
}
|
||||
const parsedCS = this.#parse(cs, options);
|
||||
|
||||
// Only cache the parsed ColorSpace globally, by reference.
|
||||
if (csRef) {
|
||||
globalColorSpaceCache.set(/* name = */ null, csRef, parsedCS);
|
||||
}
|
||||
return parsedCS;
|
||||
}
|
||||
|
||||
static #parse(cs, options) {
|
||||
const { xref, resources, pdfFunctionFactory } = options;
|
||||
|
||||
cs = xref.fetchIfRef(cs);
|
||||
if (cs instanceof Name) {
|
||||
switch (cs.name) {
|
||||
case "G":
|
||||
case "DeviceGray":
|
||||
return this.singletons.gray;
|
||||
case "RGB":
|
||||
case "DeviceRGB":
|
||||
return this.singletons.rgb;
|
||||
case "DeviceRGBA":
|
||||
return this.singletons.rgba;
|
||||
case "CMYK":
|
||||
case "DeviceCMYK":
|
||||
return this.singletons.cmyk;
|
||||
case "Pattern":
|
||||
return new PatternCS(/* baseCS = */ null);
|
||||
default:
|
||||
if (resources instanceof Dict) {
|
||||
const colorSpaces = resources.get("ColorSpace");
|
||||
if (colorSpaces instanceof Dict) {
|
||||
const resourcesCS = colorSpaces.get(cs.name);
|
||||
if (resourcesCS) {
|
||||
if (resourcesCS instanceof Name) {
|
||||
return this.#parse(resourcesCS, options);
|
||||
}
|
||||
cs = resourcesCS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback to the default gray color space.
|
||||
warn(`Unrecognized ColorSpace: ${cs.name}`);
|
||||
return this.singletons.gray;
|
||||
}
|
||||
}
|
||||
if (Array.isArray(cs)) {
|
||||
const mode = xref.fetchIfRef(cs[0]).name;
|
||||
let params, numComps, baseCS, whitePoint, blackPoint, gamma;
|
||||
|
||||
switch (mode) {
|
||||
case "G":
|
||||
case "DeviceGray":
|
||||
return this.singletons.gray;
|
||||
case "RGB":
|
||||
case "DeviceRGB":
|
||||
return this.singletons.rgb;
|
||||
case "CMYK":
|
||||
case "DeviceCMYK":
|
||||
return this.singletons.cmyk;
|
||||
case "CalGray":
|
||||
params = xref.fetchIfRef(cs[1]);
|
||||
whitePoint = params.getArray("WhitePoint");
|
||||
blackPoint = params.getArray("BlackPoint");
|
||||
gamma = params.get("Gamma");
|
||||
return new CalGrayCS(whitePoint, blackPoint, gamma);
|
||||
case "CalRGB":
|
||||
params = xref.fetchIfRef(cs[1]);
|
||||
whitePoint = params.getArray("WhitePoint");
|
||||
blackPoint = params.getArray("BlackPoint");
|
||||
gamma = params.getArray("Gamma");
|
||||
const matrix = params.getArray("Matrix");
|
||||
return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
|
||||
case "ICCBased":
|
||||
const { globalColorSpaceCache } = options;
|
||||
const isRef = cs[1] instanceof Ref;
|
||||
if (isRef) {
|
||||
const cachedCS = globalColorSpaceCache.getByRef(cs[1]);
|
||||
if (cachedCS) {
|
||||
return cachedCS;
|
||||
}
|
||||
}
|
||||
|
||||
const stream = xref.fetchIfRef(cs[1]);
|
||||
const dict = stream.dict;
|
||||
numComps = dict.get("N");
|
||||
|
||||
if (IccColorSpace.isUsable) {
|
||||
try {
|
||||
const iccCS = new IccColorSpace(stream.getBytes(), numComps);
|
||||
if (isRef) {
|
||||
globalColorSpaceCache.set(/* name = */ null, cs[1], iccCS);
|
||||
}
|
||||
return iccCS;
|
||||
} catch (ex) {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
}
|
||||
warn(`ICCBased color space (${cs[1]}): "${ex}".`);
|
||||
}
|
||||
}
|
||||
|
||||
const altRaw = dict.getRaw("Alternate");
|
||||
if (altRaw) {
|
||||
const altCS = this.#subParse(altRaw, options);
|
||||
// Ensure that the number of components are correct,
|
||||
// and also (indirectly) that it is not a PatternCS.
|
||||
if (altCS.numComps === numComps) {
|
||||
return altCS;
|
||||
}
|
||||
warn("ICCBased color space: Ignoring incorrect /Alternate entry.");
|
||||
}
|
||||
if (numComps === 1) {
|
||||
return this.singletons.gray;
|
||||
} else if (numComps === 3) {
|
||||
return this.singletons.rgb;
|
||||
} else if (numComps === 4) {
|
||||
return this.singletons.cmyk;
|
||||
}
|
||||
break;
|
||||
case "Pattern":
|
||||
baseCS = cs[1] || null;
|
||||
if (baseCS) {
|
||||
baseCS = this.#subParse(baseCS, options);
|
||||
}
|
||||
return new PatternCS(baseCS);
|
||||
case "I":
|
||||
case "Indexed":
|
||||
baseCS = this.#subParse(cs[1], options);
|
||||
const hiVal = Math.max(0, Math.min(xref.fetchIfRef(cs[2]), 255));
|
||||
const lookup = xref.fetchIfRef(cs[3]);
|
||||
return new IndexedCS(baseCS, hiVal, lookup);
|
||||
case "Separation":
|
||||
case "DeviceN":
|
||||
const name = xref.fetchIfRef(cs[1]);
|
||||
numComps = Array.isArray(name) ? name.length : 1;
|
||||
baseCS = this.#subParse(cs[2], options);
|
||||
const tintFn = pdfFunctionFactory.create(cs[3]);
|
||||
return new AlternateCS(numComps, baseCS, tintFn);
|
||||
case "Lab":
|
||||
params = xref.fetchIfRef(cs[1]);
|
||||
whitePoint = params.getArray("WhitePoint");
|
||||
blackPoint = params.getArray("BlackPoint");
|
||||
const range = params.getArray("Range");
|
||||
return new LabCS(whitePoint, blackPoint, range);
|
||||
default:
|
||||
// Fallback to the default gray color space.
|
||||
warn(`Unimplemented ColorSpace object: ${mode}`);
|
||||
return this.singletons.gray;
|
||||
}
|
||||
}
|
||||
// Fallback to the default gray color space.
|
||||
warn(`Unrecognized ColorSpace object: ${cs}`);
|
||||
return this.singletons.gray;
|
||||
}
|
||||
|
||||
static get singletons() {
|
||||
return shadow(this, "singletons", {
|
||||
get gray() {
|
||||
return shadow(this, "gray", new DeviceGrayCS());
|
||||
},
|
||||
get rgb() {
|
||||
return shadow(this, "rgb", new DeviceRgbCS());
|
||||
},
|
||||
get rgba() {
|
||||
return shadow(this, "rgba", new DeviceRgbaCS());
|
||||
},
|
||||
get cmyk() {
|
||||
return shadow(this, "cmyk", new DeviceCmykCS());
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { ColorSpaceUtils };
|
|
@ -28,7 +28,7 @@ import {
|
|||
shadow,
|
||||
warn,
|
||||
} from "../shared/util.js";
|
||||
import { ColorSpace } from "./colorspace.js";
|
||||
import { ColorSpaceUtils } from "./colorspace_utils.js";
|
||||
import { EvaluatorPreprocessor } from "./evaluator.js";
|
||||
import { LocalColorSpaceCache } from "./image_utils.js";
|
||||
import { PDFFunctionFactory } from "./function.js";
|
||||
|
@ -73,13 +73,28 @@ class DefaultAppearanceEvaluator extends EvaluatorPreprocessor {
|
|||
}
|
||||
break;
|
||||
case OPS.setFillRGBColor:
|
||||
ColorSpace.singletons.rgb.getRgbItem(args, 0, result.fontColor, 0);
|
||||
ColorSpaceUtils.singletons.rgb.getRgbItem(
|
||||
args,
|
||||
0,
|
||||
result.fontColor,
|
||||
0
|
||||
);
|
||||
break;
|
||||
case OPS.setFillGray:
|
||||
ColorSpace.singletons.gray.getRgbItem(args, 0, result.fontColor, 0);
|
||||
ColorSpaceUtils.singletons.gray.getRgbItem(
|
||||
args,
|
||||
0,
|
||||
result.fontColor,
|
||||
0
|
||||
);
|
||||
break;
|
||||
case OPS.setFillCMYKColor:
|
||||
ColorSpace.singletons.cmyk.getRgbItem(args, 0, result.fontColor, 0);
|
||||
ColorSpaceUtils.singletons.cmyk.getRgbItem(
|
||||
args,
|
||||
0,
|
||||
result.fontColor,
|
||||
0
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +132,7 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
|
|||
fontSize: 0,
|
||||
fontName: "",
|
||||
fontColor: /* black = */ new Uint8ClampedArray(3),
|
||||
fillColorSpace: ColorSpace.singletons.gray,
|
||||
fillColorSpace: ColorSpaceUtils.singletons.gray,
|
||||
};
|
||||
let breakLoop = false;
|
||||
const stack = [];
|
||||
|
@ -157,7 +172,7 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
|
|||
}
|
||||
break;
|
||||
case OPS.setFillColorSpace:
|
||||
result.fillColorSpace = ColorSpace.parse({
|
||||
result.fillColorSpace = ColorSpaceUtils.parse({
|
||||
cs: args[0],
|
||||
xref: this.xref,
|
||||
resources: this.resources,
|
||||
|
@ -171,13 +186,28 @@ class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
|
|||
cs.getRgbItem(args, 0, result.fontColor, 0);
|
||||
break;
|
||||
case OPS.setFillRGBColor:
|
||||
ColorSpace.singletons.rgb.getRgbItem(args, 0, result.fontColor, 0);
|
||||
ColorSpaceUtils.singletons.rgb.getRgbItem(
|
||||
args,
|
||||
0,
|
||||
result.fontColor,
|
||||
0
|
||||
);
|
||||
break;
|
||||
case OPS.setFillGray:
|
||||
ColorSpace.singletons.gray.getRgbItem(args, 0, result.fontColor, 0);
|
||||
ColorSpaceUtils.singletons.gray.getRgbItem(
|
||||
args,
|
||||
0,
|
||||
result.fontColor,
|
||||
0
|
||||
);
|
||||
break;
|
||||
case OPS.setFillCMYKColor:
|
||||
ColorSpace.singletons.cmyk.getRgbItem(args, 0, result.fontColor, 0);
|
||||
ColorSpaceUtils.singletons.cmyk.getRgbItem(
|
||||
args,
|
||||
0,
|
||||
result.fontColor,
|
||||
0
|
||||
);
|
||||
break;
|
||||
case OPS.showText:
|
||||
case OPS.showSpacedText:
|
||||
|
|
|
@ -68,7 +68,7 @@ import {
|
|||
} from "./image_utils.js";
|
||||
import { BaseStream } from "./base_stream.js";
|
||||
import { bidi } from "./bidi.js";
|
||||
import { ColorSpace } from "./colorspace.js";
|
||||
import { ColorSpaceUtils } from "./colorspace_utils.js";
|
||||
import { DecodeStream } from "./decode_stream.js";
|
||||
import { FontFlags } from "./fonts_utils.js";
|
||||
import { getFontSubstitution } from "./font_substitutions.js";
|
||||
|
@ -491,7 +491,7 @@ class PartialEvaluator {
|
|||
if (group.has("CS")) {
|
||||
const cs = group.getRaw("CS");
|
||||
|
||||
const cachedColorSpace = ColorSpace.getCached(
|
||||
const cachedColorSpace = ColorSpaceUtils.getCached(
|
||||
cs,
|
||||
this.xref,
|
||||
this.globalColorSpaceCache,
|
||||
|
@ -510,7 +510,7 @@ class PartialEvaluator {
|
|||
}
|
||||
|
||||
if (smask?.backdrop) {
|
||||
colorSpace ||= ColorSpace.singletons.rgb;
|
||||
colorSpace ||= ColorSpaceUtils.singletons.rgb;
|
||||
smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
|
||||
}
|
||||
|
||||
|
@ -1463,7 +1463,7 @@ class PartialEvaluator {
|
|||
}
|
||||
|
||||
parseColorSpace({ cs, resources, localColorSpaceCache }) {
|
||||
return ColorSpace.parseAsync({
|
||||
return ColorSpaceUtils.parseAsync({
|
||||
cs,
|
||||
xref: this.xref,
|
||||
resources,
|
||||
|
@ -1981,7 +1981,7 @@ class PartialEvaluator {
|
|||
break;
|
||||
|
||||
case OPS.setFillColorSpace: {
|
||||
const cachedColorSpace = ColorSpace.getCached(
|
||||
const cachedColorSpace = ColorSpaceUtils.getCached(
|
||||
args[0],
|
||||
xref,
|
||||
self.globalColorSpaceCache,
|
||||
|
@ -2001,13 +2001,13 @@ class PartialEvaluator {
|
|||
})
|
||||
.then(function (colorSpace) {
|
||||
stateManager.state.fillColorSpace =
|
||||
colorSpace || ColorSpace.singletons.gray;
|
||||
colorSpace || ColorSpaceUtils.singletons.gray;
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
case OPS.setStrokeColorSpace: {
|
||||
const cachedColorSpace = ColorSpace.getCached(
|
||||
const cachedColorSpace = ColorSpaceUtils.getCached(
|
||||
args[0],
|
||||
xref,
|
||||
self.globalColorSpaceCache,
|
||||
|
@ -2027,7 +2027,7 @@ class PartialEvaluator {
|
|||
})
|
||||
.then(function (colorSpace) {
|
||||
stateManager.state.strokeColorSpace =
|
||||
colorSpace || ColorSpace.singletons.gray;
|
||||
colorSpace || ColorSpaceUtils.singletons.gray;
|
||||
})
|
||||
);
|
||||
return;
|
||||
|
@ -2043,38 +2043,41 @@ class PartialEvaluator {
|
|||
fn = OPS.setStrokeRGBColor;
|
||||
break;
|
||||
case OPS.setFillGray:
|
||||
stateManager.state.fillColorSpace = ColorSpace.singletons.gray;
|
||||
args = ColorSpace.singletons.gray.getRgb(args, 0);
|
||||
stateManager.state.fillColorSpace = ColorSpaceUtils.singletons.gray;
|
||||
args = ColorSpaceUtils.singletons.gray.getRgb(args, 0);
|
||||
fn = OPS.setFillRGBColor;
|
||||
break;
|
||||
case OPS.setStrokeGray:
|
||||
stateManager.state.strokeColorSpace = ColorSpace.singletons.gray;
|
||||
args = ColorSpace.singletons.gray.getRgb(args, 0);
|
||||
stateManager.state.strokeColorSpace =
|
||||
ColorSpaceUtils.singletons.gray;
|
||||
args = ColorSpaceUtils.singletons.gray.getRgb(args, 0);
|
||||
fn = OPS.setStrokeRGBColor;
|
||||
break;
|
||||
case OPS.setFillCMYKColor:
|
||||
stateManager.state.fillColorSpace = ColorSpace.singletons.cmyk;
|
||||
args = ColorSpace.singletons.cmyk.getRgb(args, 0);
|
||||
stateManager.state.fillColorSpace = ColorSpaceUtils.singletons.cmyk;
|
||||
args = ColorSpaceUtils.singletons.cmyk.getRgb(args, 0);
|
||||
fn = OPS.setFillRGBColor;
|
||||
break;
|
||||
case OPS.setStrokeCMYKColor:
|
||||
stateManager.state.strokeColorSpace = ColorSpace.singletons.cmyk;
|
||||
args = ColorSpace.singletons.cmyk.getRgb(args, 0);
|
||||
stateManager.state.strokeColorSpace =
|
||||
ColorSpaceUtils.singletons.cmyk;
|
||||
args = ColorSpaceUtils.singletons.cmyk.getRgb(args, 0);
|
||||
fn = OPS.setStrokeRGBColor;
|
||||
break;
|
||||
case OPS.setFillRGBColor:
|
||||
stateManager.state.fillColorSpace = ColorSpace.singletons.rgb;
|
||||
args = ColorSpace.singletons.rgb.getRgb(args, 0);
|
||||
stateManager.state.fillColorSpace = ColorSpaceUtils.singletons.rgb;
|
||||
args = ColorSpaceUtils.singletons.rgb.getRgb(args, 0);
|
||||
break;
|
||||
case OPS.setStrokeRGBColor:
|
||||
stateManager.state.strokeColorSpace = ColorSpace.singletons.rgb;
|
||||
args = ColorSpace.singletons.rgb.getRgb(args, 0);
|
||||
stateManager.state.strokeColorSpace =
|
||||
ColorSpaceUtils.singletons.rgb;
|
||||
args = ColorSpaceUtils.singletons.rgb.getRgb(args, 0);
|
||||
break;
|
||||
case OPS.setFillColorN:
|
||||
cs = stateManager.state.patternFillColorSpace;
|
||||
if (!cs) {
|
||||
if (isNumberArray(args, null)) {
|
||||
args = ColorSpace.singletons.gray.getRgb(args, 0);
|
||||
args = ColorSpaceUtils.singletons.gray.getRgb(args, 0);
|
||||
fn = OPS.setFillRGBColor;
|
||||
break;
|
||||
}
|
||||
|
@ -2106,7 +2109,7 @@ class PartialEvaluator {
|
|||
cs = stateManager.state.patternStrokeColorSpace;
|
||||
if (!cs) {
|
||||
if (isNumberArray(args, null)) {
|
||||
args = ColorSpace.singletons.gray.getRgb(args, 0);
|
||||
args = ColorSpaceUtils.singletons.gray.getRgb(args, 0);
|
||||
fn = OPS.setStrokeRGBColor;
|
||||
break;
|
||||
}
|
||||
|
@ -4897,8 +4900,8 @@ class EvalState {
|
|||
this.ctm = new Float32Array(IDENTITY_MATRIX);
|
||||
this.font = null;
|
||||
this.textRenderingMode = TextRenderingMode.FILL;
|
||||
this._fillColorSpace = ColorSpace.singletons.gray;
|
||||
this._strokeColorSpace = ColorSpace.singletons.gray;
|
||||
this._fillColorSpace = ColorSpaceUtils.singletons.gray;
|
||||
this._strokeColorSpace = ColorSpaceUtils.singletons.gray;
|
||||
this.patternFillColorSpace = null;
|
||||
this.patternStrokeColorSpace = null;
|
||||
}
|
||||
|
|
155
src/core/icc_colorspace.js
Normal file
155
src/core/icc_colorspace.js
Normal file
|
@ -0,0 +1,155 @@
|
|||
/* Copyright 2025 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
DataType,
|
||||
initSync,
|
||||
Intent,
|
||||
qcms_convert_array,
|
||||
qcms_convert_four,
|
||||
qcms_convert_one,
|
||||
qcms_convert_three,
|
||||
qcms_drop_transformer,
|
||||
qcms_transformer_from_memory,
|
||||
} from "../../external/qcms/qcms.js";
|
||||
import { shadow, warn } from "../shared/util.js";
|
||||
import { ColorSpace } from "./colorspace.js";
|
||||
import { QCMS } from "../../external/qcms/qcms_utils.js";
|
||||
|
||||
class IccColorSpace extends ColorSpace {
|
||||
#transformer;
|
||||
|
||||
#convertPixel;
|
||||
|
||||
static #useWasm = true;
|
||||
|
||||
static #wasmUrl = null;
|
||||
|
||||
static #finalizer = new FinalizationRegistry(transformer => {
|
||||
qcms_drop_transformer(transformer);
|
||||
});
|
||||
|
||||
constructor(iccProfile, numComps) {
|
||||
if (!IccColorSpace.isUsable) {
|
||||
throw new Error("No ICC color space support");
|
||||
}
|
||||
|
||||
super("ICCBased", numComps);
|
||||
|
||||
let inType;
|
||||
switch (numComps) {
|
||||
case 1:
|
||||
inType = DataType.Gray8;
|
||||
this.#convertPixel = (src, srcOffset) =>
|
||||
qcms_convert_one(this.#transformer, src[srcOffset] * 255);
|
||||
break;
|
||||
case 3:
|
||||
inType = DataType.RGB8;
|
||||
this.#convertPixel = (src, srcOffset) =>
|
||||
qcms_convert_three(
|
||||
this.#transformer,
|
||||
src[srcOffset] * 255,
|
||||
src[srcOffset + 1] * 255,
|
||||
src[srcOffset + 2] * 255
|
||||
);
|
||||
break;
|
||||
case 4:
|
||||
inType = DataType.CMYK;
|
||||
this.#convertPixel = (src, srcOffset) =>
|
||||
qcms_convert_four(
|
||||
this.#transformer,
|
||||
src[srcOffset] * 255,
|
||||
src[srcOffset + 1] * 255,
|
||||
src[srcOffset + 2] * 255,
|
||||
src[srcOffset + 3] * 255
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported number of components: ${numComps}`);
|
||||
}
|
||||
this.#transformer = qcms_transformer_from_memory(
|
||||
iccProfile,
|
||||
inType,
|
||||
Intent.Perceptual
|
||||
);
|
||||
if (!this.#transformer) {
|
||||
throw new Error("Failed to create ICC color space");
|
||||
}
|
||||
IccColorSpace.#finalizer.register(this, this.#transformer);
|
||||
}
|
||||
|
||||
getRgbItem(src, srcOffset, dest, destOffset) {
|
||||
QCMS._destBuffer = dest.subarray(destOffset, destOffset + 3);
|
||||
this.#convertPixel(src, srcOffset);
|
||||
QCMS._destBuffer = null;
|
||||
}
|
||||
|
||||
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
|
||||
src = src.subarray(srcOffset, srcOffset + count * this.numComps);
|
||||
if (bits !== 8) {
|
||||
const scale = 255 / ((1 << bits) - 1);
|
||||
for (let i = 0, ii = src.length; i < ii; i++) {
|
||||
src[i] *= scale;
|
||||
}
|
||||
}
|
||||
QCMS._destBuffer = dest.subarray(
|
||||
destOffset,
|
||||
destOffset + count * (3 + alpha01)
|
||||
);
|
||||
qcms_convert_array(this.#transformer, src);
|
||||
QCMS._destBuffer = null;
|
||||
}
|
||||
|
||||
getOutputLength(inputLength, alpha01) {
|
||||
return ((inputLength / this.numComps) * (3 + alpha01)) | 0;
|
||||
}
|
||||
|
||||
static setOptions({ useWasm, useWorkerFetch, wasmUrl }) {
|
||||
if (!useWorkerFetch) {
|
||||
this.#useWasm = false;
|
||||
return;
|
||||
}
|
||||
this.#useWasm = useWasm;
|
||||
this.#wasmUrl = wasmUrl;
|
||||
}
|
||||
|
||||
static get isUsable() {
|
||||
let isUsable = false;
|
||||
if (this.#useWasm) {
|
||||
try {
|
||||
this._module = QCMS._module = this.#load();
|
||||
isUsable = !!this._module;
|
||||
} catch (e) {
|
||||
warn(`ICCBased color space: "${e}".`);
|
||||
}
|
||||
}
|
||||
|
||||
return shadow(this, "isUsable", isUsable);
|
||||
}
|
||||
|
||||
static #load() {
|
||||
// Parsing and using color spaces is still synchronous,
|
||||
// so we must load the wasm module synchronously.
|
||||
// TODO: Make the color space stuff asynchronous and use fetch.
|
||||
const filename = "qcms_bg.wasm";
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", `${this.#wasmUrl}${filename}`, false);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send(null);
|
||||
return initSync({ module: xhr.response });
|
||||
}
|
||||
}
|
||||
|
||||
export { IccColorSpace };
|
|
@ -26,6 +26,7 @@ import {
|
|||
} from "../shared/image_utils.js";
|
||||
import { BaseStream } from "./base_stream.js";
|
||||
import { ColorSpace } from "./colorspace.js";
|
||||
import { ColorSpaceUtils } from "./colorspace_utils.js";
|
||||
import { DecodeStream } from "./decode_stream.js";
|
||||
import { ImageResizer } from "./image_resizer.js";
|
||||
import { JpegStream } from "./jpeg_stream.js";
|
||||
|
@ -210,7 +211,7 @@ class PDFImage {
|
|||
colorSpace = Name.get("DeviceRGBA");
|
||||
}
|
||||
|
||||
this.colorSpace = ColorSpace.parse({
|
||||
this.colorSpace = ColorSpaceUtils.parse({
|
||||
cs: colorSpace,
|
||||
xref,
|
||||
resources: isInline ? res : null,
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
MissingDataException,
|
||||
} from "./core_utils.js";
|
||||
import { BaseStream } from "./base_stream.js";
|
||||
import { ColorSpace } from "./colorspace.js";
|
||||
import { ColorSpaceUtils } from "./colorspace_utils.js";
|
||||
|
||||
const ShadingType = {
|
||||
FUNCTION_BASED: 1,
|
||||
|
@ -137,7 +137,7 @@ class RadialAxialShading extends BaseShading {
|
|||
if (!isNumberArray(this.coordsArr, coordsLen)) {
|
||||
throw new FormatError("RadialAxialShading: Invalid /Coords array.");
|
||||
}
|
||||
const cs = ColorSpace.parse({
|
||||
const cs = ColorSpaceUtils.parse({
|
||||
cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"),
|
||||
xref,
|
||||
resources,
|
||||
|
@ -473,7 +473,7 @@ class MeshShading extends BaseShading {
|
|||
const dict = stream.dict;
|
||||
this.shadingType = dict.get("ShadingType");
|
||||
this.bbox = lookupNormalRect(dict.getArray("BBox"), null);
|
||||
const cs = ColorSpace.parse({
|
||||
const cs = ColorSpaceUtils.parse({
|
||||
cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"),
|
||||
xref,
|
||||
resources,
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
warn,
|
||||
} from "../shared/util.js";
|
||||
import { ChunkedStreamManager } from "./chunked_stream.js";
|
||||
import { IccColorSpace } from "./icc_colorspace.js";
|
||||
import { ImageResizer } from "./image_resizer.js";
|
||||
import { JpegStream } from "./jpeg_stream.js";
|
||||
import { JpxImage } from "./jpx.js";
|
||||
|
@ -73,7 +74,10 @@ class BasePdfManager {
|
|||
// Initialize image-options once per document.
|
||||
ImageResizer.setOptions(evaluatorOptions);
|
||||
JpegStream.setOptions(evaluatorOptions);
|
||||
JpxImage.setOptions({ ...evaluatorOptions, handler });
|
||||
|
||||
const options = { ...evaluatorOptions, handler };
|
||||
JpxImage.setOptions(options);
|
||||
IccColorSpace.setOptions(options);
|
||||
}
|
||||
|
||||
get docId() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue