UNPKG

32.6 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * JavaScript code in this page
4 *
5 * Copyright 2022 Mozilla Foundation
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * @licend The above is the entire license notice for the
20 * JavaScript code in this page
21 */
22"use strict";
23
24Object.defineProperty(exports, "__esModule", {
25 value: true
26});
27exports.ColorSpace = void 0;
28
29var _util = require("../shared/util.js");
30
31var _primitives = require("./primitives.js");
32
33var _base_stream = require("./base_stream.js");
34
35var _core_utils = require("./core_utils.js");
36
37function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) {
38 const COMPONENTS = 3;
39 alpha01 = alpha01 !== 1 ? 0 : alpha01;
40 const xRatio = w1 / w2;
41 const yRatio = h1 / h2;
42 let newIndex = 0,
43 oldIndex;
44 const xScaled = new Uint16Array(w2);
45 const w1Scanline = w1 * COMPONENTS;
46
47 for (let i = 0; i < w2; i++) {
48 xScaled[i] = Math.floor(i * xRatio) * COMPONENTS;
49 }
50
51 for (let i = 0; i < h2; i++) {
52 const py = Math.floor(i * yRatio) * w1Scanline;
53
54 for (let j = 0; j < w2; j++) {
55 oldIndex = py + xScaled[j];
56 dest[newIndex++] = src[oldIndex++];
57 dest[newIndex++] = src[oldIndex++];
58 dest[newIndex++] = src[oldIndex++];
59 newIndex += alpha01;
60 }
61 }
62}
63
64class ColorSpace {
65 constructor(name, numComps) {
66 if (this.constructor === ColorSpace) {
67 (0, _util.unreachable)("Cannot initialize ColorSpace.");
68 }
69
70 this.name = name;
71 this.numComps = numComps;
72 }
73
74 getRgb(src, srcOffset) {
75 const rgb = new Uint8ClampedArray(3);
76 this.getRgbItem(src, srcOffset, rgb, 0);
77 return rgb;
78 }
79
80 getRgbItem(src, srcOffset, dest, destOffset) {
81 (0, _util.unreachable)("Should not call ColorSpace.getRgbItem");
82 }
83
84 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
85 (0, _util.unreachable)("Should not call ColorSpace.getRgbBuffer");
86 }
87
88 getOutputLength(inputLength, alpha01) {
89 (0, _util.unreachable)("Should not call ColorSpace.getOutputLength");
90 }
91
92 isPassthrough(bits) {
93 return false;
94 }
95
96 isDefaultDecode(decodeMap, bpc) {
97 return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
98 }
99
100 fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) {
101 const count = originalWidth * originalHeight;
102 let rgbBuf = null;
103 const numComponentColors = 1 << bpc;
104 const needsResizing = originalHeight !== height || originalWidth !== width;
105
106 if (this.isPassthrough(bpc)) {
107 rgbBuf = comps;
108 } else if (this.numComps === 1 && count > numComponentColors && this.name !== "DeviceGray" && this.name !== "DeviceRGB") {
109 const allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors);
110
111 for (let i = 0; i < numComponentColors; i++) {
112 allColors[i] = i;
113 }
114
115 const colorMap = new Uint8ClampedArray(numComponentColors * 3);
116 this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0);
117
118 if (!needsResizing) {
119 let destPos = 0;
120
121 for (let i = 0; i < count; ++i) {
122 const key = comps[i] * 3;
123 dest[destPos++] = colorMap[key];
124 dest[destPos++] = colorMap[key + 1];
125 dest[destPos++] = colorMap[key + 2];
126 destPos += alpha01;
127 }
128 } else {
129 rgbBuf = new Uint8Array(count * 3);
130 let rgbPos = 0;
131
132 for (let i = 0; i < count; ++i) {
133 const key = comps[i] * 3;
134 rgbBuf[rgbPos++] = colorMap[key];
135 rgbBuf[rgbPos++] = colorMap[key + 1];
136 rgbBuf[rgbPos++] = colorMap[key + 2];
137 }
138 }
139 } else {
140 if (!needsResizing) {
141 this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01);
142 } else {
143 rgbBuf = new Uint8ClampedArray(count * 3);
144 this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0);
145 }
146 }
147
148 if (rgbBuf) {
149 if (needsResizing) {
150 resizeRgbImage(rgbBuf, dest, originalWidth, originalHeight, width, height, alpha01);
151 } else {
152 let destPos = 0,
153 rgbPos = 0;
154
155 for (let i = 0, ii = width * actualHeight; i < ii; i++) {
156 dest[destPos++] = rgbBuf[rgbPos++];
157 dest[destPos++] = rgbBuf[rgbPos++];
158 dest[destPos++] = rgbBuf[rgbPos++];
159 destPos += alpha01;
160 }
161 }
162 }
163 }
164
165 get usesZeroToOneRange() {
166 return (0, _util.shadow)(this, "usesZeroToOneRange", true);
167 }
168
169 static _cache(cacheKey, xref, localColorSpaceCache, parsedColorSpace) {
170 if (!localColorSpaceCache) {
171 throw new Error('ColorSpace._cache - expected "localColorSpaceCache" argument.');
172 }
173
174 if (!parsedColorSpace) {
175 throw new Error('ColorSpace._cache - expected "parsedColorSpace" argument.');
176 }
177
178 let csName, csRef;
179
180 if (cacheKey instanceof _primitives.Ref) {
181 csRef = cacheKey;
182 cacheKey = xref.fetch(cacheKey);
183 }
184
185 if (cacheKey instanceof _primitives.Name) {
186 csName = cacheKey.name;
187 }
188
189 if (csName || csRef) {
190 localColorSpaceCache.set(csName, csRef, parsedColorSpace);
191 }
192 }
193
194 static getCached(cacheKey, xref, localColorSpaceCache) {
195 if (!localColorSpaceCache) {
196 throw new Error('ColorSpace.getCached - expected "localColorSpaceCache" argument.');
197 }
198
199 if (cacheKey instanceof _primitives.Ref) {
200 const localColorSpace = localColorSpaceCache.getByRef(cacheKey);
201
202 if (localColorSpace) {
203 return localColorSpace;
204 }
205
206 try {
207 cacheKey = xref.fetch(cacheKey);
208 } catch (ex) {
209 if (ex instanceof _core_utils.MissingDataException) {
210 throw ex;
211 }
212 }
213 }
214
215 if (cacheKey instanceof _primitives.Name) {
216 const localColorSpace = localColorSpaceCache.getByName(cacheKey.name);
217
218 if (localColorSpace) {
219 return localColorSpace;
220 }
221 }
222
223 return null;
224 }
225
226 static async parseAsync({
227 cs,
228 xref,
229 resources = null,
230 pdfFunctionFactory,
231 localColorSpaceCache
232 }) {
233 const parsedColorSpace = this._parse(cs, xref, resources, pdfFunctionFactory);
234
235 this._cache(cs, xref, localColorSpaceCache, parsedColorSpace);
236
237 return parsedColorSpace;
238 }
239
240 static parse({
241 cs,
242 xref,
243 resources = null,
244 pdfFunctionFactory,
245 localColorSpaceCache
246 }) {
247 const cachedColorSpace = this.getCached(cs, xref, localColorSpaceCache);
248
249 if (cachedColorSpace) {
250 return cachedColorSpace;
251 }
252
253 const parsedColorSpace = this._parse(cs, xref, resources, pdfFunctionFactory);
254
255 this._cache(cs, xref, localColorSpaceCache, parsedColorSpace);
256
257 return parsedColorSpace;
258 }
259
260 static _parse(cs, xref, resources = null, pdfFunctionFactory) {
261 cs = xref.fetchIfRef(cs);
262
263 if (cs instanceof _primitives.Name) {
264 switch (cs.name) {
265 case "G":
266 case "DeviceGray":
267 return this.singletons.gray;
268
269 case "RGB":
270 case "DeviceRGB":
271 return this.singletons.rgb;
272
273 case "CMYK":
274 case "DeviceCMYK":
275 return this.singletons.cmyk;
276
277 case "Pattern":
278 return new PatternCS(null);
279
280 default:
281 if (resources instanceof _primitives.Dict) {
282 const colorSpaces = resources.get("ColorSpace");
283
284 if (colorSpaces instanceof _primitives.Dict) {
285 const resourcesCS = colorSpaces.get(cs.name);
286
287 if (resourcesCS) {
288 if (resourcesCS instanceof _primitives.Name) {
289 return this._parse(resourcesCS, xref, resources, pdfFunctionFactory);
290 }
291
292 cs = resourcesCS;
293 break;
294 }
295 }
296 }
297
298 throw new _util.FormatError(`Unrecognized ColorSpace: ${cs.name}`);
299 }
300 }
301
302 if (Array.isArray(cs)) {
303 const mode = xref.fetchIfRef(cs[0]).name;
304 let params, numComps, baseCS, whitePoint, blackPoint, gamma;
305
306 switch (mode) {
307 case "G":
308 case "DeviceGray":
309 return this.singletons.gray;
310
311 case "RGB":
312 case "DeviceRGB":
313 return this.singletons.rgb;
314
315 case "CMYK":
316 case "DeviceCMYK":
317 return this.singletons.cmyk;
318
319 case "CalGray":
320 params = xref.fetchIfRef(cs[1]);
321 whitePoint = params.getArray("WhitePoint");
322 blackPoint = params.getArray("BlackPoint");
323 gamma = params.get("Gamma");
324 return new CalGrayCS(whitePoint, blackPoint, gamma);
325
326 case "CalRGB":
327 params = xref.fetchIfRef(cs[1]);
328 whitePoint = params.getArray("WhitePoint");
329 blackPoint = params.getArray("BlackPoint");
330 gamma = params.getArray("Gamma");
331 const matrix = params.getArray("Matrix");
332 return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
333
334 case "ICCBased":
335 const stream = xref.fetchIfRef(cs[1]);
336 const dict = stream.dict;
337 numComps = dict.get("N");
338 const alt = dict.get("Alternate");
339
340 if (alt) {
341 const altCS = this._parse(alt, xref, resources, pdfFunctionFactory);
342
343 if (altCS.numComps === numComps) {
344 return altCS;
345 }
346
347 (0, _util.warn)("ICCBased color space: Ignoring incorrect /Alternate entry.");
348 }
349
350 if (numComps === 1) {
351 return this.singletons.gray;
352 } else if (numComps === 3) {
353 return this.singletons.rgb;
354 } else if (numComps === 4) {
355 return this.singletons.cmyk;
356 }
357
358 break;
359
360 case "Pattern":
361 baseCS = cs[1] || null;
362
363 if (baseCS) {
364 baseCS = this._parse(baseCS, xref, resources, pdfFunctionFactory);
365 }
366
367 return new PatternCS(baseCS);
368
369 case "I":
370 case "Indexed":
371 baseCS = this._parse(cs[1], xref, resources, pdfFunctionFactory);
372 const hiVal = xref.fetchIfRef(cs[2]) + 1;
373 const lookup = xref.fetchIfRef(cs[3]);
374 return new IndexedCS(baseCS, hiVal, lookup);
375
376 case "Separation":
377 case "DeviceN":
378 const name = xref.fetchIfRef(cs[1]);
379 numComps = Array.isArray(name) ? name.length : 1;
380 baseCS = this._parse(cs[2], xref, resources, pdfFunctionFactory);
381 const tintFn = pdfFunctionFactory.create(cs[3]);
382 return new AlternateCS(numComps, baseCS, tintFn);
383
384 case "Lab":
385 params = xref.fetchIfRef(cs[1]);
386 whitePoint = params.getArray("WhitePoint");
387 blackPoint = params.getArray("BlackPoint");
388 const range = params.getArray("Range");
389 return new LabCS(whitePoint, blackPoint, range);
390
391 default:
392 throw new _util.FormatError(`Unimplemented ColorSpace object: ${mode}`);
393 }
394 }
395
396 throw new _util.FormatError(`Unrecognized ColorSpace object: ${cs}`);
397 }
398
399 static isDefaultDecode(decode, numComps) {
400 if (!Array.isArray(decode)) {
401 return true;
402 }
403
404 if (numComps * 2 !== decode.length) {
405 (0, _util.warn)("The decode map is not the correct length");
406 return true;
407 }
408
409 for (let i = 0, ii = decode.length; i < ii; i += 2) {
410 if (decode[i] !== 0 || decode[i + 1] !== 1) {
411 return false;
412 }
413 }
414
415 return true;
416 }
417
418 static get singletons() {
419 return (0, _util.shadow)(this, "singletons", {
420 get gray() {
421 return (0, _util.shadow)(this, "gray", new DeviceGrayCS());
422 },
423
424 get rgb() {
425 return (0, _util.shadow)(this, "rgb", new DeviceRgbCS());
426 },
427
428 get cmyk() {
429 return (0, _util.shadow)(this, "cmyk", new DeviceCmykCS());
430 }
431
432 });
433 }
434
435}
436
437exports.ColorSpace = ColorSpace;
438
439class AlternateCS extends ColorSpace {
440 constructor(numComps, base, tintFn) {
441 super("Alternate", numComps);
442 this.base = base;
443 this.tintFn = tintFn;
444 this.tmpBuf = new Float32Array(base.numComps);
445 }
446
447 getRgbItem(src, srcOffset, dest, destOffset) {
448 const tmpBuf = this.tmpBuf;
449 this.tintFn(src, srcOffset, tmpBuf, 0);
450 this.base.getRgbItem(tmpBuf, 0, dest, destOffset);
451 }
452
453 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
454 const tintFn = this.tintFn;
455 const base = this.base;
456 const scale = 1 / ((1 << bits) - 1);
457 const baseNumComps = base.numComps;
458 const usesZeroToOneRange = base.usesZeroToOneRange;
459 const isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0;
460 let pos = isPassthrough ? destOffset : 0;
461 const baseBuf = isPassthrough ? dest : new Uint8ClampedArray(baseNumComps * count);
462 const numComps = this.numComps;
463 const scaled = new Float32Array(numComps);
464 const tinted = new Float32Array(baseNumComps);
465 let i, j;
466
467 for (i = 0; i < count; i++) {
468 for (j = 0; j < numComps; j++) {
469 scaled[j] = src[srcOffset++] * scale;
470 }
471
472 tintFn(scaled, 0, tinted, 0);
473
474 if (usesZeroToOneRange) {
475 for (j = 0; j < baseNumComps; j++) {
476 baseBuf[pos++] = tinted[j] * 255;
477 }
478 } else {
479 base.getRgbItem(tinted, 0, baseBuf, pos);
480 pos += baseNumComps;
481 }
482 }
483
484 if (!isPassthrough) {
485 base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
486 }
487 }
488
489 getOutputLength(inputLength, alpha01) {
490 return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01);
491 }
492
493}
494
495class PatternCS extends ColorSpace {
496 constructor(baseCS) {
497 super("Pattern", null);
498 this.base = baseCS;
499 }
500
501 isDefaultDecode(decodeMap, bpc) {
502 (0, _util.unreachable)("Should not call PatternCS.isDefaultDecode");
503 }
504
505}
506
507class IndexedCS extends ColorSpace {
508 constructor(base, highVal, lookup) {
509 super("Indexed", 1);
510 this.base = base;
511 this.highVal = highVal;
512 const length = base.numComps * highVal;
513 this.lookup = new Uint8Array(length);
514
515 if (lookup instanceof _base_stream.BaseStream) {
516 const bytes = lookup.getBytes(length);
517 this.lookup.set(bytes);
518 } else if (typeof lookup === "string") {
519 for (let i = 0; i < length; ++i) {
520 this.lookup[i] = lookup.charCodeAt(i) & 0xff;
521 }
522 } else {
523 throw new _util.FormatError(`IndexedCS - unrecognized lookup table: ${lookup}`);
524 }
525 }
526
527 getRgbItem(src, srcOffset, dest, destOffset) {
528 const numComps = this.base.numComps;
529 const start = src[srcOffset] * numComps;
530 this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0);
531 }
532
533 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
534 const base = this.base;
535 const numComps = base.numComps;
536 const outputDelta = base.getOutputLength(numComps, alpha01);
537 const lookup = this.lookup;
538
539 for (let i = 0; i < count; ++i) {
540 const lookupPos = src[srcOffset++] * numComps;
541 base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
542 destOffset += outputDelta;
543 }
544 }
545
546 getOutputLength(inputLength, alpha01) {
547 return this.base.getOutputLength(inputLength * this.base.numComps, alpha01);
548 }
549
550 isDefaultDecode(decodeMap, bpc) {
551 if (!Array.isArray(decodeMap)) {
552 return true;
553 }
554
555 if (decodeMap.length !== 2) {
556 (0, _util.warn)("Decode map length is not correct");
557 return true;
558 }
559
560 if (!Number.isInteger(bpc) || bpc < 1) {
561 (0, _util.warn)("Bits per component is not correct");
562 return true;
563 }
564
565 return decodeMap[0] === 0 && decodeMap[1] === (1 << bpc) - 1;
566 }
567
568}
569
570class DeviceGrayCS extends ColorSpace {
571 constructor() {
572 super("DeviceGray", 1);
573 }
574
575 getRgbItem(src, srcOffset, dest, destOffset) {
576 const c = src[srcOffset] * 255;
577 dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
578 }
579
580 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
581 const scale = 255 / ((1 << bits) - 1);
582 let j = srcOffset,
583 q = destOffset;
584
585 for (let i = 0; i < count; ++i) {
586 const c = scale * src[j++];
587 dest[q++] = c;
588 dest[q++] = c;
589 dest[q++] = c;
590 q += alpha01;
591 }
592 }
593
594 getOutputLength(inputLength, alpha01) {
595 return inputLength * (3 + alpha01);
596 }
597
598}
599
600class DeviceRgbCS extends ColorSpace {
601 constructor() {
602 super("DeviceRGB", 3);
603 }
604
605 getRgbItem(src, srcOffset, dest, destOffset) {
606 dest[destOffset] = src[srcOffset] * 255;
607 dest[destOffset + 1] = src[srcOffset + 1] * 255;
608 dest[destOffset + 2] = src[srcOffset + 2] * 255;
609 }
610
611 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
612 if (bits === 8 && alpha01 === 0) {
613 dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
614 return;
615 }
616
617 const scale = 255 / ((1 << bits) - 1);
618 let j = srcOffset,
619 q = destOffset;
620
621 for (let i = 0; i < count; ++i) {
622 dest[q++] = scale * src[j++];
623 dest[q++] = scale * src[j++];
624 dest[q++] = scale * src[j++];
625 q += alpha01;
626 }
627 }
628
629 getOutputLength(inputLength, alpha01) {
630 return inputLength * (3 + alpha01) / 3 | 0;
631 }
632
633 isPassthrough(bits) {
634 return bits === 8;
635 }
636
637}
638
639const DeviceCmykCS = function DeviceCmykCSClosure() {
640 function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
641 const c = src[srcOffset] * srcScale;
642 const m = src[srcOffset + 1] * srcScale;
643 const y = src[srcOffset + 2] * srcScale;
644 const k = src[srcOffset + 3] * srcScale;
645 dest[destOffset] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k + -285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y + -17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) + k * (-21.86122147463605 * k - 189.48180835922747);
646 dest[destOffset + 1] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k + -79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) + k * (-20.737325471181034 * k - 187.80453709719578);
647 dest[destOffset + 2] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k + -14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k + -193.58209356861505) + k * (-22.33816807309886 * k - 180.12613974708367);
648 }
649
650 class DeviceCmykCS extends ColorSpace {
651 constructor() {
652 super("DeviceCMYK", 4);
653 }
654
655 getRgbItem(src, srcOffset, dest, destOffset) {
656 convertToRgb(src, srcOffset, 1, dest, destOffset);
657 }
658
659 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
660 const scale = 1 / ((1 << bits) - 1);
661
662 for (let i = 0; i < count; i++) {
663 convertToRgb(src, srcOffset, scale, dest, destOffset);
664 srcOffset += 4;
665 destOffset += 3 + alpha01;
666 }
667 }
668
669 getOutputLength(inputLength, alpha01) {
670 return inputLength / 4 * (3 + alpha01) | 0;
671 }
672
673 }
674
675 return DeviceCmykCS;
676}();
677
678const CalGrayCS = function CalGrayCSClosure() {
679 function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
680 const A = src[srcOffset] * scale;
681 const AG = A ** cs.G;
682 const L = cs.YW * AG;
683 const val = Math.max(295.8 * L ** 0.3333333333333333 - 40.8, 0);
684 dest[destOffset] = val;
685 dest[destOffset + 1] = val;
686 dest[destOffset + 2] = val;
687 }
688
689 class CalGrayCS extends ColorSpace {
690 constructor(whitePoint, blackPoint, gamma) {
691 super("CalGray", 1);
692
693 if (!whitePoint) {
694 throw new _util.FormatError("WhitePoint missing - required for color space CalGray");
695 }
696
697 blackPoint = blackPoint || [0, 0, 0];
698 gamma = gamma || 1;
699 this.XW = whitePoint[0];
700 this.YW = whitePoint[1];
701 this.ZW = whitePoint[2];
702 this.XB = blackPoint[0];
703 this.YB = blackPoint[1];
704 this.ZB = blackPoint[2];
705 this.G = gamma;
706
707 if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
708 throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ", no fallback available");
709 }
710
711 if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
712 (0, _util.info)(`Invalid BlackPoint for ${this.name}, falling back to default.`);
713 this.XB = this.YB = this.ZB = 0;
714 }
715
716 if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
717 (0, _util.warn)(`${this.name}, BlackPoint: XB: ${this.XB}, YB: ${this.YB}, ` + `ZB: ${this.ZB}, only default values are supported.`);
718 }
719
720 if (this.G < 1) {
721 (0, _util.info)(`Invalid Gamma: ${this.G} for ${this.name}, ` + "falling back to default.");
722 this.G = 1;
723 }
724 }
725
726 getRgbItem(src, srcOffset, dest, destOffset) {
727 convertToRgb(this, src, srcOffset, dest, destOffset, 1);
728 }
729
730 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
731 const scale = 1 / ((1 << bits) - 1);
732
733 for (let i = 0; i < count; ++i) {
734 convertToRgb(this, src, srcOffset, dest, destOffset, scale);
735 srcOffset += 1;
736 destOffset += 3 + alpha01;
737 }
738 }
739
740 getOutputLength(inputLength, alpha01) {
741 return inputLength * (3 + alpha01);
742 }
743
744 }
745
746 return CalGrayCS;
747}();
748
749const CalRGBCS = function CalRGBCSClosure() {
750 const BRADFORD_SCALE_MATRIX = new Float32Array([0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]);
751 const BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867]);
752 const SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([3.2404542, -1.5371385, -0.4985314, -0.9692660, 1.8760108, 0.0415560, 0.0556434, -0.2040259, 1.0572252]);
753 const FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]);
754 const tempNormalizeMatrix = new Float32Array(3);
755 const tempConvertMatrix1 = new Float32Array(3);
756 const tempConvertMatrix2 = new Float32Array(3);
757 const DECODE_L_CONSTANT = ((8 + 16) / 116) ** 3 / 8.0;
758
759 function matrixProduct(a, b, result) {
760 result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
761 result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
762 result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
763 }
764
765 function convertToFlat(sourceWhitePoint, LMS, result) {
766 result[0] = LMS[0] * 1 / sourceWhitePoint[0];
767 result[1] = LMS[1] * 1 / sourceWhitePoint[1];
768 result[2] = LMS[2] * 1 / sourceWhitePoint[2];
769 }
770
771 function convertToD65(sourceWhitePoint, LMS, result) {
772 const D65X = 0.95047;
773 const D65Y = 1;
774 const D65Z = 1.08883;
775 result[0] = LMS[0] * D65X / sourceWhitePoint[0];
776 result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
777 result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
778 }
779
780 function sRGBTransferFunction(color) {
781 if (color <= 0.0031308) {
782 return adjustToRange(0, 1, 12.92 * color);
783 }
784
785 if (color >= 0.99554525) {
786 return 1;
787 }
788
789 return adjustToRange(0, 1, (1 + 0.055) * color ** (1 / 2.4) - 0.055);
790 }
791
792 function adjustToRange(min, max, value) {
793 return Math.max(min, Math.min(max, value));
794 }
795
796 function decodeL(L) {
797 if (L < 0) {
798 return -decodeL(-L);
799 }
800
801 if (L > 8.0) {
802 return ((L + 16) / 116) ** 3;
803 }
804
805 return L * DECODE_L_CONSTANT;
806 }
807
808 function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
809 if (sourceBlackPoint[0] === 0 && sourceBlackPoint[1] === 0 && sourceBlackPoint[2] === 0) {
810 result[0] = XYZ_Flat[0];
811 result[1] = XYZ_Flat[1];
812 result[2] = XYZ_Flat[2];
813 return;
814 }
815
816 const zeroDecodeL = decodeL(0);
817 const X_DST = zeroDecodeL;
818 const X_SRC = decodeL(sourceBlackPoint[0]);
819 const Y_DST = zeroDecodeL;
820 const Y_SRC = decodeL(sourceBlackPoint[1]);
821 const Z_DST = zeroDecodeL;
822 const Z_SRC = decodeL(sourceBlackPoint[2]);
823 const X_Scale = (1 - X_DST) / (1 - X_SRC);
824 const X_Offset = 1 - X_Scale;
825 const Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
826 const Y_Offset = 1 - Y_Scale;
827 const Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
828 const Z_Offset = 1 - Z_Scale;
829 result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
830 result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
831 result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
832 }
833
834 function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
835 if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
836 result[0] = XYZ_In[0];
837 result[1] = XYZ_In[1];
838 result[2] = XYZ_In[2];
839 return;
840 }
841
842 const LMS = result;
843 matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
844 const LMS_Flat = tempNormalizeMatrix;
845 convertToFlat(sourceWhitePoint, LMS, LMS_Flat);
846 matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result);
847 }
848
849 function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
850 const LMS = result;
851 matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
852 const LMS_D65 = tempNormalizeMatrix;
853 convertToD65(sourceWhitePoint, LMS, LMS_D65);
854 matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result);
855 }
856
857 function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
858 const A = adjustToRange(0, 1, src[srcOffset] * scale);
859 const B = adjustToRange(0, 1, src[srcOffset + 1] * scale);
860 const C = adjustToRange(0, 1, src[srcOffset + 2] * scale);
861 const AGR = A === 1 ? 1 : A ** cs.GR;
862 const BGG = B === 1 ? 1 : B ** cs.GG;
863 const CGB = C === 1 ? 1 : C ** cs.GB;
864 const X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB;
865 const Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB;
866 const Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB;
867 const XYZ = tempConvertMatrix1;
868 XYZ[0] = X;
869 XYZ[1] = Y;
870 XYZ[2] = Z;
871 const XYZ_Flat = tempConvertMatrix2;
872 normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat);
873 const XYZ_Black = tempConvertMatrix1;
874 compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black);
875 const XYZ_D65 = tempConvertMatrix2;
876 normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65);
877 const SRGB = tempConvertMatrix1;
878 matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);
879 dest[destOffset] = sRGBTransferFunction(SRGB[0]) * 255;
880 dest[destOffset + 1] = sRGBTransferFunction(SRGB[1]) * 255;
881 dest[destOffset + 2] = sRGBTransferFunction(SRGB[2]) * 255;
882 }
883
884 class CalRGBCS extends ColorSpace {
885 constructor(whitePoint, blackPoint, gamma, matrix) {
886 super("CalRGB", 3);
887
888 if (!whitePoint) {
889 throw new _util.FormatError("WhitePoint missing - required for color space CalRGB");
890 }
891
892 blackPoint = blackPoint || new Float32Array(3);
893 gamma = gamma || new Float32Array([1, 1, 1]);
894 matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
895 const XW = whitePoint[0];
896 const YW = whitePoint[1];
897 const ZW = whitePoint[2];
898 this.whitePoint = whitePoint;
899 const XB = blackPoint[0];
900 const YB = blackPoint[1];
901 const ZB = blackPoint[2];
902 this.blackPoint = blackPoint;
903 this.GR = gamma[0];
904 this.GG = gamma[1];
905 this.GB = gamma[2];
906 this.MXA = matrix[0];
907 this.MYA = matrix[1];
908 this.MZA = matrix[2];
909 this.MXB = matrix[3];
910 this.MYB = matrix[4];
911 this.MZB = matrix[5];
912 this.MXC = matrix[6];
913 this.MYC = matrix[7];
914 this.MZC = matrix[8];
915
916 if (XW < 0 || ZW < 0 || YW !== 1) {
917 throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ", no fallback available");
918 }
919
920 if (XB < 0 || YB < 0 || ZB < 0) {
921 (0, _util.info)(`Invalid BlackPoint for ${this.name} [${XB}, ${YB}, ${ZB}], ` + "falling back to default.");
922 this.blackPoint = new Float32Array(3);
923 }
924
925 if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
926 (0, _util.info)(`Invalid Gamma [${this.GR}, ${this.GG}, ${this.GB}] for ` + `${this.name}, falling back to default.`);
927 this.GR = this.GG = this.GB = 1;
928 }
929 }
930
931 getRgbItem(src, srcOffset, dest, destOffset) {
932 convertToRgb(this, src, srcOffset, dest, destOffset, 1);
933 }
934
935 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
936 const scale = 1 / ((1 << bits) - 1);
937
938 for (let i = 0; i < count; ++i) {
939 convertToRgb(this, src, srcOffset, dest, destOffset, scale);
940 srcOffset += 3;
941 destOffset += 3 + alpha01;
942 }
943 }
944
945 getOutputLength(inputLength, alpha01) {
946 return inputLength * (3 + alpha01) / 3 | 0;
947 }
948
949 }
950
951 return CalRGBCS;
952}();
953
954const LabCS = function LabCSClosure() {
955 function fn_g(x) {
956 let result;
957
958 if (x >= 6 / 29) {
959 result = x ** 3;
960 } else {
961 result = 108 / 841 * (x - 4 / 29);
962 }
963
964 return result;
965 }
966
967 function decode(value, high1, low2, high2) {
968 return low2 + value * (high2 - low2) / high1;
969 }
970
971 function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
972 let Ls = src[srcOffset];
973 let as = src[srcOffset + 1];
974 let bs = src[srcOffset + 2];
975
976 if (maxVal !== false) {
977 Ls = decode(Ls, maxVal, 0, 100);
978 as = decode(as, maxVal, cs.amin, cs.amax);
979 bs = decode(bs, maxVal, cs.bmin, cs.bmax);
980 }
981
982 if (as > cs.amax) {
983 as = cs.amax;
984 } else if (as < cs.amin) {
985 as = cs.amin;
986 }
987
988 if (bs > cs.bmax) {
989 bs = cs.bmax;
990 } else if (bs < cs.bmin) {
991 bs = cs.bmin;
992 }
993
994 const M = (Ls + 16) / 116;
995 const L = M + as / 500;
996 const N = M - bs / 200;
997 const X = cs.XW * fn_g(L);
998 const Y = cs.YW * fn_g(M);
999 const Z = cs.ZW * fn_g(N);
1000 let r, g, b;
1001
1002 if (cs.ZW < 1) {
1003 r = X * 3.1339 + Y * -1.617 + Z * -0.4906;
1004 g = X * -0.9785 + Y * 1.916 + Z * 0.0333;
1005 b = X * 0.072 + Y * -0.229 + Z * 1.4057;
1006 } else {
1007 r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
1008 g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
1009 b = X * 0.0557 + Y * -0.204 + Z * 1.057;
1010 }
1011
1012 dest[destOffset] = Math.sqrt(r) * 255;
1013 dest[destOffset + 1] = Math.sqrt(g) * 255;
1014 dest[destOffset + 2] = Math.sqrt(b) * 255;
1015 }
1016
1017 class LabCS extends ColorSpace {
1018 constructor(whitePoint, blackPoint, range) {
1019 super("Lab", 3);
1020
1021 if (!whitePoint) {
1022 throw new _util.FormatError("WhitePoint missing - required for color space Lab");
1023 }
1024
1025 blackPoint = blackPoint || [0, 0, 0];
1026 range = range || [-100, 100, -100, 100];
1027 this.XW = whitePoint[0];
1028 this.YW = whitePoint[1];
1029 this.ZW = whitePoint[2];
1030 this.amin = range[0];
1031 this.amax = range[1];
1032 this.bmin = range[2];
1033 this.bmax = range[3];
1034 this.XB = blackPoint[0];
1035 this.YB = blackPoint[1];
1036 this.ZB = blackPoint[2];
1037
1038 if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
1039 throw new _util.FormatError("Invalid WhitePoint components, no fallback available");
1040 }
1041
1042 if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
1043 (0, _util.info)("Invalid BlackPoint, falling back to default");
1044 this.XB = this.YB = this.ZB = 0;
1045 }
1046
1047 if (this.amin > this.amax || this.bmin > this.bmax) {
1048 (0, _util.info)("Invalid Range, falling back to defaults");
1049 this.amin = -100;
1050 this.amax = 100;
1051 this.bmin = -100;
1052 this.bmax = 100;
1053 }
1054 }
1055
1056 getRgbItem(src, srcOffset, dest, destOffset) {
1057 convertToRgb(this, src, srcOffset, false, dest, destOffset);
1058 }
1059
1060 getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
1061 const maxVal = (1 << bits) - 1;
1062
1063 for (let i = 0; i < count; i++) {
1064 convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
1065 srcOffset += 3;
1066 destOffset += 3 + alpha01;
1067 }
1068 }
1069
1070 getOutputLength(inputLength, alpha01) {
1071 return inputLength * (3 + alpha01) / 3 | 0;
1072 }
1073
1074 isDefaultDecode(decodeMap, bpc) {
1075 return true;
1076 }
1077
1078 get usesZeroToOneRange() {
1079 return (0, _util.shadow)(this, "usesZeroToOneRange", false);
1080 }
1081
1082 }
1083
1084 return LabCS;
1085}();
\No newline at end of file