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)

938 lines 41.6 kB
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