diff --git a/src/core/colorspace.js b/src/core/colorspace.js index 3ac1b9d71..081d489db 100644 --- a/src/core/colorspace.js +++ b/src/core/colorspace.js @@ -18,196 +18,200 @@ import { } from '../shared/util'; import { isDict, isName, isStream } from './primitives'; -var ColorSpace = (function ColorSpaceClosure() { +/** + * Resizes an RGB image with 3 components. + * @param {TypedArray} src - The source buffer. + * @param {TypedArray} dest - The destination buffer. + * @param {Number} w1 - Original width. + * @param {Number} h1 - Original height. + * @param {Number} w2 - New width. + * @param {Number} h2 - New height. + * @param {Number} alpha01 - Size reserved for the alpha channel. + */ +function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) { + const COMPONENTS = 3; + alpha01 = alpha01 !== 1 ? 0 : alpha01; + let xRatio = w1 / w2; + let yRatio = h1 / h2; + let newIndex = 0, oldIndex; + let xScaled = new Uint16Array(w2); + let w1Scanline = w1 * COMPONENTS; + + for (let i = 0; i < w2; i++) { + xScaled[i] = Math.floor(i * xRatio) * COMPONENTS; + } + for (let i = 0; i < h2; i++) { + const py = Math.floor(i * yRatio) * w1Scanline; + for (let j = 0; j < w2; j++) { + oldIndex = py + xScaled[j]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + newIndex += alpha01; + } + } +} + +class ColorSpace { + constructor(name, numComps) { + if (this.constructor === ColorSpace) { + unreachable('Cannot initialize ColorSpace.'); + } + this.name = name; + this.numComps = numComps; + } + /** - * Resizes an RGB image with 3 components. - * @param {TypedArray} src - The source buffer. - * @param {TypedArray} dest - The destination buffer. - * @param {Number} w1 - Original width. - * @param {Number} h1 - Original height. - * @param {Number} w2 - New width. - * @param {Number} h2 - New height. - * @param {Number} alpha01 - Size reserved for the alpha channel. + * Converts the color value to the RGB color. The color components are + * located in the src array starting from the srcOffset. Returns the array + * of the rgb components, each value ranging from [0,255]. */ - function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) { - var COMPONENTS = 3; - alpha01 = alpha01 !== 1 ? 0 : alpha01; - var xRatio = w1 / w2; - var yRatio = h1 / h2; - var i, j, py, newIndex = 0, oldIndex; - var xScaled = new Uint16Array(w2); - var w1Scanline = w1 * COMPONENTS; - - for (i = 0; i < w2; i++) { - xScaled[i] = Math.floor(i * xRatio) * COMPONENTS; - } - for (i = 0; i < h2; i++) { - py = Math.floor(i * yRatio) * w1Scanline; - for (j = 0; j < w2; j++) { - oldIndex = py + xScaled[j]; - dest[newIndex++] = src[oldIndex++]; - dest[newIndex++] = src[oldIndex++]; - dest[newIndex++] = src[oldIndex++]; - newIndex += alpha01; - } - } + getRgb(src, srcOffset) { + let rgb = new Uint8ClampedArray(3); + this.getRgbItem(src, srcOffset, rgb, 0); + return rgb; } - // Constructor should define this.numComps, this.name - function ColorSpace() { - unreachable('should not call ColorSpace constructor'); + /** + * Converts the color value to the RGB color, similar to the getRgb method. + * The result placed into the dest array starting from the destOffset. + */ + getRgbItem(src, srcOffset, dest, destOffset) { + unreachable('Should not call ColorSpace.getRgbItem'); } - ColorSpace.prototype = { - /** - * Converts the color value to the RGB color. The color components are - * located in the src array starting from the srcOffset. Returns the array - * of the rgb components, each value ranging from [0,255]. - */ - getRgb(src, srcOffset) { - let rgb = new Uint8ClampedArray(3); - this.getRgbItem(src, srcOffset, rgb, 0); - return rgb; - }, - /** - * Converts the color value to the RGB color, similar to the getRgb method. - * The result placed into the dest array starting from the destOffset. - */ - getRgbItem(src, srcOffset, dest, destOffset) { - unreachable('Should not call ColorSpace.getRgbItem'); - }, - /** - * Converts the specified number of the color values to the RGB colors. - * The colors are located in the src array starting from the srcOffset. - * The result is placed into the dest array starting from the destOffset. - * The src array items shall be in [0,2^bits) range, the dest array items - * will be in [0,255] range. alpha01 indicates how many alpha components - * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA - * array). - */ - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - unreachable('Should not call ColorSpace.getRgbBuffer'); - }, - /** - * Determines the number of bytes required to store the result of the - * conversion done by the getRgbBuffer method. As in getRgbBuffer, - * |alpha01| is either 0 (RGB output) or 1 (RGBA output). - */ - getOutputLength(inputLength, alpha01) { - unreachable('Should not call ColorSpace.getOutputLength'); - }, - /** - * Returns true if source data will be equal the result/output data. - */ - isPassthrough(bits) { - return false; - }, - /** - * Fills in the RGB colors in the destination buffer. alpha01 indicates - * how many alpha components there are in the dest array; it will be either - * 0 (RGB array) or 1 (RGBA array). - */ - fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, - bpc, comps, alpha01) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'ColorSpace.fillRgb: Unsupported "dest" type.'); + /** + * Converts the specified number of the color values to the RGB colors. + * The colors are located in the src array starting from the srcOffset. + * The result is placed into the dest array starting from the destOffset. + * The src array items shall be in [0,2^bits) range, the dest array items + * will be in [0,255] range. alpha01 indicates how many alpha components + * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA + * array). + */ + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + unreachable('Should not call ColorSpace.getRgbBuffer'); + } + + /** + * Determines the number of bytes required to store the result of the + * conversion done by the getRgbBuffer method. As in getRgbBuffer, + * |alpha01| is either 0 (RGB output) or 1 (RGBA output). + */ + getOutputLength(inputLength, alpha01) { + unreachable('Should not call ColorSpace.getOutputLength'); + } + + /** + * Returns true if source data will be equal the result/output data. + */ + isPassthrough(bits) { + return false; + } + + /** + * Fills in the RGB colors in the destination buffer. alpha01 indicates + * how many alpha components there are in the dest array; it will be either + * 0 (RGB array) or 1 (RGBA array). + */ + fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, + bpc, comps, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'ColorSpace.fillRgb: Unsupported "dest" type.'); + } + let count = originalWidth * originalHeight; + let rgbBuf = null; + let numComponentColors = 1 << bpc; + let needsResizing = originalHeight !== height || originalWidth !== width; + + if (this.isPassthrough(bpc)) { + rgbBuf = comps; + } else if (this.numComps === 1 && count > numComponentColors && + this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { + // Optimization: create a color map when there is just one component and + // we are converting more colors than the size of the color map. We + // don't build the map if the colorspace is gray or rgb since those + // methods are faster than building a map. This mainly offers big speed + // ups for indexed and alternate colorspaces. + // + // TODO it may be worth while to cache the color map. While running + // testing I never hit a cache so I will leave that out for now (perhaps + // we are reparsing colorspaces too much?). + let allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : + new Uint16Array(numComponentColors); + for (let i = 0; i < numComponentColors; i++) { + allColors[i] = i; } - var count = originalWidth * originalHeight; - var rgbBuf = null; - var numComponentColors = 1 << bpc; - var needsResizing = originalHeight !== height || originalWidth !== width; - var i, ii; + let colorMap = new Uint8ClampedArray(numComponentColors * 3); + this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, + /* alpha01 = */ 0); - if (this.isPassthrough(bpc)) { - rgbBuf = comps; - } else if (this.numComps === 1 && count > numComponentColors && - this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { - // Optimization: create a color map when there is just one component and - // we are converting more colors than the size of the color map. We - // don't build the map if the colorspace is gray or rgb since those - // methods are faster than building a map. This mainly offers big speed - // ups for indexed and alternate colorspaces. - // - // TODO it may be worth while to cache the color map. While running - // testing I never hit a cache so I will leave that out for now (perhaps - // we are reparsing colorspaces too much?). - var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : - new Uint16Array(numComponentColors); - var key; - for (i = 0; i < numComponentColors; i++) { - allColors[i] = i; - } - var colorMap = new Uint8ClampedArray(numComponentColors * 3); - this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, - /* alpha01 = */ 0); - - var destPos, rgbPos; - if (!needsResizing) { - // Fill in the RGB values directly into |dest|. - destPos = 0; - for (i = 0; i < count; ++i) { - key = comps[i] * 3; - dest[destPos++] = colorMap[key]; - dest[destPos++] = colorMap[key + 1]; - dest[destPos++] = colorMap[key + 2]; - destPos += alpha01; - } - } else { - rgbBuf = new Uint8Array(count * 3); - rgbPos = 0; - for (i = 0; i < count; ++i) { - key = comps[i] * 3; - rgbBuf[rgbPos++] = colorMap[key]; - rgbBuf[rgbPos++] = colorMap[key + 1]; - rgbBuf[rgbPos++] = colorMap[key + 2]; - } + if (!needsResizing) { + // Fill in the RGB values directly into |dest|. + let destPos = 0; + for (let i = 0; i < count; ++i) { + const key = comps[i] * 3; + dest[destPos++] = colorMap[key]; + dest[destPos++] = colorMap[key + 1]; + dest[destPos++] = colorMap[key + 2]; + destPos += alpha01; } } else { - if (!needsResizing) { - // Fill in the RGB values directly into |dest|. - this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, - alpha01); - } else { - rgbBuf = new Uint8ClampedArray(count * 3); - this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, - /* alpha01 = */ 0); + rgbBuf = new Uint8Array(count * 3); + let rgbPos = 0; + for (let i = 0; i < count; ++i) { + const key = comps[i] * 3; + rgbBuf[rgbPos++] = colorMap[key]; + rgbBuf[rgbPos++] = colorMap[key + 1]; + rgbBuf[rgbPos++] = colorMap[key + 2]; } } + } else { + if (!needsResizing) { + // Fill in the RGB values directly into |dest|. + this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, + alpha01); + } else { + rgbBuf = new Uint8ClampedArray(count * 3); + this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, /* alpha01 = */ 0); + } + } - if (rgbBuf) { - if (needsResizing) { - resizeRgbImage(rgbBuf, dest, originalWidth, originalHeight, - width, height, alpha01); - } else { - rgbPos = 0; - destPos = 0; - for (i = 0, ii = width * actualHeight; i < ii; i++) { - dest[destPos++] = rgbBuf[rgbPos++]; - dest[destPos++] = rgbBuf[rgbPos++]; - dest[destPos++] = rgbBuf[rgbPos++]; - destPos += alpha01; - } + if (rgbBuf) { + if (needsResizing) { + resizeRgbImage(rgbBuf, dest, originalWidth, originalHeight, + width, height, alpha01); + } else { + let destPos = 0, rgbPos = 0; + for (let i = 0, ii = width * actualHeight; i < ii; i++) { + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + destPos += alpha01; } } - }, - /** - * True if the colorspace has components in the default range of [0, 1]. - * This should be true for all colorspaces except for lab color spaces - * which are [0,100], [-128, 127], [-128, 127]. - */ - usesZeroToOneRange: true, - }; + } + } - ColorSpace.parse = function(cs, xref, res, pdfFunctionFactory) { - let IR = ColorSpace.parseToIR(cs, xref, res, pdfFunctionFactory); - return ColorSpace.fromIR(IR); - }; + /** + * True if the colorspace has components in the default range of [0, 1]. + * This should be true for all colorspaces except for lab color spaces + * which are [0,100], [-128, 127], [-128, 127]. + */ + get usesZeroToOneRange() { + return shadow(this, 'usesZeroToOneRange', true); + } - ColorSpace.fromIR = function(IR) { - var name = Array.isArray(IR) ? IR[0] : IR; - var whitePoint, blackPoint, gamma; + static parse(cs, xref, res, pdfFunctionFactory) { + let IR = this.parseToIR(cs, xref, res, pdfFunctionFactory); + return this.fromIR(IR); + } + + static fromIR(IR) { + let name = Array.isArray(IR) ? IR[0] : IR; + let whitePoint, blackPoint, gamma; switch (name) { case 'DeviceGrayCS': @@ -225,37 +229,35 @@ var ColorSpace = (function ColorSpaceClosure() { whitePoint = IR[1]; blackPoint = IR[2]; gamma = IR[3]; - var matrix = IR[4]; + let matrix = IR[4]; return new CalRGBCS(whitePoint, blackPoint, gamma, matrix); case 'PatternCS': - var basePatternCS = IR[1]; + let basePatternCS = IR[1]; if (basePatternCS) { - basePatternCS = ColorSpace.fromIR(basePatternCS); + basePatternCS = this.fromIR(basePatternCS); } return new PatternCS(basePatternCS); case 'IndexedCS': - var baseIndexedCS = IR[1]; - var hiVal = IR[2]; - var lookup = IR[3]; - return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), - hiVal, lookup); + let baseIndexedCS = IR[1]; + let hiVal = IR[2]; + let lookup = IR[3]; + return new IndexedCS(this.fromIR(baseIndexedCS), hiVal, lookup); case 'AlternateCS': - var numComps = IR[1]; - var alt = IR[2]; - var tintFn = IR[3]; - return new AlternateCS(numComps, ColorSpace.fromIR(alt), - tintFn); + let numComps = IR[1]; + let alt = IR[2]; + let tintFn = IR[3]; + return new AlternateCS(numComps, this.fromIR(alt), tintFn); case 'LabCS': whitePoint = IR[1]; blackPoint = IR[2]; - var range = IR[3]; + let range = IR[3]; return new LabCS(whitePoint, blackPoint, range); default: throw new FormatError(`Unknown colorspace name: ${name}`); } - }; + } - ColorSpace.parseToIR = function(cs, xref, res = null, pdfFunctionFactory) { + static parseToIR(cs, xref, res = null, pdfFunctionFactory) { cs = xref.fetchIfRef(cs); if (isName(cs)) { switch (cs.name) { @@ -277,8 +279,7 @@ var ColorSpace = (function ColorSpaceClosure() { let resCS = colorSpaces.get(cs.name); if (resCS) { if (isName(resCS)) { - return ColorSpace.parseToIR(resCS, xref, res, - pdfFunctionFactory); + return this.parseToIR(resCS, xref, res, pdfFunctionFactory); } cs = resCS; break; @@ -289,8 +290,8 @@ var ColorSpace = (function ColorSpaceClosure() { } } if (Array.isArray(cs)) { - var mode = xref.fetchIfRef(cs[0]).name; - var numComps, params, alt, whitePoint, blackPoint, gamma; + let mode = xref.fetchIfRef(cs[0]).name; + let numComps, params, alt, whitePoint, blackPoint, gamma; switch (mode) { case 'DeviceGray': @@ -313,19 +314,18 @@ var ColorSpace = (function ColorSpaceClosure() { whitePoint = params.getArray('WhitePoint'); blackPoint = params.getArray('BlackPoint'); gamma = params.getArray('Gamma'); - var matrix = params.getArray('Matrix'); + let matrix = params.getArray('Matrix'); return ['CalRGBCS', whitePoint, blackPoint, gamma, matrix]; case 'ICCBased': - var stream = xref.fetchIfRef(cs[1]); - var dict = stream.dict; + let stream = xref.fetchIfRef(cs[1]); + let dict = stream.dict; numComps = dict.get('N'); alt = dict.get('Alternate'); if (alt) { - var altIR = ColorSpace.parseToIR(alt, xref, res, - pdfFunctionFactory); + let altIR = this.parseToIR(alt, xref, res, pdfFunctionFactory); // Parse the /Alternate CS to ensure that the number of components // are correct, and also (indirectly) that it is not a PatternCS. - var altCS = ColorSpace.fromIR(altIR, pdfFunctionFactory); + let altCS = this.fromIR(altIR, pdfFunctionFactory); if (altCS.numComps === numComps) { return altIR; } @@ -340,41 +340,42 @@ var ColorSpace = (function ColorSpaceClosure() { } break; case 'Pattern': - var basePatternCS = cs[1] || null; + let basePatternCS = cs[1] || null; if (basePatternCS) { - basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res, - pdfFunctionFactory); + basePatternCS = this.parseToIR(basePatternCS, xref, res, + pdfFunctionFactory); } return ['PatternCS', basePatternCS]; case 'Indexed': case 'I': - var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res, - pdfFunctionFactory); - var hiVal = xref.fetchIfRef(cs[2]) + 1; - var lookup = xref.fetchIfRef(cs[3]); + let baseIndexedCS = this.parseToIR(cs[1], xref, res, + pdfFunctionFactory); + let hiVal = xref.fetchIfRef(cs[2]) + 1; + let lookup = xref.fetchIfRef(cs[3]); if (isStream(lookup)) { lookup = lookup.getBytes(); } return ['IndexedCS', baseIndexedCS, hiVal, lookup]; case 'Separation': case 'DeviceN': - var name = xref.fetchIfRef(cs[1]); + let name = xref.fetchIfRef(cs[1]); numComps = Array.isArray(name) ? name.length : 1; - alt = ColorSpace.parseToIR(cs[2], xref, res, pdfFunctionFactory); + alt = this.parseToIR(cs[2], xref, res, pdfFunctionFactory); let tintFn = pdfFunctionFactory.create(xref.fetchIfRef(cs[3])); return ['AlternateCS', numComps, alt, tintFn]; case 'Lab': params = xref.fetchIfRef(cs[1]); whitePoint = params.getArray('WhitePoint'); blackPoint = params.getArray('BlackPoint'); - var range = params.getArray('Range'); + let range = params.getArray('Range'); return ['LabCS', whitePoint, blackPoint, range]; default: throw new FormatError(`unimplemented color space object "${mode}"`); } } throw new FormatError(`unrecognized color space object: "${cs}"`); - }; + } + /** * 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 @@ -384,7 +385,7 @@ var ColorSpace = (function ColorSpaceClosure() { * @param {Array} decode Decode map (usually from an image). * @param {Number} n Number of components the color space has. */ - ColorSpace.isDefaultDecode = function(decode, n) { + static isDefaultDecode(decode, n) { if (!Array.isArray(decode)) { return true; } @@ -393,28 +394,28 @@ var ColorSpace = (function ColorSpaceClosure() { warn('The decode map is not the correct length'); return true; } - for (var i = 0, ii = decode.length; i < ii; i += 2) { + for (let i = 0, ii = decode.length; i < ii; i += 2) { if (decode[i] !== 0 || decode[i + 1] !== 1) { return false; } } return true; - }; + } - ColorSpace.singletons = { - get gray() { - return shadow(this, 'gray', new DeviceGrayCS()); - }, - get rgb() { - return shadow(this, 'rgb', new DeviceRgbCS()); - }, - get cmyk() { - return shadow(this, 'cmyk', new DeviceCmykCS()); - }, - }; - - return ColorSpace; -})(); + static get singletons() { + return shadow(this, 'singletons', { + get gray() { + return shadow(this, 'gray', new DeviceGrayCS()); + }, + get rgb() { + return shadow(this, 'rgb', new DeviceRgbCS()); + }, + get cmyk() { + return shadow(this, 'cmyk', new DeviceCmykCS()); + }, + }); + } +} /** * Alternate color space handles both Separation and DeviceN color spaces. A @@ -424,114 +425,104 @@ var ColorSpace = (function ColorSpaceClosure() { * * The default color is `new Float32Array(new Array(numComps).fill(1))`. */ -var AlternateCS = (function AlternateCSClosure() { - function AlternateCS(numComps, base, tintFn) { - this.name = 'Alternate'; - this.numComps = numComps; +class AlternateCS extends ColorSpace { + constructor(numComps, base, tintFn) { + super('Alternate', numComps); this.base = base; this.tintFn = tintFn; this.tmpBuf = new Float32Array(base.numComps); } - AlternateCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'AlternateCS.getRgbItem: Unsupported "dest" type.'); - } - var tmpBuf = this.tmpBuf; - this.tintFn(src, srcOffset, tmpBuf, 0); - this.base.getRgbItem(tmpBuf, 0, dest, destOffset); - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'AlternateCS.getRgbBuffer: Unsupported "dest" type.'); - } - var tintFn = this.tintFn; - var base = this.base; - var scale = 1 / ((1 << bits) - 1); - var baseNumComps = base.numComps; - var usesZeroToOneRange = base.usesZeroToOneRange; - var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && - alpha01 === 0; - var pos = isPassthrough ? destOffset : 0; - let baseBuf = isPassthrough ? - dest : new Uint8ClampedArray(baseNumComps * count); - var numComps = this.numComps; + getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'AlternateCS.getRgbItem: Unsupported "dest" type.'); + } + let tmpBuf = this.tmpBuf; + this.tintFn(src, srcOffset, tmpBuf, 0); + this.base.getRgbItem(tmpBuf, 0, dest, destOffset); + } - var scaled = new Float32Array(numComps); - var tinted = new Float32Array(baseNumComps); - var i, j; + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'AlternateCS.getRgbBuffer: Unsupported "dest" type.'); + } + let tintFn = this.tintFn; + let base = this.base; + let scale = 1 / ((1 << bits) - 1); + let baseNumComps = base.numComps; + let usesZeroToOneRange = base.usesZeroToOneRange; + let isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && + alpha01 === 0; + let pos = isPassthrough ? destOffset : 0; + let baseBuf = isPassthrough ? + dest : new Uint8ClampedArray(baseNumComps * count); + let numComps = this.numComps; - for (i = 0; i < count; i++) { - for (j = 0; j < numComps; j++) { - scaled[j] = src[srcOffset++] * scale; - } - tintFn(scaled, 0, tinted, 0); - if (usesZeroToOneRange) { - for (j = 0; j < baseNumComps; j++) { - baseBuf[pos++] = tinted[j] * 255; - } - } else { - base.getRgbItem(tinted, 0, baseBuf, pos); - pos += baseNumComps; + let scaled = new Float32Array(numComps); + let tinted = new Float32Array(baseNumComps); + let i, j; + + for (i = 0; i < count; i++) { + for (j = 0; j < numComps; j++) { + scaled[j] = src[srcOffset++] * scale; + } + tintFn(scaled, 0, tinted, 0); + if (usesZeroToOneRange) { + for (j = 0; j < baseNumComps; j++) { + baseBuf[pos++] = tinted[j] * 255; } + } else { + base.getRgbItem(tinted, 0, baseBuf, pos); + pos += baseNumComps; } + } - if (!isPassthrough) { - base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); - } - }, - getOutputLength(inputLength, alpha01) { - return this.base.getOutputLength(inputLength * - this.base.numComps / this.numComps, - alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true, - }; + if (!isPassthrough) { + base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); + } + } - return AlternateCS; -})(); + getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * + this.base.numComps / this.numComps, + alpha01); + } -var PatternCS = (function PatternCSClosure() { - function PatternCS(baseCS) { - this.name = 'Pattern'; + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + } +} + +class PatternCS extends ColorSpace { + constructor(baseCS) { + super('Pattern', null); this.base = baseCS; } - PatternCS.prototype = {}; - - return PatternCS; -})(); +} /** * The default color is `new Uint8Array([0])`. */ -var IndexedCS = (function IndexedCSClosure() { - function IndexedCS(base, highVal, lookup) { - this.name = 'Indexed'; - this.numComps = 1; +class IndexedCS extends ColorSpace { + constructor(base, highVal, lookup) { + super('Indexed', 1); this.base = base; this.highVal = highVal; - var baseNumComps = base.numComps; - var length = baseNumComps * highVal; + let baseNumComps = base.numComps; + let length = baseNumComps * highVal; if (isStream(lookup)) { this.lookup = new Uint8Array(length); - var bytes = lookup.getBytes(length); + let bytes = lookup.getBytes(length); this.lookup.set(bytes); } else if (isString(lookup)) { this.lookup = new Uint8Array(length); - for (var i = 0; i < length; ++i) { + for (let i = 0; i < length; ++i) { this.lookup[i] = lookup.charCodeAt(i); } } else if (lookup instanceof Uint8Array) { @@ -541,157 +532,144 @@ var IndexedCS = (function IndexedCSClosure() { } } - IndexedCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'IndexedCS.getRgbItem: Unsupported "dest" type.'); - } - var numComps = this.base.numComps; - var start = src[srcOffset] * numComps; - this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'IndexedCS.getRgbBuffer: Unsupported "dest" type.'); - } - var base = this.base; - var numComps = base.numComps; - var outputDelta = base.getOutputLength(numComps, alpha01); - var lookup = this.lookup; + getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'IndexedCS.getRgbItem: Unsupported "dest" type.'); + } + let numComps = this.base.numComps; + let start = src[srcOffset] * numComps; + this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); + } - for (var i = 0; i < count; ++i) { - var lookupPos = src[srcOffset++] * numComps; - base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); - destOffset += outputDelta; - } - }, - getOutputLength(inputLength, alpha01) { - return this.base.getOutputLength(inputLength * this.base.numComps, - alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - // indexed color maps shouldn't be changed - return true; - }, - usesZeroToOneRange: true, - }; - return IndexedCS; -})(); + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'IndexedCS.getRgbBuffer: Unsupported "dest" type.'); + } + let base = this.base; + let numComps = base.numComps; + let outputDelta = base.getOutputLength(numComps, alpha01); + let lookup = this.lookup; + + for (let i = 0; i < count; ++i) { + let lookupPos = src[srcOffset++] * numComps; + base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); + destOffset += outputDelta; + } + } + + getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * this.base.numComps, alpha01); + } + + isDefaultDecode(decodeMap) { + return true; // Indexed color maps shouldn't be changed. + } +} /** * The default color is `new Float32Array([0])`. */ -var DeviceGrayCS = (function DeviceGrayCSClosure() { - function DeviceGrayCS() { - this.name = 'DeviceGray'; - this.numComps = 1; +class DeviceGrayCS extends ColorSpace { + constructor() { + super('DeviceGray', 1); } - DeviceGrayCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'DeviceGrayCS.getRgbItem: Unsupported "dest" type.'); - } - let c = src[srcOffset] * 255; - dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'DeviceGrayCS.getRgbBuffer: Unsupported "dest" type.'); - } - var scale = 255 / ((1 << bits) - 1); - var j = srcOffset, q = destOffset; - for (var i = 0; i < count; ++i) { - let c = scale * src[j++]; - dest[q++] = c; - dest[q++] = c; - dest[q++] = c; - q += alpha01; - } - }, - getOutputLength(inputLength, alpha01) { - return inputLength * (3 + alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true, - }; - return DeviceGrayCS; -})(); + getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceGrayCS.getRgbItem: Unsupported "dest" type.'); + } + let c = src[srcOffset] * 255; + dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; + } + + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceGrayCS.getRgbBuffer: Unsupported "dest" type.'); + } + let scale = 255 / ((1 << bits) - 1); + let j = srcOffset, q = destOffset; + for (let i = 0; i < count; ++i) { + let c = scale * src[j++]; + dest[q++] = c; + dest[q++] = c; + dest[q++] = c; + q += alpha01; + } + } + + getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01); + } + + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + } +} /** * The default color is `new Float32Array([0, 0, 0])`. */ -var DeviceRgbCS = (function DeviceRgbCSClosure() { - function DeviceRgbCS() { - this.name = 'DeviceRGB'; - this.numComps = 3; +class DeviceRgbCS extends ColorSpace { + constructor() { + super('DeviceRGB', 3); } - DeviceRgbCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'DeviceRgbCS.getRgbItem: Unsupported "dest" type.'); - } - dest[destOffset] = src[srcOffset] * 255; - dest[destOffset + 1] = src[srcOffset + 1] * 255; - dest[destOffset + 2] = src[srcOffset + 2] * 255; - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - if (typeof PDFJSDev === 'undefined' || - PDFJSDev.test('!PRODUCTION || TESTING')) { - assert(dest instanceof Uint8ClampedArray, - 'DeviceRgbCS.getRgbBuffer: Unsupported "dest" type.'); - } - if (bits === 8 && alpha01 === 0) { - dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); - return; - } - var scale = 255 / ((1 << bits) - 1); - var j = srcOffset, q = destOffset; - for (var i = 0; i < count; ++i) { - dest[q++] = scale * src[j++]; - dest[q++] = scale * src[j++]; - dest[q++] = scale * src[j++]; - q += alpha01; - } - }, - getOutputLength(inputLength, alpha01) { - return (inputLength * (3 + alpha01) / 3) | 0; - }, - isPassthrough(bits) { - return bits === 8; - }, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true, - }; - return DeviceRgbCS; -})(); + + getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceRgbCS.getRgbItem: Unsupported "dest" type.'); + } + dest[destOffset] = src[srcOffset] * 255; + dest[destOffset + 1] = src[srcOffset + 1] * 255; + dest[destOffset + 2] = src[srcOffset + 2] * 255; + } + + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceRgbCS.getRgbBuffer: Unsupported "dest" type.'); + } + if (bits === 8 && alpha01 === 0) { + dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); + return; + } + let scale = 255 / ((1 << bits) - 1); + let j = srcOffset, q = destOffset; + for (let i = 0; i < count; ++i) { + dest[q++] = scale * src[j++]; + dest[q++] = scale * src[j++]; + dest[q++] = scale * src[j++]; + q += alpha01; + } + } + + getOutputLength(inputLength, alpha01) { + return (inputLength * (3 + alpha01) / 3) | 0; + } + + isPassthrough(bits) { + return bits === 8; + } + + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + } +} /** * The default color is `new Float32Array([0, 0, 0, 1])`. */ -var DeviceCmykCS = (function DeviceCmykCSClosure() { +const DeviceCmykCS = (function DeviceCmykCSClosure() { // The coefficients below was found using numerical analysis: the method of // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors, // where color_value is the tabular value from the table of sampled RGB colors @@ -699,10 +677,10 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() { // CMYK color conversion using the estimation below: // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255 function convertToRgb(src, srcOffset, srcScale, dest, destOffset) { - var c = src[srcOffset] * srcScale; - var m = src[srcOffset + 1] * srcScale; - var y = src[srcOffset + 2] * srcScale; - var k = src[srcOffset + 3] * srcScale; + let c = src[srcOffset] * srcScale; + let m = src[srcOffset + 1] * srcScale; + let y = src[srcOffset + 2] * srcScale; + let k = src[srcOffset + 3] * srcScale; dest[destOffset] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + @@ -734,12 +712,11 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() { k * (-22.33816807309886 * k - 180.12613974708367); } - function DeviceCmykCS() { - this.name = 'DeviceCMYK'; - this.numComps = 4; - } - DeviceCmykCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class DeviceCmykCS extends ColorSpace { + constructor() { + super('DeviceCMYK', 4); + } + getRgbItem(src, srcOffset, dest, destOffset) { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('!PRODUCTION || TESTING')) { @@ -747,31 +724,30 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() { 'DeviceCmykCS.getRgbItem: Unsupported "dest" type.'); } convertToRgb(src, srcOffset, 1, dest, destOffset); - }, + } + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('!PRODUCTION || TESTING')) { assert(dest instanceof Uint8ClampedArray, 'DeviceCmykCS.getRgbBuffer: Unsupported "dest" type.'); } - var scale = 1 / ((1 << bits) - 1); - for (var i = 0; i < count; i++) { + let scale = 1 / ((1 << bits) - 1); + for (let i = 0; i < count; i++) { convertToRgb(src, srcOffset, scale, dest, destOffset); srcOffset += 4; destOffset += 3 + alpha01; } - }, + } + getOutputLength(inputLength, alpha01) { return (inputLength / 4 * (3 + alpha01)) | 0; - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } + isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true, - }; - + } + } return DeviceCmykCS; })(); @@ -780,61 +756,16 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() { * * The default color is `new Float32Array([0])`. */ -var CalGrayCS = (function CalGrayCSClosure() { - function CalGrayCS(whitePoint, blackPoint, gamma) { - this.name = 'CalGray'; - this.numComps = 1; - - if (!whitePoint) { - throw new FormatError( - 'WhitePoint missing - required for color space CalGray'); - } - blackPoint = blackPoint || [0, 0, 0]; - gamma = gamma || 1; - - // Translate arguments to spec variables. - this.XW = whitePoint[0]; - this.YW = whitePoint[1]; - this.ZW = whitePoint[2]; - - this.XB = blackPoint[0]; - this.YB = blackPoint[1]; - this.ZB = blackPoint[2]; - - this.G = gamma; - - // Validate variables as per spec. - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { - throw new FormatError(`Invalid WhitePoint components for ${this.name}` + - ', no fallback available'); - } - - if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - info('Invalid BlackPoint for ' + this.name + ', falling back to default'); - this.XB = this.YB = this.ZB = 0; - } - - if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { - warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + - ', ZB: ' + this.ZB + ', only default values are supported.'); - } - - if (this.G < 1) { - info('Invalid Gamma: ' + this.G + ' for ' + this.name + - ', falling back to default'); - this.G = 1; - } - } - +const CalGrayCS = (function CalGrayCSClosure() { function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { // A represents a gray component of a calibrated gray space. // A <---> AG in the spec - var A = src[srcOffset] * scale; - var AG = Math.pow(A, cs.G); + let A = src[srcOffset] * scale; + let AG = Math.pow(A, cs.G); // Computes L as per spec. ( = cs.YW * AG ) // Except if other than default BlackPoint values are used. - var L = cs.YW * AG; + let L = cs.YW * AG; // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4. // Convert values to rgb range [0, 255]. let val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0); @@ -843,8 +774,51 @@ var CalGrayCS = (function CalGrayCSClosure() { dest[destOffset + 2] = val; } - CalGrayCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class CalGrayCS extends ColorSpace { + constructor(whitePoint, blackPoint, gamma) { + super('CalGray', 1); + + if (!whitePoint) { + throw new FormatError( + 'WhitePoint missing - required for color space CalGray'); + } + blackPoint = blackPoint || [0, 0, 0]; + gamma = gamma || 1; + + // Translate arguments to spec variables. + this.XW = whitePoint[0]; + this.YW = whitePoint[1]; + this.ZW = whitePoint[2]; + + this.XB = blackPoint[0]; + this.YB = blackPoint[1]; + this.ZB = blackPoint[2]; + + this.G = gamma; + + // Validate variables as per spec. + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new FormatError(`Invalid WhitePoint components for ${this.name}` + + ', no fallback available'); + } + + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + info(`Invalid BlackPoint for ${this.name}, falling back to default.`); + this.XB = this.YB = this.ZB = 0; + } + + if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { + warn(`${this.name}, BlackPoint: XB: ${this.XB}, YB: ${this.YB}, ` + + `ZB: ${this.ZB}, only default values are supported.`); + } + + if (this.G < 1) { + info(`Invalid Gamma: ${this.G} for ${this.name}, ` + + 'falling back to default.'); + this.G = 1; + } + } + getRgbItem(src, srcOffset, dest, destOffset) { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('!PRODUCTION || TESTING')) { @@ -852,31 +826,31 @@ var CalGrayCS = (function CalGrayCSClosure() { 'CalGrayCS.getRgbItem: Unsupported "dest" type.'); } convertToRgb(this, src, srcOffset, dest, destOffset, 1); - }, + } + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('!PRODUCTION || TESTING')) { assert(dest instanceof Uint8ClampedArray, 'CalGrayCS.getRgbBuffer: Unsupported "dest" type.'); } - var scale = 1 / ((1 << bits) - 1); + let scale = 1 / ((1 << bits) - 1); - for (var i = 0; i < count; ++i) { + for (let i = 0; i < count; ++i) { convertToRgb(this, src, srcOffset, dest, destOffset, scale); srcOffset += 1; destOffset += 3 + alpha01; } - }, + } + getOutputLength(inputLength, alpha01) { return inputLength * (3 + alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } + isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true, - }; + } + } return CalGrayCS; })(); @@ -885,88 +859,32 @@ var CalGrayCS = (function CalGrayCSClosure() { * * The default color is `new Float32Array([0, 0, 0])`. */ -var CalRGBCS = (function CalRGBCSClosure() { +const CalRGBCS = (function CalRGBCSClosure() { // See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html for these // matrices. - var BRADFORD_SCALE_MATRIX = new Float32Array([ + const BRADFORD_SCALE_MATRIX = new Float32Array([ 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]); - var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([ + 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]); // See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html. - var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([ + 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]); - var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]); + const FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]); - var tempNormalizeMatrix = new Float32Array(3); - var tempConvertMatrix1 = new Float32Array(3); - var tempConvertMatrix2 = new Float32Array(3); + let tempNormalizeMatrix = new Float32Array(3); + let tempConvertMatrix1 = new Float32Array(3); + let tempConvertMatrix2 = new Float32Array(3); - var DECODE_L_CONSTANT = Math.pow(((8 + 16) / 116), 3) / 8.0; - - function CalRGBCS(whitePoint, blackPoint, gamma, matrix) { - this.name = 'CalRGB'; - this.numComps = 3; - - if (!whitePoint) { - throw new FormatError( - 'WhitePoint missing - required for color space CalRGB'); - } - blackPoint = blackPoint || new Float32Array(3); - gamma = gamma || new Float32Array([1, 1, 1]); - matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); - - // Translate arguments to spec variables. - var XW = whitePoint[0]; - var YW = whitePoint[1]; - var ZW = whitePoint[2]; - this.whitePoint = whitePoint; - - var XB = blackPoint[0]; - var YB = blackPoint[1]; - var ZB = blackPoint[2]; - this.blackPoint = blackPoint; - - this.GR = gamma[0]; - this.GG = gamma[1]; - this.GB = gamma[2]; - - this.MXA = matrix[0]; - this.MYA = matrix[1]; - this.MZA = matrix[2]; - this.MXB = matrix[3]; - this.MYB = matrix[4]; - this.MZB = matrix[5]; - this.MXC = matrix[6]; - this.MYC = matrix[7]; - this.MZC = matrix[8]; - - // Validate variables as per spec. - if (XW < 0 || ZW < 0 || YW !== 1) { - throw new FormatError(`Invalid WhitePoint components for ${this.name}` + - ', no fallback available'); - } - - if (XB < 0 || YB < 0 || ZB < 0) { - info('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB + - ', ' + ZB + '], falling back to default'); - this.blackPoint = new Float32Array(3); - } - - if (this.GR < 0 || this.GG < 0 || this.GB < 0) { - info('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB + - '] for ' + this.name + ', falling back to default'); - this.GR = this.GG = this.GB = 1; - } - } + const DECODE_L_CONSTANT = Math.pow(((8 + 16) / 116), 3) / 8.0; function matrixProduct(a, b, result) { result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; @@ -981,9 +899,9 @@ var CalRGBCS = (function CalRGBCSClosure() { } function convertToD65(sourceWhitePoint, LMS, result) { - var D65X = 0.95047; - var D65Y = 1; - var D65Z = 1.08883; + const D65X = 0.95047; + const D65Y = 1; + const D65Z = 1.08883; result[0] = LMS[0] * D65X / sourceWhitePoint[0]; result[1] = LMS[1] * D65Y / sourceWhitePoint[1]; @@ -995,7 +913,6 @@ var CalRGBCS = (function CalRGBCSClosure() { if (color <= 0.0031308) { return adjustToRange(0, 1, 12.92 * color); } - return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055); } @@ -1007,19 +924,16 @@ var CalRGBCS = (function CalRGBCSClosure() { if (L < 0) { return -decodeL(-L); } - if (L > 8.0) { return Math.pow(((L + 16) / 116), 3); } - return L * DECODE_L_CONSTANT; } function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) { // In case the blackPoint is already the default blackPoint then there is // no need to do compensation. - if (sourceBlackPoint[0] === 0 && - sourceBlackPoint[1] === 0 && + if (sourceBlackPoint[0] === 0 && sourceBlackPoint[1] === 0 && sourceBlackPoint[2] === 0) { result[0] = XYZ_Flat[0]; result[1] = XYZ_Flat[1]; @@ -1031,25 +945,25 @@ var CalRGBCS = (function CalRGBCSClosure() { // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/ // AdobeBPC.pdf. // The destination blackPoint is the default blackPoint [0, 0, 0]. - var zeroDecodeL = decodeL(0); + let zeroDecodeL = decodeL(0); - var X_DST = zeroDecodeL; - var X_SRC = decodeL(sourceBlackPoint[0]); + let X_DST = zeroDecodeL; + let X_SRC = decodeL(sourceBlackPoint[0]); - var Y_DST = zeroDecodeL; - var Y_SRC = decodeL(sourceBlackPoint[1]); + let Y_DST = zeroDecodeL; + let Y_SRC = decodeL(sourceBlackPoint[1]); - var Z_DST = zeroDecodeL; - var Z_SRC = decodeL(sourceBlackPoint[2]); + let Z_DST = zeroDecodeL; + let Z_SRC = decodeL(sourceBlackPoint[2]); - var X_Scale = (1 - X_DST) / (1 - X_SRC); - var X_Offset = 1 - X_Scale; + let X_Scale = (1 - X_DST) / (1 - X_SRC); + let X_Offset = 1 - X_Scale; - var Y_Scale = (1 - Y_DST) / (1 - Y_SRC); - var Y_Offset = 1 - Y_Scale; + let Y_Scale = (1 - Y_DST) / (1 - Y_SRC); + let Y_Offset = 1 - Y_Scale; - var Z_Scale = (1 - Z_DST) / (1 - Z_SRC); - var Z_Offset = 1 - Z_Scale; + let Z_Scale = (1 - Z_DST) / (1 - Z_SRC); + let Z_Offset = 1 - Z_Scale; result[0] = XYZ_Flat[0] * X_Scale + X_Offset; result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset; @@ -1066,20 +980,20 @@ var CalRGBCS = (function CalRGBCSClosure() { return; } - var LMS = result; + let LMS = result; matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); - var LMS_Flat = tempNormalizeMatrix; + let LMS_Flat = tempNormalizeMatrix; convertToFlat(sourceWhitePoint, LMS, LMS_Flat); matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result); } function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) { - var LMS = result; + let LMS = result; matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); - var LMS_D65 = tempNormalizeMatrix; + let LMS_D65 = tempNormalizeMatrix; convertToD65(sourceWhitePoint, LMS, LMS_D65); matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result); @@ -1088,41 +1002,41 @@ var CalRGBCS = (function CalRGBCSClosure() { function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { // A, B and C represent a red, green and blue components of a calibrated // rgb space. - var A = adjustToRange(0, 1, src[srcOffset] * scale); - var B = adjustToRange(0, 1, src[srcOffset + 1] * scale); - var C = adjustToRange(0, 1, src[srcOffset + 2] * scale); + let A = adjustToRange(0, 1, src[srcOffset] * scale); + let B = adjustToRange(0, 1, src[srcOffset + 1] * scale); + let C = adjustToRange(0, 1, src[srcOffset + 2] * scale); // A <---> AGR in the spec // B <---> BGG in the spec // C <---> CGB in the spec - var AGR = Math.pow(A, cs.GR); - var BGG = Math.pow(B, cs.GG); - var CGB = Math.pow(C, cs.GB); + let AGR = Math.pow(A, cs.GR); + let BGG = Math.pow(B, cs.GG); + let CGB = Math.pow(C, cs.GB); // Computes intermediate variables L, M, N as per spec. // To decode X, Y, Z values map L, M, N directly to them. - var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB; - var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB; - var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB; + let X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB; + let Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB; + let Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB; // The following calculations are based on this document: // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/ // AdobeBPC.pdf. - var XYZ = tempConvertMatrix1; + let XYZ = tempConvertMatrix1; XYZ[0] = X; XYZ[1] = Y; XYZ[2] = Z; - var XYZ_Flat = tempConvertMatrix2; + let XYZ_Flat = tempConvertMatrix2; normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat); - var XYZ_Black = tempConvertMatrix1; + let XYZ_Black = tempConvertMatrix1; compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black); - var XYZ_D65 = tempConvertMatrix2; + let XYZ_D65 = tempConvertMatrix2; normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65); - var SRGB = tempConvertMatrix1; + let SRGB = tempConvertMatrix1; matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB); // Convert the values to rgb range [0, 255]. @@ -1131,8 +1045,62 @@ var CalRGBCS = (function CalRGBCSClosure() { dest[destOffset + 2] = sRGBTransferFunction(SRGB[2]) * 255; } - CalRGBCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class CalRGBCS extends ColorSpace { + constructor(whitePoint, blackPoint, gamma, matrix) { + super('CalRGB', 3); + + if (!whitePoint) { + throw new FormatError( + 'WhitePoint missing - required for color space CalRGB'); + } + blackPoint = blackPoint || new Float32Array(3); + gamma = gamma || new Float32Array([1, 1, 1]); + matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); + + // Translate arguments to spec variables. + let XW = whitePoint[0]; + let YW = whitePoint[1]; + let ZW = whitePoint[2]; + this.whitePoint = whitePoint; + + let XB = blackPoint[0]; + let YB = blackPoint[1]; + let ZB = blackPoint[2]; + this.blackPoint = blackPoint; + + this.GR = gamma[0]; + this.GG = gamma[1]; + this.GB = gamma[2]; + + this.MXA = matrix[0]; + this.MYA = matrix[1]; + this.MZA = matrix[2]; + this.MXB = matrix[3]; + this.MYB = matrix[4]; + this.MZB = matrix[5]; + this.MXC = matrix[6]; + this.MYC = matrix[7]; + this.MZC = matrix[8]; + + // Validate variables as per spec. + if (XW < 0 || ZW < 0 || YW !== 1) { + throw new FormatError(`Invalid WhitePoint components for ${this.name}` + + ', no fallback available'); + } + + if (XB < 0 || YB < 0 || ZB < 0) { + info(`Invalid BlackPoint for ${this.name} [${XB}, ${YB}, ${ZB}], ` + + 'falling back to default.'); + this.blackPoint = new Float32Array(3); + } + + if (this.GR < 0 || this.GG < 0 || this.GB < 0) { + info(`Invalid Gamma [${this.GR}, ${this.GG}, ${this.GB}] for ` + + `${this.name}, falling back to default.`); + this.GR = this.GG = this.GB = 1; + } + } + getRgbItem(src, srcOffset, dest, destOffset) { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('!PRODUCTION || TESTING')) { @@ -1140,31 +1108,31 @@ var CalRGBCS = (function CalRGBCSClosure() { 'CalRGBCS.getRgbItem: Unsupported "dest" type.'); } convertToRgb(this, src, srcOffset, dest, destOffset, 1); - }, + } + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('!PRODUCTION || TESTING')) { assert(dest instanceof Uint8ClampedArray, 'CalRGBCS.getRgbBuffer: Unsupported "dest" type.'); } - var scale = 1 / ((1 << bits) - 1); + let scale = 1 / ((1 << bits) - 1); - for (var i = 0; i < count; ++i) { + for (let i = 0; i < count; ++i) { convertToRgb(this, src, srcOffset, dest, destOffset, scale); srcOffset += 3; destOffset += 3 + alpha01; } - }, + } + getOutputLength(inputLength, alpha01) { return (inputLength * (3 + alpha01) / 3) | 0; - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } + isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true, - }; + } + } return CalRGBCS; })(); @@ -1173,56 +1141,10 @@ var CalRGBCS = (function CalRGBCSClosure() { * * The default color is `new Float32Array([0, 0, 0])`. */ -var LabCS = (function LabCSClosure() { - function LabCS(whitePoint, blackPoint, range) { - this.name = 'Lab'; - this.numComps = 3; - - if (!whitePoint) { - throw new FormatError( - 'WhitePoint missing - required for color space Lab'); - } - blackPoint = blackPoint || [0, 0, 0]; - range = 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; - } - } - +const LabCS = (function LabCSClosure() { // Function g(x) from spec function fn_g(x) { - var result; + let result; if (x >= 6 / 29) { result = x * x * x; } else { @@ -1243,9 +1165,9 @@ var LabCS = (function LabCSClosure() { // converting an image we have to map the values to the correct range given // above. // Ls,as,bs <---> L*,a*,b* in the spec - var Ls = src[srcOffset]; - var as = src[srcOffset + 1]; - var bs = src[srcOffset + 2]; + let Ls = src[srcOffset]; + 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); @@ -1257,15 +1179,15 @@ var LabCS = (function LabCSClosure() { bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs; // Computes intermediate variables X,Y,Z as per spec - var M = (Ls + 16) / 116; - var L = M + (as / 500); - var N = M - (bs / 200); + let M = (Ls + 16) / 116; + let L = M + (as / 500); + let N = M - (bs / 200); - var X = cs.XW * fn_g(L); - var Y = cs.YW * fn_g(M); - var Z = cs.ZW * fn_g(N); + let X = cs.XW * fn_g(L); + let Y = cs.YW * fn_g(M); + let Z = cs.ZW * fn_g(N); - var r, g, b; + let r, g, b; // Using different conversions for D50 and D65 white points, // per http://www.color.org/srgb.pdf if (cs.ZW < 1) { @@ -1285,8 +1207,52 @@ var LabCS = (function LabCSClosure() { dest[destOffset + 2] = Math.sqrt(b) * 255; } - LabCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class LabCS extends ColorSpace { + constructor(whitePoint, blackPoint, range) { + super('Lab', 3); + + if (!whitePoint) { + throw new FormatError( + 'WhitePoint missing - required for color space Lab'); + } + blackPoint = blackPoint || [0, 0, 0]; + range = 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('!PRODUCTION || TESTING')) { @@ -1294,32 +1260,36 @@ var LabCS = (function LabCSClosure() { '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('!PRODUCTION || TESTING')) { assert(dest instanceof Uint8ClampedArray, 'LabCS.getRgbBuffer: Unsupported "dest" type.'); } - var maxVal = (1 << bits) - 1; - for (var i = 0; i < count; i++) { + let 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; - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } + isDefaultDecode(decodeMap) { // XXX: Decoding is handled with the lab conversion because of the strange // ranges that are used. return true; - }, - usesZeroToOneRange: false, - }; + } + + get usesZeroToOneRange() { + return shadow(this, 'usesZeroToOneRange', false); + } + } return LabCS; })();