mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-11 19:58:15 +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
|
@ -5,6 +5,8 @@ node_modules/
|
|||
external/bcmaps/
|
||||
external/builder/fixtures/
|
||||
external/builder/fixtures_babel/
|
||||
external/openjpeg/
|
||||
external/qcms/
|
||||
external/quickjs/
|
||||
test/stats/results/
|
||||
test/tmp/
|
||||
|
|
|
@ -33,8 +33,9 @@ export default [
|
|||
"external/bcmaps/",
|
||||
"external/builder/fixtures/",
|
||||
"external/builder/fixtures_babel/",
|
||||
"external/quickjs/",
|
||||
"external/openjpeg/",
|
||||
"external/qcms/",
|
||||
"external/quickjs/",
|
||||
"test/stats/results/",
|
||||
"test/tmp/",
|
||||
"test/pdfs/",
|
||||
|
|
22
external/qcms/LICENSE_PDFJS_QCMS
vendored
Normal file
22
external/qcms/LICENSE_PDFJS_QCMS
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2025, Mozilla Foundation
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21
external/qcms/LICENSE_QCMS
vendored
Normal file
21
external/qcms/LICENSE_QCMS
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
qcms
|
||||
Copyright (C) 2009-2024 Mozilla Corporation
|
||||
Copyright (C) 1998-2007 Marti Maria
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
12
external/qcms/README.md
vendored
Normal file
12
external/qcms/README.md
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
## Build
|
||||
|
||||
In order to generate the files `qcms.js` and `qcms_bg.wasm`:
|
||||
* git clone https://github.com/mozilla/pdf.js.qcms/
|
||||
* the build requires to have a [Docker](https://www.docker.com/) setup and then:
|
||||
* `node build.js -C` to build the Docker image
|
||||
* `node build.js -co /pdf.js/external/qcms/` to compile the decoder
|
||||
|
||||
## Licensing
|
||||
|
||||
[qcms](https://github.com/FirefoxGraphics/qcms) is under [MIT](https://github.com/FirefoxGraphics/qcms/blob/main/COPYING)
|
||||
and [pdf.js.qcms](https://github.com/mozilla/pdf.js.qcms/) is released under [MIT](https://github.com/mozilla/pdf.js.qcms/blob/main/LICENSE) license so `qcms.js` and `qcms_bg.wasm` are released under [MIT](https://github.com/mozilla/pdf.js.qcms/blob/main/LICENSE) license too.
|
255
external/qcms/qcms.js
vendored
Normal file
255
external/qcms/qcms.js
vendored
Normal file
|
@ -0,0 +1,255 @@
|
|||
/* THIS FILE IS GENERATED - DO NOT EDIT */
|
||||
import { copy_result, copy_rgb } from './qcms_utils.js';
|
||||
|
||||
let wasm;
|
||||
|
||||
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
||||
|
||||
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
|
||||
|
||||
let cachedUint8ArrayMemory0 = null;
|
||||
|
||||
function getUint8ArrayMemory0() {
|
||||
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
||||
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedUint8ArrayMemory0;
|
||||
}
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
ptr = ptr >>> 0;
|
||||
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
function passArray8ToWasm0(arg, malloc) {
|
||||
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
||||
getUint8ArrayMemory0().set(arg, ptr / 1);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {Uint8Array} src
|
||||
*/
|
||||
export function qcms_convert_array(transformer, src) {
|
||||
const ptr0 = passArray8ToWasm0(src, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
wasm.qcms_convert_array(transformer, ptr0, len0);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {number} src
|
||||
*/
|
||||
export function qcms_convert_one(transformer, src) {
|
||||
wasm.qcms_convert_one(transformer, src);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {number} src1
|
||||
* @param {number} src2
|
||||
* @param {number} src3
|
||||
*/
|
||||
export function qcms_convert_three(transformer, src1, src2, src3) {
|
||||
wasm.qcms_convert_three(transformer, src1, src2, src3);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {number} src1
|
||||
* @param {number} src2
|
||||
* @param {number} src3
|
||||
* @param {number} src4
|
||||
*/
|
||||
export function qcms_convert_four(transformer, src1, src2, src3, src4) {
|
||||
wasm.qcms_convert_four(transformer, src1, src2, src3, src4);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {Uint8Array} mem
|
||||
* @param {DataType} in_type
|
||||
* @param {Intent} intent
|
||||
* @returns {number}
|
||||
*/
|
||||
export function qcms_transformer_from_memory(mem, in_type, intent) {
|
||||
const ptr0 = passArray8ToWasm0(mem, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.qcms_transformer_from_memory(ptr0, len0, in_type, intent);
|
||||
return ret >>> 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
*/
|
||||
export function qcms_drop_transformer(transformer) {
|
||||
wasm.qcms_drop_transformer(transformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @enum {0 | 1 | 2 | 3 | 4 | 5}
|
||||
*/
|
||||
export const DataType = Object.freeze({
|
||||
RGB8: 0, "0": "RGB8",
|
||||
RGBA8: 1, "1": "RGBA8",
|
||||
BGRA8: 2, "2": "BGRA8",
|
||||
Gray8: 3, "3": "Gray8",
|
||||
GrayA8: 4, "4": "GrayA8",
|
||||
CMYK: 5, "5": "CMYK",
|
||||
});
|
||||
/**
|
||||
* @enum {0 | 1 | 2 | 3}
|
||||
*/
|
||||
export const Intent = Object.freeze({
|
||||
Perceptual: 0, "0": "Perceptual",
|
||||
RelativeColorimetric: 1, "1": "RelativeColorimetric",
|
||||
Saturation: 2, "2": "Saturation",
|
||||
AbsoluteColorimetric: 3, "3": "AbsoluteColorimetric",
|
||||
});
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
if (typeof Response === 'function' && module instanceof Response) {
|
||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
try {
|
||||
return await WebAssembly.instantiateStreaming(module, imports);
|
||||
|
||||
} catch (e) {
|
||||
if (module.headers.get('Content-Type') != 'application/wasm') {
|
||||
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
||||
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bytes = await module.arrayBuffer();
|
||||
return await WebAssembly.instantiate(bytes, imports);
|
||||
|
||||
} else {
|
||||
const instance = await WebAssembly.instantiate(module, imports);
|
||||
|
||||
if (instance instanceof WebAssembly.Instance) {
|
||||
return { instance, module };
|
||||
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function __wbg_get_imports() {
|
||||
const imports = {};
|
||||
imports.wbg = {};
|
||||
imports.wbg.__wbg_copyresult_b08ee7d273f295dd = function(arg0, arg1) {
|
||||
copy_result(arg0 >>> 0, arg1 >>> 0);
|
||||
};
|
||||
imports.wbg.__wbg_copyrgb_d60ce17bb05d9b67 = function(arg0) {
|
||||
copy_rgb(arg0 >>> 0);
|
||||
};
|
||||
imports.wbg.__wbindgen_init_externref_table = function() {
|
||||
const table = wasm.__wbindgen_export_0;
|
||||
const offset = table.grow(4);
|
||||
table.set(0, undefined);
|
||||
table.set(offset + 0, undefined);
|
||||
table.set(offset + 1, null);
|
||||
table.set(offset + 2, true);
|
||||
table.set(offset + 3, false);
|
||||
;
|
||||
};
|
||||
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
};
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
function __wbg_init_memory(imports, memory) {
|
||||
|
||||
}
|
||||
|
||||
function __wbg_finalize_init(instance, module) {
|
||||
wasm = instance.exports;
|
||||
__wbg_init.__wbindgen_wasm_module = module;
|
||||
cachedUint8ArrayMemory0 = null;
|
||||
|
||||
|
||||
wasm.__wbindgen_start();
|
||||
return wasm;
|
||||
}
|
||||
|
||||
function initSync(module) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
|
||||
if (typeof module !== 'undefined') {
|
||||
if (Object.getPrototypeOf(module) === Object.prototype) {
|
||||
({module} = module)
|
||||
} else {
|
||||
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
|
||||
}
|
||||
}
|
||||
|
||||
const imports = __wbg_get_imports();
|
||||
|
||||
__wbg_init_memory(imports);
|
||||
|
||||
if (!(module instanceof WebAssembly.Module)) {
|
||||
module = new WebAssembly.Module(module);
|
||||
}
|
||||
|
||||
const instance = new WebAssembly.Instance(module, imports);
|
||||
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
async function __wbg_init(module_or_path) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
|
||||
if (typeof module_or_path !== 'undefined') {
|
||||
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
|
||||
({module_or_path} = module_or_path)
|
||||
} else {
|
||||
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module_or_path === 'undefined') {
|
||||
module_or_path = new URL('qcms_bg.wasm', import.meta.url);
|
||||
}
|
||||
const imports = __wbg_get_imports();
|
||||
|
||||
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
|
||||
module_or_path = fetch(module_or_path);
|
||||
}
|
||||
|
||||
__wbg_init_memory(imports);
|
||||
|
||||
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
||||
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
export { initSync };
|
||||
export default __wbg_init;
|
BIN
external/qcms/qcms_bg.wasm
vendored
Normal file
BIN
external/qcms/qcms_bg.wasm
vendored
Normal file
Binary file not shown.
43
external/qcms/qcms_utils.js
vendored
Normal file
43
external/qcms/qcms_utils.js
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
class QCMS {
|
||||
static _module = null;
|
||||
|
||||
static _destBuffer = null;
|
||||
}
|
||||
|
||||
function copy_result(ptr, len) {
|
||||
// This function is called from the wasm module (it's an external
|
||||
// "C" function). Its goal is to copy the result from the wasm memory
|
||||
// to the destination buffer without any intermediate copies.
|
||||
const { _module, _destBuffer } = QCMS;
|
||||
const result = new Uint8Array(_module.memory.buffer, ptr, len);
|
||||
if (result.length === _destBuffer.length) {
|
||||
_destBuffer.set(result);
|
||||
return;
|
||||
}
|
||||
for (let i = 0, j = 0, ii = result.length; i < ii; i += 3, j += 4) {
|
||||
_destBuffer[j] = result[i];
|
||||
_destBuffer[j + 1] = result[i + 1];
|
||||
_destBuffer[j + 2] = result[i + 2];
|
||||
}
|
||||
}
|
||||
|
||||
function copy_rgb(ptr) {
|
||||
QCMS._destBuffer.set(new Uint8Array(QCMS._module.memory.buffer, ptr, 3));
|
||||
}
|
||||
|
||||
export { copy_result, copy_rgb, QCMS };
|
|
@ -663,6 +663,10 @@ function createWasmBundle() {
|
|||
encoding: false,
|
||||
}
|
||||
),
|
||||
gulp.src(["external/qcms/*.wasm", "external/qcms/LICENSE_*"], {
|
||||
base: "external/qcms",
|
||||
encoding: false,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1659,6 +1663,7 @@ function buildLib(defines, dir) {
|
|||
}),
|
||||
gulp.src("test/unit/*.js", { base: ".", encoding: false }),
|
||||
gulp.src("external/openjpeg/*.js", { base: "openjpeg/", encoding: false }),
|
||||
gulp.src("external/qcms/*.js", { base: "qcms/", encoding: false }),
|
||||
]);
|
||||
|
||||
return buildLibHelper(bundleDefines, inputStream, dir);
|
||||
|
@ -2140,7 +2145,7 @@ gulp.task(
|
|||
},
|
||||
function watchWasm() {
|
||||
gulp.watch(
|
||||
"external/openjpeg/*",
|
||||
["external/openjpeg/*", "external/qcms/*"],
|
||||
{ ignoreInitial: false },
|
||||
gulp.series("dev-wasm")
|
||||
);
|
||||
|
|
|
@ -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() {
|
||||
|
|
1
test/pdfs/issue2856.pdf.link
Normal file
1
test/pdfs/issue2856.pdf.link
Normal file
|
@ -0,0 +1 @@
|
|||
https://github.com/user-attachments/files/19016079/version4pdf.pdf
|
|
@ -11946,5 +11946,13 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "issue2856",
|
||||
"file": "pdfs/issue2856.pdf",
|
||||
"md5": "a13033722b99d7b24a1383ac793d2b51",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
} from "../../src/core/image_utils.js";
|
||||
import { Stream, StringStream } from "../../src/core/stream.js";
|
||||
import { ColorSpace } from "../../src/core/colorspace.js";
|
||||
import { ColorSpaceUtils } from "../../src/core/colorspace_utils.js";
|
||||
import { PDFFunctionFactory } from "../../src/core/function.js";
|
||||
import { XRefMock } from "./test_utils.js";
|
||||
|
||||
|
@ -71,7 +72,7 @@ describe("colorspace", function () {
|
|||
xref,
|
||||
});
|
||||
|
||||
const colorSpace1 = ColorSpace.parse({
|
||||
const colorSpace1 = ColorSpaceUtils.parse({
|
||||
cs: Name.get("Pattern"),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -81,7 +82,7 @@ describe("colorspace", function () {
|
|||
});
|
||||
expect(colorSpace1.name).toEqual("Pattern");
|
||||
|
||||
const colorSpace2 = ColorSpace.parse({
|
||||
const colorSpace2 = ColorSpaceUtils.parse({
|
||||
cs: Name.get("Pattern"),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -91,7 +92,7 @@ describe("colorspace", function () {
|
|||
});
|
||||
expect(colorSpace2.name).toEqual("Pattern");
|
||||
|
||||
const colorSpaceNonCached = ColorSpace.parse({
|
||||
const colorSpaceNonCached = ColorSpaceUtils.parse({
|
||||
cs: Name.get("Pattern"),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -101,7 +102,7 @@ describe("colorspace", function () {
|
|||
});
|
||||
expect(colorSpaceNonCached.name).toEqual("Pattern");
|
||||
|
||||
const colorSpaceOther = ColorSpace.parse({
|
||||
const colorSpaceOther = ColorSpaceUtils.parse({
|
||||
cs: Name.get("RGB"),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -144,7 +145,7 @@ describe("colorspace", function () {
|
|||
xref,
|
||||
});
|
||||
|
||||
const colorSpace1 = ColorSpace.parse({
|
||||
const colorSpace1 = ColorSpaceUtils.parse({
|
||||
cs: Ref.get(50, 0),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -154,7 +155,7 @@ describe("colorspace", function () {
|
|||
});
|
||||
expect(colorSpace1.name).toEqual("CalGray");
|
||||
|
||||
const colorSpace2 = ColorSpace.parse({
|
||||
const colorSpace2 = ColorSpaceUtils.parse({
|
||||
cs: Ref.get(50, 0),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -164,7 +165,7 @@ describe("colorspace", function () {
|
|||
});
|
||||
expect(colorSpace2.name).toEqual("CalGray");
|
||||
|
||||
const colorSpaceNonCached = ColorSpace.parse({
|
||||
const colorSpaceNonCached = ColorSpaceUtils.parse({
|
||||
cs: Ref.get(50, 0),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -174,7 +175,7 @@ describe("colorspace", function () {
|
|||
});
|
||||
expect(colorSpaceNonCached.name).toEqual("CalGray");
|
||||
|
||||
const colorSpaceOther = ColorSpace.parse({
|
||||
const colorSpaceOther = ColorSpaceUtils.parse({
|
||||
cs: Ref.get(100, 0),
|
||||
xref,
|
||||
resources: null,
|
||||
|
@ -216,7 +217,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -268,7 +269,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -326,7 +327,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -384,7 +385,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -448,7 +449,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -506,7 +507,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -575,7 +576,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -646,7 +647,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -715,7 +716,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -788,7 +789,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
@ -867,7 +868,7 @@ describe("colorspace", function () {
|
|||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref,
|
||||
});
|
||||
const colorSpace = ColorSpace.parse({
|
||||
const colorSpace = ColorSpaceUtils.parse({
|
||||
cs,
|
||||
xref,
|
||||
resources,
|
||||
|
|
Loading…
Add table
Reference in a new issue