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)
900 lines • 37.7 kB
JavaScript
import { ChannelOrder, ChannelOrderLength } from '../color/channel-order.js';
import { ColorUint8 } from '../color/color-uint8.js';
import { ColorUtils } from '../color/color-utils.js';
import { Format, FormatMaxValue, FormatType, getRowStride, } from '../color/format.js';
import { ArrayUtils } from '../common/array-utils.js';
import { Interpolation } from '../common/interpolation.js';
import { MathUtils } from '../common/math-utils.js';
import { LibError } from '../error/lib-error.js';
import { ExifData } from '../exif/exif-data.js';
import { FrameType } from './frame-type.js';
import { MemoryImageDataFloat16 } from './image-data-float16.js';
import { MemoryImageDataFloat32 } from './image-data-float32.js';
import { MemoryImageDataFloat64 } from './image-data-float64.js';
import { MemoryImageDataInt16 } from './image-data-int16.js';
import { MemoryImageDataInt32 } from './image-data-int32.js';
import { MemoryImageDataInt8 } from './image-data-int8.js';
import { MemoryImageDataUint1 } from './image-data-uint1.js';
import { MemoryImageDataUint16 } from './image-data-uint16.js';
import { MemoryImageDataUint2 } from './image-data-uint2.js';
import { MemoryImageDataUint32 } from './image-data-uint32.js';
import { MemoryImageDataUint4 } from './image-data-uint4.js';
import { MemoryImageDataUint8 } from './image-data-uint8.js';
import { PaletteFloat16 } from './palette-float16.js';
import { PaletteFloat32 } from './palette-float32.js';
import { PaletteFloat64 } from './palette-float64.js';
import { PaletteInt16 } from './palette-int16.js';
import { PaletteInt32 } from './palette-int32.js';
import { PaletteInt8 } from './palette-int8.js';
import { PaletteUint16 } from './palette-uint16.js';
import { PaletteUint32 } from './palette-uint32.js';
import { PaletteUint8 } from './palette-uint8.js';
import { UndefinedPixel } from './pixel.js';
export class MemoryImage {
get data() {
return this._data;
}
get format() {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.format) !== null && _b !== void 0 ? _b : Format.uint8;
}
get hasPalette() {
var _a;
return ((_a = this._data) === null || _a === void 0 ? void 0 : _a.palette) !== undefined;
}
get palette() {
var _a;
return (_a = this._data) === null || _a === void 0 ? void 0 : _a.palette;
}
set palette(p) {
if (this._data !== undefined) {
this._data.palette = p;
}
}
get numChannels() {
var _a, _b, _c, _d;
return (_d = (_b = (_a = this.palette) === null || _a === void 0 ? void 0 : _a.numChannels) !== null && _b !== void 0 ? _b : (_c = this._data) === null || _c === void 0 ? void 0 : _c.numChannels) !== null && _d !== void 0 ? _d : 0;
}
get hasAnimation() {
return this._frames.length > 1;
}
get numFrames() {
return this._frames.length;
}
get exifData() {
var _a;
(_a = this._exifData) !== null && _a !== void 0 ? _a : (this._exifData = new ExifData());
return this._exifData;
}
set exifData(exif) {
this._exifData = exif;
}
get maxChannelValue() {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.maxChannelValue) !== null && _b !== void 0 ? _b : 0;
}
get maxIndexValue() {
var _a, _b;
return (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.maxIndexValue) !== null && _b !== void 0 ? _b : 0;
}
get supportsPalette() {
return (this.format === Format.uint1 ||
this.format === Format.uint2 ||
this.format === Format.uint4 ||
this.format === Format.uint8 ||
this.format === Format.uint16);
}
get width() {
var _a, _b;
return (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : 0;
}
get height() {
var _a, _b;
return (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : 0;
}
get formatType() {
var _a, _b;
return (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.formatType) !== null && _b !== void 0 ? _b : FormatType.uint;
}
get isValid() {
return this._data !== undefined && this.width > 0 && this.height > 0;
}
get buffer() {
var _a;
return (_a = this._data) === null || _a === void 0 ? void 0 : _a.buffer;
}
get byteLength() {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.buffer.byteLength) !== null && _b !== void 0 ? _b : 0;
}
get rowStride() {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.rowStride) !== null && _b !== void 0 ? _b : 0;
}
get isLdrFormat() {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.isLdrFormat) !== null && _b !== void 0 ? _b : false;
}
get isHdrFormat() {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.isHdrFormat) !== null && _b !== void 0 ? _b : false;
}
get bitsPerChannel() {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.bitsPerChannel) !== null && _b !== void 0 ? _b : 0;
}
get hasAlpha() {
return this.numChannels === 2 || this.numChannels === 4;
}
get iccProfile() {
return this._iccProfile;
}
set iccProfile(v) {
this._iccProfile = v;
}
get textData() {
return this._textData;
}
get backgroundColor() {
return this._backgroundColor;
}
set backgroundColor(v) {
this._backgroundColor = v;
}
get loopCount() {
return this._loopCount;
}
set loopCount(v) {
this._loopCount = v;
}
get frameType() {
return this._frameType;
}
set frameType(v) {
this._frameType = v;
}
get frames() {
return this._frames;
}
get frameDuration() {
return this._frameDuration;
}
set frameDuration(v) {
this._frameDuration = v;
}
get frameIndex() {
return this._frameIndex;
}
set frameIndex(v) {
this._frameIndex = v;
}
constructor(opt) {
var _a, _b, _c, _d, _e, _f, _g, _h;
this._frames = [];
if (opt !== undefined) {
this._loopCount = (_a = opt.loopCount) !== null && _a !== void 0 ? _a : 0;
this._frameType = (_b = opt.frameType) !== null && _b !== void 0 ? _b : FrameType.sequence;
this._frameDuration = (_c = opt.frameDuration) !== null && _c !== void 0 ? _c : 0;
this._frameIndex = (_d = opt.frameIndex) !== null && _d !== void 0 ? _d : 0;
this._backgroundColor = opt.backgroundColor;
this._textData = opt.textData;
this._frames.push(this);
this.initialize({
width: opt.width,
height: opt.height,
format: (_e = opt.format) !== null && _e !== void 0 ? _e : Format.uint8,
numChannels: (_f = opt.numChannels) !== null && _f !== void 0 ? _f : 3,
withPalette: (_g = opt.withPalette) !== null && _g !== void 0 ? _g : false,
paletteFormat: (_h = opt.paletteFormat) !== null && _h !== void 0 ? _h : Format.uint8,
palette: opt.palette,
exifData: opt.exifData,
iccProfile: opt.iccProfile,
});
}
else {
this._loopCount = 0;
this._frameType = FrameType.sequence;
this._frameDuration = 0;
this._frameIndex = 0;
}
}
static getNumPixelColors(format) {
return format === Format.uint1
? 2
: format === Format.uint2
? 4
: format === Format.uint4
? 16
: format === Format.uint8
? 256
: format === Format.uint16
? 65536
: 0;
}
static fromResized(other, width, height, skipAnimation = false) {
var _a, _b, _c, _d;
const image = new MemoryImage({
width: width,
height: height,
loopCount: other._loopCount,
frameType: other._frameType,
frameDuration: other._frameDuration,
frameIndex: other._frameIndex,
backgroundColor: (_a = other._backgroundColor) === null || _a === void 0 ? void 0 : _a.clone(),
format: other.format,
numChannels: other.numChannels,
withPalette: other.hasPalette,
paletteFormat: (_b = other.palette) === null || _b === void 0 ? void 0 : _b.format,
palette: other.palette,
exifData: (_c = other._exifData) === null || _c === void 0 ? void 0 : _c.clone(),
iccProfile: (_d = other._iccProfile) === null || _d === void 0 ? void 0 : _d.clone(),
textData: other._textData !== undefined
? new Map(other._textData)
: undefined,
});
if (other._extraChannels !== undefined) {
image._extraChannels = new Map(other._extraChannels);
}
if (!skipAnimation) {
const numFrames = other.numFrames;
for (let fi = 1; fi < numFrames; ++fi) {
const frame = other._frames[fi];
image.addFrame(MemoryImage.fromResized(frame, width, height));
}
}
return image;
}
static from(other, skipAnimation = false, skipPixels = false) {
var _a, _b, _c, _d;
const image = new MemoryImage();
image._data = (_a = other.data) === null || _a === void 0 ? void 0 : _a.clone(skipPixels);
image._exifData = (_b = other._exifData) === null || _b === void 0 ? void 0 : _b.clone();
image._iccProfile = (_c = other.iccProfile) === null || _c === void 0 ? void 0 : _c.clone();
image._frameType = other.frameType;
image._loopCount = other._loopCount;
image._backgroundColor = (_d = other._backgroundColor) === null || _d === void 0 ? void 0 : _d.clone();
image._frameDuration = other._frameDuration;
image._frameIndex = other._frameIndex;
if (other._extraChannels !== undefined) {
image._extraChannels = new Map(other._extraChannels);
}
if (other._textData !== undefined) {
image._textData = new Map(other.textData);
}
image._frames.push(image);
if (!skipAnimation && other.hasAnimation) {
const numFrames = other.numFrames;
for (let fi = 1; fi < numFrames; ++fi) {
const frame = other._frames[fi];
image.addFrame(MemoryImage.from(frame));
}
}
return image;
}
static fromBytes(opt) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
const byteOffset = (_a = opt.byteOffset) !== null && _a !== void 0 ? _a : 0;
const image = new MemoryImage();
image._loopCount = (_b = opt.loopCount) !== null && _b !== void 0 ? _b : 0;
image._frameType = (_c = opt.frameType) !== null && _c !== void 0 ? _c : FrameType.sequence;
image._frameDuration = (_d = opt.frameDuration) !== null && _d !== void 0 ? _d : 0;
image._frameIndex = (_e = opt.frameIndex) !== null && _e !== void 0 ? _e : 0;
image._backgroundColor = opt.backgroundColor;
image._textData = opt.textData;
image._frames.push(image);
const format = (_f = opt.format) !== null && _f !== void 0 ? _f : Format.uint8;
const withPalette = (_g = opt.withPalette) !== null && _g !== void 0 ? _g : false;
const paletteFormat = (_h = opt.paletteFormat) !== null && _h !== void 0 ? _h : Format.uint8;
const numChannels = (_j = opt.numChannels) !== null && _j !== void 0 ? _j : (opt.channelOrder !== undefined
? ChannelOrderLength.get(opt.channelOrder)
: 3);
if (numChannels < 0 || numChannels > 4) {
throw new LibError('A MemoryImage can only have 1-4 channels.');
}
let channelOrder = (_k = opt.channelOrder) !== null && _k !== void 0 ? _k : (numChannels === 3
? ChannelOrder.rgb
: numChannels === 4
? ChannelOrder.rgba
: numChannels === 1
? ChannelOrder.red
: ChannelOrder.grayAlpha);
if (numChannels === 1) {
channelOrder = ChannelOrder.red;
}
else if (numChannels === 2) {
channelOrder = ChannelOrder.grayAlpha;
}
else if (numChannels === 3) {
if (channelOrder !== ChannelOrder.rgb &&
channelOrder !== ChannelOrder.bgr) {
channelOrder = ChannelOrder.rgb;
}
}
else if (numChannels === 4) {
if (channelOrder !== ChannelOrder.bgra &&
channelOrder !== ChannelOrder.rgba &&
channelOrder !== ChannelOrder.abgr &&
channelOrder !== ChannelOrder.argb) {
channelOrder = ChannelOrder.rgba;
}
}
image.initialize({
width: opt.width,
height: opt.height,
format: format,
numChannels: numChannels,
withPalette: withPalette,
paletteFormat: paletteFormat,
palette: opt.palette,
exifData: opt.exifData,
iccProfile: opt.iccProfile,
});
if (image.data !== undefined) {
const toBytes = image.data.toUint8Array();
const fromBytes = new Uint8Array(opt.bytes, byteOffset);
const rowStride = (_l = opt.rowStride) !== null && _l !== void 0 ? _l : getRowStride(opt.width, numChannels, format);
const dataStride = image.data.rowStride;
const stride = Math.min(rowStride, dataStride);
let dOff = 0;
let bOff = 0;
for (let y = 0; y < opt.height; ++y, bOff += rowStride, dOff += dataStride) {
ArrayUtils.copyRange(fromBytes, bOff, toBytes, dOff, stride);
}
if (numChannels === 3 && channelOrder === ChannelOrder.bgr) {
for (const p of image) {
const r = p.r;
p.r = p.b;
p.b = r;
}
}
else if (numChannels === 4 && channelOrder === ChannelOrder.abgr) {
for (const p of image) {
const r = p.r;
const g = p.g;
const b = p.b;
const a = p.a;
p.r = a;
p.g = b;
p.b = g;
p.a = r;
}
}
else if (numChannels === 4 && channelOrder === ChannelOrder.argb) {
for (const p of image) {
const r = p.r;
const g = p.g;
const b = p.b;
const a = p.a;
p.r = a;
p.g = r;
p.b = g;
p.a = b;
}
}
else if (numChannels === 4 && channelOrder === ChannelOrder.bgra) {
for (const p of image) {
const r = p.r;
const g = p.g;
const b = p.b;
const a = p.a;
p.r = b;
p.g = g;
p.b = r;
p.a = a;
}
}
}
return image;
}
initialize(opt) {
var _a, _b, _c, _d, _e;
const format = (_a = opt.format) !== null && _a !== void 0 ? _a : Format.uint8;
const numChannels = (_b = opt.numChannels) !== null && _b !== void 0 ? _b : 3;
const withPalette = (_c = opt.withPalette) !== null && _c !== void 0 ? _c : false;
const paletteFormat = (_d = opt.paletteFormat) !== null && _d !== void 0 ? _d : Format.uint8;
this._iccProfile = opt.iccProfile;
if (opt.exifData !== undefined) {
this._exifData = opt.exifData.clone();
}
const palette = (_e = opt.palette) !== null && _e !== void 0 ? _e : (withPalette && this.supportsPalette
? this.createPalette(format, paletteFormat, numChannels)
: undefined);
this.createImageData(opt.width, opt.height, format, numChannels, palette);
}
createImageData(width, height, format, numChannels, palette) {
switch (format) {
case Format.uint1:
if (palette === undefined) {
this._data = new MemoryImageDataUint1(width, height, numChannels);
}
else {
this._data = MemoryImageDataUint1.palette(width, height, palette);
}
break;
case Format.uint2:
if (palette === undefined) {
this._data = new MemoryImageDataUint2(width, height, numChannels);
}
else {
this._data = MemoryImageDataUint2.palette(width, height, palette);
}
break;
case Format.uint4:
if (palette === undefined) {
this._data = new MemoryImageDataUint4(width, height, numChannels);
}
else {
this._data = MemoryImageDataUint4.palette(width, height, palette);
}
break;
case Format.uint8:
if (palette === undefined) {
this._data = new MemoryImageDataUint8(width, height, numChannels);
}
else {
this._data = MemoryImageDataUint8.palette(width, height, palette);
}
break;
case Format.uint16:
if (palette === undefined) {
this._data = new MemoryImageDataUint16(width, height, numChannels);
}
else {
this._data = MemoryImageDataUint16.palette(width, height, palette);
}
break;
case Format.uint32:
this._data = new MemoryImageDataUint32(width, height, numChannels);
break;
case Format.int8:
this._data = new MemoryImageDataInt8(width, height, numChannels);
break;
case Format.int16:
this._data = new MemoryImageDataInt16(width, height, numChannels);
break;
case Format.int32:
this._data = new MemoryImageDataInt32(width, height, numChannels);
break;
case Format.float16:
this._data = new MemoryImageDataFloat16(width, height, numChannels);
break;
case Format.float32:
this._data = new MemoryImageDataFloat32(width, height, numChannels);
break;
case Format.float64:
this._data = new MemoryImageDataFloat64(width, height, numChannels);
break;
}
}
createPalette(format, paletteFormat, numChannels) {
switch (paletteFormat) {
case Format.uint1:
return undefined;
case Format.uint2:
return undefined;
case Format.uint4:
return undefined;
case Format.uint8:
return new PaletteUint8(MemoryImage.getNumPixelColors(format), numChannels);
case Format.uint16:
return new PaletteUint16(MemoryImage.getNumPixelColors(format), numChannels);
case Format.uint32:
return new PaletteUint32(MemoryImage.getNumPixelColors(format), numChannels);
case Format.int8:
return new PaletteInt8(MemoryImage.getNumPixelColors(format), numChannels);
case Format.int16:
return new PaletteInt16(MemoryImage.getNumPixelColors(format), numChannels);
case Format.int32:
return new PaletteInt32(MemoryImage.getNumPixelColors(format), numChannels);
case Format.float16:
return new PaletteFloat16(MemoryImage.getNumPixelColors(format), numChannels);
case Format.float32:
return new PaletteFloat32(MemoryImage.getNumPixelColors(format), numChannels);
case Format.float64:
return new PaletteFloat64(MemoryImage.getNumPixelColors(format), numChannels);
}
throw new LibError('Unknown palette format.');
}
addFrame(image) {
const img = image !== null && image !== void 0 ? image : MemoryImage.from(this, true, true);
img._frameIndex = this._frames.length;
if (this._frames[this._frames.length - 1] !== img) {
this._frames.push(img);
}
return img;
}
getFrame(index) {
return this._frames[index];
}
clone(opt) {
var _a, _b;
const skipAnimation = (_a = opt === null || opt === void 0 ? void 0 : opt.skipAnimation) !== null && _a !== void 0 ? _a : false;
const skipPixels = (_b = opt === null || opt === void 0 ? void 0 : opt.skipPixels) !== null && _b !== void 0 ? _b : false;
return MemoryImage.from(this, skipAnimation, skipPixels);
}
hasExtraChannel(name) {
return this._extraChannels !== undefined && this._extraChannels.has(name);
}
getExtraChannel(name) {
return this._extraChannels !== undefined
? this._extraChannels.get(name)
: undefined;
}
setExtraChannel(name, data) {
var _a;
if (this._extraChannels === undefined && data === undefined) {
return;
}
(_a = this._extraChannels) !== null && _a !== void 0 ? _a : (this._extraChannels = new Map());
if (data === undefined) {
this._extraChannels.delete(name);
}
else {
this._extraChannels.set(name, data);
}
if (this._extraChannels.size === 0) {
this._extraChannels = undefined;
}
}
getRange(x, y, width, height) {
return this.data.getRange(x, y, width, height);
}
toUint8Array() {
var _a, _b;
return ((_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.toUint8Array()) !== null && _b !== void 0 ? _b : (this.buffer !== undefined
? new Uint8Array(this.buffer)
: new Uint8Array()));
}
getBytes(opt) {
var _a, _b, _c, _d, _e, _f;
const order = opt === null || opt === void 0 ? void 0 : opt.order;
const alpha = opt === null || opt === void 0 ? void 0 : opt.alpha;
if (order !== undefined) {
const length = ChannelOrderLength.get(order);
if (length !== this.numChannels) {
const self = this.convert({
numChannels: length,
alpha: alpha,
});
return ((_b = (_a = self.data) === null || _a === void 0 ? void 0 : _a.getBytes({
order: order,
inPlace: true,
})) !== null && _b !== void 0 ? _b : this.toUint8Array());
}
else {
return ((_d = (_c = this.data) === null || _c === void 0 ? void 0 : _c.getBytes({
order: order,
inPlace: false,
})) !== null && _d !== void 0 ? _d : this.toUint8Array());
}
}
else {
return ((_f = (_e = this.data) === null || _e === void 0 ? void 0 : _e.getBytes({
order: order,
})) !== null && _f !== void 0 ? _f : this.toUint8Array());
}
}
remapChannels(order) {
if (this.numChannels === 4) {
if (order === ChannelOrder.abgr ||
order === ChannelOrder.argb ||
order === ChannelOrder.bgra) {
if (order === ChannelOrder.abgr) {
for (const p of this) {
const r = p.r;
const g = p.g;
const b = p.b;
const a = p.a;
p.r = a;
p.g = b;
p.b = g;
p.a = r;
}
}
else if (order === ChannelOrder.argb) {
for (const p of this) {
const r = p.r;
const g = p.g;
const b = p.b;
const a = p.a;
p.r = a;
p.g = r;
p.b = g;
p.a = b;
}
}
else if (order === ChannelOrder.bgra) {
for (const p of this) {
const r = p.r;
const g = p.g;
const b = p.b;
const a = p.a;
p.r = b;
p.g = g;
p.b = r;
p.a = a;
}
}
}
}
else if (this.numChannels === 3) {
if (order === ChannelOrder.bgr) {
for (const p of this) {
const r = p.r;
p.r = p.b;
p.b = r;
}
}
}
}
isBoundsSafe(x, y) {
return x >= 0 && y >= 0 && x < this.width && y < this.height;
}
getColor(r, g, b, a) {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.getColor(r, g, b, a)) !== null && _b !== void 0 ? _b : new ColorUint8(0);
}
getPixel(x, y, pixel) {
var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.getPixel(x, y, pixel)) !== null && _b !== void 0 ? _b : UndefinedPixel;
}
getPixelSafe(x, y, pixel) {
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
return UndefinedPixel;
}
return this.getPixel(x, y, pixel);
}
getPixelClamped(x, y, pixel) {
const _x = MathUtils.clamp(x, 0, this.width - 1);
const _y = MathUtils.clamp(y, 0, this.height - 1);
return this.getPixel(_x, _y, pixel);
}
getPixelIndex(x, y) {
var _a;
const index = (_a = this._data) === null || _a === void 0 ? void 0 : _a.getPixel(x, y).index;
return index !== undefined ? Math.trunc(index) : 0;
}
getPixelInterpolate(fx, fy, interpolation = Interpolation.linear) {
switch (interpolation) {
case Interpolation.nearest:
return this.getPixelSafe(Math.trunc(fx), Math.trunc(fy));
case Interpolation.linear:
case Interpolation.average:
return this.getPixelLinear(fx, fy);
case Interpolation.cubic:
return this.getPixelCubic(fx, fy);
}
throw new LibError('Unknown Interpolation mode.');
}
getPixelLinear(fx, fy) {
const x = Math.trunc(fx) - (fx >= 0 ? 0 : 1);
const nx = x + 1;
const y = Math.trunc(fy) - (fy >= 0 ? 0 : 1);
const ny = y + 1;
const dx = fx - x;
const dy = fy - y;
const linear = (icc, inc, icn, inn) => {
return (icc + dx * (inc - icc + dy * (icc + inn - icn - inc)) + dy * (icn - icc));
};
const icc = this.getPixelSafe(x, y);
const icn = ny >= this.height ? icc : this.getPixelSafe(x, ny);
const inc = nx >= this.width ? icc : this.getPixelSafe(nx, y);
const inn = nx >= this.width || ny >= this.height ? icc : this.getPixelSafe(nx, ny);
return this.getColor(linear(icc.r, inc.r, icn.r, inn.r), linear(icc.g, inc.g, icn.g, inn.g), linear(icc.b, inc.b, icn.b, inn.b), linear(icc.a, inc.a, icn.a, inn.a));
}
getPixelCubic(fx, fy) {
const x = Math.trunc(fx) - (fx >= 0 ? 0 : 1);
const px = x - 1;
const nx = x + 1;
const ax = x + 2;
const y = Math.trunc(fy) - (fy >= 0 ? 0 : 1);
const py = y - 1;
const ny = y + 1;
const ay = y + 2;
const dx = fx - x;
const dy = fy - y;
const cubic = (dx, ipp, icp, inp, iap) => {
return (icp +
0.5 *
(dx * (-ipp + inp) +
dx * dx * (2 * ipp - 5 * icp + 4 * inp - iap) +
dx * dx * dx * (-ipp + 3 * icp - 3 * inp + iap)));
};
const icc = this.getPixelSafe(x, y);
const ipp = px < 0 || py < 0 ? icc : this.getPixelSafe(px, py);
const icp = px < 0 ? icc : this.getPixelSafe(x, py);
const inp = py < 0 || nx >= this.width ? icc : this.getPixelSafe(nx, py);
const iap = ax >= this.width || py < 0 ? icc : this.getPixelSafe(ax, py);
const ip0 = cubic(dx, ipp.r, icp.r, inp.r, iap.r);
const ip1 = cubic(dx, ipp.g, icp.g, inp.g, iap.g);
const ip2 = cubic(dx, ipp.b, icp.b, inp.b, iap.b);
const ip3 = cubic(dx, ipp.a, icp.a, inp.a, iap.a);
const ipc = px < 0 ? icc : this.getPixelSafe(px, y);
const inc = nx >= this.width ? icc : this.getPixelSafe(nx, y);
const iac = ax >= this.width ? icc : this.getPixelSafe(ax, y);
const ic0 = cubic(dx, ipc.r, icc.r, inc.r, iac.r);
const ic1 = cubic(dx, ipc.g, icc.g, inc.g, iac.g);
const ic2 = cubic(dx, ipc.b, icc.b, inc.b, iac.b);
const ic3 = cubic(dx, ipc.a, icc.a, inc.a, iac.a);
const ipn = px < 0 || ny >= this.height ? icc : this.getPixelSafe(px, ny);
const icn = ny >= this.height ? icc : this.getPixelSafe(x, ny);
const inn = nx >= this.width || ny >= this.height ? icc : this.getPixelSafe(nx, ny);
const ian = ax >= this.width || ny >= this.height ? icc : this.getPixelSafe(ax, ny);
const in0 = cubic(dx, ipn.r, icn.r, inn.r, ian.r);
const in1 = cubic(dx, ipn.g, icn.g, inn.g, ian.g);
const in2 = cubic(dx, ipn.b, icn.b, inn.b, ian.b);
const in3 = cubic(dx, ipn.a, icn.a, inn.a, ian.a);
const ipa = px < 0 || ay >= this.height ? icc : this.getPixelSafe(px, ay);
const ica = ay >= this.height ? icc : this.getPixelSafe(x, ay);
const ina = nx >= this.width || ay >= this.height ? icc : this.getPixelSafe(nx, ay);
const iaa = ax >= this.width || ay >= this.height ? icc : this.getPixelSafe(ax, ay);
const ia0 = cubic(dx, ipa.r, ica.r, ina.r, iaa.r);
const ia1 = cubic(dx, ipa.g, ica.g, ina.g, iaa.g);
const ia2 = cubic(dx, ipa.b, ica.b, ina.b, iaa.b);
const ia3 = cubic(dx, ipa.a, ica.a, ina.a, iaa.a);
const c0 = cubic(dy, ip0, ic0, in0, ia0);
const c1 = cubic(dy, ip1, ic1, in1, ia1);
const c2 = cubic(dy, ip2, ic2, in2, ia2);
const c3 = cubic(dy, ip3, ic3, in3, ia3);
return this.getColor(Math.trunc(c0), Math.trunc(c1), Math.trunc(c2), Math.trunc(c3));
}
setPixel(x, y, c) {
var _a;
if ('image' in c && 'index' in c) {
if (c.image.hasPalette) {
if (this.hasPalette) {
this.setPixelIndex(x, y, c.index);
return;
}
}
}
(_a = this._data) === null || _a === void 0 ? void 0 : _a.setPixelRgba(x, y, c.r, c.g, c.b, c.a);
}
setPixelIndex(x, y, i) {
var _a;
(_a = this._data) === null || _a === void 0 ? void 0 : _a.setPixelR(x, y, i);
}
setPixelR(x, y, i) {
var _a;
(_a = this._data) === null || _a === void 0 ? void 0 : _a.setPixelR(x, y, i);
}
setPixelRgb(x, y, r, g, b) {
var _a;
(_a = this._data) === null || _a === void 0 ? void 0 : _a.setPixelRgb(x, y, r, g, b);
}
setPixelRgba(x, y, r, g, b, a) {
var _a;
(_a = this._data) === null || _a === void 0 ? void 0 : _a.setPixelRgba(x, y, r, g, b, a);
}
clear(color) {
var _a;
(_a = this._data) === null || _a === void 0 ? void 0 : _a.clear(color);
}
convert(opt) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
const format = (_a = opt.format) !== null && _a !== void 0 ? _a : this.format;
const numChannels = (_b = opt.numChannels) !== null && _b !== void 0 ? _b : this.numChannels;
const alpha = (_c = opt.alpha) !== null && _c !== void 0 ? _c : FormatMaxValue.get(format);
const withPalette = (_d = opt.withPalette) !== null && _d !== void 0 ? _d : false;
const skipAnimation = (_e = opt.skipAnimation) !== null && _e !== void 0 ? _e : false;
if (format === this.format &&
numChannels === this.numChannels &&
((!withPalette && this.palette === undefined) ||
(withPalette && this.palette !== undefined))) {
return MemoryImage.from(this);
}
let firstFrame = undefined;
for (const frame of this._frames) {
const newImage = new MemoryImage({
width: frame.width,
height: frame.height,
format: format,
numChannels: numChannels,
withPalette: withPalette,
exifData: (_f = frame._exifData) === null || _f === void 0 ? void 0 : _f.clone(),
iccProfile: (_g = frame._iccProfile) === null || _g === void 0 ? void 0 : _g.clone(),
backgroundColor: (_h = frame._backgroundColor) === null || _h === void 0 ? void 0 : _h.clone(),
frameType: frame._frameType,
loopCount: frame._loopCount,
frameDuration: frame._frameDuration,
textData: frame._textData !== undefined
? new Map(frame.textData)
: undefined,
});
if (firstFrame !== undefined) {
firstFrame.addFrame(newImage);
}
else {
firstFrame = newImage;
}
const pal = newImage.palette;
const f = (_k = (_j = newImage.palette) === null || _j === void 0 ? void 0 : _j.format) !== null && _k !== void 0 ? _k : format;
if (pal !== undefined) {
const usedColors = new Map();
let numColors = 0;
const op = frame.getPixel(0, 0);
let c = undefined;
for (const np of newImage) {
const nr = Math.floor(op.rNormalized * 255);
const ng = Math.floor(op.gNormalized * 255);
const nb = Math.floor(op.bNormalized * 255);
const h = ColorUtils.rgbaToUint32(nr, ng, nb, 0);
if (usedColors.has(h)) {
np.index = usedColors.get(h);
}
else {
usedColors.set(h, numColors);
np.index = numColors;
c = ColorUtils.convertColor({
from: op,
to: c,
format: f,
numChannels: numChannels,
alpha: alpha,
});
pal.setRgb(numColors, c.r, c.g, c.b);
numColors++;
}
op.next();
}
}
else {
const op = frame.getPixel(0, 0);
for (const np of newImage) {
ColorUtils.convertColor({
from: op,
to: np,
alpha: alpha,
});
op.next();
}
}
if (skipAnimation) {
break;
}
}
return firstFrame;
}
addTextData(data) {
var _a;
(_a = this._textData) !== null && _a !== void 0 ? _a : (this._textData = new Map());
for (const [key, value] of data) {
this._textData.set(key, value);
}
}
getColorExtremes() {
let first = true;
let min = 0;
let max = 0;
for (const p of this) {
for (let i = 0; i < p.length; i++) {
const c = p.getChannel(i);
if (first || c < min) {
min = c;
}
if (first || c > max) {
max = c;
}
}
first = false;
}
return {
min: min,
max: max,
};
}
toString() {
return `${this.constructor.name} (w: ${this.width}, h: ${this.height}, f: ${Format[this.format]}, ch: ${this.numChannels})`;
}
[Symbol.iterator]() {
return this._data !== undefined
? this._data[Symbol.iterator]()
: {
next: () => ({
done: true,
value: UndefinedPixel,
}),
};
}
}
//# sourceMappingURL=image.js.map