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)

264 lines 9.82 kB
import { BitUtils } from '../../common/bit-utils.js'; import { LibError } from '../../error/lib-error.js'; import { PaletteUint8 } from '../../image/palette-uint8.js'; import { BmpCompressionMode } from './bmp-compression-mode.js'; import { BmpFileHeader } from './bmp-file-header.js'; export class BmpInfo { get width() { return this._width; } get height() { return Math.abs(this._height); } get backgroundColor() { return this._backgroundColor; } get numFrames() { return this._numFrames; } get header() { return this._header; } get headerSize() { return this._headerSize; } get planes() { return this._planes; } get bitsPerPixel() { return this._bitsPerPixel; } get compression() { return this._compression; } get imageSize() { return this._imageSize; } get xppm() { return this._xppm; } get yppm() { return this._yppm; } get totalColors() { return this._totalColors; } get importantColors() { return this._importantColors; } get redMask() { return this._redMask; } get greenMask() { return this._greenMask; } get blueMask() { return this._blueMask; } get alphaMask() { return this._alphaMask; } get palette() { return this._palette; } get readBottomUp() { return this._height >= 0; } get ignoreAlphaChannel() { return (this._headerSize === 40 || (this._headerSize === 124 && this._alphaMask === 0)); } constructor(p, header) { this._redShift = 0; this._redScale = 0; this._greenShift = 0; this._greenScale = 0; this._blueShift = 0; this._blueScale = 0; this._alphaShift = 0; this._alphaScale = 0; this._width = 0; this._height = 0; this._backgroundColor = undefined; this._numFrames = 1; this._redMask = 0; this._greenMask = 0; this._blueMask = 0; this._alphaMask = 0; this._header = header !== null && header !== void 0 ? header : new BmpFileHeader(p); this._startPos = p.offset; this._headerSize = p.readUint32(); this._width = p.readInt32(); this._height = p.readInt32(); this._planes = p.readUint16(); this._bitsPerPixel = p.readUint16(); this._compression = p.readUint32(); this._imageSize = p.readUint32(); this._xppm = p.readInt32(); this._yppm = p.readInt32(); this._totalColors = p.readUint32(); this._importantColors = p.readUint32(); const maxChannelValue = 255.0; if (this._headerSize > 40 || this._compression === BmpCompressionMode.bitfields || this._compression === BmpCompressionMode.alphaBitfields) { this._redMask = p.readUint32(); this._redShift = BitUtils.countTrailingZeroBits(this._redMask); const redDepth = this._redMask >>> this._redShift; this._redScale = redDepth > 0 ? maxChannelValue / redDepth : 0; this._greenMask = p.readUint32(); this._greenShift = BitUtils.countTrailingZeroBits(this._greenMask); const greenDepth = this._greenMask >>> this._greenShift; this._greenScale = redDepth > 0 ? maxChannelValue / greenDepth : 0; this._blueMask = p.readUint32(); this._blueShift = BitUtils.countTrailingZeroBits(this._blueMask); const blueDepth = this._blueMask >>> this._blueShift; this._blueScale = redDepth > 0 ? maxChannelValue / blueDepth : 0; if (this._headerSize > 40 || this._compression === BmpCompressionMode.alphaBitfields) { this._alphaMask = p.readUint32(); this._alphaShift = BitUtils.countTrailingZeroBits(this._alphaMask); const alphaDepth = this._alphaMask >>> this._alphaShift; this._alphaScale = alphaDepth > 0 ? maxChannelValue / alphaDepth : 0; } else { if (this._bitsPerPixel === 16) { this._alphaMask = 0xff000000; this._alphaShift = 24; this._alphaScale = 1.0; } else { this._alphaMask = 0xff000000; this._alphaShift = 24; this._alphaScale = 1.0; } } } else { if (this._bitsPerPixel === 16) { this._redMask = 0x7c00; this._redShift = 10; const redDepth = this._redMask >>> this._redShift; this._redScale = redDepth > 0 ? maxChannelValue / redDepth : 0; this._greenMask = 0x03e0; this._greenShift = 5; const greenDepth = this._greenMask >>> this._greenShift; this._greenScale = redDepth > 0 ? maxChannelValue / greenDepth : 0; this._blueMask = 0x001f; this._blueShift = 0; const blueDepth = this._blueMask >>> this._blueShift; this._blueScale = redDepth > 0 ? maxChannelValue / blueDepth : 0; this._alphaMask = 0x00000000; this._alphaShift = 0; this._alphaScale = 0.0; } else { this._redMask = 0x00ff0000; this._redShift = 16; this._redScale = 1.0; this._greenMask = 0x0000ff00; this._greenShift = 8; this._greenScale = 1.0; this._blueMask = 0x000000ff; this._blueShift = 0; this._blueScale = 1.0; this._alphaMask = 0xff000000; this._alphaShift = 24; this._alphaScale = 1.0; } } const headerRead = p.offset - this._startPos; const remainingHeaderBytes = this._headerSize - headerRead; p.skip(remainingHeaderBytes); if (this._bitsPerPixel <= 8) { this.readPalette(p); } } readPalette(input) { const numColors = this._totalColors === 0 ? 1 << this._bitsPerPixel : this._totalColors; const numChannels = 3; this._palette = new PaletteUint8(numColors, numChannels); for (let i = 0; i < numColors; ++i) { const b = input.read(); const g = input.read(); const r = input.read(); const a = input.read(); this._palette.setRgba(i, r, g, b, a); } } decodePixel(input, pixel) { if (this._palette !== undefined) { if (this._bitsPerPixel === 1) { const bi = input.read(); for (let i = 7; i >= 0; --i) { const b = (bi >>> i) & 0x1; pixel(b, 0, 0, 0); } return; } else if (this._bitsPerPixel === 2) { const bi = input.read(); for (let i = 6; i >= 0; i -= 2) { const b = (bi >>> i) & 0x2; pixel(b, 0, 0, 0); } } else if (this._bitsPerPixel === 4) { const bi = input.read(); const b1 = (bi >>> 4) & 0xf; pixel(b1, 0, 0, 0); const b2 = bi & 0xf; pixel(b2, 0, 0, 0); return; } else if (this._bitsPerPixel === 8) { const b = input.read(); pixel(b, 0, 0, 0); return; } } if (this._compression === BmpCompressionMode.bitfields && this._bitsPerPixel === 32) { const p = input.readUint32(); const r = Math.trunc(((p & this._redMask) >>> this._redShift) * this._redScale); const g = Math.trunc(((p & this._greenMask) >>> this._greenShift) * this._greenScale); const b = Math.trunc(((p & this._blueMask) >>> this._blueShift) * this._blueScale); const a = this.ignoreAlphaChannel ? 255 : Math.trunc(((p & this._alphaMask) >>> this._alphaShift) * this._alphaScale); pixel(r, g, b, a); return; } else if (this._bitsPerPixel === 32 && this._compression === BmpCompressionMode.none) { const b = input.read(); const g = input.read(); const r = input.read(); const a = input.read(); pixel(r, g, b, this.ignoreAlphaChannel ? 255 : a); return; } else if (this._bitsPerPixel === 24) { const b = input.read(); const g = input.read(); const r = input.read(); pixel(r, g, b, 255); return; } else if (this._bitsPerPixel === 16) { const p = input.readUint16(); const r = Math.trunc(((p & this._redMask) >>> this._redShift) * this._redScale); const g = Math.trunc(((p & this._greenMask) >>> this._greenShift) * this._greenScale); const b = Math.trunc(((p & this._blueMask) >>> this._blueShift) * this._blueScale); const a = this.ignoreAlphaChannel ? 255 : Math.trunc(((p & this._alphaMask) >>> this._alphaShift) * this._alphaScale); pixel(r, g, b, a); return; } else { throw new LibError(`Unsupported bitsPerPixel (${this._bitsPerPixel}) or compression (${this._compression}).`); } } } //# sourceMappingURL=bmp-info.js.map