Less copying in the JPX decoder

The goal of this PR is to reduce the copy operations during JPX decoding.

In the existing code, JPX image are decoded to individual UInt8Arrays for each tile and each color channel in JPX.js, and then joined to a single (rgb) data array in stream.js. This PR now creates a single rgb array for each tile, so merging those in streams.js is simplified, and can be even avoided if only one tile is present (which is the case for example in #2790 and #3181, so it should save time and memory).

I also refactored the shifting and clamping in the JPX code (so this PR supersedes #4531).
Before, there where two loops: one loop for shifting in the unsigned case (L1065), and one loop that shifted in the signed case and clamped to UInt8 (L1080).
I avoided those loops and instead used a shift-and-clamp function when the data is written in the first place.

This patch will **not pass** the equality test of S2.pdf, because there is a slightly different rounding behavior.
You can make it pass the test by changing line 1024 from
`return (value <= -128) ? 0 : ((value >= 127) ? 255 : (value + 128) | 0);`
`return (value <= -128) ? 0 : ((value >= 127) ? 255 : new Float32Array([value + 128])[0] | 0);`
The s2.pdf example contains values that are so close to an integer that truncating to 32 bit precision does make a difference, e.g. `(new Float32Array([119.99999237060547 + 128])[0] | 0) != ((119.99999237060547 + 128) | 0)`.
In the old code, the truncation to 32 bit precision happened in line 1075, and so 119.99..+128 was rounded up, whereas now it is rounded down.

When I tried to figure out which of the two possibilities is the correct behavior, I noticed that the jj2000 java reference code produces neither of them: the floating point values differ up to +-4 (in the [-128, 128] range), so if a handful of 119.99-pixels is rounded up or down shouldn't matter here, given that all the other pixels might be off by up to 4.