Merge pull request #4365 from fkaelberer/FixJpxParsing

Fix parsing of JP2 images
This commit is contained in:
Yury Delendik 2014-03-02 16:47:14 -06:00
commit 28d5ddbe2d

View File

@ -50,6 +50,14 @@ var JpxImage = (function JpxImageClosure() {
n = n * 256 + (data[offset + i] & 0xFF);
return n;
}
var head = readUint(data, 0, 2);
// No box header, immediate start of codestream (SOC)
if (head === 0xFF4F) {
this.parseCodestream(data, 0, data.length);
return;
}
var position = 0, length = data.length;
while (position < length) {
var headerSize = 8;
@ -254,9 +262,9 @@ var JpxImage = (function JpxImageClosure() {
cod.segmentationSymbolUsed = !!(blockStyle & 32);
cod.transformation = data[j++];
if (cod.entropyCoderWithCustomPrecincts) {
var precinctsSizes = {};
var precinctsSizes = [];
while (j < length + position) {
var precinctsSize = data[j];
var precinctsSize = data[j++];
precinctsSizes.push({
PPx: precinctsSize & 0xF,
PPy: precinctsSize >> 4
@ -519,8 +527,9 @@ var JpxImage = (function JpxImageClosure() {
var codeblocks = subband.codeblocks;
for (var j = 0, jj = codeblocks.length; j < jj; j++) {
var codeblock = codeblocks[j];
if (codeblock.precinctNumber != precinctNumber)
if (codeblock.precinctNumber != precinctNumber) {
continue;
}
precinctCodeblocks.push(codeblock);
}
}
@ -734,17 +743,21 @@ var JpxImage = (function JpxImageClosure() {
}
function readCodingpasses() {
var value = readBits(1);
if (value === 0)
if (value === 0) {
return 1;
}
value = (value << 1) | readBits(1);
if (value == 0x02)
if (value == 0x02) {
return 2;
}
value = (value << 2) | readBits(2);
if (value <= 0x0E)
if (value <= 0x0E) {
return (value & 0x03) + 3;
}
value = (value << 5) | readBits(5);
if (value <= 0x1FE)
if (value <= 0x1FE) {
return (value & 0x1F) + 6;
}
value = (value << 7) | readBits(7);
return (value & 0x7F) + 37;
}
@ -800,24 +813,28 @@ var JpxImage = (function JpxImageClosure() {
}
}
}
if (!codeblockIncluded)
if (!codeblockIncluded) {
continue;
}
if (firstTimeInclusion) {
zeroBitPlanesTree = precinct.zeroBitPlanesTree;
zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
while (true) {
if (readBits(1)) {
var valueReady = !zeroBitPlanesTree.nextLevel();
if (valueReady)
if (valueReady) {
break;
} else
}
} else {
zeroBitPlanesTree.incrementValue();
}
}
codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
}
var codingpasses = readCodingpasses();
while (readBits(1))
while (readBits(1)) {
codeblock.Lblock++;
}
var codingpassesLog2 = log2(codingpasses);
// rounding down log2
var bits = ((codingpasses < (1 << codingpassesLog2)) ?
@ -833,8 +850,9 @@ var JpxImage = (function JpxImageClosure() {
while (queue.length > 0) {
var packetItem = queue.shift();
var codeblock = packetItem.codeblock;
if (!('data' in codeblock))
if (!('data' in codeblock)) {
codeblock.data = [];
}
codeblock.data.push({
data: data,
start: offset + position,
@ -854,10 +872,12 @@ var JpxImage = (function JpxImageClosure() {
var codeblock = codeblocks[i];
var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
var blockHeight = codeblock.tby1_ - codeblock.tby0_;
if (blockWidth === 0 || blockHeight === 0)
if (blockWidth === 0 || blockHeight === 0) {
continue;
if (!('data' in codeblock))
}
if (!('data' in codeblock)) {
continue;
}
var bitModel, currentCodingpassType;
bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
@ -892,8 +912,9 @@ var JpxImage = (function JpxImageClosure() {
break;
case 2:
bitModel.runCleanupPass();
if (segmentationSymbolUsed)
if (segmentationSymbolUsed) {
bitModel.checkSegmentationSymbol();
}
break;
}
currentCodingpassType = (currentCodingpassType + 1) % 3;
@ -911,8 +932,9 @@ var JpxImage = (function JpxImageClosure() {
// not all bitplanes were decoded for reversible transformation
n += n < 0 ? n - r : n > 0 ? n + r : 0;
correction = 1 << (mb - nb);
} else
} else {
correction = 1;
}
coefficients[offset++] = n * correction * delta;
position++;
}
@ -1017,14 +1039,16 @@ var JpxImage = (function JpxImageClosure() {
// Section G.1 DC level shifting to unsigned component values
for (var c = 0; c < componentsCount; c++) {
var component = components[c];
if (component.isSigned)
if (component.isSigned) {
continue;
}
var offset = 1 << (component.precision - 1);
var tileImage = result[c];
var items = tileImage.items;
for (var j = 0, jj = items.length; j < jj; j++)
for (var j = 0, jj = items.length; j < jj; j++) {
items[j] += offset;
}
}
// To simplify things: shift and clamp output to 8 bit unsigned
@ -1129,8 +1153,9 @@ var JpxImage = (function JpxImageClosure() {
this.levels = [];
for (var i = 0; i < levelsLength; i++) {
var items = new Uint8Array(width * height);
for (var j = 0, jj = items.length; j < jj; j++)
for (var j = 0, jj = items.length; j < jj; j++) {
items[j] = defaultValue;
}
var level = {
width: width,
@ -1152,8 +1177,9 @@ var JpxImage = (function JpxImageClosure() {
level.index = index;
var value = level.items[index];
if (value == 0xFF)
if (value == 0xFF) {
break;
}
if (value > stopValue) {
this.currentLevel = currentLevel;
@ -1189,8 +1215,9 @@ var JpxImage = (function JpxImageClosure() {
var value = level.items[level.index];
level.items[level.index] = 0xFF;
currentLevel--;
if (currentLevel < 0)
if (currentLevel < 0) {
return false;
}
this.currentLevel = currentLevel;
var level = this.levels[currentLevel];
@ -1316,8 +1343,9 @@ var JpxImage = (function JpxImageClosure() {
},
renormD: function ArithmeticDecoder_renormD() {
do {
if (this.ct === 0)
if (this.ct === 0) {
this.byteIn();
}
this.a <<= 1;
this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
@ -1388,12 +1416,14 @@ var JpxImage = (function JpxImageClosure() {
// Table D-2
function calcSignContribution(significance0, sign0, significance1, sign1) {
if (significance1) {
if (!sign1)
if (!sign1) {
return significance0 ? (!sign0 ? 1 : 0) : 1;
else
} else {
return significance0 ? (!sign0 ? 0 : -1) : -1;
} else
}
} else {
return significance0 ? (!sign0 ? 1 : -1) : 0;
}
}
// Table D-3
var SignContextLabels = [
@ -1441,8 +1471,9 @@ var JpxImage = (function JpxImageClosure() {
this.runLengthContext = {index: 3, mps: 0};
this.contexts = [];
this.contexts.push({index: 4, mps: 0});
for (var i = 1; i <= 16; i++)
for (var i = 1; i <= 16; i++) {
this.contexts.push({index: 0, mps: 0});
}
},
setNeighborsSignificance:
function BitModel_setNeighborsSignificance(row, column) {
@ -1450,23 +1481,29 @@ var JpxImage = (function JpxImageClosure() {
var width = this.width, height = this.height;
var index = row * width + column;
if (row > 0) {
if (column > 0)
if (column > 0) {
neighborsSignificance[index - width - 1] += 0x10;
if (column + 1 < width)
}
if (column + 1 < width) {
neighborsSignificance[index - width + 1] += 0x10;
}
neighborsSignificance[index - width] += 0x04;
}
if (row + 1 < height) {
if (column > 0)
if (column > 0) {
neighborsSignificance[index + width - 1] += 0x10;
if (column + 1 < width)
}
if (column + 1 < width) {
neighborsSignificance[index + width + 1] += 0x10;
}
neighborsSignificance[index + width] += 0x04;
}
if (column > 0)
if (column > 0) {
neighborsSignificance[index - 1] += 0x01;
if (column + 1 < width)
}
if (column + 1 < width) {
neighborsSignificance[index + 1] += 0x01;
}
neighborsSignificance[index] |= 0x80;
},
runSignificancePropogationPass:
@ -1485,16 +1522,18 @@ var JpxImage = (function JpxImageClosure() {
var processedInverseMask = ~1;
var processedMask = 1;
var firstMagnitudeBitMask = 2;
for (var q = 0, qq = width * height; q < qq; q++)
for (var q = 0, qq = width * height; q < qq; q++) {
processingFlags[q] &= processedInverseMask;
}
for (var i0 = 0; i0 < height; i0 += 4) {
for (var j = 0; j < width; j++) {
var index = i0 * width + j;
for (var i1 = 0; i1 < 4; i1++, index += width) {
var i = i0 + i1;
if (i >= height)
if (i >= height) {
break;
}
if (coefficentsMagnitude[index] || !neighborsSignificance[index])
continue;
@ -1553,14 +1592,16 @@ var JpxImage = (function JpxImageClosure() {
for (var j = 0; j < width; j++) {
for (var i1 = 0; i1 < 4; i1++) {
var i = i0 + i1;
if (i >= height)
if (i >= height) {
break;
}
var index = i * width + j;
// significant but not those that have just become
if (!coefficentsMagnitude[index] ||
(processingFlags[index] & processedMask) !== 0)
(processingFlags[index] & processedMask) !== 0) {
continue;
}
var contextLabel = 16;
if ((processingFlags[index] &
@ -1637,19 +1678,22 @@ var JpxImage = (function JpxImageClosure() {
processingFlags[index] |= firstMagnitudeBitMask;
index = index0;
for (var i2 = i0; i2 <= i; i2++, index += width)
for (var i2 = i0; i2 <= i; i2++, index += width) {
bitsDecoded[index]++;
}
i1++;
}
for (; i1 < 4; i1++, index += width) {
i = i0 + i1;
if (i >= height)
if (i >= height) {
break;
}
if (coefficentsMagnitude[index] ||
(processingFlags[index] & processedMask) !== 0)
(processingFlags[index] & processedMask) !== 0) {
continue;
}
var contextLabel = labels[neighborsSignificance[index]];
cx = contexts[contextLabel];
@ -1671,8 +1715,9 @@ var JpxImage = (function JpxImageClosure() {
var cx = this.uniformContext;
var symbol = (decoder.readBit(cx) << 3) | (decoder.readBit(cx) << 2) |
(decoder.readBit(cx) << 1) | decoder.readBit(cx);
if (symbol != 0xA)
if (symbol != 0xA) {
throw 'Invalid segmentation symbol';
}
}
};