From 74ad90cb8ff638642a40a4d4b62d31e906392493 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 16 Aug 2017 13:21:33 +0200 Subject: [PATCH 1/3] Update the mask data inversion in `PDFImage.createMask` to be compatible with both `Uint8Array` and `Uint8ClampedArray` --- src/core/image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/image.js b/src/core/image.js index 466b49833e3b6..7e01fb5281081 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -253,7 +253,7 @@ var PDFImage = (function PDFImageClosure() { // in this thread can be relying on its contents. if (inverseDecode) { for (i = 0; i < actualLength; i++) { - data[i] = ~data[i]; + data[i] ^= 0xFF; } } From f6636d6b19442ffbc59ee8df8383f046c886c622 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 15 Aug 2017 16:06:55 +0200 Subject: [PATCH 2/3] Use `Uint8ClampedArray` when returning image data in `src/core/jbig2.js` and `src/core/jpg.js` --- src/core/jbig2.js | 2 +- src/core/jpx.js | 2 +- src/core/stream.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/jbig2.js b/src/core/jbig2.js index c0beebcdfa069..d7cd398ff2cfe 100644 --- a/src/core/jbig2.js +++ b/src/core/jbig2.js @@ -955,7 +955,7 @@ var Jbig2Image = (function Jbig2ImageClosure() { onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) { this.currentPageInfo = info; var rowSize = (info.width + 7) >> 3; - var buffer = new Uint8Array(rowSize * info.height); + var buffer = new Uint8ClampedArray(rowSize * info.height); // The contents of ArrayBuffers are initialized to 0. // Fill the buffer with 0xFF only if info.defaultPixelValue is set if (info.defaultPixelValue) { diff --git a/src/core/jpx.js b/src/core/jpx.js index d6925b44ad3de..7d5490df106c1 100644 --- a/src/core/jpx.js +++ b/src/core/jpx.js @@ -1386,7 +1386,7 @@ var JpxImage = (function JpxImageClosure() { transformedTiles[c] = transformTile(context, tile, c); } var tile0 = transformedTiles[0]; - var out = new Uint8Array(tile0.items.length * componentsCount); + var out = new Uint8ClampedArray(tile0.items.length * componentsCount); var result = { left: tile0.left, top: tile0.top, diff --git a/src/core/stream.js b/src/core/stream.js index 17b764e6ea11b..5aa78c3922ed2 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -991,7 +991,7 @@ var JpxStream = (function JpxStreamClosure() { if (tileCount === 1) { this.buffer = jpxImage.tiles[0].items; } else { - var data = new Uint8Array(width * height * componentsCount); + var data = new Uint8ClampedArray(width * height * componentsCount); for (var k = 0; k < tileCount; k++) { var tileComponents = jpxImage.tiles[k]; From 563b68e74d82fec352783f2b54dac90228b59a72 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 15 Aug 2017 16:45:33 +0200 Subject: [PATCH 3/3] Remove manual clamping code in `src/core/jpx.js` Since we're now using `Uint8ClampedArray`, rather than `Uint8Array`, doing manual clamping shouldn't be necessary given that that is now handled natively. This shouldn't have any measurable performance impact, but just to sanity check that I've done some quick benchmarking with the following manifest file: ```json [ { "id": "S2-eq", "file": "pdfs/S2.pdf", "md5": "d0b6137846df6e0fe058f234a87fb588", "rounds": 100, "type": "eq" } ] ``` which gave the following results against the current `master` (repeated benchmark runs didn't result in any meaningful differences): ``` -- Grouped By browser, stat -- browser | stat | Count | Baseline(ms) | Current(ms) | +/- | % | Result(P<.05) ------- | ------------ | ----- | ------------ | ----------- | --- | ----- | ------------- firefox | Overall | 100 | 592 | 592 | 1 | 0.12 | firefox | Page Request | 100 | 3 | 3 | 0 | -9.88 | firefox | Rendering | 100 | 588 | 589 | 1 | 0.18 | ``` --- src/core/jpx.js | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/core/jpx.js b/src/core/jpx.js index 7d5490df106c1..7139d6602e02f 100644 --- a/src/core/jpx.js +++ b/src/core/jpx.js @@ -1396,8 +1396,8 @@ var JpxImage = (function JpxImageClosure() { }; // Section G.2.2 Inverse multi component transform - var shift, offset, max, min, maxK; - var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val; + var shift, offset; + var pos = 0, j, jj, y0, y1, y2; if (tile.codingStyleDefaultParameters.multipleComponentTransform) { var fourComponents = componentsCount === 4; var y0items = transformedTiles[0].items; @@ -1410,9 +1410,6 @@ var JpxImage = (function JpxImageClosure() { // compute shift and offset only once. shift = components[0].precision - 8; offset = (128 << shift) + 0.5; - max = 255 * (1 << shift); - maxK = max * 0.5; - min = -maxK; var component0 = tile.components[0]; var alpha01 = componentsCount - 3; @@ -1423,12 +1420,9 @@ var JpxImage = (function JpxImageClosure() { y0 = y0items[j] + offset; 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 <= 0 ? 0 : r >= max ? 255 : r >> shift; - out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift; - out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift; + out[pos++] = (y0 + 1.402 * y2) >> shift; + out[pos++] = (y0 - 0.34413 * y1 - 0.71414 * y2) >> shift; + out[pos++] = (y0 + 1.772 * y1) >> shift; } } else { // inverse reversible multiple component transform @@ -1436,18 +1430,16 @@ var JpxImage = (function JpxImageClosure() { y0 = y0items[j] + offset; y1 = y1items[j]; y2 = y2items[j]; - g = y0 - ((y2 + y1) >> 2); - r = g + y2; - b = g + y1; - out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift; - out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift; - out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift; + let g = y0 - ((y2 + y1) >> 2); + + out[pos++] = (g + y2) >> shift; + out[pos++] = g >> shift; + out[pos++] = (g + y1) >> shift; } } if (fourComponents) { for (j = 0, pos = 3; j < jj; j++, pos += 4) { - k = y3items[j]; - out[pos] = k <= min ? 0 : k >= maxK ? 255 : (k + offset) >> shift; + out[pos] = (y3items[j] + offset) >> shift; } } } else { // no multi-component transform @@ -1455,12 +1447,8 @@ var JpxImage = (function JpxImageClosure() { 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; + out[pos] = (items[j] + offset) >> shift; pos += componentsCount; } }