From 32367c596803cff992401f1a69d7ae7b7772a19f Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Mon, 11 Jun 2018 17:25:30 +0200 Subject: [PATCH] Make the `getBytes`/`peekBytes` methods of `Stream`/`DecodeStream`/`ChunkedStream` able to return `Uint8ClampedArray`s The built-in image decoders are already returning data as `Uint8ClampedArray`, and subsequently the JPEG/JBIG2/JPX streams are as well. However, for general streams we obviously don't want to force the use of `Uint8ClampedArray` unless an "Image" is actually being decoded. Hence this patch, which adds a parameter that allows the caller of the `getBytes`/`peekBytes` methods to force a `Uint8ClampedArray` (rather than a `Uint8Array`) to be returned. --- src/core/chunked_stream.js | 17 ++++++++++------- src/core/stream.js | 28 +++++++++++++++++----------- test/unit/stream_spec.js | 5 +++++ 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/core/chunked_stream.js b/src/core/chunked_stream.js index 8fcb5799d..1b9068b3d 100644 --- a/src/core/chunked_stream.js +++ b/src/core/chunked_stream.js @@ -181,16 +181,17 @@ var ChunkedStream = (function ChunkedStreamClosure() { return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; }, - // returns subarray of original buffer - // should only be read - getBytes: function ChunkedStream_getBytes(length) { + // Returns subarray of original buffer, should only be read. + getBytes(length, forceClamped = false) { var bytes = this.bytes; var pos = this.pos; var strEnd = this.end; if (!length) { this.ensureRange(pos, strEnd); - return bytes.subarray(pos, strEnd); + let subarray = bytes.subarray(pos, strEnd); + // `this.bytes` is always a `Uint8Array` here. + return (forceClamped ? new Uint8ClampedArray(subarray) : subarray); } var end = pos + length; @@ -200,7 +201,9 @@ var ChunkedStream = (function ChunkedStreamClosure() { this.ensureRange(pos, end); this.pos = end; - return bytes.subarray(pos, end); + let subarray = bytes.subarray(pos, end); + // `this.bytes` is always a `Uint8Array` here. + return (forceClamped ? new Uint8ClampedArray(subarray) : subarray); }, peekByte: function ChunkedStream_peekByte() { @@ -209,8 +212,8 @@ var ChunkedStream = (function ChunkedStreamClosure() { return peekedByte; }, - peekBytes: function ChunkedStream_peekBytes(length) { - var bytes = this.getBytes(length); + peekBytes(length, forceClamped = false) { + var bytes = this.getBytes(length, forceClamped); this.pos -= bytes.length; return bytes; }, diff --git a/src/core/stream.js b/src/core/stream.js index 4d7eb7e37..eefb04d46 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -56,30 +56,33 @@ var Stream = (function StreamClosure() { var b3 = this.getByte(); return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; }, - // returns subarray of original buffer - // should only be read - getBytes: function Stream_getBytes(length) { + // Returns subarray of original buffer, should only be read. + getBytes(length, forceClamped = false) { var bytes = this.bytes; var pos = this.pos; var strEnd = this.end; if (!length) { - return bytes.subarray(pos, strEnd); + let subarray = bytes.subarray(pos, strEnd); + // `this.bytes` is always a `Uint8Array` here. + return (forceClamped ? new Uint8ClampedArray(subarray) : subarray); } var end = pos + length; if (end > strEnd) { end = strEnd; } this.pos = end; - return bytes.subarray(pos, end); + let subarray = bytes.subarray(pos, end); + // `this.bytes` is always a `Uint8Array` here. + return (forceClamped ? new Uint8ClampedArray(subarray) : subarray); }, peekByte: function Stream_peekByte() { var peekedByte = this.getByte(); this.pos--; return peekedByte; }, - peekBytes: function Stream_peekBytes(length) { - var bytes = this.getBytes(length); + peekBytes(length, forceClamped = false) { + var bytes = this.getBytes(length, forceClamped); this.pos -= bytes.length; return bytes; }, @@ -181,7 +184,7 @@ var DecodeStream = (function DecodeStreamClosure() { var b3 = this.getByte(); return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; }, - getBytes: function DecodeStream_getBytes(length) { + getBytes(length, forceClamped = false) { var end, pos = this.pos; if (length) { @@ -203,15 +206,18 @@ var DecodeStream = (function DecodeStreamClosure() { } this.pos = end; - return this.buffer.subarray(pos, end); + let subarray = this.buffer.subarray(pos, end); + // `this.buffer` is either a `Uint8Array` or `Uint8ClampedArray` here. + return (forceClamped && !(subarray instanceof Uint8ClampedArray) ? + new Uint8ClampedArray(subarray) : subarray); }, peekByte: function DecodeStream_peekByte() { var peekedByte = this.getByte(); this.pos--; return peekedByte; }, - peekBytes: function DecodeStream_peekBytes(length) { - var bytes = this.getBytes(length); + peekBytes(length, forceClamped = false) { + var bytes = this.getBytes(length, forceClamped); this.pos -= bytes.length; return bytes; }, diff --git a/test/unit/stream_spec.js b/test/unit/stream_spec.js index b87301aeb..a53e95d95 100644 --- a/test/unit/stream_spec.js +++ b/test/unit/stream_spec.js @@ -59,6 +59,11 @@ describe('stream', function() { expect(result).toMatchTypedArray( new Uint8Array([100, 3, 101, 2, 102, 1]) ); + + predictor.reset(); + let clampedResult = predictor.getBytes(6, /* forceClamped = */ true); + expect(clampedResult).toEqual( + new Uint8ClampedArray([100, 3, 101, 2, 102, 1])); }); }); });