@abasb75/jpeg-lossless-decoder
Version:
A JavaScript JPEG Lossless decoder.
1,014 lines (1,013 loc) • 37.6 kB
JavaScript
import { DataStream } from './data-stream';
import { FrameHeader } from './frame-header';
import { HuffmanTable } from './huffman-table';
import { QuantizationTable } from './quantization-table';
import { ScanHeader } from './scan-header';
import { createArray } from './utils';
var littleEndian = (function () {
var buffer = new ArrayBuffer(2);
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
// Int16Array uses the platform's endianness.
return new Int16Array(buffer)[0] === 256;
})();
var Decoder = /** @class */ (function () {
/**
* The Decoder constructor.
* @property {number} numBytes - number of bytes per component
* @type {Function}
*/
function Decoder(buffer, numBytes) {
Object.defineProperty(this, "buffer", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "stream", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "frame", {
enumerable: true,
configurable: true,
writable: true,
value: new FrameHeader()
});
Object.defineProperty(this, "huffTable", {
enumerable: true,
configurable: true,
writable: true,
value: new HuffmanTable()
});
Object.defineProperty(this, "quantTable", {
enumerable: true,
configurable: true,
writable: true,
value: new QuantizationTable()
});
Object.defineProperty(this, "scan", {
enumerable: true,
configurable: true,
writable: true,
value: new ScanHeader()
});
Object.defineProperty(this, "DU", {
enumerable: true,
configurable: true,
writable: true,
value: createArray(10, 4, 64)
}); // at most 10 data units in a MCU, at most 4 data units in one component
Object.defineProperty(this, "HuffTab", {
enumerable: true,
configurable: true,
writable: true,
value: createArray(4, 2, 50 * 256)
});
Object.defineProperty(this, "IDCT_Source", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "nBlock", {
enumerable: true,
configurable: true,
writable: true,
value: []
}); // number of blocks in the i-th Comp in a scan
Object.defineProperty(this, "acTab", {
enumerable: true,
configurable: true,
writable: true,
value: createArray(10, 1)
}); // ac HuffTab for the i-th Comp in a scan
Object.defineProperty(this, "dcTab", {
enumerable: true,
configurable: true,
writable: true,
value: createArray(10, 1)
}); // dc HuffTab for the i-th Comp in a scan
Object.defineProperty(this, "qTab", {
enumerable: true,
configurable: true,
writable: true,
value: createArray(10, 1)
}); // quantization table for the i-th Comp in a scan
Object.defineProperty(this, "marker", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "markerIndex", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "numComp", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "restartInterval", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "selection", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "xDim", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "yDim", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "xLoc", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "yLoc", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "outputData", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "restarting", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "mask", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "numBytes", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "precision", {
enumerable: true,
configurable: true,
writable: true,
value: undefined
});
Object.defineProperty(this, "components", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "getter", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "setter", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "output", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "selector", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
this.buffer = buffer !== null && buffer !== void 0 ? buffer : null;
this.numBytes = numBytes !== null && numBytes !== void 0 ? numBytes : 0;
}
/**
* Returns decompressed data.
*/
Object.defineProperty(Decoder.prototype, "decompress", {
enumerable: false,
configurable: true,
writable: true,
value: function (buffer, offset, length) {
var result = this.decode(buffer, offset, length);
return result.buffer;
}
});
Object.defineProperty(Decoder.prototype, "decode", {
enumerable: false,
configurable: true,
writable: true,
value: function (buffer, offset, length, numBytes) {
var _a, _b;
var scanNum = 0;
var pred = [];
var i;
var compN;
var temp = [];
var index = [];
var mcuNum;
if (buffer) {
this.buffer = buffer;
}
if (numBytes !== undefined) {
this.numBytes = numBytes;
}
this.stream = new DataStream(this.buffer, offset, length);
this.buffer = null;
this.xLoc = 0;
this.yLoc = 0;
var current = this.stream.get16();
if (current !== 0xffd8) {
// SOI
throw new Error('Not a JPEG file');
}
current = this.stream.get16();
while (current >> 4 !== 0x0ffc || current === 0xffc4) {
// SOF 0~15
switch (current) {
case 0xffc4: // DHT
this.huffTable.read(this.stream, this.HuffTab);
break;
case 0xffcc: // DAC
throw new Error("Program doesn't support arithmetic coding. (format throw new IOException)");
case 0xffdb:
this.quantTable.read(this.stream, Decoder.TABLE);
break;
case 0xffdd:
this.restartInterval = (_a = this.readNumber()) !== null && _a !== void 0 ? _a : 0;
break;
case 0xffe0:
case 0xffe1:
case 0xffe2:
case 0xffe3:
case 0xffe4:
case 0xffe5:
case 0xffe6:
case 0xffe7:
case 0xffe8:
case 0xffe9:
case 0xffea:
case 0xffeb:
case 0xffec:
case 0xffed:
case 0xffee:
case 0xffef:
this.readApp();
break;
case 0xfffe:
this.readComment();
break;
default:
if (current >> 8 !== 0xff) {
throw new Error('ERROR: format throw new IOException! (decode)');
}
}
current = this.stream.get16();
}
if (current < 0xffc0 || current > 0xffc7) {
throw new Error('ERROR: could not handle arithmetic code!');
}
this.frame.read(this.stream);
current = this.stream.get16();
do {
while (current !== 0x0ffda) {
// SOS
switch (current) {
case 0xffc4: // DHT
this.huffTable.read(this.stream, this.HuffTab);
break;
case 0xffcc: // DAC
throw new Error("Program doesn't support arithmetic coding. (format throw new IOException)");
case 0xffdb:
this.quantTable.read(this.stream, Decoder.TABLE);
break;
case 0xffdd:
this.restartInterval = (_b = this.readNumber()) !== null && _b !== void 0 ? _b : 0;
break;
case 0xffe0:
case 0xffe1:
case 0xffe2:
case 0xffe3:
case 0xffe4:
case 0xffe5:
case 0xffe6:
case 0xffe7:
case 0xffe8:
case 0xffe9:
case 0xffea:
case 0xffeb:
case 0xffec:
case 0xffed:
case 0xffee:
case 0xffef:
this.readApp();
break;
case 0xfffe:
this.readComment();
break;
default:
if (current >> 8 !== 0xff) {
throw new Error('ERROR: format throw new IOException! (Parser.decode)');
}
}
current = this.stream.get16();
}
this.precision = this.frame.precision;
this.components = this.frame.components;
if (!this.numBytes) {
this.numBytes = Math.round(Math.ceil(this.precision / 8));
}
if (this.numBytes === 1) {
this.mask = 0xff;
}
else {
this.mask = 0xffff;
}
this.scan.read(this.stream);
this.numComp = this.scan.numComp;
this.selection = this.scan.selection;
if (this.numBytes === 1) {
if (this.numComp === 3) {
this.getter = this.getValueRGB;
this.setter = this.setValueRGB;
this.output = this.outputRGB;
}
else {
this.getter = this.getValue8;
this.setter = this.setValue8;
this.output = this.outputSingle;
}
}
else {
this.getter = this.getValue8;
this.setter = this.setValue8;
this.output = this.outputSingle;
}
switch (this.selection) {
case 2:
this.selector = this.select2;
break;
case 3:
this.selector = this.select3;
break;
case 4:
this.selector = this.select4;
break;
case 5:
this.selector = this.select5;
break;
case 6:
this.selector = this.select6;
break;
case 7:
this.selector = this.select7;
break;
default:
this.selector = this.select1;
break;
}
// this.scanComps = this.scan.components
// this.quantTables = this.quantTable.quantTables
for (i = 0; i < this.numComp; i += 1) {
compN = this.scan.components[i].scanCompSel;
this.qTab[i] = this.quantTable.quantTables[this.components[compN].quantTableSel];
this.nBlock[i] = this.components[compN].vSamp * this.components[compN].hSamp;
this.dcTab[i] = this.HuffTab[this.scan.components[i].dcTabSel][0];
this.acTab[i] = this.HuffTab[this.scan.components[i].acTabSel][1];
}
this.xDim = this.frame.dimX;
this.yDim = this.frame.dimY;
if (this.numBytes === 1) {
this.outputData = new Uint8Array(new ArrayBuffer(this.xDim * this.yDim * this.numBytes * this.numComp));
}
else {
this.outputData = new Uint16Array(new ArrayBuffer(this.xDim * this.yDim * this.numBytes * this.numComp));
}
scanNum += 1;
while (true) {
// Decode one scan
temp[0] = 0;
index[0] = 0;
for (i = 0; i < 10; i += 1) {
pred[i] = 1 << (this.precision - 1);
}
if (this.restartInterval === 0) {
current = this.decodeUnit(pred, temp, index);
while (current === 0 && this.xLoc < this.xDim && this.yLoc < this.yDim) {
this.output(pred);
current = this.decodeUnit(pred, temp, index);
}
break; // current=MARKER
}
for (mcuNum = 0; mcuNum < this.restartInterval; mcuNum += 1) {
this.restarting = mcuNum === 0;
current = this.decodeUnit(pred, temp, index);
this.output(pred);
if (current !== 0) {
break;
}
}
if (current === 0) {
if (this.markerIndex !== 0) {
current = 0xff00 | this.marker;
this.markerIndex = 0;
}
else {
current = this.stream.get16();
}
}
if (!(current >= Decoder.RESTART_MARKER_BEGIN && current <= Decoder.RESTART_MARKER_END)) {
break; // current=MARKER
}
}
if (current === 0xffdc && scanNum === 1) {
// DNL
this.readNumber();
current = this.stream.get16();
}
} while (current !== 0xffd9 && this.xLoc < this.xDim && this.yLoc < this.yDim && scanNum === 0);
return this.outputData;
}
});
Object.defineProperty(Decoder.prototype, "decodeUnit", {
enumerable: false,
configurable: true,
writable: true,
value: function (prev, temp, index) {
if (this.numComp === 1) {
return this.decodeSingle(prev, temp, index);
}
else if (this.numComp === 3) {
return this.decodeRGB(prev, temp, index);
}
else {
return -1;
}
}
});
Object.defineProperty(Decoder.prototype, "select1", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
return this.getPreviousX(compOffset);
}
});
Object.defineProperty(Decoder.prototype, "select2", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
return this.getPreviousY(compOffset);
}
});
Object.defineProperty(Decoder.prototype, "select3", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
return this.getPreviousXY(compOffset);
}
});
Object.defineProperty(Decoder.prototype, "select4", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
return this.getPreviousX(compOffset) + this.getPreviousY(compOffset) - this.getPreviousXY(compOffset);
}
});
Object.defineProperty(Decoder.prototype, "select5", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
return this.getPreviousX(compOffset) + ((this.getPreviousY(compOffset) - this.getPreviousXY(compOffset)) >> 1);
}
});
Object.defineProperty(Decoder.prototype, "select6", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
return this.getPreviousY(compOffset) + ((this.getPreviousX(compOffset) - this.getPreviousXY(compOffset)) >> 1);
}
});
Object.defineProperty(Decoder.prototype, "select7", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
return (this.getPreviousX(compOffset) + this.getPreviousY(compOffset)) / 2;
}
});
Object.defineProperty(Decoder.prototype, "decodeRGB", {
enumerable: false,
configurable: true,
writable: true,
value: function (prev, temp, index) {
if (this.selector === null)
throw new Error("decode hasn't run yet");
var actab, dctab, qtab, ctrC, i, k, j;
prev[0] = this.selector(0);
prev[1] = this.selector(1);
prev[2] = this.selector(2);
for (ctrC = 0; ctrC < this.numComp; ctrC += 1) {
qtab = this.qTab[ctrC];
actab = this.acTab[ctrC];
dctab = this.dcTab[ctrC];
for (i = 0; i < this.nBlock[ctrC]; i += 1) {
for (k = 0; k < this.IDCT_Source.length; k += 1) {
this.IDCT_Source[k] = 0;
}
var value = this.getHuffmanValue(dctab, temp, index);
if (value >= 0xff00) {
return value;
}
prev[ctrC] = this.IDCT_Source[0] = prev[ctrC] + this.getn(index, value, temp, index);
this.IDCT_Source[0] *= qtab[0];
for (j = 1; j < 64; j += 1) {
value = this.getHuffmanValue(actab, temp, index);
if (value >= 0xff00) {
return value;
}
j += value >> 4;
if ((value & 0x0f) === 0) {
if (value >> 4 === 0) {
break;
}
}
else {
this.IDCT_Source[Decoder.IDCT_P[j]] = this.getn(index, value & 0x0f, temp, index) * qtab[j];
}
}
}
}
return 0;
}
});
Object.defineProperty(Decoder.prototype, "decodeSingle", {
enumerable: false,
configurable: true,
writable: true,
value: function (prev, temp, index) {
if (this.selector === null)
throw new Error("decode hasn't run yet");
var value, i, n, nRestart;
if (this.restarting) {
this.restarting = false;
prev[0] = 1 << (this.frame.precision - 1);
}
else {
prev[0] = this.selector();
}
for (i = 0; i < this.nBlock[0]; i += 1) {
value = this.getHuffmanValue(this.dcTab[0], temp, index);
if (value >= 0xff00) {
return value;
}
n = this.getn(prev, value, temp, index);
nRestart = n >> 8;
if (nRestart >= Decoder.RESTART_MARKER_BEGIN && nRestart <= Decoder.RESTART_MARKER_END) {
return nRestart;
}
prev[0] += n;
}
return 0;
}
});
// Huffman table for fast search: (HuffTab) 8-bit Look up table 2-layer search architecture, 1st-layer represent 256 node (8 bits) if codeword-length > 8
// bits, then the entry of 1st-layer = (# of 2nd-layer table) | MSB and it is stored in the 2nd-layer Size of tables in each layer are 256.
// HuffTab[*][*][0-256] is always the only 1st-layer table.
//
// An entry can be: (1) (# of 2nd-layer table) | MSB , for code length > 8 in 1st-layer (2) (Code length) << 8 | HuffVal
//
// HuffmanValue(table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...)
// ):
// return: Huffman Value of table
// 0xFF?? if it receives a MARKER
// Parameter: table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...)
// temp temp storage for remainded bits
// index index to bit of temp
// in FILE pointer
// Effect:
// temp store new remainded bits
// index change to new index
// in change to new position
// NOTE:
// Initial by temp=0; index=0;
// NOTE: (explain temp and index)
// temp: is always in the form at calling time or returning time
// | byte 4 | byte 3 | byte 2 | byte 1 |
// | 0 | 0 | 00000000 | 00000??? | if not a MARKER
// ^index=3 (from 0 to 15)
// 321
// NOTE (marker and marker_index):
// If get a MARKER from 'in', marker=the low-byte of the MARKER
// and marker_index=9
// If marker_index=9 then index is always > 8, or HuffmanValue()
// will not be called
Object.defineProperty(Decoder.prototype, "getHuffmanValue", {
enumerable: false,
configurable: true,
writable: true,
value: function (table, temp, index) {
var code, input;
var mask = 0xffff;
if (!this.stream)
throw new Error('stream not initialized');
if (index[0] < 8) {
temp[0] <<= 8;
input = this.stream.get8();
if (input === 0xff) {
this.marker = this.stream.get8();
if (this.marker !== 0) {
this.markerIndex = 9;
}
}
temp[0] |= input;
}
else {
index[0] -= 8;
}
code = table[temp[0] >> index[0]];
if ((code & Decoder.MSB) !== 0) {
if (this.markerIndex !== 0) {
this.markerIndex = 0;
return 0xff00 | this.marker;
}
temp[0] &= mask >> (16 - index[0]);
temp[0] <<= 8;
input = this.stream.get8();
if (input === 0xff) {
this.marker = this.stream.get8();
if (this.marker !== 0) {
this.markerIndex = 9;
}
}
temp[0] |= input;
code = table[(code & 0xff) * 256 + (temp[0] >> index[0])];
index[0] += 8;
}
index[0] += 8 - (code >> 8);
if (index[0] < 0) {
throw new Error('index=' + index[0] + ' temp=' + temp[0] + ' code=' + code + ' in HuffmanValue()');
}
if (index[0] < this.markerIndex) {
this.markerIndex = 0;
return 0xff00 | this.marker;
}
temp[0] &= mask >> (16 - index[0]);
return code & 0xff;
}
});
Object.defineProperty(Decoder.prototype, "getn", {
enumerable: false,
configurable: true,
writable: true,
value: function (PRED, n, temp, index) {
var result, input;
var one = 1;
var n_one = -1;
var mask = 0xffff;
if (this.stream === null)
throw new Error('stream not initialized');
if (n === 0) {
return 0;
}
if (n === 16) {
if (PRED[0] >= 0) {
return -32768;
}
else {
return 32768;
}
}
index[0] -= n;
if (index[0] >= 0) {
if (index[0] < this.markerIndex && !this.isLastPixel()) {
// this was corrupting the last pixel in some cases
this.markerIndex = 0;
return (0xff00 | this.marker) << 8;
}
result = temp[0] >> index[0];
temp[0] &= mask >> (16 - index[0]);
}
else {
temp[0] <<= 8;
input = this.stream.get8();
if (input === 0xff) {
this.marker = this.stream.get8();
if (this.marker !== 0) {
this.markerIndex = 9;
}
}
temp[0] |= input;
index[0] += 8;
if (index[0] < 0) {
if (this.markerIndex !== 0) {
this.markerIndex = 0;
return (0xff00 | this.marker) << 8;
}
temp[0] <<= 8;
input = this.stream.get8();
if (input === 0xff) {
this.marker = this.stream.get8();
if (this.marker !== 0) {
this.markerIndex = 9;
}
}
temp[0] |= input;
index[0] += 8;
}
if (index[0] < 0) {
throw new Error('index=' + index[0] + ' in getn()');
}
if (index[0] < this.markerIndex) {
this.markerIndex = 0;
return (0xff00 | this.marker) << 8;
}
result = temp[0] >> index[0];
temp[0] &= mask >> (16 - index[0]);
}
if (result < one << (n - 1)) {
result += (n_one << n) + 1;
}
return result;
}
});
Object.defineProperty(Decoder.prototype, "getPreviousX", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
if (compOffset === void 0) { compOffset = 0; }
if (this.getter === null)
throw new Error("decode hasn't run yet");
if (this.xLoc > 0) {
return this.getter(this.yLoc * this.xDim + this.xLoc - 1, compOffset);
}
else if (this.yLoc > 0) {
return this.getPreviousY(compOffset);
}
else {
return 1 << (this.frame.precision - 1);
}
}
});
Object.defineProperty(Decoder.prototype, "getPreviousXY", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
if (compOffset === void 0) { compOffset = 0; }
if (this.getter === null)
throw new Error("decode hasn't run yet");
if (this.xLoc > 0 && this.yLoc > 0) {
return this.getter((this.yLoc - 1) * this.xDim + this.xLoc - 1, compOffset);
}
else {
return this.getPreviousY(compOffset);
}
}
});
Object.defineProperty(Decoder.prototype, "getPreviousY", {
enumerable: false,
configurable: true,
writable: true,
value: function (compOffset) {
if (compOffset === void 0) { compOffset = 0; }
if (this.getter === null)
throw new Error("decode hasn't run yet");
if (this.yLoc > 0) {
return this.getter((this.yLoc - 1) * this.xDim + this.xLoc, compOffset);
}
else {
return this.getPreviousX(compOffset);
}
}
});
Object.defineProperty(Decoder.prototype, "isLastPixel", {
enumerable: false,
configurable: true,
writable: true,
value: function () {
return this.xLoc === this.xDim - 1 && this.yLoc === this.yDim - 1;
}
});
Object.defineProperty(Decoder.prototype, "outputSingle", {
enumerable: false,
configurable: true,
writable: true,
value: function (PRED) {
if (this.setter === null)
throw new Error("decode hasn't run yet");
if (this.xLoc < this.xDim && this.yLoc < this.yDim) {
this.setter(this.yLoc * this.xDim + this.xLoc, this.mask & PRED[0]);
this.xLoc += 1;
if (this.xLoc >= this.xDim) {
this.yLoc += 1;
this.xLoc = 0;
}
}
}
});
Object.defineProperty(Decoder.prototype, "outputRGB", {
enumerable: false,
configurable: true,
writable: true,
value: function (PRED) {
if (this.setter === null)
throw new Error("decode hasn't run yet");
var offset = this.yLoc * this.xDim + this.xLoc;
if (this.xLoc < this.xDim && this.yLoc < this.yDim) {
this.setter(offset, PRED[0], 0);
this.setter(offset, PRED[1], 1);
this.setter(offset, PRED[2], 2);
this.xLoc += 1;
if (this.xLoc >= this.xDim) {
this.yLoc += 1;
this.xLoc = 0;
}
}
}
});
Object.defineProperty(Decoder.prototype, "setValue8", {
enumerable: false,
configurable: true,
writable: true,
value: function (index, val) {
if (!this.outputData)
throw new Error('output data not ready');
if (littleEndian) {
this.outputData[index] = val;
}
else {
this.outputData[index] = ((val & 0xff) << 8) | ((val >> 8) & 0xff);
}
}
});
Object.defineProperty(Decoder.prototype, "getValue8", {
enumerable: false,
configurable: true,
writable: true,
value: function (index) {
if (this.outputData === null)
throw new Error('output data not ready');
if (littleEndian) {
return this.outputData[index]; // mask should not be necessary because outputData is either Int8Array or Int16Array
}
else {
var val = this.outputData[index];
return ((val & 0xff) << 8) | ((val >> 8) & 0xff);
}
}
});
Object.defineProperty(Decoder.prototype, "setValueRGB", {
enumerable: false,
configurable: true,
writable: true,
value: function (index, val, compOffset) {
if (compOffset === void 0) { compOffset = 0; }
if (this.outputData === null)
return;
this.outputData[index * 3 + compOffset] = val;
}
});
Object.defineProperty(Decoder.prototype, "getValueRGB", {
enumerable: false,
configurable: true,
writable: true,
value: function (index, compOffset) {
if (this.outputData === null)
throw new Error('output data not ready');
return this.outputData[index * 3 + compOffset];
}
});
Object.defineProperty(Decoder.prototype, "readApp", {
enumerable: false,
configurable: true,
writable: true,
value: function () {
if (this.stream === null)
return null;
var count = 0;
var length = this.stream.get16();
count += 2;
while (count < length) {
this.stream.get8();
count += 1;
}
return length;
}
});
Object.defineProperty(Decoder.prototype, "readComment", {
enumerable: false,
configurable: true,
writable: true,
value: function () {
if (this.stream === null)
return null;
var sb = '';
var count = 0;
var length = this.stream.get16();
count += 2;
while (count < length) {
sb += this.stream.get8();
count += 1;
}
return sb;
}
});
Object.defineProperty(Decoder.prototype, "readNumber", {
enumerable: false,
configurable: true,
writable: true,
value: function () {
if (this.stream === null)
return null;
var Ld = this.stream.get16();
if (Ld !== 4) {
throw new Error('ERROR: Define number format throw new IOException [Ld!=4]');
}
return this.stream.get16();
}
});
Object.defineProperty(Decoder, "IDCT_P", {
enumerable: true,
configurable: true,
writable: true,
value: [
0, 5, 40, 16, 45, 2, 7, 42, 21, 56, 8, 61, 18, 47, 1, 4, 41, 23, 58, 13, 32, 24, 37, 10, 63, 17, 44, 3, 6, 43, 20,
57, 15, 34, 29, 48, 53, 26, 39, 9, 60, 19, 46, 22, 59, 12, 33, 31, 50, 55, 25, 36, 11, 62, 14, 35, 28, 49, 52, 27,
38, 30, 51, 54
]
});
Object.defineProperty(Decoder, "TABLE", {
enumerable: true,
configurable: true,
writable: true,
value: [
0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44,
53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49,
57, 58, 62, 63
]
});
Object.defineProperty(Decoder, "MAX_HUFFMAN_SUBTREE", {
enumerable: true,
configurable: true,
writable: true,
value: 50
});
Object.defineProperty(Decoder, "MSB", {
enumerable: true,
configurable: true,
writable: true,
value: 0x80000000
});
Object.defineProperty(Decoder, "RESTART_MARKER_BEGIN", {
enumerable: true,
configurable: true,
writable: true,
value: 0xffd0
});
Object.defineProperty(Decoder, "RESTART_MARKER_END", {
enumerable: true,
configurable: true,
writable: true,
value: 0xffd7
});
return Decoder;
}());
export { Decoder };