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)
110 lines • 3.91 kB
JavaScript
import { Format } from '../color/format.js';
import { InputBuffer } from '../common/input-buffer.js';
import { MemoryImage } from '../image/image.js';
import { BmpFileHeader } from './bmp/bmp-file-header.js';
import { BmpInfo } from './bmp/bmp-info.js';
import { ImageFormat } from './image-format.js';
export class BmpDecoder {
get format() {
return ImageFormat.bmp;
}
get numFrames() {
return this._info !== undefined ? this._info.numFrames : 0;
}
constructor(forceRgba = false) {
this._forceRgba = forceRgba;
}
isValidFile(bytes) {
return BmpFileHeader.isValidFile(new InputBuffer({
buffer: bytes,
}));
}
startDecode(bytes) {
if (!this.isValidFile(bytes)) {
return undefined;
}
this._input = new InputBuffer({
buffer: bytes,
});
this._info = new BmpInfo(this._input);
return this._info;
}
decodeFrame(_frameIndex) {
if (this._input === undefined || this._info === undefined) {
return undefined;
}
const inf = this._info;
this._input.offset = inf.header.imageOffset;
const bpp = inf.bitsPerPixel;
const rowStride = Math.trunc((inf.width * bpp + 31) / 32) * 4;
const nc = this._forceRgba
? 4
: bpp === 1 || bpp === 4 || bpp === 8
? 1
: bpp === 32
? 4
: 3;
const format = this._forceRgba
? Format.uint8
: bpp === 1
? Format.uint1
: bpp === 2
? Format.uint2
: bpp === 4
? Format.uint4
: bpp === 8
? Format.uint8
: bpp === 16
? Format.uint8
: bpp === 24
? Format.uint8
: bpp === 32
? Format.uint8
: Format.uint8;
const palette = this._forceRgba ? undefined : inf.palette;
const image = new MemoryImage({
width: inf.width,
height: inf.height,
format: format,
numChannels: nc,
palette: palette,
});
for (let y = image.height - 1; y >= 0; --y) {
const line = inf.readBottomUp ? y : image.height - 1 - y;
const row = this._input.readRange(rowStride);
const w = image.width;
let x = 0;
const p = image.getPixel(0, line);
while (x < w) {
inf.decodePixel(row, (r, g, b, a) => {
if (x < w) {
if (this._forceRgba && inf.palette !== undefined) {
const pi = Math.trunc(r);
const pr = inf.palette.getRed(pi);
const pg = inf.palette.getGreen(pi);
const pb = inf.palette.getBlue(pi);
const pa = inf.palette.getAlpha(pi);
p.setRgba(pr, pg, pb, pa);
}
else {
p.setRgba(r, g, b, a);
}
p.next();
x++;
}
});
}
}
return image;
}
decode(opt) {
var _a;
const bytes = opt.bytes;
const frameIndex = (_a = opt.frameIndex) !== null && _a !== void 0 ? _a : 0;
if (this.startDecode(bytes) === undefined) {
return undefined;
}
return this.decodeFrame(frameIndex);
}
}
//# sourceMappingURL=bmp-decoder.js.map