[Pkg-javascript-commits] [pdf.js] 12/56: Less copying in the JPX coder, merged and rebased
David Prévot
taffit at moszumanska.debian.org
Thu May 15 15:17:43 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository pdf.js.
commit 04602c8a5e95bf6c1d57e94188fb88249a9ad105
Author: fkaelberer <o_0_o at gmx.de>
Date: Wed Apr 16 10:40:04 2014 +0200
Less copying in the JPX coder, merged and rebased
---
src/core/image.js | 1 -
src/core/jpx.js | 228 +++++++++++++++++++++++++++++------------------------
src/core/stream.js | 97 +++++++----------------
3 files changed, 150 insertions(+), 176 deletions(-)
diff --git a/src/core/image.js b/src/core/image.js
index 5b913f6..e1a2b97 100644
--- a/src/core/image.js
+++ b/src/core/image.js
@@ -59,7 +59,6 @@ var PDFImage = (function PDFImageClosure() {
if (dict.has('Filter')) {
var filter = dict.get('Filter').name;
if (filter === 'JPXDecode') {
- info('get image params from JPX stream');
var jpxImage = new JpxImage();
jpxImage.parseImageProperties(image.stream);
image.stream.reset();
diff --git a/src/core/jpx.js b/src/core/jpx.js
index 66815b0..6f55574 100644
--- a/src/core/jpx.js
+++ b/src/core/jpx.js
@@ -281,7 +281,6 @@ var JpxImage = (function JpxImageClosure() {
cod.entropyCoderWithCustomPrecincts = !!(scod & 1);
cod.sopMarkerUsed = !!(scod & 2);
cod.ephMarkerUsed = !!(scod & 4);
- var codingStyle = {};
cod.progressionOrder = data[j++];
cod.layersCount = readUint16(data, j);
j += 2;
@@ -905,9 +904,15 @@ var JpxImage = (function JpxImageClosure() {
}
return position;
}
- function copyCoefficients(coefficients, x0, y0, width, height,
- delta, mb, codeblocks, reversible,
- segmentationSymbolUsed) {
+ function copyCoefficients(coefficients, levelWidth, levelHeight, subband,
+ delta, mb, reversible, segmentationSymbolUsed) {
+ var x0 = subband.tbx0;
+ var y0 = subband.tby0;
+ var width = subband.tbx1 - subband.tbx0;
+ var codeblocks = subband.codeblocks;
+ var right = subband.type.charAt(0) === 'H' ? 1 : 0;
+ var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0;
+
for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
var codeblock = codeblocks[i];
var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
@@ -921,29 +926,30 @@ var JpxImage = (function JpxImageClosure() {
var bitModel, currentCodingpassType;
bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
- codeblock.zeroBitPlanes);
+ codeblock.zeroBitPlanes, mb);
currentCodingpassType = 2; // first bit plane starts from cleanup
// collect data
var data = codeblock.data, totalLength = 0, codingpasses = 0;
- var q, qq, dataItem;
- for (q = 0, qq = data.length; q < qq; q++) {
- dataItem = data[q];
+ var j, jj, dataItem;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
totalLength += dataItem.end - dataItem.start;
codingpasses += dataItem.codingpasses;
}
- var encodedData = new Uint8Array(totalLength), k = 0;
- for (q = 0, qq = data.length; q < qq; q++) {
- dataItem = data[q];
+ var encodedData = new Uint8Array(totalLength);
+ var position = 0;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
var chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
- encodedData.set(chunk, k);
- k += chunk.length;
+ encodedData.set(chunk, position);
+ position += chunk.length;
}
// decoding the item
var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
bitModel.setDecoder(decoder);
- for (q = 0; q < codingpasses; q++) {
+ for (j = 0; j < codingpasses; j++) {
switch (currentCodingpassType) {
case 0:
bitModel.runSignificancePropogationPass();
@@ -962,13 +968,18 @@ var JpxImage = (function JpxImageClosure() {
}
var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
- var n, nb, position = 0;
- var irreversible = !reversible;
var sign = bitModel.coefficentsSign;
var magnitude = bitModel.coefficentsMagnitude;
var bitsDecoded = bitModel.bitsDecoded;
var magnitudeCorrection = reversible ? 0 : 0.5;
- for (var j = 0; j < blockHeight; j++) {
+ var k, n, nb;
+ position = 0;
+ // Do the interleaving of Section F.3.3 here, so we do not need
+ // to copy later. LL level is not interleaved, just copied.
+ var interleave = (subband.type !== 'LL');
+ for (j = 0; j < blockHeight; j++) {
+ var row = (offset / width) | 0; // row in the non-interleaved subband
+ var levelOffset = 2 * row * (levelWidth - width) + right + bottom;
for (k = 0; k < blockWidth; k++) {
n = magnitude[position];
if (n !== 0) {
@@ -977,10 +988,11 @@ var JpxImage = (function JpxImageClosure() {
n = -n;
}
nb = bitsDecoded[position];
- if (irreversible || mb > nb) {
- coefficients[offset] = n * (1 << (mb - nb));
+ var pos = interleave ? (levelOffset + (offset << 1)) : offset;
+ if (reversible && (nb >= mb)) {
+ coefficients[pos] = n;
} else {
- coefficients[offset] = n;
+ coefficients[pos] = n * (1 << (mb - nb));
}
}
offset++;
@@ -1011,6 +1023,11 @@ var JpxImage = (function JpxImageClosure() {
for (var i = 0; i <= decompositionLevelsCount; i++) {
var resolution = component.resolutions[i];
+ var width = resolution.trx1 - resolution.trx0;
+ var height = resolution.try1 - resolution.try0;
+ // Allocate space for the whole sublevel.
+ var coefficients = new Float32Array(width * height);
+
for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
var mu, epsilon;
if (!scalarExpounded) {
@@ -1020,11 +1037,10 @@ var JpxImage = (function JpxImageClosure() {
} else {
mu = spqcds[b].mu;
epsilon = spqcds[b].epsilon;
+ b++;
}
var subband = resolution.subbands[j];
- var width = subband.tbx1 - subband.tbx0;
- var height = subband.tby1 - subband.tby0;
var gainLog2 = SubbandsGainLog2[subband.type];
// calulate quantization coefficient (Section E.1.1.1)
@@ -1032,19 +1048,19 @@ var JpxImage = (function JpxImageClosure() {
Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048));
var mb = (guardBits + epsilon - 1);
- var coefficients = new Float32Array(width * height);
- copyCoefficients(coefficients, subband.tbx0, subband.tby0,
- width, height, delta, mb, subband.codeblocks, reversible,
- segmentationSymbolUsed);
-
- subbandCoefficients.push({
- width: width,
- height: height,
- items: coefficients
- });
-
- b++;
+ // In the first resolution level, copyCoefficients will fill the
+ // whole array with coefficients. In the succeding passes,
+ // copyCoefficients will consecutively fill in the values that belong
+ // to the interleaved positions of the HL, LH, and HH coefficients.
+ // The LL coefficients will then be interleaved in Transform.iterate().
+ copyCoefficients(coefficients, width, height, subband, delta, mb,
+ reversible, segmentationSymbolUsed);
}
+ subbandCoefficients.push({
+ width: width,
+ height: height,
+ items: coefficients
+ });
}
var result = transform.calculate(subbandCoefficients,
@@ -1064,60 +1080,80 @@ var JpxImage = (function JpxImageClosure() {
var resultImages = [];
for (var i = 0, ii = context.tiles.length; i < ii; i++) {
var tile = context.tiles[i];
- var result = [];
+ var transformedTiles = [];
var c;
for (c = 0; c < componentsCount; c++) {
- var image = transformTile(context, tile, c);
- result.push(image);
+ transformedTiles[c] = transformTile(context, tile, c);
}
+ var tile0 = transformedTiles[0];
+ var out = new Uint8Array(tile0.items.length * componentsCount);
+ var result = {
+ left: tile0.left,
+ top: tile0.top,
+ width: tile0.width,
+ height: tile0.height,
+ items: out
+ };
// Section G.2.2 Inverse multi component transform
- var y0items, y1items, y2items, j, jj, y0, y1, y2;
- var component, tileImage, items;
+ var shift, offset, max, min;
+ var pos = 0, j, jj, y0, y1, y2, r, g, b, val;
if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
+ var y2items = transformedTiles[2].items;
+ var y1items = transformedTiles[1].items;
+ var y0items = transformedTiles[0].items;
+
+ // HACK: The multiple component transform formulas below assume that
+ // all components have the same precision. With this in mind, we
+ // compute shift and offset only once.
+ shift = components[0].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = (127.5 * (1 << shift));
+ min = -max;
+
var component0 = tile.components[0];
if (!component0.codingStyleParameters.reversibleTransformation) {
// inverse irreversible multiple component transform
- y0items = result[0].items;
- y1items = result[1].items;
- y2items = result[2].items;
for (j = 0, jj = y0items.length; j < jj; ++j) {
- y0 = y0items[j] + 0.5; y1 = y1items[j]; y2 = y2items[j];
- y0items[j] = y0 + 1.402 * y2;
- y1items[j] = y0 - 0.34413 * y1 - 0.71414 * y2;
- y2items[j] = y0 + 1.772 * y1;
+ y0 = y0items[j];
+ y1 = y1items[j];
+ y2 = y2items[j];
+ r = y0 + 1.402 * y2;
+ g = y0 - 0.34413 * y1 - 0.71414 * y2;
+ b = y0 + 1.772 * y1;
+ out[pos++] = r <= min ? 0 : r >= max ? 255 : (r + offset) >> shift;
+ out[pos++] = g <= min ? 0 : g >= max ? 255 : (g + offset) >> shift;
+ out[pos++] = b <= min ? 0 : b >= max ? 255 : (b + offset) >> shift;
}
} else {
// inverse reversible multiple component transform
- y0items = result[0].items;
- y1items = result[1].items;
- y2items = result[2].items;
for (j = 0, jj = y0items.length; j < jj; ++j) {
- y0 = y0items[j]; y1 = y1items[j]; y2 = y2items[j];
- var i1 = y0 - ((y2 + y1) >> 2);
- y1items[j] = i1;
- y0items[j] = y2 + i1;
- y2items[j] = y1 + i1;
+ y0 = y0items[j];
+ y1 = y1items[j];
+ y2 = y2items[j];
+ g = y0 - ((y2 + y1) >> 2);
+ r = g + y2;
+ b = g + y1;
+ out[pos++] = r <= min ? 0 : r >= max ? 255 : (r + offset) >> shift;
+ out[pos++] = g <= min ? 0 : g >= max ? 255 : (g + offset) >> shift;
+ out[pos++] = b <= min ? 0 : b >= max ? 255 : (b + offset) >> shift;
}
}
- }
-
- // To simplify things: shift and clamp output to 8 bit unsigned
- for (c = 0; c < componentsCount; c++) {
- component = components[c];
- var shift = component.precision - 8;
- tileImage = result[c];
- items = tileImage.items;
- var data = new Uint8Array(items.length);
- var low = -(128 << shift);
- var high = 127 << shift;
- for (j = 0, jj = items.length; j < jj; j++) {
- var val = items[j];
- data[j] = val <= low ? 0 : val >= high ? 255 : (val >> shift) + 128;
+ } else { // no multi-component transform
+ for (c = 0; c < componentsCount; c++) {
+ var items = transformedTiles[c].items;
+ shift = components[c].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = (127.5 * (1 << shift));
+ min = -max;
+ for (pos = c, j = 0, jj = items.length; j < jj; j++) {
+ val = items[j];
+ out[pos] = val <= min ? 0 :
+ val >= max ? 255 : (val + offset) >> shift;
+ pos += componentsCount;
+ }
}
- result[c].items = data;
}
-
resultImages.push(result);
}
return resultImages;
@@ -1302,7 +1338,7 @@ var JpxImage = (function JpxImageClosure() {
8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8
]);
- function BitModel(width, height, subband, zeroBitPlanes) {
+ function BitModel(width, height, subband, zeroBitPlanes, mb) {
this.width = width;
this.height = height;
@@ -1315,7 +1351,9 @@ var JpxImage = (function JpxImageClosure() {
// add border state cells for significanceState
this.neighborsSignificance = new Uint8Array(coefficientCount);
this.coefficentsSign = new Uint8Array(coefficientCount);
- this.coefficentsMagnitude = new Uint32Array(coefficientCount);
+ this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) :
+ mb > 6 ? new Uint16Array(coefficientCount) :
+ new Uint8Array(coefficientCount);
this.processingFlags = new Uint8Array(coefficientCount);
var bitsDecoded = new Uint8Array(coefficientCount);
@@ -1628,9 +1666,8 @@ var JpxImage = (function JpxImageClosure() {
Transform.prototype.calculate =
function transformCalculate(subbands, u0, v0) {
var ll = subbands[0];
- for (var i = 1, ii = subbands.length; i < ii; i += 3) {
- ll = this.iterate(ll, subbands[i], subbands[i + 1],
- subbands[i + 2], u0, v0);
+ for (var i = 1, ii = subbands.length; i < ii; i++) {
+ ll = this.iterate(ll, subbands[i], u0, v0);
}
return ll;
};
@@ -1647,43 +1684,24 @@ var JpxImage = (function JpxImageClosure() {
buffer[i1] = buffer[j1];
buffer[j2] = buffer[i2];
};
- Transform.prototype.iterate = function Transform_iterate(ll, hl, lh, hh,
- u0, v0) {
- var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
- var hlWidth = hl.width, hlHeight = hl.height, hlItems = hl.items;
- var lhWidth = lh.width, lhHeight = lh.height, lhItems = lh.items;
- var hhWidth = hh.width, hhHeight = hh.height, hhItems = hh.items;
+ Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,
+ u0, v0) {
- // Section F.3.3 interleave
- var width = llWidth + hlWidth;
- var height = llHeight + lhHeight;
- var items = new Float32Array(width * height);
- var i, j, k, l, v, u;
+ var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
+ var width = hl_lh_hh.width;
+ var height = hl_lh_hh.height;
+ var items = hl_lh_hh.items;
+ var i, j, k, l, u, v;
- for (i = 0, k = 0; i < llHeight; i++) {
+ // Interleave LL according to Section F.3.3
+ for (k = 0, i = 0; i < llHeight; i++) {
l = i * 2 * width;
for (j = 0; j < llWidth; j++, k++, l += 2) {
items[l] = llItems[k];
}
}
- for (i = 0, k = 0; i < hlHeight; i++) {
- l = i * 2 * width + 1;
- for (j = 0; j < hlWidth; j++, k++, l += 2) {
- items[l] = hlItems[k];
- }
- }
- for (i = 0, k = 0; i < lhHeight; i++) {
- l = (i * 2 + 1) * width;
- for (j = 0; j < lhWidth; j++, k++, l += 2) {
- items[l] = lhItems[k];
- }
- }
- for (i = 0, k = 0; i < hhHeight; i++) {
- l = (i * 2 + 1) * width + 1;
- for (j = 0; j < hhWidth; j++, k++, l += 2) {
- items[l] = hhItems[k];
- }
- }
+ // The LL band is not needed anymore.
+ llItems = ll.items = null;
var bufferPadding = 4;
var rowBuffer = new Float32Array(width + 2 * bufferPadding);
diff --git a/src/core/stream.js b/src/core/stream.js
index 02235bc..320533c 100644
--- a/src/core/stream.js
+++ b/src/core/stream.js
@@ -942,78 +942,35 @@ var JpxStream = (function JpxStreamClosure() {
var width = jpxImage.width;
var height = jpxImage.height;
var componentsCount = jpxImage.componentsCount;
- if (componentsCount != 1 && componentsCount != 3 && componentsCount != 4) {
- error('JPX with ' + componentsCount + ' components is not supported');
- }
-
- var data = new Uint8Array(width * height * componentsCount);
-
- for (var k = 0, kk = jpxImage.tiles.length; k < kk; k++) {
- var tileCompoments = jpxImage.tiles[k];
- var tileWidth = tileCompoments[0].width;
- var tileHeight = tileCompoments[0].height;
- var tileLeft = tileCompoments[0].left;
- var tileTop = tileCompoments[0].top;
-
- var dataPosition, sourcePosition, data0, data1, data2, data3, rowFeed;
- var i, j;
- switch (componentsCount) {
- case 1:
- data0 = tileCompoments[0].items;
-
- dataPosition = width * tileTop + tileLeft;
- rowFeed = width - tileWidth;
- sourcePosition = 0;
- for (j = 0; j < tileHeight; j++) {
- for (i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition++];
- }
- dataPosition += rowFeed;
- }
- break;
- case 3:
- data0 = tileCompoments[0].items;
- data1 = tileCompoments[1].items;
- data2 = tileCompoments[2].items;
-
- dataPosition = (width * tileTop + tileLeft) * 3;
- rowFeed = (width - tileWidth) * 3;
- sourcePosition = 0;
- for (j = 0; j < tileHeight; j++) {
- for (i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition];
- data[dataPosition++] = data1[sourcePosition];
- data[dataPosition++] = data2[sourcePosition];
- sourcePosition++;
- }
- dataPosition += rowFeed;
- }
- break;
- case 4:
- data0 = tileCompoments[0].items;
- data1 = tileCompoments[1].items;
- data2 = tileCompoments[2].items;
- data3 = tileCompoments[3].items;
-
- dataPosition = (width * tileTop + tileLeft) * 4;
- rowFeed = (width - tileWidth) * 4;
- sourcePosition = 0;
- for (j = 0; j < tileHeight; j++) {
- for (i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition];
- data[dataPosition++] = data1[sourcePosition];
- data[dataPosition++] = data2[sourcePosition];
- data[dataPosition++] = data3[sourcePosition];
- sourcePosition++;
- }
- dataPosition += rowFeed;
- }
- break;
+ var tileCount = jpxImage.tiles.length;
+ if (tileCount === 1) {
+ this.buffer = jpxImage.tiles[0].items;
+ } else {
+ var data = new Uint8Array(width * height * componentsCount);
+
+ for (var k = 0; k < tileCount; k++) {
+ var tileComponents = jpxImage.tiles[k];
+ var tileWidth = tileComponents.width;
+ var tileHeight = tileComponents.height;
+ var tileLeft = tileComponents.left;
+ var tileTop = tileComponents.top;
+
+ var src = tileComponents.items;
+ var srcPosition = 0;
+ var dataPosition = (width * tileTop + tileLeft) * componentsCount;
+ var imgRowSize = width * componentsCount;
+ var tileRowSize = tileWidth * componentsCount;
+
+ for (var j = 0; j < tileHeight; j++) {
+ var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
+ data.set(rowBytes, dataPosition);
+ srcPosition += tileRowSize;
+ dataPosition += imgRowSize;
+ }
}
+ this.buffer = data;
}
-
- this.buffer = data;
- this.bufferLength = data.length;
+ this.bufferLength = this.buffer.length;
this.eof = true;
};
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/pdf.js.git
More information about the Pkg-javascript-commits
mailing list