UNPKG

image-in-browser

Version:

Package for encoding / decoding images, transforming images, applying filters, drawing primitives on images on the client side (no need for server Node.js)

537 lines 17.3 kB
import { MathUtils } from '../common/math-utils.js'; import { LibError } from '../error/lib-error.js'; import { ColorFloat16 } from './color-float16.js'; import { ColorFloat32 } from './color-float32.js'; import { ColorFloat64 } from './color-float64.js'; import { ColorInt16 } from './color-int16.js'; import { ColorInt32 } from './color-int32.js'; import { ColorInt8 } from './color-int8.js'; import { ColorUint1 } from './color-uint1.js'; import { ColorUint16 } from './color-uint16.js'; import { ColorUint2 } from './color-uint2.js'; import { ColorUint32 } from './color-uint32.js'; import { ColorUint4 } from './color-uint4.js'; import { ColorUint8 } from './color-uint8.js'; import { convertFormatValue, Format } from './format.js'; export class ColorUtils { static convertColorInternal(c, c2, a) { var _a, _d; const numChannels = c2.length; const format = c2.format; const fromFormat = (_d = (_a = c.palette) === null || _a === void 0 ? void 0 : _a.format) !== null && _d !== void 0 ? _d : c.format; const cl = c.length; if (numChannels === 1) { const g = Math.trunc(c.length > 2 ? c.luminance : c.getChannel(0)); c2.setChannel(0, convertFormatValue(g, fromFormat, format)); } else if (numChannels <= cl) { for (let ci = 0; ci < numChannels; ++ci) { c2.setChannel(ci, convertFormatValue(c.getChannel(ci), fromFormat, format)); } } else { if (cl === 2) { const l = convertFormatValue(c.getChannel(0), fromFormat, format); if (numChannels === 3) { c2.setChannel(0, l); c2.setChannel(1, l); c2.setChannel(2, l); } else { const a = convertFormatValue(c.getChannel(1), fromFormat, format); c2.setChannel(0, l); c2.setChannel(1, l); c2.setChannel(2, l); c2.setChannel(3, a); } } else { for (let ci = 0; ci < cl; ++ci) { c2.setChannel(ci, convertFormatValue(c.getChannel(ci), fromFormat, format)); } const v = cl === 1 ? c2.getChannel(0) : 0; for (let ci = cl; ci < numChannels; ++ci) { c2.setChannel(ci, ci === 3 ? a : v); } } } return c2; } static uint32ToRed(c) { return c & 0xff; } static uint32ToGreen(c) { return (c >>> 8) & 0xff; } static uint32ToBlue(c) { return (c >>> 16) & 0xff; } static uint32ToAlpha(c) { return (c >>> 24) & 0xff; } static rgbaToUint32(r, g, b, a) { return (MathUtils.clampInt255(r) | (MathUtils.clampInt255(g) << 8) | (MathUtils.clampInt255(b) << 16) | (MathUtils.clampInt255(a) << 24)); } static convertColor(opt) { var _a, _d, _e, _f, _j, _l, _o, _p, _q, _s, _u, _v, _w, _0, _1, _2, _3, _4, _5, _6, _7; const fromFormat = (_d = (_a = opt.from.palette) === null || _a === void 0 ? void 0 : _a.format) !== null && _d !== void 0 ? _d : opt.from.format; const format = (_j = (_f = (_e = opt.to) === null || _e === void 0 ? void 0 : _e.format) !== null && _f !== void 0 ? _f : opt.format) !== null && _j !== void 0 ? _j : opt.from.format; const numChannels = (_p = (_o = (_l = opt.to) === null || _l === void 0 ? void 0 : _l.length) !== null && _o !== void 0 ? _o : opt.numChannels) !== null && _p !== void 0 ? _p : opt.from.length; const alpha = (_q = opt.alpha) !== null && _q !== void 0 ? _q : 0; if (format === fromFormat && numChannels === opt.from.length) { if (opt.to === undefined) { return opt.from.clone(); } opt.to.set(opt.from); return opt.to; } switch (format) { case Format.uint8: { const c2 = (_s = opt.to) !== null && _s !== void 0 ? _s : new ColorUint8(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.uint1: { const c2 = (_u = opt.to) !== null && _u !== void 0 ? _u : new ColorUint1(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.uint2: { const c2 = (_v = opt.to) !== null && _v !== void 0 ? _v : new ColorUint2(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.uint4: { const c2 = (_w = opt.to) !== null && _w !== void 0 ? _w : new ColorUint4(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.uint16: { const c2 = (_0 = opt.to) !== null && _0 !== void 0 ? _0 : new ColorUint16(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.uint32: { const c2 = (_1 = opt.to) !== null && _1 !== void 0 ? _1 : new ColorUint32(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.int8: { const c2 = (_2 = opt.to) !== null && _2 !== void 0 ? _2 : new ColorInt8(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.int16: { const c2 = (_3 = opt.to) !== null && _3 !== void 0 ? _3 : new ColorInt16(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.int32: { const c2 = (_4 = opt.to) !== null && _4 !== void 0 ? _4 : new ColorInt32(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.float16: { const c2 = (_5 = opt.to) !== null && _5 !== void 0 ? _5 : new ColorFloat16(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.float32: { const c2 = (_6 = opt.to) !== null && _6 !== void 0 ? _6 : new ColorFloat32(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } case Format.float64: { const c2 = (_7 = opt.to) !== null && _7 !== void 0 ? _7 : new ColorFloat64(numChannels); return this.convertColorInternal(opt.from, c2, alpha); } } throw new LibError('Unknown format.'); } static getLuminance(c) { return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; } static getLuminanceNormalized(c) { return (0.299 * c.rNormalized + 0.587 * c.gNormalized + 0.114 * c.bNormalized); } static getLuminanceRgb(r, g, b) { return 0.299 * r + 0.587 * g + 0.114 * b; } static hslToRgb(hue, saturation, lightness, rgb) { if (saturation === 0) { const gray = Math.trunc(lightness * 255); rgb[0] = gray; rgb[1] = gray; rgb[2] = gray; return; } const hue2rgb = (p, q, t) => { let _t = t; if (_t < 0) { _t += 1; } if (_t > 1) { _t -= 1; } if (_t < 1 / 6) { return p + (q - p) * 6 * _t; } if (_t < 1 / 2) { return q; } if (_t < 2 / 3) { return p + (q - p) * (2 / 3 - _t) * 6; } return p; }; const q = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation; const p = 2 * lightness - q; const r = hue2rgb(p, q, hue + 1 / 3); const g = hue2rgb(p, q, hue); const b = hue2rgb(p, q, hue - 1 / 3); rgb[0] = Math.round(r * 255); rgb[1] = Math.round(g * 255); rgb[2] = Math.round(b * 255); } static rgbToHsv(r, g, b, hsv) { const minCh = Math.min(r, Math.min(g, b)); const maxCh = Math.max(r, Math.max(g, b)); const delta = maxCh - minCh; if (maxCh === 0 || delta === 0) { hsv[0] = 0; hsv[1] = 0; hsv[2] = 0; return; } let h = 0; let s = 0; let v = 0; v = maxCh; s = delta / maxCh; if (r === maxCh) { h = (g - b) / delta; } else if (g === maxCh) { h = 2 + (b - r) / delta; } else { h = 4 + (r - g) / delta; } h *= 60; if (h < 0) { h += 360; } hsv[0] = h; hsv[1] = s; hsv[2] = v; } static hsvToRgb(h, s, v, rgb) { let _h = h; if (s === 0) { const g = MathUtils.clamp(v, 0, 1); rgb[0] = g; rgb[1] = g; rgb[2] = g; return; } while (h < 0) { _h += 360; } while (h > 360) { _h -= 360; } _h /= 60; const i = Math.floor(_h); const f = _h - i; const p = MathUtils.clamp(v * (1 - s), 0, 1); const q = MathUtils.clamp(v * (1 - s * f), 0, 1); const t = MathUtils.clamp(v * (1 - s * (1 - f)), 0, 1); switch (i) { case 0: rgb[0] = v; rgb[1] = t; rgb[2] = p; return; case 1: rgb[0] = q; rgb[1] = v; rgb[2] = p; return; case 2: rgb[0] = p; rgb[1] = v; rgb[2] = t; return; case 3: rgb[0] = p; rgb[1] = q; rgb[2] = v; return; case 4: rgb[0] = t; rgb[1] = p; rgb[2] = v; return; default: rgb[0] = v; rgb[1] = p; rgb[2] = q; return; } } static rgbToHsl(r, g, b) { const _r = r / 255; const _g = g / 255; const _b = b / 255; const mx = Math.max(_r, Math.max(_g, _b)); const mn = Math.min(_r, Math.min(_g, _b)); const l = (mx + mn) / 2; if (mx === mn) { return [0, 0, l]; } const d = mx - mn; const s = l > 0.5 ? d / (2 - mx - mn) : d / (mx + mn); let h = 0; if (mx === _r) { h = (_g - _b) / d + (_g < _b ? 6 : 0); } else if (mx === _g) { h = (_b - _r) / d + 2; } else { h = (_r - _g) / d + 4; } h /= 6; return [h, s, l]; } static labToXyz(l, a, b) { let y = (l + 16) / 116; let x = y + a / 500; let z = y - b / 200; if (Math.pow(x, 3) > 0.008856) { x = Math.pow(x, 3); } else { x = (x - 16 / 116) / 7.787; } if (Math.pow(y, 3) > 0.008856) { y = Math.pow(y, 3); } else { y = (y - 16 / 116) / 7.787; } if (Math.pow(z, 3) > 0.008856) { z = Math.pow(z, 3); } else { z = (z - 16 / 116) / 7.787; } return [ Math.trunc(x * 95.047), Math.trunc(y * 100), Math.trunc(z * 108.883), ]; } static xyzToRgb(x, y, z) { const _x = x / 100; const _y = y / 100; const _z = z / 100; let r = 3.2406 * _x + -1.5372 * _y + -0.4986 * _z; let g = -0.9689 * _x + 1.8758 * _y + 0.0415 * _z; let b = 0.0557 * _x + -0.204 * _y + 1.057 * _z; if (r > 0.0031308) { r = 1.055 * Math.pow(r, 0.4166666667) - 0.055; } else { r *= 12.92; } if (g > 0.0031308) { g = 1.055 * Math.pow(g, 0.4166666667) - 0.055; } else { g *= 12.92; } if (b > 0.0031308) { b = 1.055 * Math.pow(b, 0.4166666667) - 0.055; } else { b *= 12.92; } return [ MathUtils.clampInt255(r * 255), MathUtils.clampInt255(g * 255), MathUtils.clampInt255(b * 255), ]; } static cmykToRgb(c, m, y, k, rgb) { const _c = c / 255; const _m = m / 255; const _y = y / 255; const _k = k / 255; rgb[0] = Math.round(255 * (1 - _c) * (1 - _k)); rgb[1] = Math.round(255 * (1 - _m) * (1 - _k)); rgb[2] = Math.round(255 * (1 - _y) * (1 - _k)); } static labToRgb(l, a, b) { const refX = 95.047; const refY = 100.0; const refZ = 108.883; let y = (l + 16) / 116; let x = a / 500 + y; let z = y - b / 200; const y3 = Math.pow(y, 3); if (y3 > 0.008856) { y = y3; } else { y = (y - 16 / 116) / 7.787; } const x3 = Math.pow(x, 3); if (x3 > 0.008856) { x = x3; } else { x = (x - 16 / 116) / 7.787; } const z3 = Math.pow(z, 3); if (z3 > 0.008856) { z = z3; } else { z = (z - 16 / 116) / 7.787; } x *= refX; y *= refY; z *= refZ; x /= 100; y /= 100; z /= 100; let R = x * 3.2406 + y * -1.5372 + z * -0.4986; let G = x * -0.9689 + y * 1.8758 + z * 0.0415; let B = x * 0.0557 + y * -0.204 + z * 1.057; if (R > 0.0031308) { R = 1.055 * Math.pow(R, 1 / 2.4) - 0.055; } else { R *= 12.92; } if (G > 0.0031308) { G = 1.055 * Math.pow(G, 1 / 2.4) - 0.055; } else { G *= 12.92; } if (B > 0.0031308) { B = 1.055 * Math.pow(B, 1 / 2.4) - 0.055; } else { B *= 12.92; } return [ MathUtils.clampInt255(R * 255), MathUtils.clampInt255(G * 255), MathUtils.clampInt255(B * 255), ]; } static rgbToXyz(r, g, b) { let _r = r / 255; let _g = g / 255; let _b = b / 255; if (_r > 0.04045) { _r = Math.pow((_r + 0.055) / 1.055, 2.4); } else { _r /= 12.92; } if (_g > 0.04045) { _g = Math.pow((_g + 0.055) / 1.055, 2.4); } else { _g /= 12.92; } if (_b > 0.04045) { _b = Math.pow((_b + 0.055) / 1.055, 2.4); } else { _b /= 12.92; } _r *= 100; _g *= 100; _b *= 100; return [ _r * 0.4124 + _g * 0.3576 + _b * 0.1805, _r * 0.2126 + _g * 0.7152 + _b * 0.0722, _r * 0.0193 + _g * 0.1192 + _b * 0.9505, ]; } static xyzToLab(x, y, z) { let _x = x / 95.047; let _y = y / 100; let _z = z / 108.883; if (_x > 0.008856) { _x = Math.pow(_x, 1 / 3); } else { _x = 7.787 * _x + 16 / 116; } if (_y > 0.008856) { _y = Math.pow(_y, 1 / 3); } else { _y = 7.787 * _y + 16 / 116; } if (_z > 0.008856) { _z = Math.pow(_z, 1 / 3); } else { _z = 7.787 * _z + 16 / 116; } return [116 * _y - 16, 500 * (_x - _y), 200 * (_y - _z)]; } static rgbToLab(r, g, b) { let _r = r / 255; let _g = g / 255; let _b = b / 255; if (_r > 0.04045) { _r = Math.pow((_r + 0.055) / 1.055, 2.4); } else { _r /= 12.92; } if (_g > 0.04045) { _g = Math.pow((_g + 0.055) / 1.055, 2.4); } else { _g /= 12.92; } if (_b > 0.04045) { _b = Math.pow((_b + 0.055) / 1.055, 2.4); } else { _b /= 12.92; } _r *= 100; _g *= 100; _b *= 100; let x = _r * 0.4124 + _g * 0.3576 + _b * 0.1805; let y = _r * 0.2126 + _g * 0.7152 + _b * 0.0722; let z = _r * 0.0193 + _g * 0.1192 + _b * 0.9505; x /= 95.047; y /= 100; z /= 108.883; if (x > 0.008856) { x = Math.pow(x, 1 / 3); } else { x = 7.787 * x + 16 / 116; } if (y > 0.008856) { y = Math.pow(y, 1 / 3); } else { y = 7.787 * y + 16 / 116; } if (z > 0.008856) { z = Math.pow(z, 1 / 3); } else { z = 7.787 * z + 16 / 116; } return [116 * y - 16, 500 * (x - y), 200 * (y - z)]; } } //# sourceMappingURL=color-utils.js.map