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
JavaScript
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