Skip to content

Commit 4450904

Browse files
authored
Merge pull request #32 from jerch/prepare_new_release
prepare new release
2 parents a741014 + b9eb2b1 commit 4450904

15 files changed

+934
-2128
lines changed

README.md

+36-46
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ SIXEL image decoding / encoding library for node and the browser.
55

66
### Decoding
77

8-
For decoding the library provides a stream decoder, that can either be used directly or with the convenient functions.
8+
For decoding the library provides a stream decoder, that can either be used directly,
9+
or with the following convenient functions:
910

1011
- `decode(data: UintTypedArray | string, opts?: IDecoderOptions): IDecodeResult`
1112
Convenient function to decode the sixel data in `data`. Can be used for casual decoding and when you have the full image data at hand (not chunked). The function is actually a thin wrapper around the decoder, and spawns a new instance for every call.
@@ -17,9 +18,8 @@ For decoding the library provides a stream decoder, that can either be used dire
1718

1819
#### Decoder
1920

20-
The decoder uses webassembly for data decoding (see [/wasm](wasm/) for the webassembly parts), which gives a major performance improvement, compared to the old JS-based decoder.
21-
22-
Properties of `Decoder`:
21+
The decoder uses webassembly for data decoding (see [/wasm](wasm/) for the webassembly parts).
22+
It exposes the following properties:
2323

2424
- `constructor(opts?: IDecoderOptions)`
2525
Creates a new decoder instance. Spawns the internal wasm part synchronously, which will work in nodejs or a web worker context, but not in the main context of all browsers. Use the promisified constructor function `DecoderAsync` there instead.
@@ -50,11 +50,15 @@ Properties of `Decoder`:
5050
Getter of the pixel data as 32-bit data (RGBA8888). The pixel array will always be sized as full image of the currently reported `width` and `height` dimensions (with `fillColor` applied). Note that the array is only borrowed in most cases and you may want to copy it before doing further processing.
5151
It is possible to grab the pixels of partially transmitted images during chunk decoding. Here image dimensions may not be final yet and keep shifting until all data was processed.
5252

53+
- `data8: Uint8ClampedArray`
54+
Getter of the pixel data as 8-bit channel array, e.g. for direct usage at the `ImageData` constructor.
55+
The getter refers internally to `data32`, thus exhibits the same dimension and borrow mechanics.
56+
5357
- `width: number`
5458
Reports the current width of the current image. For `truncate=true` this may report the raster width, if a valid raster attribute was found. Otherwise reports rightmost band cursor advance seen so far.
5559

5660
- `height: number`
57-
Reports the current height of the current image. Note that for `trancate=true` this may report the raster height, if a valid raster attribute was found. Otherwise reports the height in multiple of 6 pixels (seen sixel bands).
61+
Reports the current height of the current image. Note that for `trancate=true` this may report the raster height, if a valid raster attribute was found. Otherwise reports the lowermost pixel position touched by a sixel.
5862

5963
- `memoryUsage: number`
6064
Reports the current memory usage of the decoder for wasm module memory and allocated pixel buffer.
@@ -141,40 +145,25 @@ The test image repeats the palette image 6 times to form a 640x480 image with 51
141145

