diff --git a/src/core/colorspace.js b/src/core/colorspace.js index 7f0a301e1..354dadbf8 100644 --- a/src/core/colorspace.js +++ b/src/core/colorspace.js @@ -1280,18 +1280,57 @@ class CalRGBCS extends ColorSpace { * * The default color is `new Float32Array([0, 0, 0])`. */ -const LabCS = (function LabCSClosure() { +class LabCS extends ColorSpace { + constructor(whitePoint, blackPoint, range) { + super("Lab", 3); + + if (!whitePoint) { + throw new FormatError( + "WhitePoint missing - required for color space Lab" + ); + } + // Translate args to spec variables + [this.XW, this.YW, this.ZW] = whitePoint; + [this.amin, this.amax, this.bmin, this.bmax] = range || [ + -100, 100, -100, 100, + ]; + + // These are here just for completeness - the spec doesn't offer any + // formulas that use BlackPoint in Lab + [this.XB, this.YB, this.ZB] = blackPoint || [0, 0, 0]; + + // Validate vars as per spec + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new FormatError( + "Invalid WhitePoint components, no fallback available" + ); + } + + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + info("Invalid BlackPoint, falling back to default"); + this.XB = this.YB = this.ZB = 0; + } + + if (this.amin > this.amax || this.bmin > this.bmax) { + info("Invalid Range, falling back to defaults"); + this.amin = -100; + this.amax = 100; + this.bmin = -100; + this.bmax = 100; + } + } + // Function g(x) from spec - function fn_g(x) { + #fn_g(x) { return x >= 6 / 29 ? x ** 3 : (108 / 841) * (x - 4 / 29); } - function decode(value, high1, low2, high2) { + #decode(value, high1, low2, high2) { return low2 + (value * (high2 - low2)) / high1; } // If decoding is needed maxVal should be 2^bits per component - 1. - function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) { + #toRgb(src, srcOffset, maxVal, dest, destOffset) { // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax] // not the usual [0, 1]. If a command like setFillColor is used the src // values will already be within the correct range. However, if we are @@ -1302,21 +1341,21 @@ const LabCS = (function LabCSClosure() { let as = src[srcOffset + 1]; let bs = src[srcOffset + 2]; if (maxVal !== false) { - Ls = decode(Ls, maxVal, 0, 100); - as = decode(as, maxVal, cs.amin, cs.amax); - bs = decode(bs, maxVal, cs.bmin, cs.bmax); + Ls = this.#decode(Ls, maxVal, 0, 100); + as = this.#decode(as, maxVal, this.amin, this.amax); + bs = this.#decode(bs, maxVal, this.bmin, this.bmax); } // Adjust limits of 'as' and 'bs' - if (as > cs.amax) { - as = cs.amax; - } else if (as < cs.amin) { - as = cs.amin; + if (as > this.amax) { + as = this.amax; + } else if (as < this.amin) { + as = this.amin; } - if (bs > cs.bmax) { - bs = cs.bmax; - } else if (bs < cs.bmin) { - bs = cs.bmin; + if (bs > this.bmax) { + bs = this.bmax; + } else if (bs < this.bmin) { + bs = this.bmin; } // Computes intermediate variables X,Y,Z as per spec @@ -1324,14 +1363,14 @@ const LabCS = (function LabCSClosure() { const L = M + as / 500; const N = M - bs / 200; - const X = cs.XW * fn_g(L); - const Y = cs.YW * fn_g(M); - const Z = cs.ZW * fn_g(N); + const X = this.XW * this.#fn_g(L); + const Y = this.YW * this.#fn_g(M); + const Z = this.ZW * this.#fn_g(N); let r, g, b; // Using different conversions for D50 and D65 white points, // per http://www.color.org/srgb.pdf - if (cs.ZW < 1) { + if (this.ZW < 1) { // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249) r = X * 3.1339 + Y * -1.617 + Z * -0.4906; g = X * -0.9785 + Y * 1.916 + Z * 0.0333; @@ -1348,95 +1387,44 @@ const LabCS = (function LabCSClosure() { dest[destOffset + 2] = Math.sqrt(b) * 255; } - // eslint-disable-next-line no-shadow - class LabCS extends ColorSpace { - constructor(whitePoint, blackPoint, range) { - super("Lab", 3); - - if (!whitePoint) { - throw new FormatError( - "WhitePoint missing - required for color space Lab" - ); - } - blackPoint ||= [0, 0, 0]; - range ||= [-100, 100, -100, 100]; - - // Translate args to spec variables - this.XW = whitePoint[0]; - this.YW = whitePoint[1]; - this.ZW = whitePoint[2]; - this.amin = range[0]; - this.amax = range[1]; - this.bmin = range[2]; - this.bmax = range[3]; - - // These are here just for completeness - the spec doesn't offer any - // formulas that use BlackPoint in Lab - this.XB = blackPoint[0]; - this.YB = blackPoint[1]; - this.ZB = blackPoint[2]; - - // Validate vars as per spec - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { - throw new FormatError( - "Invalid WhitePoint components, no fallback available" - ); - } - - if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - info("Invalid BlackPoint, falling back to default"); - this.XB = this.YB = this.ZB = 0; - } - - if (this.amin > this.amax || this.bmin > this.bmax) { - info("Invalid Range, falling back to defaults"); - this.amin = -100; - this.amax = 100; - this.bmin = -100; - this.bmax = 100; - } + getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { + assert( + dest instanceof Uint8ClampedArray, + 'LabCS.getRgbItem: Unsupported "dest" type.' + ); } + this.#toRgb(src, srcOffset, false, dest, destOffset); + } - getRgbItem(src, srcOffset, dest, destOffset) { - if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { - assert( - dest instanceof Uint8ClampedArray, - 'LabCS.getRgbItem: Unsupported "dest" type.' - ); - } - convertToRgb(this, src, srcOffset, false, dest, destOffset); + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { + assert( + dest instanceof Uint8ClampedArray, + 'LabCS.getRgbBuffer: Unsupported "dest" type.' + ); } - - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { - assert( - dest instanceof Uint8ClampedArray, - 'LabCS.getRgbBuffer: Unsupported "dest" type.' - ); - } - const maxVal = (1 << bits) - 1; - for (let i = 0; i < count; i++) { - convertToRgb(this, src, srcOffset, maxVal, dest, destOffset); - srcOffset += 3; - destOffset += 3 + alpha01; - } - } - - getOutputLength(inputLength, alpha01) { - return ((inputLength * (3 + alpha01)) / 3) | 0; - } - - isDefaultDecode(decodeMap, bpc) { - // XXX: Decoding is handled with the lab conversion because of the strange - // ranges that are used. - return true; - } - - get usesZeroToOneRange() { - return shadow(this, "usesZeroToOneRange", false); + const maxVal = (1 << bits) - 1; + for (let i = 0; i < count; i++) { + this.#toRgb(src, srcOffset, maxVal, dest, destOffset); + srcOffset += 3; + destOffset += 3 + alpha01; } } - return LabCS; -})(); + + getOutputLength(inputLength, alpha01) { + return ((inputLength * (3 + alpha01)) / 3) | 0; + } + + isDefaultDecode(decodeMap, bpc) { + // XXX: Decoding is handled with the lab conversion because of the strange + // ranges that are used. + return true; + } + + get usesZeroToOneRange() { + return shadow(this, "usesZeroToOneRange", false); + } +} export { ColorSpace };