[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