142146
Results:
143147
```
144-
Context "./lib/index.benchmark.js"
148+
Context "lib/index.benchmark.js"
145149
Context "testimage"
146-
Context "pixel transfer"
147-
Case "toPixelData - with fillColor" : 20 runs - average runtime: 1.48 ms
148-
Case "toPixelData - without fillColor" : 20 runs - average runtime: 0.87 ms
149-
Context "decode (DefaultDecoder)"
150-
Case "decode" : 20 runs - average runtime: 3.83 ms
151-
Case "decodeString" : 20 runs - average runtime: 4.11 ms
152-
Case "decode + pixel transfer" : 20 runs - average runtime: 3.09 ms
153-
Context "decode (WasmDecoder)"
154-
Case "decode" : 20 runs - average runtime: 0.76 ms
155-
Case "decodeString" : 20 runs - average runtime: 1.48 ms
150+
Context "decode"
151+
Case "decode" : 20 runs - average runtime: 0.77 ms
152+
Case "decodeString" : 20 runs - average runtime: 1.76 ms
156153
Context "encode"
157-
Case "sixelEncode" : 20 runs - average runtime: 21.57 ms
158-
Context "decode - testfiles (DefaultDecoder)"
159-
Case "test1_clean.sixel" : 20 runs - average runtime: 16.20 ms
160-
Case "test1_clean.sixel" : 20 runs - average throughput: 38.57 MB/s
161-
Case "test2_clean.sixel" : 20 runs - average runtime: 6.49 ms
162-
Case "test2_clean.sixel" : 20 runs - average throughput: 48.75 MB/s
163-
Case "sampsa_reencoded_clean.six" : 20 runs - average runtime: 15.76 ms
164-
Case "sampsa_reencoded_clean.six" : 20 runs - average throughput: 40.98 MB/s
165-
Case "FullHD 12bit noise" : 20 runs - average runtime: 224.61 ms
166-
Case "FullHD 12bit noise" : 20 runs - average throughput: 69.03 MB/s
167-
Context "decode - testfiles (WasmDecoder)"
168-
Case "test1_clean.sixel" : 20 runs - average runtime: 3.89 ms
169-
Case "test1_clean.sixel" : 20 runs - average throughput: 152.63 MB/s
170-
Case "test2_clean.sixel" : 20 runs - average runtime: 1.91 ms
171-
Case "test2_clean.sixel" : 20 runs - average throughput: 165.01 MB/s
172-
Case "sampsa_reencoded_clean.six" : 20 runs - average runtime: 4.47 ms
173-
Case "sampsa_reencoded_clean.six" : 20 runs - average throughput: 146.42 MB/s
174-
Case "FullHD 12bit noise" : 20 runs - average runtime: 48.53 ms
175-
Case "FullHD 12bit noise" : 20 runs - average throughput: 319.51 MB/s
154+
Case "sixelEncode" : 20 runs - average runtime: 21.52 ms
155+
Context "decode - testfiles"
156+
Case "test1_clean.sixel" : 20 runs - average runtime: 4.36 ms
157+
Case "test1_clean.sixel" : 20 runs - average throughput: 144.83 MB/s
158+
Case "test2_clean.sixel" : 20 runs - average runtime: 1.96 ms
159+
Case "test2_clean.sixel" : 20 runs - average throughput: 161.27 MB/s
160+
Case "sampsa_reencoded_clean.six" : 20 runs - average runtime: 4.36 ms
161+
Case "sampsa_reencoded_clean.six" : 20 runs - average throughput: 148.78 MB/s
162+
Case "FullHD 12bit noise" : 20 runs - average runtime: 50.70 ms
163+
Case "FullHD 12bit noise" : 20 runs - average throughput: 306.03 MB/s
164+
Case "640x480 9bit tiles" : 20 runs - average runtime: 0.68 ms
165+
Case "640x480 9bit tiles" : 20 runs - average throughput: 148.33 MB/s
176166
```
177-
Note that the new decoder is roughly 3-4 times faster than the old one. Therefore the old decoder will be removed with one of the next releases.
178167

179168

180169
### Decoder usage
@@ -184,10 +173,10 @@ you can use the convenient functions `decode` or `decodeAsync`.
184173

185174
_Example (Typescript):_
186175
```typescript
187-
import { decode, decodeAsync, ISixelDecoderOptions } from 'sixel';
176+
import { decode, decodeAsync, IDecoderOptions } from 'sixel';
188177

189178
// some options
190-
const OPTIONS: ISixelDecoderOptions = {
179+
const OPTIONS: IDecoderOptions = {
191180
memoryLimit: 65536 * 256, // limit pixel memory to 16 MB (2048 x 2048 pixels)
192181
...
193182
};
@@ -211,19 +200,20 @@ use the stream decoder directly.
211200

212201
_Example (Typescript):_
213202
```typescript
214-
import { Decoder, DecoderAsync, ISixelDecoderOptions } from 'sixel';
203+
import { Decoder, DecoderAsync, IDecoderOptions } from 'sixel';
215204

