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)
938 lines • 41.6 kB
JavaScript
import { inflate } from '../../packer/packer.js';
import { ColorUtils } from '../../color/color-utils.js';
import { Format } from '../../color/format.js';
import { ArrayUtils } from '../../common/array-utils.js';
import { BitUtils } from '../../common/bit-utils.js';
import { Float16 } from '../../common/float16.js';
import { InputBuffer } from '../../common/input-buffer.js';
import { LibError } from '../../error/lib-error.js';
import { ExifTagNameToID } from '../../exif/exif-tag.js';
import { IfdValueTypeSize } from '../../exif/ifd-value-type.js';
import { MemoryImage } from '../../image/image.js';
import { JpegDecoder } from '../jpeg-decoder.js';
import { TiffBitReader } from './tiff-bit-reader.js';
import { TiffCompression } from './tiff-compression.js';
import { TiffEntry } from './tiff-entry.js';
import { TiffFaxDecoder } from './tiff-fax-decoder.js';
import { TiffFormat } from './tiff-format.js';
import { TiffImageType } from './tiff-image-type.js';
import { LzwDecoder } from './tiff-lzw-decoder.js';
import { TiffPhotometricType, TiffPhotometricTypeLength, } from './tiff-photometric-type.js';
export class TiffImage {
get tags() {
return this._tags;
}
get width() {
return this._width;
}
get height() {
return this._height;
}
get photometricType() {
return this._photometricType;
}
get compression() {
return this._compression;
}
get bitsPerSample() {
return this._bitsPerSample;
}
get samplesPerPixel() {
return this._samplesPerPixel;
}
get channelsPerPixel() {
return this._channelsPerPixel;
}
get sampleFormat() {
return this._sampleFormat;
}
get imageType() {
return this._imageType;
}
get isWhiteZero() {
return this._isWhiteZero;
}
get predictor() {
return this._predictor;
}
get chromaSubH() {
return this._chromaSubH;
}
get chromaSubV() {
return this._chromaSubV;
}
get tiled() {
return this._tiled;
}
get tileWidth() {
return this._tileWidth;
}
get tileHeight() {
return this._tileHeight;
}
get tileOffsets() {
return this._tileOffsets;
}
get tileByteCounts() {
return this._tileByteCounts;
}
get tilesX() {
return this._tilesX;
}
get tilesY() {
return this._tilesY;
}
get tileSize() {
return this._tileSize;
}
get fillOrder() {
return this._fillOrder;
}
get t4Options() {
return this._t4Options;
}
get t6Options() {
return this._t6Options;
}
get extraSamples() {
return this._extraSamples;
}
get colorMapSamples() {
return this._colorMapSamples;
}
get colorMap() {
return this._colorMap;
}
get isValid() {
return this._width !== 0 && this._height !== 0;
}
constructor(p) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
this._tags = new Map();
this._width = 0;
this._height = 0;
this._photometricType = TiffPhotometricType.unknown;
this._compression = 1;
this._bitsPerSample = 1;
this._samplesPerPixel = 1;
this._channelsPerPixel = 1;
this._sampleFormat = TiffFormat.uint;
this._imageType = TiffImageType.invalid;
this._isWhiteZero = false;
this._predictor = 1;
this._chromaSubH = 0;
this._chromaSubV = 0;
this._tiled = false;
this._tileWidth = 0;
this._tileHeight = 0;
this._tilesX = 0;
this._tilesY = 0;
this._fillOrder = 1;
this._t4Options = 0;
this._t6Options = 0;
this._colorMapSamples = 0;
this._colorMapRed = 0;
this._colorMapGreen = 0;
this._colorMapBlue = 0;
const p3 = InputBuffer.from(p);
const numDirEntries = p.readUint16();
for (let i = 0; i < numDirEntries; ++i) {
const tag = p.readUint16();
const ti = p.readUint16();
const type = ti;
const typeSize = IfdValueTypeSize[ti];
const count = p.readUint32();
let valueOffset = 0;
if (count * typeSize > 4) {
valueOffset = p.readUint32();
}
else {
valueOffset = p.offset;
p.skip(4);
}
const entry = new TiffEntry({
tag: tag,
type: type,
count: count,
p: p3,
valueOffset: valueOffset,
});
this._tags.set(entry.tag, entry);
if (tag === ExifTagNameToID.get('ImageWidth')) {
this._width = (_b = (_a = entry.read()) === null || _a === void 0 ? void 0 : _a.toInt()) !== null && _b !== void 0 ? _b : 0;
}
else if (tag === ExifTagNameToID.get('ImageLength')) {
this._height = (_d = (_c = entry.read()) === null || _c === void 0 ? void 0 : _c.toInt()) !== null && _d !== void 0 ? _d : 0;
}
else if (tag === ExifTagNameToID.get('PhotometricInterpretation')) {
const v = entry.read();
if (v === undefined) {
this._photometricType = TiffPhotometricType.unknown;
}
else {
const pt = v.toInt();
if (pt < TiffPhotometricTypeLength) {
this._photometricType = pt;
}
else {
this._photometricType = TiffPhotometricType.unknown;
}
}
}
else if (tag === ExifTagNameToID.get('Compression')) {
this._compression = (_f = (_e = entry.read()) === null || _e === void 0 ? void 0 : _e.toInt()) !== null && _f !== void 0 ? _f : 0;
}
else if (tag === ExifTagNameToID.get('BitsPerSample')) {
this._bitsPerSample = (_h = (_g = entry.read()) === null || _g === void 0 ? void 0 : _g.toInt()) !== null && _h !== void 0 ? _h : 0;
}
else if (tag === ExifTagNameToID.get('SamplesPerPixel')) {
this._samplesPerPixel = (_k = (_j = entry.read()) === null || _j === void 0 ? void 0 : _j.toInt()) !== null && _k !== void 0 ? _k : 0;
}
else if (tag === ExifTagNameToID.get('Predictor')) {
this._predictor = (_m = (_l = entry.read()) === null || _l === void 0 ? void 0 : _l.toInt()) !== null && _m !== void 0 ? _m : 0;
}
else if (tag === ExifTagNameToID.get('SampleFormat')) {
const v = (_p = (_o = entry.read()) === null || _o === void 0 ? void 0 : _o.toInt()) !== null && _p !== void 0 ? _p : 0;
this._sampleFormat = v;
}
else if (tag === ExifTagNameToID.get('ColorMap')) {
const v = entry.read();
if (v !== undefined) {
this._colorMap = new Uint16Array(v.toData().buffer);
this._colorMapRed = 0;
this._colorMapGreen = Math.trunc(this._colorMap.length / 3);
this._colorMapBlue = this._colorMapGreen * 2;
}
}
}
if (this._colorMap !== undefined &&
this._photometricType === TiffPhotometricType.palette) {
this._colorMapSamples = 3;
this._samplesPerPixel = 1;
}
if (this._width === 0 || this._height === 0) {
return;
}
if (this._colorMap !== undefined && this._bitsPerSample === 8) {
const cm = this._colorMap;
const len = cm.length;
for (let i = 0; i < len; ++i) {
cm[i] >>>= 8;
}
}
if (this._photometricType === TiffPhotometricType.whiteIsZero) {
this._isWhiteZero = true;
}
this._channelsPerPixel = this._samplesPerPixel;
if (this.hasTag(ExifTagNameToID.get('TileOffsets'))) {
this._tiled = true;
this._tileWidth = this.readTag(ExifTagNameToID.get('TileWidth'));
this._tileHeight = this.readTag(ExifTagNameToID.get('TileLength'));
this._tileOffsets = this.readTagList(ExifTagNameToID.get('TileOffsets'));
this._tileByteCounts = this.readTagList(ExifTagNameToID.get('TileByteCounts'));
}
else {
this._tiled = false;
this._tileWidth = this.readTag(ExifTagNameToID.get('TileWidth'), this._width);
if (!this.hasTag(ExifTagNameToID.get('RowsPerStrip'))) {
this._tileHeight = this.readTag(ExifTagNameToID.get('TileLength'), this._height);
}
else {
const l = this.readTag(ExifTagNameToID.get('RowsPerStrip'));
let infinity = 1;
infinity = (infinity << 32) - 1;
if (l === infinity) {
this._tileHeight = this._height;
}
else {
this._tileHeight = l;
}
}
this._tileOffsets = this.readTagList(ExifTagNameToID.get('StripOffsets'));
this._tileByteCounts = this.readTagList(ExifTagNameToID.get('StripByteCounts'));
}
this._tilesX = Math.trunc((this._width + this._tileWidth - 1) / this._tileWidth);
this._tilesY = Math.trunc((this._height + this._tileHeight - 1) / this._tileHeight);
this._tileSize = this._tileWidth * this._tileHeight * this._samplesPerPixel;
this._fillOrder = this.readTag(ExifTagNameToID.get('FillOrder'), 1);
this._t4Options = this.readTag(ExifTagNameToID.get('T4Options'));
this._t6Options = this.readTag(ExifTagNameToID.get('T6Options'));
this._extraSamples = this.readTag(ExifTagNameToID.get('ExtraSamples'));
switch (this._photometricType) {
case TiffPhotometricType.whiteIsZero:
case TiffPhotometricType.blackIsZero:
if (this._bitsPerSample === 1 && this._samplesPerPixel === 1) {
this._imageType = TiffImageType.bilevel;
}
else if (this._bitsPerSample === 4 && this._samplesPerPixel === 1) {
this._imageType = TiffImageType.gray4bit;
}
else if (this._bitsPerSample % 8 === 0) {
if (this._samplesPerPixel === 1) {
this._imageType = TiffImageType.gray;
}
else if (this._samplesPerPixel === 2) {
this._imageType = TiffImageType.grayAlpha;
}
else {
this._imageType = TiffImageType.generic;
}
}
break;
case TiffPhotometricType.rgb:
if (this._bitsPerSample % 8 === 0) {
if (this._samplesPerPixel === 3) {
this._imageType = TiffImageType.rgb;
}
else if (this._samplesPerPixel === 4) {
this._imageType = TiffImageType.rgba;
}
else {
this._imageType = TiffImageType.generic;
}
}
break;
case TiffPhotometricType.palette:
if (this._samplesPerPixel === 1 &&
this._colorMap !== undefined &&
(this._bitsPerSample === 4 ||
this._bitsPerSample === 8 ||
this._bitsPerSample === 16)) {
this._imageType = TiffImageType.palette;
}
break;
case TiffPhotometricType.transparencyMask:
if (this._bitsPerSample === 1 && this._samplesPerPixel === 1) {
this._imageType = TiffImageType.bilevel;
}
break;
case TiffPhotometricType.yCbCr:
if (this._compression === TiffCompression.jpeg &&
this._bitsPerSample === 8 &&
this._samplesPerPixel === 3) {
this._imageType = TiffImageType.rgb;
}
else {
if (this.hasTag(ExifTagNameToID.get('YCbCrSubSampling'))) {
const s = ExifTagNameToID.get('YCbCrSubSampling');
const v = this._tags.get(s).read();
this._chromaSubH = v.toInt();
this._chromaSubV = v.toInt(1);
}
else {
this._chromaSubH = 2;
this._chromaSubV = 2;
}
if (this._chromaSubH * this._chromaSubV === 1) {
this._imageType = TiffImageType.generic;
}
else if (this._bitsPerSample === 8 && this._samplesPerPixel === 3) {
this._imageType = TiffImageType.yCbCrSub;
}
}
break;
case TiffPhotometricType.cmyk:
if (this._bitsPerSample % 8 === 0) {
this._imageType = TiffImageType.generic;
}
if (this._samplesPerPixel === 4) {
this._channelsPerPixel = 3;
}
else if (this._samplesPerPixel === 5) {
this._channelsPerPixel = 4;
}
break;
default:
if (this._bitsPerSample % 8 === 0) {
this._imageType = TiffImageType.generic;
}
break;
}
}
readTag(type, defaultValue = 0) {
var _a, _b;
if (!this.hasTag(type)) {
return defaultValue;
}
return (_b = (_a = this._tags.get(type).read()) === null || _a === void 0 ? void 0 : _a.toInt()) !== null && _b !== void 0 ? _b : 0;
}
readTagList(type) {
if (!this.hasTag(type)) {
return undefined;
}
const tag = this._tags.get(type);
const value = tag.read();
return ArrayUtils.generate(tag.count, (i) => value.toInt(i));
}
decodeBilevelTile(p, image, tileX, tileY) {
const tileIndex = tileY * this._tilesX + tileX;
p.offset = this._tileOffsets[tileIndex];
const outX = tileX * this._tileWidth;
const outY = tileY * this._tileHeight;
const byteCount = this._tileByteCounts[tileIndex];
let byteData = undefined;
if (this._compression === TiffCompression.packBits) {
let bytesInThisTile = 0;
if (this._tileWidth % 8 === 0) {
bytesInThisTile = Math.trunc(this._tileWidth / 8) * this._tileHeight;
}
else {
bytesInThisTile =
(Math.trunc(this._tileWidth / 8) + 1) * this._tileHeight;
}
byteData = new InputBuffer({
buffer: new Uint8Array(this._tileWidth * this._tileHeight),
});
this.decodePackBits(p, bytesInThisTile, byteData.buffer);
}
else if (this._compression === TiffCompression.lzw) {
byteData = new InputBuffer({
buffer: new Uint8Array(this._tileWidth * this._tileHeight),
});
const decoder = new LzwDecoder();
decoder.decode(InputBuffer.from(p, 0, byteCount), byteData.buffer);
if (this._predictor === 2) {
let count = 0;
for (let j = 0; j < this._height; j++) {
count = this._samplesPerPixel * (j * this._width + 1);
for (let i = this._samplesPerPixel; i < this._width * this._samplesPerPixel; i++) {
const b = byteData.get(count) + byteData.get(count - this._samplesPerPixel);
byteData.set(count, b);
count++;
}
}
}
}
else if (this._compression === TiffCompression.ccittRle) {
byteData = new InputBuffer({
buffer: new Uint8Array(this._tileWidth * this._tileHeight),
});
try {
const decoder = new TiffFaxDecoder({
fillOrder: this._fillOrder,
width: this._tileWidth,
height: this._tileHeight,
});
decoder.decode1D(byteData, p, 0, this._tileHeight);
}
catch (_) {
}
}
else if (this._compression === TiffCompression.ccittFax3) {
byteData = new InputBuffer({
buffer: new Uint8Array(this._tileWidth * this._tileHeight),
});
try {
const decoder = new TiffFaxDecoder({
fillOrder: this._fillOrder,
width: this._tileWidth,
height: this._tileHeight,
});
decoder.decode2D(byteData, p, 0, this._tileHeight, this._t4Options);
}
catch (_) {
}
}
else if (this._compression === TiffCompression.ccittFax4) {
byteData = new InputBuffer({
buffer: new Uint8Array(this._tileWidth * this._tileHeight),
});
try {
const decoder = new TiffFaxDecoder({
fillOrder: this._fillOrder,
width: this._tileWidth,
height: this._tileHeight,
});
decoder.decodeT6(byteData, p, 0, this._tileHeight, this._t6Options);
}
catch (_) {
}
}
else if (this._compression === TiffCompression.zip) {
const data = p.toUint8Array(0, byteCount);
const outData = inflate(data);
byteData = new InputBuffer({
buffer: outData,
});
}
else if (this._compression === TiffCompression.deflate) {
const data = p.toUint8Array(0, byteCount);
const outData = inflate(data);
byteData = new InputBuffer({
buffer: outData,
});
}
else if (this._compression === TiffCompression.none) {
byteData = p;
}
else {
throw new LibError(`Unsupported Compression Type: ${this._compression}`);
}
const br = new TiffBitReader(byteData);
const mx = image.maxChannelValue;
const black = this._isWhiteZero ? mx : 0;
const white = this._isWhiteZero ? 0 : mx;
for (let y = 0, py = outY; y < this._tileHeight; ++y, ++py) {
for (let x = 0, px = outX; x < this._tileWidth; ++x, ++px) {
if (py >= image.height || px >= image.width)
break;
if (br.readBits(1) === 0) {
image.setPixelRgb(px, py, black, 0, 0);
}
else {
image.setPixelRgb(px, py, white, 0, 0);
}
}
br.flushByte();
}
}
decodeTile(p, image, tileX, tileY) {
if (this._imageType === TiffImageType.bilevel) {
this.decodeBilevelTile(p, image, tileX, tileY);
return;
}
const tileIndex = tileY * this._tilesX + tileX;
p.offset = this._tileOffsets[tileIndex];
const outX = tileX * this._tileWidth;
const outY = tileY * this._tileHeight;
const byteCount = this._tileByteCounts[tileIndex];
let bytesInThisTile = this._tileWidth * this._tileHeight * this._samplesPerPixel;
if (this._bitsPerSample === 16) {
bytesInThisTile *= 2;
}
else if (this._bitsPerSample === 32) {
bytesInThisTile *= 4;
}
let byteData = undefined;
if (this._bitsPerSample === 8 ||
this._bitsPerSample === 16 ||
this._bitsPerSample === 32 ||
this._bitsPerSample === 64) {
if (this._compression === TiffCompression.none) {
byteData = p;
}
else if (this._compression === TiffCompression.lzw) {
byteData = new InputBuffer({
buffer: new Uint8Array(bytesInThisTile),
});
const decoder = new LzwDecoder();
try {
decoder.decode(InputBuffer.from(p, 0, byteCount), byteData.buffer);
}
catch (e) {
}
if (this._predictor === 2) {
let count = 0;
for (let j = 0; j < this._tileHeight; j++) {
count = this._samplesPerPixel * (j * this._tileWidth + 1);
const len = this._tileWidth * this._samplesPerPixel;
for (let i = this._samplesPerPixel; i < len; i++) {
byteData.set(count, byteData.get(count) +
byteData.get(count - this._samplesPerPixel));
count++;
}
}
}
}
else if (this._compression === TiffCompression.packBits) {
byteData = new InputBuffer({
buffer: new Uint8Array(bytesInThisTile),
});
this.decodePackBits(p, bytesInThisTile, byteData.buffer);
}
else if (this._compression === TiffCompression.deflate) {
const data = p.toUint8Array(0, byteCount);
const outData = inflate(data);
byteData = new InputBuffer({
buffer: outData,
});
}
else if (this._compression === TiffCompression.zip) {
const data = p.toUint8Array(0, byteCount);
const outData = inflate(data);
byteData = new InputBuffer({
buffer: outData,
});
}
else if (this._compression === TiffCompression.oldJpeg) {
const data = p.toUint8Array(0, byteCount);
const tile = new JpegDecoder().decode({
bytes: data,
});
if (tile !== undefined) {
this.jpegToImage(tile, image, outX, outY, this._tileWidth, this._tileHeight);
}
return;
}
else {
throw new LibError(`Unsupported Compression Type: ${this._compression}`);
}
const rgb = [0, 0, 0];
for (let y = 0, py = outY; y < this._tileHeight; ++y, ++py) {
for (let x = 0, px = outX; x < this._tileWidth; ++x, ++px) {
if (byteData.isEOS || px >= this._width || py >= this._height) {
break;
}
if (this._samplesPerPixel === 1) {
if (this._sampleFormat === TiffFormat.float) {
let sample = 0;
if (this._bitsPerSample === 32) {
sample = byteData.readFloat32();
}
else if (this._bitsPerSample === 64) {
sample = byteData.readFloat64();
}
else if (this._bitsPerSample === 16) {
sample = Float16.float16ToDouble(byteData.readUint16());
}
image.setPixelR(px, py, sample);
}
else {
let sample = 0;
if (this._bitsPerSample === 8) {
sample =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
}
else if (this._bitsPerSample === 16) {
sample =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
}
else if (this._bitsPerSample === 32) {
sample =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
}
if (this._photometricType === TiffPhotometricType.whiteIsZero) {
const mx = Math.trunc(image.maxChannelValue);
sample = mx - sample;
}
image.setPixelR(px, py, sample);
}
}
else if (this._samplesPerPixel === 2) {
let gray = 0;
let alpha = 0;
if (this._bitsPerSample === 8) {
gray =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
alpha =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
}
else if (this._bitsPerSample === 16) {
gray =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
alpha =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
}
else if (this._bitsPerSample === 32) {
gray =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
alpha =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
}
image.setPixelRgb(px, py, gray, alpha, 0);
}
else if (this._samplesPerPixel === 3) {
if (this._sampleFormat === TiffFormat.float) {
let r = 0.0;
let g = 0.0;
let b = 0.0;
if (this._bitsPerSample === 32) {
r = byteData.readFloat32();
g = byteData.readFloat32();
b = byteData.readFloat32();
}
else if (this._bitsPerSample === 64) {
r = byteData.readFloat64();
g = byteData.readFloat64();
b = byteData.readFloat64();
}
else if (this._bitsPerSample === 16) {
r = Float16.float16ToDouble(byteData.readUint16());
g = Float16.float16ToDouble(byteData.readUint16());
b = Float16.float16ToDouble(byteData.readUint16());
}
image.setPixelRgb(px, py, r, g, b);
}
else {
let r = 0;
let g = 0;
let b = 0;
if (this._bitsPerSample === 8) {
r =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
g =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
b =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
}
else if (this._bitsPerSample === 16) {
r =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
g =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
b =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
}
else if (this._bitsPerSample === 32) {
r =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
g =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
b =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
}
image.setPixelRgb(px, py, r, g, b);
}
}
else if (this._samplesPerPixel >= 4) {
if (this._sampleFormat === TiffFormat.float) {
let r = 0.0;
let g = 0.0;
let b = 0.0;
let a = 0.0;
if (this._bitsPerSample === 32) {
r = byteData.readFloat32();
g = byteData.readFloat32();
b = byteData.readFloat32();
a = byteData.readFloat32();
}
else if (this._bitsPerSample === 64) {
r = byteData.readFloat64();
g = byteData.readFloat64();
b = byteData.readFloat64();
a = byteData.readFloat64();
}
else if (this._bitsPerSample === 16) {
r = Float16.float16ToDouble(byteData.readUint16());
g = Float16.float16ToDouble(byteData.readUint16());
b = Float16.float16ToDouble(byteData.readUint16());
a = Float16.float16ToDouble(byteData.readUint16());
}
image.setPixelRgba(px, py, r, g, b, a);
}
else {
let r = 0;
let g = 0;
let b = 0;
let a = 0;
let alpha = image.maxChannelValue;
if (this._bitsPerSample === 8) {
r =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
g =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
b =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
a =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
if (this._samplesPerPixel === 5) {
alpha =
this._sampleFormat === TiffFormat.int
? byteData.readInt8()
: byteData.read();
}
}
else if (this._bitsPerSample === 16) {
r =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
g =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
b =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
a =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
if (this._samplesPerPixel === 5) {
alpha =
this._sampleFormat === TiffFormat.int
? byteData.readInt16()
: byteData.readUint16();
}
}
else if (this._bitsPerSample === 32) {
r =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
g =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
b =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
a =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
if (this._samplesPerPixel === 5) {
alpha =
this._sampleFormat === TiffFormat.int
? byteData.readInt32()
: byteData.readUint32();
}
}
if (this._photometricType === TiffPhotometricType.cmyk) {
ColorUtils.cmykToRgb(r, g, b, a, rgb);
r = rgb[0];
g = rgb[1];
b = rgb[2];
a = alpha;
}
image.setPixelRgba(px, py, r, g, b, a);
}
}
}
}
}
else {
throw new LibError(`Unsupported bitsPerSample: ${this._bitsPerSample}`);
}
}
jpegToImage(tile, image, outX, outY, tileWidth, tileHeight) {
const width = tileWidth;
const height = tileHeight;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
image.setPixel(x + outX, y + outY, tile.getPixel(x, y));
}
}
}
decodePackBits(data, arraySize, dst) {
let srcCount = 0;
let dstCount = 0;
while (dstCount < arraySize) {
const b = BitUtils.uint8ToInt8(data.get(srcCount++));
if (b >= 0 && b <= 127) {
for (let i = 0; i < b + 1; ++i) {
dst[dstCount++] = data.get(srcCount++);
}
}
else if (b <= -1 && b >= -127) {
const repeat = data.get(srcCount++);
for (let i = 0; i < -b + 1; ++i) {
dst[dstCount++] = repeat;
}
}
else {
srcCount++;
}
}
}
decode(p) {
const isFloat = this._sampleFormat === TiffFormat.float;
const isInt = this._sampleFormat === TiffFormat.int;
const format = this._bitsPerSample === 1
? Format.uint1
: this._bitsPerSample === 2
? Format.uint2
: this._bitsPerSample === 4
? Format.uint4
: isFloat && this._bitsPerSample === 16
? Format.float16
: isFloat && this._bitsPerSample === 32
? Format.float32
: isFloat && this._bitsPerSample === 64
? Format.float64
: isInt && this._bitsPerSample === 8
? Format.int8
: isInt && this._bitsPerSample === 16
? Format.int16
: isInt && this._bitsPerSample === 32
? Format.int32
: this._bitsPerSample === 16
? Format.uint16
: this._bitsPerSample === 32
? Format.uint32
: Format.uint8;
const hasPalette = this._colorMap !== undefined &&
this._photometricType === TiffPhotometricType.palette;
const numChannels = hasPalette ? 3 : this._channelsPerPixel;
const image = new MemoryImage({
width: this._width,
height: this._height,
format: format,
numChannels: numChannels,
withPalette: hasPalette,
paletteFormat: format,
});
if (hasPalette) {
const p = image.palette;
const cm = this._colorMap;
const numChannels = 3;
const numColors = Math.trunc(cm.length / numChannels);
let ri = this._colorMapRed;
let gi = this._colorMapGreen;
let bi = this._colorMapBlue;
const colorMapSize = cm.length;
for (let i = 0; i < numColors; ++i, ++ri, ++gi, ++bi) {
if (bi >= colorMapSize) {
break;
}
p.setRgb(i, cm[ri], cm[gi], cm[bi]);
}
}
for (let tileY = 0, ti = 0; tileY < this._tilesY; ++tileY) {
for (let tileX = 0; tileX < this._tilesX; ++tileX, ++ti) {
this.decodeTile(p, image, tileX, tileY);
}
}
return image;
}
hasTag(tag) {
return this._tags.has(tag);
}
}
//# sourceMappingURL=tiff-image.js.map