las-laz-js 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/NOTICE +1 -1
- package/README.md +56 -14
- package/package.json +2 -2
- package/src/index.js +1 -1
- package/src/laz/ArithmeticEncoder.js +123 -0
- package/src/laz/IntegerCompressor.js +76 -0
- package/src/laz/LazVlr.js +63 -1
- package/src/laz/chunkTable.js +139 -109
- package/src/laz/chunkWorker.js +51 -18
- package/src/laz/compressChunk.js +107 -0
- package/src/laz/decompressChunk.js +40 -10
- package/src/laz/pool.js +77 -34
- package/src/laz/v2/byte.js +23 -7
- package/src/laz/v2/gpstime11.js +165 -25
- package/src/laz/v2/point10.js +91 -22
- package/src/laz/v2/rgb12.js +62 -7
- package/src/laz/v3/layered.js +138 -40
- package/src/laz/v3/point14.js +231 -33
- package/src/write/encodeRecords.js +3 -2
- package/src/write/writeLas.js +259 -6
package/src/laz/v2/rgb12.js
CHANGED
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
// LASzip RGB12 item, version 2: the 6 colour bytes. A symbol says which
|
|
4
4
|
// bytes changed and whether green and blue differ from red; red's byte
|
|
5
5
|
// differences predict green's, and the mean of red's and green's
|
|
6
|
-
// predicts blue's (clamped to a byte). Shared by the 1.4 RGB14 item
|
|
6
|
+
// predicts blue's (clamped to a byte). Shared by the 1.4 RGB14 item;
|
|
7
|
+
// encodeRgb is decodeRgb's mirror, over the same RgbModels.
|
|
7
8
|
//
|
|
8
9
|
// Ported from laz-rs src/las/rgb.rs, module v2 (https://github.com/laz-rs/laz-rs),
|
|
9
10
|
// itself a port of LASzip by rapidlasso. (c) 2007-2014 martin isenburg,
|
|
10
11
|
// rapidlasso; (c) 2014 Uday Verma, Hobu, Inc.; (c) 2019 Thomas Montaigu.
|
|
11
12
|
// Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE and
|
|
12
|
-
// NOTICE). Changes: translated from Rust to JavaScript, Brent Buffham 2026
|
|
13
|
+
// NOTICE). Changes: translated from Rust to JavaScript, Brent Buffham 2026;
|
|
14
|
+
// the compressor (encodeRgb, Rgb12Compressor) added beside the decompressor.
|
|
13
15
|
//==========================================================
|
|
14
16
|
|
|
15
17
|
import { ArithmeticModel } from "../models.js";
|
|
@@ -61,13 +63,16 @@ export function decodeRgb(dec, m, last) {
|
|
|
61
63
|
last[0] = r; last[1] = g; last[2] = b;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
// The state and models both halves start a chunk with
|
|
67
|
+
function initRgb12(self) {
|
|
68
|
+
self.size = 6;
|
|
69
|
+
self.models = new RgbModels();
|
|
70
|
+
self.last = new Uint16Array(3);
|
|
69
71
|
}
|
|
70
72
|
|
|
73
|
+
/** RGB12 v2 decompressor: one per chunk. */
|
|
74
|
+
export function Rgb12Decompressor() { initRgb12(this); }
|
|
75
|
+
|
|
71
76
|
Rgb12Decompressor.prototype.first = function (src, s, view, o) {
|
|
72
77
|
for (var i = 0; i < 6; i++) view.setUint8(o + i, src[s + i]);
|
|
73
78
|
this.last[0] = view.getUint16(o, LE); this.last[1] = view.getUint16(o + 2, LE); this.last[2] = view.getUint16(o + 4, LE);
|
|
@@ -77,3 +82,53 @@ Rgb12Decompressor.prototype.next = function (dec, view, o) {
|
|
|
77
82
|
decodeRgb(dec, this.models, this.last);
|
|
78
83
|
view.setUint16(o, this.last[0], LE); view.setUint16(o + 2, this.last[1], LE); view.setUint16(o + 4, this.last[2], LE);
|
|
79
84
|
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Encode one colour against the last one: the mirror of decodeRgb.
|
|
88
|
+
* @param {object} enc - ArithmeticEncoder
|
|
89
|
+
* @param {RgbModels} m
|
|
90
|
+
* @param {Uint16Array} last - [r, g, b] of the last point (not changed)
|
|
91
|
+
* @param {Uint16Array} cur - [r, g, b] of this point
|
|
92
|
+
* @returns {number} the symbol coded: which bytes changed, and bit 6 when it is not grey
|
|
93
|
+
*/
|
|
94
|
+
export function encodeRgb(enc, m, last, cur) {
|
|
95
|
+
var lr = last[0], lg = last[1], lb = last[2], r = cur[0], g = cur[1], b = cur[2];
|
|
96
|
+
var sym = ((lr ^ r) & 255 ? 1 : 0) | ((lr ^ r) & 0xFF00 ? 2 : 0) | ((lg ^ g) & 255 ? 4 : 0) | ((lg ^ g) & 0xFF00 ? 8 : 0) |
|
|
97
|
+
((lb ^ b) & 255 ? 16 : 0) | ((lb ^ b) & 0xFF00 ? 32 : 0) | (r !== g || r !== b ? 64 : 0);
|
|
98
|
+
var diffL = 0, diffH = 0;
|
|
99
|
+
enc.encodeSymbol(m.byteUsed, sym);
|
|
100
|
+
if (sym & 1) { diffL = (r & 255) - (lr & 255); enc.encodeSymbol(m.lowRed, diffL & 255); }
|
|
101
|
+
if (sym & 2) { diffH = (r >>> 8) - (lr >>> 8); enc.encodeSymbol(m.highRed, diffH & 255); }
|
|
102
|
+
if (sym & 64) {
|
|
103
|
+
if (sym & 4) enc.encodeSymbol(m.lowGreen, ((g & 255) - clamp8(diffL + (lg & 255))) & 255);
|
|
104
|
+
if (sym & 16) {
|
|
105
|
+
diffL = Math.trunc((diffL + (g & 255) - (lg & 255)) / 2);
|
|
106
|
+
enc.encodeSymbol(m.lowBlue, ((b & 255) - clamp8(diffL + (lb & 255))) & 255);
|
|
107
|
+
}
|
|
108
|
+
if (sym & 8) enc.encodeSymbol(m.highGreen, ((g >>> 8) - clamp8(diffH + (lg >>> 8))) & 255);
|
|
109
|
+
if (sym & 32) {
|
|
110
|
+
diffH = Math.trunc((diffH + (g >>> 8) - (lg >>> 8)) / 2);
|
|
111
|
+
enc.encodeSymbol(m.highBlue, ((b >>> 8) - clamp8(diffH + (lb >>> 8))) & 255);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return sym;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** RGB12 v2 compressor: one per chunk, the mirror of Rgb12Decompressor. */
|
|
118
|
+
export function Rgb12Compressor() {
|
|
119
|
+
initRgb12(this);
|
|
120
|
+
this.cur = new Uint16Array(3);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** [r, g, b] of the record bytes at s, into out (RGB14 reads them the same way). */
|
|
124
|
+
export function readRgb(out, src, s) {
|
|
125
|
+
out[0] = src[s] + src[s + 1] * 256; out[1] = src[s + 2] + src[s + 3] * 256; out[2] = src[s + 4] + src[s + 5] * 256;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Rgb12Compressor.prototype.first = function (src, s) { readRgb(this.last, src, s); };
|
|
129
|
+
|
|
130
|
+
Rgb12Compressor.prototype.next = function (enc, src, s) {
|
|
131
|
+
readRgb(this.cur, src, s);
|
|
132
|
+
encodeRgb(enc, this.models, this.last, this.cur);
|
|
133
|
+
var t = this.last; this.last = this.cur; this.cur = t;
|
|
134
|
+
};
|
package/src/laz/v3/layered.js
CHANGED
|
@@ -6,20 +6,27 @@
|
|
|
6
6
|
// Point14 passes on, with the version-3 quirk preserved: a context
|
|
7
7
|
// first used is seeded from the last one, and in version 3 later
|
|
8
8
|
// values are predicted from whichever context it was entered from.
|
|
9
|
+
// Each compressor shares its decompressor's setup and context switch,
|
|
10
|
+
// so the two stay in step point for point.
|
|
9
11
|
//
|
|
10
12
|
// Ported from laz-rs src/las/rgb.rs, nir.rs and extra_bytes.rs, modules
|
|
11
13
|
// v3_v4 (https://github.com/laz-rs/laz-rs), itself a port of LASzip by
|
|
12
14
|
// rapidlasso. (c) 2007-2015 martin isenburg, rapidlasso; (c) 2019-2023
|
|
13
15
|
// Thomas Montaigu.
|
|
14
16
|
// Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE and
|
|
15
|
-
// NOTICE). Changes: translated from Rust to JavaScript, Brent Buffham 2026
|
|
17
|
+
// NOTICE). Changes: translated from Rust to JavaScript, Brent Buffham 2026;
|
|
18
|
+
// the compressors (Rgb14Compressor, Nir14Compressor, Byte14Compressor)
|
|
19
|
+
// added beside the decompressors, writing a layer once a value changes
|
|
20
|
+
// as LAZperf (hobuinc/laz-perf, field_rgb14/nir14/byte14.cpp) does.
|
|
16
21
|
//==========================================================
|
|
17
22
|
|
|
18
23
|
import { ArithmeticDecoder } from "../ArithmeticDecoder.js";
|
|
24
|
+
import { ArithmeticEncoder } from "../ArithmeticEncoder.js";
|
|
19
25
|
import { ArithmeticModel } from "../models.js";
|
|
20
|
-
import { RgbModels, decodeRgb } from "../v2/rgb12.js";
|
|
26
|
+
import { RgbModels, decodeRgb, encodeRgb, readRgb } from "../v2/rgb12.js";
|
|
21
27
|
|
|
22
28
|
var LE = true;
|
|
29
|
+
var EMPTY = new Uint8Array(0);
|
|
23
30
|
|
|
24
31
|
// laz-rs's context switch, shared by the three items: returns the index whose
|
|
25
32
|
// last value predicts this point (`last_idx`), after switching to `ctx`.
|
|
@@ -38,6 +45,13 @@ function enterContext(item, ctx) {
|
|
|
38
45
|
return lastIdx;
|
|
39
46
|
}
|
|
40
47
|
|
|
48
|
+
// The first point of a chunk: only its channel's context is in use
|
|
49
|
+
function firstContext(item, ctx) {
|
|
50
|
+
item.unused = [true, true, true, true];
|
|
51
|
+
item.unused[ctx] = false;
|
|
52
|
+
item.lastContext = ctx;
|
|
53
|
+
}
|
|
54
|
+
|
|
41
55
|
function layer(item, bytes, q, n, fail, e, base) {
|
|
42
56
|
if (q + n > e) fail(q);
|
|
43
57
|
if (n === 0) return null;
|
|
@@ -46,27 +60,30 @@ function layer(item, bytes, q, n, fail, e, base) {
|
|
|
46
60
|
return d;
|
|
47
61
|
}
|
|
48
62
|
|
|
63
|
+
// The state and models both halves of RGB14 start a chunk with
|
|
64
|
+
function initRgb14(self, version) {
|
|
65
|
+
self.size = 6;
|
|
66
|
+
self.version = version;
|
|
67
|
+
self.models = [new RgbModels(), new RgbModels(), new RgbModels(), new RgbModels()];
|
|
68
|
+
self.last = [new Uint16Array(3), new Uint16Array(3), new Uint16Array(3), new Uint16Array(3)];
|
|
69
|
+
self.unused = [true, true, true, true];
|
|
70
|
+
self.lastContext = 0;
|
|
71
|
+
}
|
|
72
|
+
function seedRgb(from, to) { this.last[to].set(this.last[from]); }
|
|
73
|
+
|
|
49
74
|
/** RGB14 (version 3 or 4). */
|
|
50
75
|
export function Rgb14Decompressor(version) {
|
|
51
|
-
this
|
|
52
|
-
this.version = version;
|
|
53
|
-
this.models = [new RgbModels(), new RgbModels(), new RgbModels(), new RgbModels()];
|
|
54
|
-
this.last = [new Uint16Array(3), new Uint16Array(3), new Uint16Array(3), new Uint16Array(3)];
|
|
55
|
-
this.unused = [true, true, true, true];
|
|
56
|
-
this.lastContext = 0;
|
|
76
|
+
initRgb14(this, version);
|
|
57
77
|
this.dec = null;
|
|
58
78
|
}
|
|
59
79
|
Rgb14Decompressor.prototype.first = function (src, s, view, o, ctx) {
|
|
60
80
|
for (var i = 0; i < 6; i++) view.setUint8(o + i, src[s + i]);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.unused = [true, true, true, true];
|
|
64
|
-
this.unused[c] = false;
|
|
65
|
-
this.lastContext = c;
|
|
81
|
+
readRgb(this.last[ctx.v], src, s);
|
|
82
|
+
firstContext(this, ctx.v);
|
|
66
83
|
};
|
|
67
84
|
Rgb14Decompressor.prototype.readLayerSizes = function (dv, q) { this.layerSize = dv.getUint32(q, LE); return q + 4; };
|
|
68
85
|
Rgb14Decompressor.prototype.readLayers = function (bytes, q, e, fail, base) { this.dec = layer(this, bytes, q, this.layerSize, fail, e, base); return q + this.layerSize; };
|
|
69
|
-
Rgb14Decompressor.prototype.seed =
|
|
86
|
+
Rgb14Decompressor.prototype.seed = seedRgb;
|
|
70
87
|
Rgb14Decompressor.prototype.next = function (view, o, ctx) {
|
|
71
88
|
var idx = enterContext(this, ctx.v);
|
|
72
89
|
var rgb = this.last[idx];
|
|
@@ -74,32 +91,57 @@ Rgb14Decompressor.prototype.next = function (view, o, ctx) {
|
|
|
74
91
|
view.setUint16(o, rgb[0], LE); view.setUint16(o + 2, rgb[1], LE); view.setUint16(o + 4, rgb[2], LE);
|
|
75
92
|
};
|
|
76
93
|
|
|
94
|
+
/** RGB14 compressor (version 3 or 4): one layer, written once a colour differs or is not grey. */
|
|
95
|
+
export function Rgb14Compressor(version) {
|
|
96
|
+
initRgb14(this, version);
|
|
97
|
+
this.enc = new ArithmeticEncoder();
|
|
98
|
+
this.used = false;
|
|
99
|
+
this.cur = new Uint16Array(3);
|
|
100
|
+
}
|
|
101
|
+
Rgb14Compressor.prototype.first = function (src, s, ctx) {
|
|
102
|
+
readRgb(this.last[ctx.v], src, s);
|
|
103
|
+
firstContext(this, ctx.v);
|
|
104
|
+
};
|
|
105
|
+
Rgb14Compressor.prototype.seed = seedRgb;
|
|
106
|
+
Rgb14Compressor.prototype.next = function (src, s, ctx) {
|
|
107
|
+
var idx = enterContext(this, ctx.v);
|
|
108
|
+
readRgb(this.cur, src, s);
|
|
109
|
+
if (encodeRgb(this.enc, this.models[this.lastContext], this.last[idx], this.cur)) this.used = true;
|
|
110
|
+
this.last[idx].set(this.cur);
|
|
111
|
+
};
|
|
112
|
+
/** @returns {Array<Uint8Array>} the one layer (empty when nothing was coded) */
|
|
113
|
+
Rgb14Compressor.prototype.finish = function () { return [this.used ? this.enc.done() : EMPTY]; };
|
|
114
|
+
|
|
115
|
+
// The state and models both halves of NIR14 start a chunk with
|
|
116
|
+
function initNir14(self, version) {
|
|
117
|
+
self.size = 2;
|
|
118
|
+
self.version = version;
|
|
119
|
+
self.usedModel = []; self.low = []; self.high = [];
|
|
120
|
+
for (var i = 0; i < 4; i++) { self.usedModel.push(new ArithmeticModel(4)); self.low.push(new ArithmeticModel(256)); self.high.push(new ArithmeticModel(256)); }
|
|
121
|
+
self.last = new Uint16Array(4);
|
|
122
|
+
self.unused = [true, true, true, true];
|
|
123
|
+
self.lastContext = 0;
|
|
124
|
+
}
|
|
125
|
+
function seedNir(from, to) { this.last[to] = this.last[from]; }
|
|
126
|
+
|
|
77
127
|
/** NIR14 (version 3 or 4): the near-infrared word of RGBNIR14. */
|
|
78
128
|
export function Nir14Decompressor(version) {
|
|
79
|
-
this
|
|
80
|
-
this.version = version;
|
|
81
|
-
this.used = []; this.low = []; this.high = [];
|
|
82
|
-
for (var i = 0; i < 4; i++) { this.used.push(new ArithmeticModel(4)); this.low.push(new ArithmeticModel(256)); this.high.push(new ArithmeticModel(256)); }
|
|
83
|
-
this.last = new Uint16Array(4);
|
|
84
|
-
this.unused = [true, true, true, true];
|
|
85
|
-
this.lastContext = 0;
|
|
129
|
+
initNir14(this, version);
|
|
86
130
|
this.dec = null;
|
|
87
131
|
}
|
|
88
132
|
Nir14Decompressor.prototype.first = function (src, s, view, o, ctx) {
|
|
89
133
|
view.setUint8(o, src[s]); view.setUint8(o + 1, src[s + 1]);
|
|
90
|
-
this.last[ctx.v] =
|
|
91
|
-
this
|
|
92
|
-
this.unused[ctx.v] = false;
|
|
93
|
-
this.lastContext = ctx.v;
|
|
134
|
+
this.last[ctx.v] = src[s] + src[s + 1] * 256;
|
|
135
|
+
firstContext(this, ctx.v);
|
|
94
136
|
};
|
|
95
137
|
Nir14Decompressor.prototype.readLayerSizes = Rgb14Decompressor.prototype.readLayerSizes;
|
|
96
138
|
Nir14Decompressor.prototype.readLayers = Rgb14Decompressor.prototype.readLayers;
|
|
97
|
-
Nir14Decompressor.prototype.seed =
|
|
139
|
+
Nir14Decompressor.prototype.seed = seedNir;
|
|
98
140
|
Nir14Decompressor.prototype.next = function (view, o, ctx) {
|
|
99
141
|
var idx = enterContext(this, ctx.v);
|
|
100
142
|
if (this.dec) {
|
|
101
143
|
var c = this.lastContext, last = this.last[idx];
|
|
102
|
-
var sym = this.dec.decodeSymbol(this.
|
|
144
|
+
var sym = this.dec.decodeSymbol(this.usedModel[c]);
|
|
103
145
|
var v = sym & 1 ? (this.dec.decodeSymbol(this.low[c]) + (last & 255)) & 255 : last & 255;
|
|
104
146
|
v += sym & 2 ? ((this.dec.decodeSymbol(this.high[c]) + (last >>> 8)) & 255) * 256 : last & 0xFF00;
|
|
105
147
|
this.last[idx] = v;
|
|
@@ -107,25 +149,56 @@ Nir14Decompressor.prototype.next = function (view, o, ctx) {
|
|
|
107
149
|
view.setUint16(o, this.last[idx], LE);
|
|
108
150
|
};
|
|
109
151
|
|
|
152
|
+
/** NIR14 compressor (version 3 or 4): one layer, written once the value changes. */
|
|
153
|
+
export function Nir14Compressor(version) {
|
|
154
|
+
initNir14(this, version);
|
|
155
|
+
this.enc = new ArithmeticEncoder();
|
|
156
|
+
this.used = false;
|
|
157
|
+
}
|
|
158
|
+
Nir14Compressor.prototype.first = function (src, s, ctx) {
|
|
159
|
+
this.last[ctx.v] = src[s] + src[s + 1] * 256;
|
|
160
|
+
firstContext(this, ctx.v);
|
|
161
|
+
};
|
|
162
|
+
Nir14Compressor.prototype.seed = seedNir;
|
|
163
|
+
Nir14Compressor.prototype.next = function (src, s, ctx) {
|
|
164
|
+
var idx = enterContext(this, ctx.v), c = this.lastContext;
|
|
165
|
+
var last = this.last[idx], v = src[s] + src[s + 1] * 256;
|
|
166
|
+
var sym = ((last ^ v) & 255 ? 1 : 0) + ((last ^ v) & 0xFF00 ? 2 : 0);
|
|
167
|
+
this.enc.encodeSymbol(this.usedModel[c], sym);
|
|
168
|
+
if (sym & 1) this.enc.encodeSymbol(this.low[c], ((v & 255) - (last & 255)) & 255);
|
|
169
|
+
if (sym & 2) this.enc.encodeSymbol(this.high[c], ((v >>> 8) - (last >>> 8)) & 255);
|
|
170
|
+
if (sym) this.used = true;
|
|
171
|
+
this.last[idx] = v;
|
|
172
|
+
};
|
|
173
|
+
/** @returns {Array<Uint8Array>} the one layer (empty when the value never changed) */
|
|
174
|
+
Nir14Compressor.prototype.finish = Rgb14Compressor.prototype.finish;
|
|
175
|
+
|
|
176
|
+
// The state both halves of Byte14 start a chunk with; a context's models are made when it is first used
|
|
177
|
+
function initByte14(self, count, version) {
|
|
178
|
+
self.size = count;
|
|
179
|
+
self.version = version;
|
|
180
|
+
self.models = [null, null, null, null];
|
|
181
|
+
self.last = [new Uint8Array(count), new Uint8Array(count), new Uint8Array(count), new Uint8Array(count)];
|
|
182
|
+
self.unused = [true, true, true, true];
|
|
183
|
+
self.lastContext = 0;
|
|
184
|
+
}
|
|
185
|
+
function byteModels(count) { var m = []; for (var i = 0; i < count; i++) m.push(new ArithmeticModel(256)); return m; }
|
|
186
|
+
function firstBytes(item, src, s, ctx) {
|
|
187
|
+
item.last[ctx.v].set(src.subarray(s, s + item.size));
|
|
188
|
+
firstContext(item, ctx.v);
|
|
189
|
+
item.models[ctx.v] = byteModels(item.size);
|
|
190
|
+
}
|
|
191
|
+
function seedBytes(from, to) { this.models[to] = byteModels(this.size); this.last[to].set(this.last[from]); }
|
|
192
|
+
|
|
110
193
|
/** Byte14 (version 3 or 4): `count` extra bytes, one layer each. */
|
|
111
194
|
export function Byte14Decompressor(count, version) {
|
|
112
|
-
this
|
|
113
|
-
this.version = version;
|
|
114
|
-
this.models = [null, null, null, null];
|
|
115
|
-
this.last = [new Uint8Array(count), new Uint8Array(count), new Uint8Array(count), new Uint8Array(count)];
|
|
116
|
-
this.unused = [true, true, true, true];
|
|
117
|
-
this.lastContext = 0;
|
|
195
|
+
initByte14(this, count, version);
|
|
118
196
|
this.sizes = new Array(count);
|
|
119
197
|
this.dec = new Array(count);
|
|
120
198
|
}
|
|
121
|
-
function byteModels(count) { var m = []; for (var i = 0; i < count; i++) m.push(new ArithmeticModel(256)); return m; }
|
|
122
199
|
Byte14Decompressor.prototype.first = function (src, s, view, o, ctx) {
|
|
123
200
|
for (var i = 0; i < this.size; i++) view.setUint8(o + i, src[s + i]);
|
|
124
|
-
this
|
|
125
|
-
this.unused = [true, true, true, true];
|
|
126
|
-
this.unused[ctx.v] = false;
|
|
127
|
-
this.models[ctx.v] = byteModels(this.size);
|
|
128
|
-
this.lastContext = ctx.v;
|
|
201
|
+
firstBytes(this, src, s, ctx);
|
|
129
202
|
};
|
|
130
203
|
Byte14Decompressor.prototype.readLayerSizes = function (dv, q) {
|
|
131
204
|
for (var i = 0; i < this.size; i++) { this.sizes[i] = dv.getUint32(q, LE); q += 4; }
|
|
@@ -135,7 +208,7 @@ Byte14Decompressor.prototype.readLayers = function (bytes, q, e, fail, base) {
|
|
|
135
208
|
for (var i = 0; i < this.size; i++) { this.dec[i] = layer(this, bytes, q, this.sizes[i], fail, e, base); q += this.sizes[i]; }
|
|
136
209
|
return q;
|
|
137
210
|
};
|
|
138
|
-
Byte14Decompressor.prototype.seed =
|
|
211
|
+
Byte14Decompressor.prototype.seed = seedBytes;
|
|
139
212
|
Byte14Decompressor.prototype.next = function (view, o, ctx) {
|
|
140
213
|
var idx = enterContext(this, ctx.v);
|
|
141
214
|
var last = this.last[idx], models = this.models[ctx.v];
|
|
@@ -144,3 +217,28 @@ Byte14Decompressor.prototype.next = function (view, o, ctx) {
|
|
|
144
217
|
view.setUint8(o + i, last[i]);
|
|
145
218
|
}
|
|
146
219
|
};
|
|
220
|
+
|
|
221
|
+
/** Byte14 compressor (version 3 or 4): `count` extra bytes, a layer each, written once that byte changes. */
|
|
222
|
+
export function Byte14Compressor(count, version) {
|
|
223
|
+
initByte14(this, count, version);
|
|
224
|
+
this.enc = [];
|
|
225
|
+
this.used = [];
|
|
226
|
+
for (var i = 0; i < count; i++) { this.enc.push(new ArithmeticEncoder()); this.used.push(false); }
|
|
227
|
+
}
|
|
228
|
+
Byte14Compressor.prototype.first = function (src, s, ctx) { firstBytes(this, src, s, ctx); };
|
|
229
|
+
Byte14Compressor.prototype.seed = seedBytes;
|
|
230
|
+
Byte14Compressor.prototype.next = function (src, s, ctx) {
|
|
231
|
+
var idx = enterContext(this, ctx.v);
|
|
232
|
+
var last = this.last[idx], models = this.models[ctx.v];
|
|
233
|
+
for (var i = 0; i < this.size; i++) {
|
|
234
|
+
var d = (src[s + i] - last[i]) & 255; // u8 wrapping_sub
|
|
235
|
+
this.enc[i].encodeSymbol(models[i], d);
|
|
236
|
+
if (d) { this.used[i] = true; last[i] = src[s + i]; }
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
/** @returns {Array<Uint8Array>} one layer per byte (empty when that byte never changed) */
|
|
240
|
+
Byte14Compressor.prototype.finish = function () {
|
|
241
|
+
var out = [];
|
|
242
|
+
for (var i = 0; i < this.size; i++) out.push(this.used[i] ? this.enc[i].done() : EMPTY);
|
|
243
|
+
return out;
|
|
244
|
+
};
|