216205
// some options
217-
const OPTIONS: ISixelDecoderOptions = {
206+
const OPTIONS: IDecoderOptions = {
218207
memoryLimit: 65536 * 256, // limit pixel memory to 16 MB (2048 x 2048 pixels)
219208
...
220209
};
221210

222211
// in nodejs or web worker context
223212
const decoder = new Decoder(OPTIONS);
224213
// in browser main context
225-
const decoder = DecoderAsync(OPTIONS);
214+
const decoderPromise = DecoderAsync(OPTIONS).then(decoder => ...);
226215

216+
// and later on:
227217
for (image of images) {
228218
// initialize for next image with defaults
229219
// for a more terminal like behavior you may want to override default settings
@@ -235,11 +225,11 @@ for (image of images) {
235225
decoder.decode(chunk);
236226
// optional: check your memory limits
237227
if (decoder.memoryUsage > YOUR_LIMIT) {
238-
// the decoder is meant to be resilient for exceptional conditions
239-
// and can be re-used after calling .release (if not, please file a bug)
240-
// (for simplicity example exists whole loop)
241-
decoder.release();
242-
throw new Error('dont like your data, way too big');
228+
// the decoder is meant to be resilient for exceptional conditions
229+
// and can be re-used after calling .release (if not, please file a bug)
230+
// (for simplicity example exits whole loop)
231+
decoder.release();
232+
throw new Error('dont like your data, way too big');
243233
}
244234
// optional: grab partial data (useful for slow transmission)
245235
somePartialRawImageAction(decoder.data32, decoder.width, decoder.height);

index.html

+19-1
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@
3535
<br><br>
3636
<label><input type="checkbox" name="slow" id="slow" value="value"> Simulate slow chunks</label>
3737
<br>
38+
<label><input type="checkbox" name="m1" id="m1" value="value"> Force M1 Mode (truncate: false)</label>
39+
<br>
3840
<label><input type="color" name="fillColor" id="fillColor" value="#000000"> background color</label>
3941
<br><br>
4042
<span id="stats"></span>
43+
<br>
44+
<span id="decodetime"></span>
4145
<br><br>
4246
<canvas id="output_wasm" style="border: 1px solid black"></canvas>
4347
<script src="/dist/full.umd.js"></script>
@@ -75,7 +79,16 @@
7579
clearInterval(drawHandle);
7680

7781
// initialize decoder
78-
decoder.init(sixel.toRGBA8888(...hexColorToRGB(document.getElementById('fillColor').value)));
82+
decoder.init(
83+
// fillColor - BG color
84+
sixel.toRGBA8888(...hexColorToRGB(document.getElementById('fillColor').value)),
85+
// palette (null: dont change, undefined: pull default)
86+
undefined,
87+
// paletteLimit - max usable palette slots
88+
256,
89+
// truncate - whether to cut at raster dimensions (false - always M1 mode, true - maybe M2)
90+
!document.getElementById('m1').checked
91+
);
7992

8093
// read in
8194
if (s === 'wiki') {
@@ -84,6 +97,9 @@
8497
const response = await fetch('/testfiles/' + s);
8598
const bytes = new Uint8Array(await response.arrayBuffer());
8699
if (document.getElementById('slow').checked) {
100+
// inspect slow transmission image construction
101+
// (dont copy this, its just a wild hack w'o proper async state handling)
102+
document.getElementById('decodetime').innerText = '';
87103
let localHandle = drawHandle = setInterval(() => drawImageWasm(), 100);
88104
let i = 0;
89105
const endTens = bytes.length - (bytes.length % 10);
@@ -99,7 +115,9 @@
99115
}
100116
clearInterval(drawHandle);
101117
} else {
118+
const start = Date.now();
102119
decoder.decode(bytes);
120+
document.getElementById('decodetime').innerText = 'decoding time: ' + (Date.now() - start) + 'ms';
103121
}
104122
}
105123
document.getElementById('stats').innerText = 'width: ' + decoder.width + '\nheight: ' + decoder.height;

0 commit comments

Comments
 (0)