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)
149 lines • 4.95 kB
JavaScript
import { ArrayUtils } from '../../common/array-utils.js';
import { VP8LImageTransformType } from './vp8l-image-transform-type.js';
import { VP8LInternal } from './vp8l-internal.js';
import { WebPFilters } from './webp-filters.js';
import { WebPInfo } from './webp-info.js';
export class WebPAlpha {
get input() {
return this._input;
}
get width() {
return this._width;
}
get height() {
return this._height;
}
get method() {
return this._method;
}
get filter() {
return this._filter;
}
get preProcessing() {
return this._preProcessing;
}
get rsrv() {
return this._rsrv;
}
get isAlphaDecoded() {
return this._isAlphaDecoded;
}
get vp8l() {
return this._vp8l;
}
get use8bDecode() {
return this._use8bDecode;
}
get isValid() {
if (this._method < WebPAlpha.alphaNoCompression ||
this._method > WebPAlpha.alphaLosslessCompression ||
this._filter >= WebPFilters.fitlerLast ||
this._preProcessing > WebPAlpha.alphaPreprocessedLevels ||
this._rsrv !== 0) {
return false;
}
return true;
}
constructor(input, width, height) {
this._width = 0;
this._height = 0;
this._method = 0;
this._filter = 0;
this._preProcessing = 0;
this._rsrv = 1;
this._isAlphaDecoded = false;
this._use8bDecode = false;
this._input = input;
this._width = width;
this._height = height;
const b = input.read();
this._method = b & 0x03;
this._filter = (b >>> 2) & 0x03;
this._preProcessing = (b >>> 4) & 0x03;
this._rsrv = (b >>> 6) & 0x03;
if (this.isValid) {
if (this._method === WebPAlpha.alphaNoCompression) {
const alphaDecodedSize = width * height;
if (input.length < alphaDecodedSize) {
this._rsrv = 1;
}
}
else if (this._method === WebPAlpha.alphaLosslessCompression) {
if (!this.decodeAlphaHeader()) {
this._rsrv = 1;
}
}
else {
this._rsrv = 1;
}
}
}
dequantizeLevels(_data, width, height, row, numRows) {
if (width <= 0 ||
height <= 0 ||
row < 0 ||
numRows < 0 ||
row + numRows > height) {
return false;
}
return true;
}
decodeAlphaImageStream(lastRow, output) {
this._vp8l.opaque = output;
return this._use8bDecode
? this._vp8l.decodeAlphaData(this._vp8l.webp.width, this._vp8l.webp.height, lastRow)
: this._vp8l.decodeImageData(this._vp8l.pixels, this._vp8l.webp.width, this._vp8l.webp.height, lastRow, this._vp8l.extractAlphaRows);
}
decodeAlphaHeader() {
const webp = new WebPInfo();
webp.width = this._width;
webp.height = this._height;
this._vp8l = new VP8LInternal(this._input, webp);
this._vp8l.ioWidth = this._width;
this._vp8l.ioHeight = this._height;
this._vp8l.decodeImageStream(webp.width, webp.height, true);
if (this._vp8l.transforms.length === 1 &&
this._vp8l.transforms[0].type === VP8LImageTransformType.colorIndexing &&
this._vp8l.is8bOptimizable()) {
this._use8bDecode = true;
this._vp8l.allocateInternalBuffers8b();
}
else {
this._use8bDecode = false;
this._vp8l.allocateInternalBuffers32b();
}
return true;
}
decode(row, numRows, output) {
if (!this.isValid) {
return false;
}
const unfilterFunc = WebPFilters.unfilters[this._filter];
if (this._method === WebPAlpha.alphaNoCompression) {
const offset = row * this._width;
const numPixels = numRows * this._width;
ArrayUtils.copyRange(this._input.buffer, this._input.position + offset, output, offset, numPixels);
}
else {
if (!this.decodeAlphaImageStream(row + numRows, output)) {
return false;
}
}
if (unfilterFunc !== undefined) {
unfilterFunc(this._width, this._height, this._width, row, numRows, output);
}
if (this._preProcessing === WebPAlpha.alphaPreprocessedLevels) {
if (!this.dequantizeLevels(output, this._width, this._height, row, numRows)) {
return false;
}
}
if (row + numRows === this._height) {
this._isAlphaDecoded = true;
}
return true;
}
}
WebPAlpha.alphaNoCompression = 0;
WebPAlpha.alphaLosslessCompression = 1;
WebPAlpha.alphaPreprocessedLevels = 1;
//# sourceMappingURL=webp-alpha.js.map