rapier-jxl 2.0.0 → 2.2.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.
Files changed (55) hide show
  1. package/AGENTS.md +10 -1
  2. package/ENCODER-COMPARISON.md +6 -6
  3. package/KERNELS.md +58 -0
  4. package/README.md +75 -18
  5. package/admit.mjs +5 -1
  6. package/ans.mjs +157 -0
  7. package/bits.mjs +5 -2
  8. package/build-jxl-kernels.mjs +29 -0
  9. package/coefficient-ans.mjs +26 -0
  10. package/coefficient-effort.mjs +62 -0
  11. package/effort-job.mjs +229 -0
  12. package/effort-level.mjs +10 -0
  13. package/effort.d.mts +4 -2
  14. package/effort.min.mjs +2 -2
  15. package/effort.mjs +7 -199
  16. package/frame.mjs +29 -1
  17. package/index.mjs +2 -2
  18. package/jfif.mjs +11 -0
  19. package/jpeg-ans.d.mts +3 -0
  20. package/jpeg-ans.min.mjs +2 -0
  21. package/jpeg-ans.mjs +9 -0
  22. package/jpeg-job.mjs +29 -0
  23. package/jpeg.d.mts +6 -2
  24. package/jpeg.min.mjs +2 -2
  25. package/jpeg.mjs +12 -36
  26. package/kernel-control.d.mts +3 -0
  27. package/kernel-hooks.mjs +3 -0
  28. package/kernels-bytes.mjs +4 -0
  29. package/kernels-probe.wat +1 -0
  30. package/kernels-scalar.wat +831 -0
  31. package/kernels-simd.wat +252 -0
  32. package/kernels.mjs +141 -0
  33. package/local.mjs +201 -0
  34. package/lossless-coding.mjs +30 -0
  35. package/lossless.mjs +88 -67
  36. package/modular.mjs +11 -7
  37. package/package.json +40 -6
  38. package/photo-ans.d.mts +3 -0
  39. package/photo-ans.min.mjs +2 -0
  40. package/photo-ans.mjs +9 -0
  41. package/photo-dct.mjs +83 -0
  42. package/photo-job.mjs +27 -0
  43. package/photo-quant.mjs +150 -0
  44. package/photo.d.mts +5 -1
  45. package/photo.min.mjs +2 -2
  46. package/photo.mjs +7 -101
  47. package/pool.mjs +136 -0
  48. package/rapier-jxl.min.mjs +2 -2
  49. package/rct-search.mjs +61 -0
  50. package/sizes.json +237 -56
  51. package/vardct.mjs +45 -8
  52. package/wasm.d.mts +4 -0
  53. package/wasm.min.mjs +2 -0
  54. package/wasm.mjs +6 -0
  55. package/weighted.mjs +22 -10
package/effort-job.mjs ADDED
@@ -0,0 +1,229 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // The effort door's work (effort.mjs): effort 1's stream, the rungs above it, and the group work of the weighted search
3
+ // that a pool of workers shares (pool.mjs). Every choice is integer arithmetic: the same input and options write the
4
+ // same bytes everywhere, on one thread or many.
5
+ import {BitWriter, part, scaled} from './bits.mjs';
6
+ import {writeImageHeader, writeModularFrameHeader, groupLayout, groupRect, groupPass, addCounts, assembleCodestream, GROUP_DIM} from './frame.mjs';
7
+ import {buildCode, writePrefixCode} from './prefix.mjs';
8
+ import {AVERAGE_PREDICTOR, GRADIENT_PREDICTOR, ALPHABET, leaf, split, channelTree, writeTree, writeModularHeader, writeChannelHistograms, codeChannel} from './modular.mjs';
9
+ import {inspectPixels, losslessSteps, planeFill} from './lossless.mjs';
10
+ import {lossySteps} from './lossy.mjs';
11
+ import {WEIGHTED_PREDICTOR, WEIGHTED_PROPERTY, WEIGHTED_CUTS, codeWeighted} from './weighted.mjs';
12
+ import {fault, admitOptions, admitPixels} from './admit.mjs';
13
+ import {localSteps} from './local.mjs';
14
+ import {rctSearchSteps} from './rct-search.mjs';
15
+
16
+ // The hurry in a step's reply: the caller's flag, or for a pooled pass a reply of null (ended) or {hurried}.
17
+ const hurryOf = reply => reply === null || (typeof reply === 'object' ? reply.hurried : reply);
18
+
19
+ // The door's options as every door reads them, and the effort, which this door alone reads (the core, one rung, does
20
+ // not): a whole number from 1 to 9, 1 when absent. Admitted at once; the steps follow. With `pool` (pool.mjs drives
21
+ // them), an exact picture of more than one group yields each pass over its groups as one request: the same bytes.
22
+ export function effortJob(data, width, height, options, pool) {
23
+ const {quality, colorSpace} = admitOptions(options), effort = options?.effort === undefined ? 1 : options.effort;
24
+ if (!Number.isInteger(effort) || effort < 1 || effort > 9) throw fault('JXL_INPUT', 'Effort is a whole number from 1 to 9.');
25
+ admitPixels(data, width, height);
26
+ return effortSteps(data, width, height, quality, colorSpace, effort, pool && quality >= 100 && !groupLayout(width, height).single);
27
+ }
28
+
29
+ // Effort 1 is the core's work (index.mjs), step for step; the rungs run after it and keep a smaller stream if they
30
+ // find one. A search that runs out of memory leaves the smallest completed stream standing.
31
+ function* effortSteps(data, width, height, quality, colorSpace, effort, pooled) {
32
+ const shape = inspectPixels(data, width, height);
33
+ if (quality < 100) {
34
+ if (!shape.palette) return yield* lossySteps(data, width, height, {quality, shape, colorSpace});
35
+ const exact = yield* part(losslessSteps(data, width, height, {shape, colorSpace}), 0, 2);
36
+ let bytes;
37
+ try { bytes = yield* part(lossySteps(data, width, height, {quality, shape, colorSpace}), 1, 2); }
38
+ catch (error) { if (error.code !== 'JXL_SIZE' && (!(error instanceof RangeError) || error.code)) throw error; bytes = exact; }
39
+ return exact.length <= bytes.length ? exact : bytes;
40
+ }
41
+ if (effort < 2) return yield* losslessSteps(data, width, height, {shape, colorSpace, pooled});
42
+ let best = yield* part(losslessSteps(data, width, height, {shape, colorSpace, pooled}), 0, 2);
43
+ const direct = shape.palette ? {...shape, palette: null} : shape;
44
+ if (effort >= 4) {
45
+ const searches = [searchSteps(data, width, height, direct, colorSpace, 3, pooled)];
46
+ if (shape.palette) searches.push(localSteps(data, width, height, shape, colorSpace, 4, true, pooled));
47
+ if (effort >= 6) {
48
+ searches.push(localSteps(data, width, height, shape, colorSpace, 6, false, pooled));
49
+ if (shape.palette) searches.push(localSteps(data, width, height, shape, colorSpace, 6, true, pooled));
50
+ }
51
+ searches.push(rctSearchSteps(data, width, height, shape, colorSpace, pooled));
52
+ for (let i = 0; i < searches.length; i++) {
53
+ try {
54
+ let step, reply, hurried = false;
55
+ while (!(step = searches[i].next(reply)).done) hurried = hurryOf(reply = yield scaled(step.value, done => 0.5 + (i + done) / (2 * searches.length)));
56
+ if (step.value && step.value.length < best.length) best = step.value;
57
+ if (hurried) return best;
58
+ } catch (error) { if (error.code !== 'JXL_SIZE' && (!(error instanceof RangeError) || error.code)) throw error; }
59
+ }
60
+ return best;
61
+ }
62
+ try {
63
+ const bytes = yield* part(searchSteps(data, width, height, direct, colorSpace, effort, pooled), 1, 2);
64
+ if (bytes && bytes.length < best.length) best = bytes;
65
+ } catch (error) { if (error.code !== 'JXL_SIZE' && (!(error instanceof RangeError) || error.code)) throw error; }
66
+ return best;
67
+ }
68
+
69
+ // A token's raw bits: a residual token s above zero carries s - 1 of them, an LZ77 length token above 235 s - 236.
70
+ const raw = s => Math.max(0, s < 224 ? s - 1 : s - 236);
71
+ // A histogram's complete cost in bits: its prefix code's header and every token's code and raw bits.
72
+ function cost(freqs) {
73
+ const code = buildCode(freqs), writer = new BitWriter(128);
74
+ writePrefixCode(writer, code);
75
+ let bits = writer.bitLength;
76
+ for (let s = 0; s < freqs.length; s++) if (freqs[s]) bits += freqs[s] * (code.lengths[s] + raw(s));
77
+ return bits;
78
+ }
79
+ const sum = histograms => { const out = new Uint32Array(ALPHABET); for (const h of histograms) for (let s = 0; s < ALPHABET; s++) out[s] += h[s]; return out; };
80
+
81
+ const CONTEXTS = WEIGHTED_CUTS.length + 1, IDENTITY = Int32Array.from({length: CONTEXTS}, (_, k) => k);
82
+
83
+ // A group of the search, here or in a pool's worker. Counting, every channel goes into `target` twice: under effort 1's
84
+ // predictor (`first`, one histogram per channel) and under the weighted one, its tokens kept by error interval
85
+ // (CONTEXTS histograms per channel after those). Writing, each channel through its plan (`plans`: the leaf, its codes
86
+ // and the intervals' contexts) into `target`, or, when none, as the group's own section, whose bytes it returns.
87
+ export function searchGroup(setup) {
88
+ const {channels, first, plans} = setup, fill = planeFill(setup), leaves = first?.map(p => leaf(p));
89
+ const planes = Array.from({length: channels}, () => new Int16Array(GROUP_DIM * GROUP_DIM));
90
+ return (rgba, stride, x0, y0, w, h, target) => {
91
+ fill(planes, rgba, stride, x0, y0, w, h);
92
+ if (!plans) {
93
+ for (let c = 0; c < channels; c++) {
94
+ codeChannel(null, target[c], planes[c], w, h, leaves[c]);
95
+ codeWeighted(null, target.slice(channels + c * CONTEXTS, channels + (c + 1) * CONTEXTS), planes[c], w, h, 0, IDENTITY);
96
+ }
97
+ return;
98
+ }
99
+ const section = target || new BitWriter(w * h * channels + 64);
100
+ if (!target) writeModularHeader(section, {useGlobalTree: true, transforms: []});
101
+ plans.forEach(({leaf: l, codes, contextOf}, c) => {
102
+ if (l.predictor === WEIGHTED_PREDICTOR) codeWeighted(section, codes, planes[c], w, h, 0, contextOf);
103
+ else codeChannel(section, codes[0], planes[c], w, h, l);
104
+ });
105
+ return target ? undefined : section.finish();
106
+ };
107
+ }
108
+
109
+ // The direct plan of lossless.mjs (YCoCg, 256-pixel groups), every channel counted over the whole picture under effort
110
+ // 1's predictor (chosen by samples, as the core chooses it) and under the weighted one; each rung's plan takes every
111
+ // channel's cheapest, and the plans are written the cheapest way. Nothing written (null) when no plan leaves effort 1.
112
+ function* searchSteps(rgba, width, height, shape, colorSpace, effort, pooled) {
113
+ const {channels} = shape, layout = groupLayout(width, height), groups = layout.groupsX * layout.groupsY;
114
+ const setup = {channels, alpha: shape.alpha, palette: null}, fill = planeFill(setup);
115
+ const planes = Array.from({length: channels}, () => new Int16Array(32 * 32));
116
+ const rect = g => groupRect(layout, width, height, g);
117
+ // Effort 1's predictor per channel: three 32-pixel samples priced under gradient and average, as the core does.
118
+ const sw = Math.min(width, 32), sh = Math.min(height, 32);
119
+ const sampled = [GRADIENT_PREDICTOR, AVERAGE_PREDICTOR].map(predictor => ({predictor, freqs: planes.map(() => new Uint32Array(ALPHABET))}));
120
+ for (const fraction of [0, 0.5, 1]) {
121
+ fill(planes, rgba, width, Math.floor((width - sw) * fraction), Math.floor((height - sh) * fraction), sw, sh);
122
+ for (const candidate of sampled) for (let c = 0; c < channels; c++) codeChannel(null, candidate.freqs[c], planes[c], sw, sh, leaf(candidate.predictor));
123
+ }
124
+ const first = planes.map((_, c) => leaf(sampled[cost(sampled[1].freqs[c]) < cost(sampled[0].freqs[c]) ? 1 : 0].predictor));
125
+ // Every channel counted under effort 1's predictor and under the weighted one, its tokens kept by error interval.
126
+ // A step is a group of the counting pass (the first half of the search's fractions) or of a plan's writing (the
127
+ // second half, shared by the plans written), so the pace of the steps holds whether one plan is written or two.
128
+ const contexts = CONTEXTS;
129
+ const firstCounts = planes.map(() => new Uint32Array(ALPHABET)), intervals = planes.map(() => Array.from({length: contexts}, () => new Uint32Array(ALPHABET)));
130
+ const counts = [...firstCounts, ...intervals.flat()], counted = {...setup, first: first.map(l => l.predictor)}, count = searchGroup(counted);
131
+ if ((yield* groupPass({pooled, kind: 'search', setup: {...counted, sizes: counts.map(h => h.length)}, at: g => (g + 1) / (2 * groups), stop: () => true},
132
+ groups, g => count(rgba, width, ...rect(g), counts), (g, partial) => addCounts(counts, partial))) === null) return null;
133
+ // Rung 2: each channel's cheaper of effort 1's predictor and the weighted one in one context.
134
+ const rung2 = planes.map((_, c) => {
135
+ const plan = {cost: cost(firstCounts[c]), leaves: [first[c]], freqs: [firstCounts[c]], cuts: []};
136
+ const whole = sum(intervals[c]), single = cost(whole);
137
+ return single < plan.cost ? {cost: single, leaves: [leaf(WEIGHTED_PREDICTOR)], freqs: [whole], cuts: []} : plan;
138
+ });
139
+ // Rung 3: or its intervals grouped into runs of neighbours, the grouping of least cost found exactly by dynamic
140
+ // programming. best[j] is the least cost of intervals 0..j-1 grouped, `from[j]` where its last group begins; an
141
+ // interval no token reaches leaves the merged cost as it was.
142
+ const rung3 = effort < 3 ? rung2 : rung2.map((plan, c) => {
143
+ const filled = intervals[c].map(h => h.some(v => v));
144
+ const best = new Float64Array(contexts + 1).fill(Infinity), from = new Int32Array(contexts + 1);
145
+ best[0] = 0;
146
+ for (let j = 1; j <= contexts; j++) {
147
+ const merged = new Uint32Array(ALPHABET);
148
+ let bits = 0;
149
+ for (let i = j - 1; i >= 0; i--) {
150
+ if (filled[i]) { const h = intervals[c][i]; for (let s = 0; s < ALPHABET; s++) merged[s] += h[s]; bits = cost(merged); }
151
+ // Every group is a leaf of the tree and an entry of the context map: 24 bits more, so an interval no token
152
+ // reaches joins its neighbour.
153
+ const price = best[i] + bits + 24;
154
+ if (price < best[j]) { best[j] = price; from[j] = i; }
155
+ }
156
+ }
157
+ if (!(best[contexts] < plan.cost)) return plan;
158
+ const groupsOf = [];
159
+ for (let j = contexts; j > 0; j = from[j]) groupsOf.unshift([from[j], j]);
160
+ return {cost: best[contexts], leaves: groupsOf.map(() => leaf(WEIGHTED_PREDICTOR)), freqs: groupsOf.map(([i, j]) => sum(intervals[c].slice(i, j))), cuts: groupsOf.slice(0, -1).map(([, j]) => WEIGHTED_CUTS[j - 1]),
161
+ contextOf: Int32Array.from({length: contexts}, (_, k) => groupsOf.findIndex(([i, j]) => k >= i && k < j))};
162
+ });
163
+ const candidates = [rung2, rung3].filter((plans, k) => k ? plans.some((plan, c) => plan !== rung2[c]) : plans.some((plan, c) => plan.leaves[0] !== first[c]));
164
+ if (!candidates.length) return null;
165
+ // The tree: one subtree per channel on the channel property, and inside a split channel a balanced tree on the
166
+ // weighted predictor's property, values above a cut to the left.
167
+ const byError = (leaves, cuts) => {
168
+ const build = (lo, hi) => { if (lo === hi) return leaves[lo]; const mid = (lo + hi) >> 1; return split(WEIGHTED_PROPERTY, cuts[mid], build(mid + 1, hi), build(lo, mid)); };
169
+ return build(0, leaves.length - 1);
170
+ };
171
+ const assemble = plans => ({tree: channelTree(plans.map(plan => byError(plan.leaves, plan.cuts))), leaves: plans.flatMap(plan => plan.leaves), freqs: plans.flatMap(plan => plan.freqs)});
172
+ // A plan's price in bits: its tree and histograms as written, and every token's code and raw bits. Two plans' streams
173
+ // differ by their prices and at most 27 bits a section more (a section's padding, and its size's field in the table
174
+ // of contents, 12 to 32 bits) and a byte: a plan that far cheaper is written alone, closer plans both.
175
+ const price = plans => {
176
+ const {tree, leaves, freqs} = assemble(plans), w = new BitWriter(4096);
177
+ const histograms = writeChannelHistograms(w, writeTree(w, tree), freqs, l => leaves.indexOf(l));
178
+ let bits = w.bitLength;
179
+ freqs.forEach((f, i) => { const {lengths} = histograms[i + 1].code; for (let s = 0; s < f.length; s++) if (f[s]) bits += f[s] * (lengths[s] + raw(s)); });
180
+ return bits;
181
+ };
182
+ let chosen = candidates;
183
+ if (candidates.length > 1) {
184
+ const [a, b] = candidates.map(price), margin = 27 * (layout.single ? 1 : groups + 1) + 8;
185
+ if (b + margin <= a) chosen = [candidates[1]];
186
+ else if (a + margin <= b) chosen = [candidates[0]];
187
+ else if (b < a) chosen = [candidates[1], candidates[0]];
188
+ }
189
+ let written = 0, hurried = false;
190
+ let smallest = null;
191
+ for (const plans of chosen) {
192
+ const bytes = yield* write(plans);
193
+ if (!bytes) return smallest;
194
+ // Price the likely winner first, but retain rung 2's byte choice on an equal-length completed pair.
195
+ if (!smallest || bytes.length < smallest.length || (bytes.length === smallest.length && plans === candidates[0])) smallest = bytes;
196
+ if (hurried) return smallest;
197
+ }
198
+ return smallest;
199
+
200
+ // A plan's stream, a group per step; a hurry at its final group keeps the already-completed candidate.
201
+ function* write(plans) {
202
+ const {tree, leaves, freqs} = assemble(plans);
203
+ const transforms = channels >= 3 ? [{type: 'rct', beginC: 0, rctType: 6}] : [];
204
+ const header = new BitWriter(256);
205
+ writeImageHeader(header, width, height, shape.colour, shape.alpha, {colorSpace});
206
+ writeModularFrameHeader(header, {alpha: shape.alpha});
207
+ const global = new BitWriter(4096);
208
+ global.write(1, 1); // default DC quantisation
209
+ global.write(1, 1); // a global tree
210
+ const histograms = writeChannelHistograms(global, writeTree(global, tree), freqs, l => leaves.indexOf(l));
211
+ writeModularHeader(global, {useGlobalTree: true, transforms});
212
+ const coded = {...setup, plans: plans.map(plan => ({leaf: plan.leaves[0], codes: plan.leaves.map(l => histograms[leaves.indexOf(l) + 1].code), contextOf: plan.contextOf}))};
213
+ const group = searchGroup(coded), sections = [];
214
+ if (layout.single) {
215
+ group(rgba, width, 0, 0, width, height, global);
216
+ hurried = yield 0.5 + ++written / (2 * chosen.length * groups);
217
+ sections.push(global.finish());
218
+ } else {
219
+ sections.push(global.finish());
220
+ for (let i = 0; i < layout.dcGroupsX * layout.dcGroupsY + 1; i++) sections.push(new Uint8Array(0));
221
+ const at = written, base = sections.length, place = (g, section) => { sections[base + g] = section; };
222
+ hurried = yield* groupPass({pooled, kind: 'search', setup: coded, at: g => 0.5 + (at + g + 1) / (2 * chosen.length * groups), stop: g => g + 1 < groups},
223
+ groups, g => place(g, group(rgba, width, ...rect(g))), place);
224
+ if (hurried === null) return null;
225
+ written += groups;
226
+ }
227
+ return assembleCodestream(header, sections);
228
+ }
229
+ }
@@ -0,0 +1,10 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Only doors with a search read effort; keeping it here adds no work or bytes to the pixel core.
3
+ import {fault} from './admit.mjs';
4
+
5
+ export function admitEffort(options = {}) {
6
+ if (options === null || typeof options !== 'object') throw fault('JXL_INPUT', 'Options are an object.');
7
+ const effort = options.effort === undefined ? 1 : options.effort;
8
+ if (!Number.isInteger(effort) || effort < 1 || effort > 9) throw fault('JXL_INPUT', 'Effort is a whole number from 1 to 9.');
9
+ return effort;
10
+ }
package/effort.d.mts CHANGED
@@ -3,8 +3,10 @@ import type {Pixels, EncodeOptions, Job} from './index.mjs';
3
3
  export {LIMITS} from './index.mjs';
4
4
  export type {Pixels, Limits, EncodeOptions, ErrorCode, EncoderError, Job} from './index.mjs';
5
5
  /** The core's encode with a search above it for exact pictures: effort 1 (the default) writes the core's bytes; 2 tries
6
- * the weighted predictor on every channel, 3 also splits its contexts by the predictor's error. Never larger than the
7
- * effort below; slower. */
6
+ * the weighted predictor on every channel, 3 splits its contexts by that predictor's error, 4 models palette indices
7
+ * per group and tries the other reversible colour transforms, and 6 also learns gradient-property splits. A level
8
+ * without another rung uses the preceding one.
9
+ * Never larger than the effort below; slower. */
8
10
  export function encode(data: Pixels, width: number, height: number, options?: EncodeOptions): Uint8Array;
9
11
  /** encode's work and bytes as steps. Above effort 1 an exact picture's first half (fractions up to 0.5) writes effort
10
12
  * 1's stream and the second searches; `hurry` ends the search with the smallest stream written so far. */
package/effort.min.mjs CHANGED
@@ -1,2 +1,2 @@
1
- /*! Rapier JXL 2.0.0 | MIT License Copyright (c) 2026 rapier.website Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
2
- function*t(t,n,e){let o,r;for(;!(o=t.next(r)).done;)r=yield(n+o.value)/e;return o.value}function n(t){return t>=0?2*t:2*-t-1}function e(t){return 31-Math.clz32(t)}function o(t){return t<=1?0:32-Math.clz32(t-1)}function r(t,n){t.t([[9,1],[13,1],[18,1],[30,1]],n)}function s(t,n,e,o,s,{xyb:i=!1,orientation:c=1,colorSpace:l}={}){t.write(16,2815),t.write(1,0),r(t,e),t.write(3,0),r(t,n),t.write(1,0);const f=1!==c;t.write(1,f?1:0),f&&t.write(6,c-1),t.write(4,8),s?t.write(3,5):t.write(2,0),t.write(1,i?1:0),3===o&&"display-p3"===l?t.write(21,903568):3===o?t.write(1,1):t.write(15,14100),f&&t.write(1,1),t.write(2,0),t.write(1,1),t.o()}function i(t,{alpha:n,shift:e=1}){t.write(9,8),n&&t.write(2,0),t.write(2,e),function(t,n){t.write(n?7:5,0),t.write(11,1)}(t,n)}function c(t,n,e=256){const o=Math.ceil(t/e),r=Math.ceil(n/e);return{i:o,u:r,p:Math.ceil(t/(8*e)),M:Math.ceil(n/(8*e)),A:1===o&&1===r}}function l(t,n){const e=n.map(t=>t.length);!function(t,n){t.write(1,0),t.o();for(const e of n)t.t([[10,0],[14,1024],[22,17408],[30,4211712]],e);t.o()}(t,e);const o=t.finish(),r=new Uint8Array(o.length+e.reduce((t,n)=>t+n,0));r.set(o);let s=o.length;for(const t of n)r.set(t,s),s+=t.length;return r}function f(t,n){const e=new Uint8Array(t.length),o=[];for(let n=0;n<t.length;n++)t[n]>0&&o.push(n);if(!o.length)return e;if(1===o.length)return e[o[0]]=1,e;for(let r=1;;r*=2){const s=o.map(n=>({w:Math.max(t[n],r),m:n,l:null,r:null})).sort((t,n)=>t.w-n.w||t.m-n.m),i=[];let c=0,l=0;const f=()=>c<s.length&&(l>=i.length||s[c].w<=i[l].w)?s[c++]:i[l++];for(;s.length-c+(i.length-l)>1;){const t=f(),n=f();i.push({w:t.w+n.w,m:-1,l:t,r:n})}const a=[[f(),0]];let u=0;for(;a.length;){const[t,n]=a.pop();t.m>=0?(e[t.m]=n,n>u&&(u=n)):a.push([t.l,n+1],[t.r,n+1])}if(u<=n)return e}}function a(t,n,e,o,r,s){const i=[];for(;i.push(o&r),o>>=s;)o--;for(let o=i.length-1;o>=0;o--)t.push(e),n.push(i[o])}function u(t,n){let e=0;for(let o=0;o<n;o++)e=e<<1|1&t,t>>=1;return e}function h(t){const n=new Uint32Array(17),e=new Uint32Array(17),o=new Uint16Array(t.length);for(const e of t)n[e]++;n[0]=0;for(let t=1,o=0;t<=16;t++)o=o+n[t-1]<<1,e[t]=o;for(let n=0;n<t.length;n++)t[n]&&(o[n]=u(e[t[n]]++,t[n]));return o}function y(t){const n=[];for(let e=0;e<t.length;e++)t[e]>0&&n.push(e);const e=n.length,o=n[e-1]+1||1,r=e<=4?new Uint8Array(o):f(t,15).subarray(0,o);let s=0;if(e<=4){n.sort((n,e)=>t[e]-t[n]||n-e),s=4===e&&t[n[0]]>t[n[2]]+t[n[3]]?1:0;const o=e<2?[0]:2===e?[1,1]:3===e?[1,2,2]:s?[1,2,3,3]:[2,2,2,2];n.forEach((t,n)=>{r[t]=o[n]}),n.sort((t,n)=>r[t]-r[n]||t-n)}return{U:o,I:r,S:h(r),T:e&&e<=4?n:null,v:s}}function w(t,n){if(n.U<=1)return;if(n.T){const o=e(n.U-1)+1;t.write(2,1),t.write(2,n.T.length-1);for(const e of n.T)t.write(o,e);return void(4===n.T.length&&t.write(1,n.v))}const o=n.I,r=[],s=[];let i=o.length-1;for(;i>0&&!o[i];)i--;let c=8;for(let t=0;t<=i;){const n=o[t];let e=1;for(;t+e<=i&&o[t+e]===n;)e++;let l=e;if(n&&n!==c&&(r.push(n),s.push(0),l--,c=n),l<3)for(let t=0;t<l;t++)r.push(n),s.push(0);else a(r,s,n?16:17,l-3,n?3:7,n?2:3);t+=e}const l=new Uint32Array(18);for(const t of r)l[t]++;let u=0;for(const t of l)t&&u++;1===u&&(l[r[0]?0:1]=l[r[0]]);const y=f(l,5),w=h(y);let p=18;for(;p>0&&!y[D[p-1]];)p--;t.write(2,0);for(let n=0;n<p;n++){const e=y[D[n]];t.write(F[e],Q[e])}for(let n=0;n<r.length;n++){const e=r[n];t.write(y[e],w[e]),16===e?t.write(2,s[n]):17===e&&t.write(3,s[n])}}function p(t,n=0,e=0){return{split:t,C:n,q:e,L:1<<t}}function d(t,n,e=15){t.write(o(e+1),n.split),n.split!==e&&(t.write(o(n.split+1),n.C),t.write(o(n.split-n.C+1),n.q))}function M(t,n,o){if(n<t.L)return o[0]=n,o[1]=0,void(o[2]=0);const r=e(n),s=n-(1<<r),i=r-t.C-t.q;o[0]=t.L+(r-t.split<<t.C+t.q|s>>r-t.C<<t.q|s&(1<<t.q)-1),o[1]=i,o[2]=n>>t.q&(1<<i)-1}function A(t,n,e,o=0){M(t,n,H),e[o+H[0]]++}function g(t,n,e,o,r=0){M(e,o,H);const s=r+H[0];t.write(n.I[s],n.S[s]),H[1]&&t.write(H[1],H[2])}function m(t,{N:n=null,P:r,X:s}){t.write(1,n?1:0),n&&(t.t([[0,224],[0,512],[0,4096],[15,8]],n.J),t.t([[0,3],[0,4],[2,5],[8,9]],n.minLength),d(t,n._,8)),r.length>1&&function(t,n){let e=0;for(const t of n)e=Math.max(e,t);const r=e?o(e+1):0;if(r<=3){if(t.write(1,1),t.write(2,r),r)for(const e of n)t.write(r,e);return}t.write(1,0),t.write(1,0);const s=p(8),i=p(4),c=n.length>=64,l=new Uint32Array(c?257:e+1),f=[];for(let t=0;t<n.length;){let e=1;for(;c&&t+e<n.length&&n[t+e]===n[t];)e++;if(e>=8)f.push([n[t],e-1]),l[n[t]]++,A(i,e-1-7,l,224),t+=e;else{for(let o=0;o<e;o++)f.push([n[t],0]),l[n[t]]++;t+=e}}const a=y(l);if(!c){m(t,{P:new Uint8Array(1),X:[{config:s,code:a}]});for(const[n]of f)g(t,a,s,n);return}const u=new Uint32Array(1);u[0]=1,m(t,{N:{J:224,minLength:7,_:i},P:new Uint8Array([1,0]),X:[{config:p(0),code:y(u)},{config:s,code:a}]});for(const[n,e]of f)g(t,a,s,n),e&&g(t,a,i,e-7,224)}(t,r),t.write(1,1);for(const n of s)d(t,n.config,15);for(const n of s){const o=n.code.U-1;if(o){const n=e(o);t.write(1,1),t.write(4,n),t.write(n,o-(1<<n))}else t.write(1,0)}for(const n of s)w(t,n.code)}function b(t,n=0,e=1){return{G:t,offset:n,O:e,context:-1}}function U(t,n,e,o){return{j:t,R:n,left:e,right:o}}function I(t,n){const e=(o,r)=>{if(o===r)return n?t[o].B:t[o];const s=o+r>>1;return U(n,n?t[s].k:s,e(s+1,r),e(o,s))};return e(0,t.length-1)}function S(t){return I(t,0)}function x(t,e){const o=[e],r=[],s=[];for(const t of o){if(t.left){r.push(t.j+1,n(t.R)),o.push(t.left,t.right);continue}t.context=s.length,s.push(t);const e=1===t.O?0:31-Math.clz32(t.O&-t.O);r.push(0,t.G,n(t.offset),e,(t.O>>e)-1)}const i=new Uint32Array(64);for(const t of r)A(tt,t,i);const c=y(i);m(t,{P:new Uint8Array(6),X:[{config:tt,code:c}]});for(const n of r)g(t,c,tt,n);return s}function T(t,n){const e=[[3,0],[6,8],[10,72],[13,1096]];if("rct"===n.type)t.write(2,0),t.t(e,n.Y),t.t([[0,6],[2,0],[4,2],[6,10]],n.Z??6);else if("palette"===n.type)t.write(2,1),t.t(e,n.Y),t.t([[0,1],[0,3],[0,4],[13,1]],n.D),t.t([[8,0],[10,256],[12,1280],[16,5376]],n.F),t.t([[0,0],[8,1],[10,257],[16,1281]],n.H??0),t.write(4,n.G??0);else{if("squeeze"!==n.type)throw new Error("unknown transform "+n.type);{t.write(2,2);const o=n.K??[];t.t([[0,0],[4,1],[6,9],[8,41]],o.length);for(const n of o)t.write(1,n.V?1:0),t.write(1,n.W?1:0),t.t(e,n.Y),t.t([[0,1],[0,2],[0,3],[4,4]],n.D)}}}function v(t,{$:n=!0,tt:e=[]}={}){t.write(1,n?1:0),t.write(1,1),t.t([[0,0],[0,1],[4,2],[8,18]],e.length);for(const n of e)T(t,n)}function C(t,n,e,o=t=>t.context){const r=new Uint8Array(n.length+1);for(const t of n)r[t.context]=o(t)+1;const s=new Uint32Array(2);s[1]=1;const i=[{config:tt,code:y(s)}],c=Math.max(...r);for(let t=0;t<c;t++)i.push({config:tt,code:y(e[t])});return m(t,{N:$,P:r,X:i}),i}function q(t,e,o,r,s,i){const c=i.G,l=i.offset,f=i.O,a=tt,u=W;let h=0;const y=(n,o=a,r=0)=>{t?g(t,e,o,n,r):A(o,n,e,r)},w=()=>{if(h){if(h>=8)y(0),y(h-7-1,u,224);else for(let t=0;t<h;t++)y(0);h=0}},p=(t,e)=>{const r=o[t];let s;1===f?s=r-e-l:(s=Math.round((r-e-l)/f),o[t]=e+l+s*f),0!==s?(w(),y(n(s))):h++};for(let t=0,n=0;t<s;t++)for(let e=0;e<r;e++,n++){let s;if(0===c)s=0;else{const i=e?o[n-1]:t?o[n-r]:0,l=t?o[n-r]:i;if(1===c)s=i;else if(2===c)s=l;else if(3===c)s=(i+l)/2|0;else{const f=i+l-(e&&t?o[n-r-1]:i);if(5===c){const t=i<l?i:l,n=i<l?l:i;s=f<t?t:f>n?n:f}else{if(4!==c)throw new Error("predictor "+c+" is not coded here");s=Math.abs(f-i)<Math.abs(f-l)?i:l}}}p(n,s)}w()}function E(t,n,e,{palette:o=!0}={}){const r=n*e;let s=!0,i=!0;for(let n=0,e=0;e<r&&(255===t[n+3]||(s=!1,i))&&(t[n]===t[n+1]&&t[n]===t[n+2]||(i=!1,s));e++,n+=4);const c=i?1:3,l=!s,f=c+(l?1:0),a=n=>i?l?t[n]+256*t[n+3]:t[n]:t[n]+256*t[n+1]+65536*t[n+2]+(l?16777216*t[n+3]:0),u=new Map;let h=null;for(let t=0,n=0;o&&n<r;n++,t+=4){const n=a(t);if(0!==n&&!u.has(n)&&(u.set(n,1),u.size>=2048))break}if(o&&u.size<2048){const t=[...u.keys()],n=(t,n)=>t>>>8*n&255,e=t=>(.299*n(t,0)+.587*n(t,1)+.114*n(t,2)+.01)*(4===f?n(t,3):1);t.sort((t,n)=>e(t)-e(n));const o=new Map([[0,0]]);t.forEach((t,n)=>o.set(t,n+1)),h={colours:[0,...t],index:o,key:a,byte:n}}return{colour:c,alpha:l,channels:f,palette:h}}function*L(n,e,o,{shape:r=E(n,e,o),colorSpace:s}={}){let i,c;const l=r.palette?[r,{...r,palette:null}]:[r];for(let r=0;r<l.length;r++)try{const c=yield*t(N(n,e,o,l[r],s),r,l.length);(!i||c.length<i.length)&&(i=c)}catch(t){if("JXL_SIZE"!==t.code)throw t;c=t}if(!i)throw c;return i}function*N(t,n,e,o,r){const{channels:f,palette:a}=o,u=c(n,e),h=a?2:f,p=Array.from({length:h},()=>b(V)),d=S(p),M=Array.from({length:h},()=>new Int16Array(65536)),A=(e,o,r,s)=>{for(let i=0;i<s;i++){let s=4*((o+i)*n+e),c=i*r;for(let n=0;n<r;n++,s+=4,c++)if(a)M[0][c]=a.index.get(a.key(s));else if(f>=3){const n=t[s],e=t[s+1],o=t[s+2],r=n-o,i=o+(r>>1),l=e-i;M[0][c]=i+(l>>1),M[1][c]=r,M[2][c]=l,4===f&&(M[3][c]=t[s+3])}else M[0][c]=t[s],2===f&&(M[1][c]=t[s+3])}};let g=null;if(a){const t=a.colours.length;g=new Int16Array(t*f),a.colours.forEach((n,e)=>{for(let o=0;o<f;o++)g[o*t+e]=a.byte(n,o)})}const m=t=>p[a?u.A?1:0:t],U=a?1:f,I=u.i*u.u,T=2*I,E=(t,o)=>{const r=t%u.i*Z,s=(t/u.i|0)*Z,i=Math.min(Z,n-r),c=Math.min(Z,e-s);A(r,s,i,c),o(i,c)};let L=0;if(!a){const t=t=>{const n=y(t),e=new Y(128);w(e,n);let o=e.nt;for(let e=0;e<t.length;e++)t[e]&&(o+=t[e]*(n.I[e]+Math.max(0,e<224?e-1:e-236)));return o},o=Math.min(n,32),r=Math.min(e,32),s=[V,K].map(t=>({G:t,et:p.map(()=>new Uint32Array(nt))}));for(const t of[0,.5,1]){A(Math.floor((n-o)*t),Math.floor((e-r)*t),o,r);for(const t of s)for(let n=0;n<f;n++)q(null,t.et[n],M[n],o,r,b(t.G))}p.forEach((n,e)=>{const o=s.map(n=>t(n.et[e])),r=o[1]<o[0]?1:0;n.G=s[r].G})}const N=a?[{type:"palette",Y:0,D:f,F:a.colours.length}]:f>=3?[{type:"rct",Y:0,Z:6}]:[],P=p.map(()=>new Uint32Array(nt)),X=t=>P[p.indexOf(t)];g&&q(null,X(p[0]),g,a.colours.length,f,p[0]);for(let t=0;t<I;t++)E(t,(t,n)=>{for(let e=0;e<U;e++)q(null,X(m(e)),M[e],t,n,m(e))}),yield++L/T;const J=new Y(256);s(J,n,e,o.colour,o.alpha,{colorSpace:r}),i(J,{alpha:o.alpha});const _=new Y(4096);_.write(1,1),_.write(1,1);const z=x(_,d),G=C(_,z,P,t=>p.indexOf(t)),O=t=>G[p.indexOf(t)+1].code;v(_,{$:!0,tt:N}),g&&q(_,O(p[0]),g,a.colours.length,f,p[0]);const j=[];if(u.A)E(0,(t,n)=>{for(let e=0;e<U;e++)q(_,O(m(e)),M[e],t,n,m(e))}),yield 1,j.push(_.finish());else{j.push(_.finish());for(let t=0;t<u.p*u.M+1;t++)j.push(new Uint8Array(0));for(let t=0;t<I;t++)E(t,(t,n)=>{const e=new Y(t*n*U+64);v(e,{$:!0,tt:[]});for(let o=0;o<U;o++)q(e,O(m(o)),M[o],t,n,m(o));j.push(e.finish())}),yield++L/T}return l(J,j)}function P(t,n,e){const o=t>=n&&n>=e?1:t<=n&&n<=e?-1:0;if(!o)return 0;let r=(4*(t*=o)-3*(e*=o)-(n*=o)+6)/12|0;return r-(1&r)>2*(t-n)&&(r=2*(t-n)+1),r+(1&r)>2*(n-e)&&(r=2*(n-e)),o*r}function X(t,n){const{w:e,h:o,data:r}=t,s=n?e:o,i=s+1>>1,c=s-i,l=n?i:e,f=n?o:i,a=n?c:e,u=n?o:c,h=new Int16Array(l*f),y=new Int16Array(a*u),w=n?1:e;for(let t=0;t<f;t++)for(let o=0;o<l;o++){const i=n?o:t,f=n?t*e+2*o:2*t*e+o;if(i===c){h[t*l+o]=r[f];continue}const u=r[f],p=r[f+w],d=et(u,p),M=i+1<c?et(r[f+2*w],r[f+3*w]):1&s?r[f+2*w]:d;h[t*l+o]=d,y[t*a+o]=u-p-P(i?r[f-w]:d,d,M)}const p=(e,o,r)=>({w:o,h:r,ot:t.ot+ +n,rt:t.rt+!n,data:e});return[p(h,l,f),p(y,a,u)]}function J(t){const n=[],e=t.length;let o=t[0].w,r=t[0].h;for(e>2&&t[1].w===o&&t[1].h===r&&(n.push({V:!0,W:!1,Y:1,D:2}),n.push({V:!1,W:!1,Y:1,D:2})),!(o>r)&&r>8&&(n.push({V:!1,W:!0,Y:0,D:e}),r=r+1>>1);o>8||r>8;)o>8&&(n.push({V:!0,W:!0,Y:0,D:e}),o=o+1>>1),r>8&&(n.push({V:!1,W:!0,Y:0,D:e}),r=r+1>>1);return n}function*_(t,n,e,{quality:o=90,shape:r=E(t,n,e,{palette:!1}),colorSpace:f}={}){const a=function(t){return t>=100?0:t>=30?.1+.09*(100-t):53/3e3*t*t-1.15*t+25}(o);if(!(a>0))throw new Error("lossy encoding needs a quality below 100");const{colour:u,alpha:h,channels:y}=r,w=n*e,p=Array.from({length:y},()=>new Int16Array(w));for(let n=0,e=0;e<w;e++,n+=4){if(3===u){const o=t[n],r=t[n+1],s=t[n+2],i=o-s,c=s+(i>>1),l=r-c;p[0][e]=c+(l>>1),p[1][e]=i,p[2][e]=l}else p[0][e]=t[n];h&&(p[y-1][e]=t[n+3])}const d=p.map((t,o)=>({w:n,h:e,ot:0,rt:0,data:t,component:3===u?o:0===o?0:3})),M=1===n&&e>ot&&3===u,A=M?J(d).filter(t=>!t.V):1!==n&&1!==e||3!==u?[]:J(d),g=function(t,n=J(t)){const e=t.map(t=>({...t,level:0,st:!1}));for(const t of n){const n=t.Y+t.D-1,o=t.W?n+1:e.length;for(let r=t.Y;r<=n;r++){const[n,s]=X(e[r],t.V),i=e[r].level+1;e[r]={...n,level:i,st:e[r].st,component:e[r].component},e.splice(o+(r-t.Y),0,{...s,level:i,st:!0,component:e[r].component})}}return e}(d,A.length?A:void 0),m=t=>t.st?0:V,U=t=>function(t,n,e,o){let r=Math.min(16,n+e);if(r>0&&r--,3===t)return 1;const s=.25*function(t){let n=1;for(let e=0;e<24;e++)n=(4*n+t/(n*n*n*n))/5;return t*n}(o),i=1<<r,c=1===t||2===t?.35*s*Math.max(.5,1024/i):.35*s*1.1*(163.84/i);return Math.max(1,Math.floor(c))}(t.component,t.ot+(M&&t.component>0&&t.component<3?1:0),t.rt,a),T=[...3===u?[{type:"rct",Y:0,Z:6}]:[],{type:"squeeze",K:A}],L=c(n,e,ot),N=L.p*L.M,P=L.i*L.u;let _=0;for(;_<g.length&&g[_].w<=ot&&g[_].h<=ot;)_++;const z=(t,n,e,o)=>{const r=n>>t.ot,s=e>>t.rt;return{x:r,y:s,w:Math.min(t.w,r+(o>>t.ot))-r,h:Math.min(t.h,s+(o>>t.rt))-s}},G=[{index:0,k:0,it:[]}];for(let t=0;t<_;t++)G[0].it.push({c:t,rect:{x:0,y:0,w:g[t].w,h:g[t].h}});if(!L.A){for(let t=0;t<N;t++){const n=t%L.p,e=t/L.p|0,o={index:1+t,k:1+N+t,it:[]};for(let t=_;t<g.length;t++){const r=g[t];if(Math.min(r.ot,r.rt)<3)continue;const s=z(r,n*rt,e*rt,rt);s.w>0&&s.h>0&&o.it.push({c:t,rect:s})}G.push(o)}for(let t=0;t<P;t++){const n=t%L.i,e=t/L.i|0,o={index:2+N+t,k:1+3*N+17+t,it:[]};for(let t=_;t<g.length;t++){const r=g[t];if(Math.min(r.ot,r.rt)>2)continue;const s=z(r,n*ot,e*ot,ot);s.w>0&&s.h>0&&o.it.push({c:t,rect:s})}G.push(o)}}for(const t of G)for(const n of t.it){const t=g[n.c];n.ct=b(m(t),0,U(t)),n.ct.channel=n.c}const O=G.filter(t=>t.it.length),j=1===O.length?S(O[0].it.map(t=>t.ct)):function(t){return I(t,1)}(O.map(t=>({k:t.k,B:S(t.it.map(t=>t.ct))}))),R=new Int16Array(1048576),B=t=>{const n=g[t.c],e=t.rect;if(e.w===n.w&&e.h===n.h)return n.data;for(let t=0;t<e.h;t++)R.set(n.data.subarray((e.y+t)*n.w+e.x,(e.y+t)*n.w+e.x+e.w),t*e.w);return R},k=[...new Set(G.flatMap(t=>t.it.map(t=>t.c)))].sort((t,n)=>t-n),Z=new Map(k.map((t,n)=>[t,n])),D=k.map(()=>new Uint32Array(nt)),F=1+2*G.length;let Q=1;yield Q/F;for(const t of G){for(const n of t.it)q(null,D[Z.get(n.c)],B(n),n.rect.w,n.rect.h,n.ct);yield++Q/F}const H=new Y(256);s(H,n,e,u,h,{colorSpace:f}),i(H,{alpha:h,shift:n>256||e>256?3:1});const K=Array.from({length:L.A?1:2+N+P},()=>null),W=K[0]=new Y(65536);W.write(1,1),W.write(1,1);const $=C(W,x(W,j),D,t=>Z.get(t.channel));v(W,{$:!0,tt:T});for(const t of G){let n=K[t.index];n||(n=K[t.index]=new Y(4096),t.it.length&&v(n,{$:!0,tt:[]}));for(const e of t.it)q(n,$[Z.get(e.c)+1].code,B(e),e.rect.w,e.rect.h,e.ct);yield++Q/F}return l(H,function(t){return t.map(t=>t?t.finish():new Uint8Array(0))}(K))}function z(t,e,o,r,s,i=0,c=ft){const l=r+2,f=new Int32Array(2*l),a=new Int32Array(2*l),u=new Int32Array(2*l),h=new Int32Array(2*l),y=new Int32Array(2*l),w=new Int32Array(8);let p=0;const d=(n,o,r=tt,s=0)=>{t?g(t,e[n],r,o,s):A(r,o,e[n],s)},M=()=>{if(p){if(p>$.minLength)d(w[0],0),d(w[1],p-$.minLength-1,$._,$.J);else for(let t=0;t<p;t++)d(w[t],0);p=0}};for(let t=0,e=0;t<s;t++){const s=1&t?0:l,A=1&t?l:0;for(let l=0;l<r;l++,e++){const g=l?o[e-1]:t?o[e-r]:0,m=t?o[e-r]:g,b=l&&t?o[e-r-1]:g,U=l+1<r&&t?o[e-r+1]:m,I=t>1?o[e-2*r]:m,S=A+l,x=l<r-1?S+1:S,T=l?S-1:S;let v=lt(f[S]+f[x]+f[T],13),C=lt(a[S]+a[x]+a[T],12),q=lt(u[S]+u[x]+u[T],12),E=lt(h[S]+h[x]+h[T],12);const L=8*m,N=8*g,P=8*U,X=8*b,J=8*I,_=l?y[s+l-1]:0,z=y[S],G=y[T],O=y[x],j=z+_;let R=_;Math.abs(z)>Math.abs(R)&&(R=z),Math.abs(G)>Math.abs(R)&&(R=G),Math.abs(O)>Math.abs(R)&&(R=O);const B=c[it[R<-501?0:R>501?1002:R+501]],k=N+P-L,Y=L-(16*(j+O)>>5),Z=N-(10*(j+G)>>5),D=L-(7*G+7*z+7*O+0*(J-L)+0*(X-N)>>5),F=27-Math.clz32(v+C+q+E);v>>=F,C>>=F,q>>=F,E>>=F;const Q=v+C+q+E;let H=Math.floor(((Q>>1)-1+k*v+Y*C+Z*q+D*E)*ct[Q-1]/16777216);if((z^_|z^G)<=0){const t=Math.min(N,P,L),n=Math.max(N,P,L);H=H<t?t:H>n?n:H}const K=o[e],V=K-(H+3>>3)-i;0===V?(p<8&&(w[p]=B),p++):(M(),d(B,n(V)));const W=8*K,$=Math.abs(k-W)+3>>3,tt=Math.abs(Y-W)+3>>3,nt=Math.abs(Z-W)+3>>3,et=Math.abs(D-W)+3>>3;y[s+l]=H-W,f[s+l]=$,a[s+l]=tt,u[s+l]=nt,h[s+l]=et,f[A+l+1]+=$,a[A+l+1]+=tt,u[A+l+1]+=nt,h[A+l+1]+=et}}M()}function G(t){try{return t()}catch(t){if(t instanceof RangeError&&!t.code)throw at("JXL_MEMORY","Not enough memory for this picture.");throw t}}function O(t,n,e,o){return function(t){let n;for(;!(n=t.next()).done;);return n.value}(j(t,n,e,o))}function j(n,e,o,r){const{quality:f,colorSpace:a}=function(t={},n=100){if(null===t||"object"!=typeof t)throw at("JXL_INPUT","Options are an object: {quality, colorSpace}.");if(void 0!==t.quality&&(n=t.quality),"number"!=typeof n||!Number.isFinite(n)||n<1||n>100)throw at("JXL_INPUT","Quality is a number from 1 to 100.");const e=void 0===t.colorSpace?"srgb":t.colorSpace;if("srgb"!==e&&"display-p3"!==e)throw at("JXL_INPUT","The colour space is srgb or display-p3.");return{quality:n,colorSpace:e}}(r),u=void 0===r?.effort?1:r.effort;if(!Number.isInteger(u)||u<1||u>9)throw at("JXL_INPUT","Effort is a whole number from 1 to 9.");return function(t,n,e,o){if(function(t,n,e=B){if(!Number.isInteger(t)||!Number.isInteger(n)||t<1||n<1)throw at("JXL_INPUT","A picture is at least one pixel wide and high, in whole pixels.");if(t>e.edge||n>e.edge)throw at("JXL_DIMENSIONS","A picture is at most "+e.edge+" pixels on a side.");if(t*n>e.pixels)throw at("JXL_DIMENSIONS","A picture is at most "+e.pixels.toLocaleString("en-US")+" pixels.")}(n,e,o),!(t instanceof Uint8Array||t instanceof Uint8ClampedArray))throw at("JXL_INPUT","Pixels are a Uint8Array or Uint8ClampedArray of RGBA bytes.");if(t.length!==n*e*4)throw at("JXL_INPUT","Pixels are width * height * 4 bytes: straight (not premultiplied) RGBA, row by row.")}(n,e,o),function(t){const n=function*(){let e,o;for(;!(e=G(()=>t.next(n.hurry))).done;)yield o=e.value;return o<1&&(yield 1),n.bytes=function(t){if(t.length>B.bytes)throw at("JXL_SIZE","The encoded picture exceeds 16 MiB.");return t}(e.value)}();return n.bytes=null,n.hurry=!1,n}(function*(n,e,o,r,f,a){const u=E(n,e,o);if(r<100){if(!u.palette)return yield*_(n,e,o,{quality:r,shape:u,colorSpace:f});const s=yield*t(L(n,e,o,{shape:u,colorSpace:f}),0,2);let i;try{i=yield*t(_(n,e,o,{quality:r,shape:u,colorSpace:f}),1,2)}catch(t){if(!(t instanceof RangeError)||t.code)throw t;i=s}return s.length<=i.length?s:i}if(a<2)return yield*L(n,e,o,{shape:u,colorSpace:f});let h=yield*t(L(n,e,o,{shape:u,colorSpace:f}),0,2);try{const r=yield*t(function*(t,n,e,o,r,f){function*a(t){const{B:c,leaves:f,et:a}=_(t),p=u>=3?[{type:"rct",Y:0,Z:6}]:[],M=new Y(256);s(M,n,e,o.colour,o.alpha,{colorSpace:r}),i(M,{alpha:o.alpha});const A=new Y(4096);A.write(1,1),A.write(1,1);const g=C(A,x(A,c),a,t=>f.indexOf(t));v(A,{$:!0,tt:p});const m=t.map(t=>t.leaves.map(t=>g[f.indexOf(t)+1].code)),b=(n,e,o,r)=>{const s=t[e];6===s.leaves[0].G?z(n,m[e],w[e],o,r,0,s.lt):q(n,m[e][0],w[e],o,r,s.leaves[0])},U=[];if(h.A){if(d(0,(t,n)=>{for(let e=0;e<u;e++)b(A,e,t,n)}),yield B())return null;U.push(A.finish())}else{U.push(A.finish());for(let t=0;t<h.p*h.M+1;t++)U.push(new Uint8Array(0));for(let t=0;t<y;t++)if(d(t,(t,n)=>{const e=new Y(t*n*u+64);v(e,{$:!0,tt:[]});for(let o=0;o<u;o++)b(e,o,t,n);U.push(e.finish())}),yield B())return null}return l(M,U)}const{channels:u}=o,h=c(n,e),y=h.i*h.u,w=Array.from({length:u},()=>new Int16Array(65536)),p=(e,o,r,s)=>{for(let i=0;i<s;i++){let s=4*((o+i)*n+e),c=i*r;for(let n=0;n<r;n++,s+=4,c++)if(u>=3){const n=t[s],e=t[s+1],o=t[s+2],r=n-o,i=o+(r>>1),l=e-i;w[0][c]=i+(l>>1),w[1][c]=r,w[2][c]=l,4===u&&(w[3][c]=t[s+3])}else w[0][c]=t[s],2===u&&(w[1][c]=t[s+3])}},d=(t,o)=>{const r=t%h.i*Z,s=(t/h.i|0)*Z,i=Math.min(Z,n-r),c=Math.min(Z,e-s);p(r,s,i,c),o(i,c)},M=Math.min(n,32),A=Math.min(e,32),g=[V,K].map(t=>({G:t,et:w.map(()=>new Uint32Array(nt))}));for(const t of[0,.5,1]){p(Math.floor((n-M)*t),Math.floor((e-A)*t),M,A);for(const t of g)for(let n=0;n<u;n++)q(null,t.et[n],w[n],M,A,b(t.G))}const m=w.map((t,n)=>b(g[R(g[1].et[n])<R(g[0].et[n])?1:0].G)),I=st.length+1,T=Int32Array.from({length:I},(t,n)=>n),E=w.map(()=>new Uint32Array(nt)),L=w.map(()=>Array.from({length:I},()=>new Uint32Array(nt)));let N=0;for(let t=0;t<y;t++)if(d(t,(t,n)=>{for(let e=0;e<u;e++)q(null,E[e],w[e],t,n,m[e]),z(null,L[e],w[e],t,n,0,T)}),yield++N/(2*y))return null;const P=w.map((t,n)=>{const e={ft:R(E[n]),leaves:[m[n]],et:[E[n]],cuts:[]},o=ht(L[n]),r=R(o);return r<e.ft?{ft:r,leaves:[b(6)],et:[o],cuts:[]}:e}),X=f<3?P:P.map((t,n)=>{const e=L[n].map(t=>t.some(t=>t)),o=new Float64Array(I+1).fill(1/0),r=new Int32Array(I+1);o[0]=0;for(let t=1;t<=I;t++){const s=new Uint32Array(nt);let i=0;for(let c=t-1;c>=0;c--){if(e[c]){const t=L[n][c];for(let n=0;n<nt;n++)s[n]+=t[n];i=R(s)}const l=o[c]+i+24;l<o[t]&&(o[t]=l,r[t]=c)}}if(!(o[I]<t.ft))return t;const s=[];for(let t=I;t>0;t=r[t])s.unshift([r[t],t]);return{ft:o[I],leaves:s.map(()=>b(6)),et:s.map(([t,e])=>ht(L[n].slice(t,e))),cuts:s.slice(0,-1).map(([,t])=>st[t-1]),lt:Int32Array.from({length:I},(t,n)=>s.findIndex(([t,e])=>n>=t&&n<e))}}),J=[P,X].filter((t,n)=>n?t.some((t,n)=>t!==P[n]):t.some((t,n)=>t.leaves[0]!==m[n]));if(!J.length)return null;const _=t=>({B:S(t.map(t=>((t,n)=>{const e=(o,r)=>{if(o===r)return t[o];const s=o+r>>1;return U(15,n[s],e(s+1,r),e(o,s))};return e(0,t.length-1)})(t.leaves,t.cuts))),leaves:t.flatMap(t=>t.leaves),et:t.flatMap(t=>t.et)}),G=t=>{const{B:n,leaves:e,et:o}=_(t),r=new Y(4096),s=C(r,x(r,n),o,t=>e.indexOf(t));let i=r.nt;return o.forEach((t,n)=>{const{I:e}=s[n+1].code;for(let n=0;n<t.length;n++)t[n]&&(i+=t[n]*(e[n]+ut(n)))}),i};let O=J;if(J.length>1){const[t,n]=J.map(G),e=27*(h.A?1:y+1)+8;n+e<=t?O=[J[1]]:t+e<=n&&(O=[J[0]])}let j=0;const B=()=>.5+ ++j/(2*O.length*y);let k=null;for(const t of O){const n=yield*a(t);if(!n)return k;(!k||n.length<k.length)&&(k=n)}return k}(n,e,o,u.palette?{...u,palette:null}:u,f,a),1,2);r&&r.length<h.length&&(h=r)}catch(t){if(!(t instanceof RangeError)||t.code)throw t}return h}(n,e,o,f,a,u))}function R(t){const n=y(t),e=new Y(128);w(e,n);let o=e.nt;for(let e=0;e<t.length;e++)t[e]&&(o+=t[e]*(n.I[e]+ut(e)));return o}const B=Object.freeze({bytes:16777216,pixels:24e6,edge:16384}),k=[1];for(let t=1;t<=32;t++)k.push(2*k[t-1]);class Y{constructor(t=4096){this.bytes=new Uint8Array(t),this.at=0,this.ut=0,this.pending=0}write(t,n){if(!(n>=0&&n<k[t]))throw new Error("bit write out of range: "+t+" bits, "+n);let e=this.ut+n*(1<<this.pending),o=this.pending+t;this.at+5>=this.bytes.length&&this.grow();const r=this.bytes;for(;o>=8;)r[this.at++]=255&e,e=Math.floor(e/256),o-=8;this.ut=e,this.pending=o}t(t,n){for(let e=0;e<4;e++){const[o,r]=t[e];if(n>=r&&n-r<k[o])return this.write(2,e),void(o&&this.write(o,n-r))}throw new Error("U32 value out of range: "+n)}o(){this.pending&&(this.at+1>=this.bytes.length&&this.grow(),this.bytes[this.at++]=this.ut,this.ut=0,this.pending=0)}get nt(){return 8*this.at+this.pending}grow(t=0){const n=B.bytes+64;if(this.at+t+16>n)throw Object.assign(new Error("The encoded picture exceeds 16 MiB."),{code:"JXL_SIZE"});const e=new Uint8Array(Math.min(n,Math.max(2*this.bytes.length,this.at+t+16)));e.set(this.bytes.subarray(0,this.at)),this.bytes=e}append(t){if(this.at+t.at+8>=this.bytes.length&&this.grow(t.at+8),this.pending)for(let n=0;n<t.at;n++)this.write(8,t.bytes[n]);else this.bytes.set(t.bytes.subarray(0,t.at),this.at),this.at+=t.at;t.pending&&this.write(t.pending,t.ut)}finish(){const t=this.at+(this.pending?1:0),n=this.bytes.slice(0,t);return this.pending&&(n[this.at]=this.ut),n}}const Z=256,D=[1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15],F=[2,4,3,2,2,4],Q=[0,7,3,2,1,15],H=[0,0,0],K=3,V=5,W=p(4),$=Object.freeze({J:224,minLength:7,_:W}),tt=p(0),nt=257,et=(t,n)=>t+n+(t>n?1:0)>>1,ot=1024,rt=8192,st=[-500,-392,-255,-191,-127,-95,-63,-47,-31,-23,-15,-11,-7,-4,-3,-1,0,1,3,5,7,11,15,23,31,47,63,95,127,191,255,392,500],it=Int8Array.from({length:1003},(t,n)=>st.filter(t=>t<n-501).length),ct=Int32Array.from({length:64},(t,n)=>Math.floor(16777216/(n+1))),lt=(t,n)=>{const e=Math.max(0,26-Math.clz32(t+1));return 4+(n*ct[t>>e]>>e)},ft=new Int32Array(st.length+1),at=(t,n)=>Object.assign(new Error(n),{code:t}),ut=t=>Math.max(0,t<224?t-1:t-236),ht=t=>{const n=new Uint32Array(nt);for(const e of t)for(let t=0;t<nt;t++)n[t]+=e[t];return n};export{B as LIMITS,O as encode,j as encodeSteps};
1
+ /*! Rapier JXL 2.2.0 | MIT License Copyright (c) 2026 rapier.website Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
2
+ const t=Object.freeze({bytes:16777216,pixels:24e6,edge:16384}),n=[1];for(let t=1;t<=32;t++)n.push(2*n[t-1]);class e{constructor(t=4096){this.bytes=new Uint8Array(t),this.at=0,this.t=0,this.pending=0}write(t,e){if(!(e>=0&&e<n[t]))throw new Error("bit write out of range: "+t+" bits, "+e);let r=this.t+e*(1<<this.pending),o=this.pending+t;this.at+5>=this.bytes.length&&this.grow();const s=this.bytes;for(;o>=8;)s[this.at++]=255&r,r=Math.floor(r/256),o-=8;this.t=r,this.pending=o}o(t,e){for(let r=0;r<4;r++){const[o,s]=t[r];if(e>=s&&e-s<n[o])return this.write(2,r),void(o&&this.write(o,e-s))}throw new Error("U32 value out of range: "+e)}i(){this.pending&&(this.at+1>=this.bytes.length&&this.grow(),this.bytes[this.at++]=this.t,this.t=0,this.pending=0)}get u(){return 8*this.at+this.pending}grow(n=0){const e=t.bytes+64;if(this.at+n+16>e)throw Object.assign(new Error("The encoded picture exceeds 16 MiB."),{code:"JXL_SIZE"});const r=new Uint8Array(Math.min(e,Math.max(2*this.bytes.length,this.at+n+16)));r.set(this.bytes.subarray(0,this.at)),this.bytes=r}append(t){if(this.at+t.at+8>=this.bytes.length&&this.grow(t.at+8),this.pending)for(let n=0;n<t.at;n++)this.write(8,t.bytes[n]);else this.bytes.set(t.bytes.subarray(0,t.at),this.at),this.at+=t.at;t.pending&&this.write(t.pending,t.t)}finish(){const t=this.at+(this.pending?1:0),n=this.bytes.slice(0,t);return this.pending&&(n[this.at]=this.t),n}}function*r(t,n,e){let r,s;for(;!(r=t.next(s)).done;)s=yield o(r.value,t=>(n+t)/e);return r.value}const o=(t,n)=>"number"==typeof t?n(t):{...t,at:e=>n(t.at(e))};function s(t){return t>=0?2*t:2*-t-1}function c(t){return 31-Math.clz32(t)}function l(t){return t<=1?0:32-Math.clz32(t-1)}const i=(t,n)=>Object.assign(new Error(n),{code:t});function f(n){if(n>t.bytes)throw i("JXL_SIZE","The encoded picture exceeds 16 MiB.")}function a(t){try{return t()}catch(t){if(t instanceof RangeError&&!t.code)throw i("JXL_MEMORY","Not enough memory for this picture.");throw t}}const u=256;function h(t,n){t.o([[9,1],[13,1],[18,1],[30,1]],n)}function y(t,n,e,r,o,{xyb:s=!1,orientation:c=1,colorSpace:l}={}){t.write(16,2815),t.write(1,0),h(t,e),t.write(3,0),h(t,n),t.write(1,0);const i=1!==c;t.write(1,i?1:0),i&&t.write(6,c-1),t.write(4,8),o?t.write(3,5):t.write(2,0),t.write(1,s?1:0),3===r&&"display-p3"===l?t.write(21,903568):3===r?t.write(1,1):t.write(15,14100),i&&t.write(1,1),t.write(2,0),t.write(1,1),t.i()}function p(t,{alpha:n,shift:e=1}){t.write(9,8),n&&t.write(2,0),t.write(2,e),function(t,n){t.write(n?7:5,0),t.write(11,1)}(t,n)}function w(t,n,e=256){const r=Math.ceil(t/e),o=Math.ceil(n/e);return{p:r,A:o,M:Math.ceil(t/(8*e)),m:Math.ceil(n/(8*e)),U:1===r&&1===o}}function d(t,n,e,r){const o=r%t.p*u,s=(r/t.p|0)*u;return[o,s,Math.min(u,n-o),Math.min(u,e-s)]}function*A(t,n,e,r){if(t.pooled){const n=yield t;return n?(n.results.forEach((t,n)=>r(n,t)),n.hurried):null}let o=!1;for(let r=0;r<n;r++)if(e(r),o=yield t.at(r),o&&t.stop(r))return null;return o}function M(t,n){t.forEach((t,e)=>{const r=n[e];for(let n=0;n<t.length;n++)t[n]+=r[n]})}function g(t,n){const e=n.map(t=>t.length);!function(t,n){t.write(1,0),t.i();for(const e of n)t.o([[10,0],[14,1024],[22,17408],[30,4211712]],e);t.i()}(t,e);const r=t.finish(),o=r.length+e.reduce((t,n)=>t+n,0);f(o);const s=new Uint8Array(o);s.set(r);let c=r.length;for(const t of n)s.set(t,c),c+=t.length;return s}const b=[1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15],m=[2,4,3,2,2,4],U=[0,7,3,2,1,15];function I(t,n){const e=new Uint8Array(t.length),r=[];for(let n=0;n<t.length;n++)t[n]>0&&r.push(n);if(!r.length)return e;if(1===r.length)return e[r[0]]=1,e;for(let o=1;;o*=2){const s=r.map(n=>({w:Math.max(t[n],o),I:n,l:null,r:null})).sort((t,n)=>t.w-n.w||t.I-n.I),c=[];let l=0,i=0;const f=()=>l<s.length&&(i>=c.length||s[l].w<=c[i].w)?s[l++]:c[i++];for(;s.length-l+(c.length-i)>1;){const t=f(),n=f();c.push({w:t.w+n.w,I:-1,l:t,r:n})}const a=[[f(),0]];let u=0;for(;a.length;){const[t,n]=a.pop();t.I>=0?(e[t.I]=n,n>u&&(u=n)):a.push([t.l,n+1],[t.r,n+1])}if(u<=n)return e}}function S(t,n,e,r,o,s){const c=[];for(;c.push(r&o),r>>=s;)r--;for(let r=c.length-1;r>=0;r--)t.push(e),n.push(c[r])}function v(t,n){let e=0;for(let r=0;r<n;r++)e=e<<1|1&t,t>>=1;return e}function x(t){const n=new Uint32Array(17),e=new Uint32Array(17),r=new Uint16Array(t.length);for(const e of t)n[e]++;n[0]=0;for(let t=1,r=0;t<=16;t++)r=r+n[t-1]<<1,e[t]=r;for(let n=0;n<t.length;n++)t[n]&&(r[n]=v(e[t[n]]++,t[n]));return r}function C(t){const n=[];for(let e=0;e<t.length;e++)t[e]>0&&n.push(e);const e=n.length,r=n[e-1]+1||1,o=e<=4?new Uint8Array(r):I(t,15).subarray(0,r);let s=0;if(e<=4){n.sort((n,e)=>t[e]-t[n]||n-e),s=4===e&&t[n[0]]>t[n[2]]+t[n[3]]?1:0;const r=e<2?[0]:2===e?[1,1]:3===e?[1,2,2]:s?[1,2,3,3]:[2,2,2,2];n.forEach((t,n)=>{o[t]=r[n]}),n.sort((t,n)=>o[t]-o[n]||t-n)}return{S:r,v:o,C:x(o),T:e&&e<=4?n:null,q:s}}function T(t,n){if(n.S<=1)return;if(n.T){const e=c(n.S-1)+1;t.write(2,1),t.write(2,n.T.length-1);for(const r of n.T)t.write(e,r);return void(4===n.T.length&&t.write(1,n.q))}const e=n.v,r=[],o=[];let s=e.length-1;for(;s>0&&!e[s];)s--;let l=8;for(let t=0;t<=s;){const n=e[t];let c=1;for(;t+c<=s&&e[t+c]===n;)c++;let i=c;if(n&&n!==l&&(r.push(n),o.push(0),i--,l=n),i<3)for(let t=0;t<i;t++)r.push(n),o.push(0);else S(r,o,n?16:17,i-3,n?3:7,n?2:3);t+=c}const i=new Uint32Array(18);for(const t of r)i[t]++;let f=0;for(const t of i)t&&f++;1===f&&(i[r[0]?0:1]=i[r[0]]);const a=I(i,5),u=x(a);let h=18;for(;h>0&&!a[b[h-1]];)h--;t.write(2,0);for(let n=0;n<h;n++){const e=a[b[n]];t.write(m[e],U[e])}for(let n=0;n<r.length;n++){const e=r[n];t.write(a[e],u[e]),16===e?t.write(2,o[n]):17===e&&t.write(3,o[n])}}function q(t,n=0,e=0){return{split:t,L:n,X:e,J:1<<t}}function E(t,n,e=15){t.write(l(e+1),n.split),n.split!==e&&(t.write(l(n.split+1),n.L),t.write(l(n.split-n.L+1),n.X))}function L(t,n,e){if(n<t.J)return e[0]=n,e[1]=0,void(e[2]=0);const r=c(n),o=n-(1<<r),s=r-t.L-t.X;e[0]=t.J+(r-t.split<<t.L+t.X|o>>r-t.L<<t.X|o&(1<<t.X)-1),e[1]=s,e[2]=n>>t.X&(1<<s)-1}function X(t,n,e,r=0){L(t,n,J),e[r+J[0]]++}const J=[0,0,0];function N(t,n,e,r,o=0){L(e,r,J);const s=o+J[0];t.write(n.v[s],n.C[s]),J[1]&&t.write(J[1],J[2])}function _(t,{N:n=null,_:e,P:r}){t.write(1,n?1:0),n&&(t.o([[0,224],[0,512],[0,4096],[15,8]],n.G),t.o([[0,3],[0,4],[2,5],[8,9]],n.minLength),E(t,n.O,8)),e.length>1&&function(t,n){let e=0;for(const t of n)e=Math.max(e,t);const r=e?l(e+1):0;if(r<=3){if(t.write(1,1),t.write(2,r),r)for(const e of n)t.write(r,e);return}t.write(1,0),t.write(1,0);const o=q(8),s=q(4),c=n.length>=64,i=new Uint32Array(c?257:e+1),f=[];for(let t=0;t<n.length;){let e=1;for(;c&&t+e<n.length&&n[t+e]===n[t];)e++;if(e>=8)f.push([n[t],e-1]),i[n[t]]++,X(s,e-1-7,i,224),t+=e;else{for(let r=0;r<e;r++)f.push([n[t],0]),i[n[t]]++;t+=e}}const a=C(i);if(!c){_(t,{_:new Uint8Array(1),P:[{config:o,code:a}]});for(const[n]of f)N(t,a,o,n);return}const u=new Uint32Array(1);u[0]=1,_(t,{N:{G:224,minLength:7,O:s},_:new Uint8Array([1,0]),P:[{config:q(0),code:C(u)},{config:o,code:a}]});for(const[n,e]of f)N(t,a,o,n),e&&N(t,a,s,e-7,224)}(t,e),t.write(1,1);for(const n of r)E(t,n.config,15);for(const n of r){const e=n.code.S-1;if(e){const n=c(e);t.write(1,1),t.write(4,n),t.write(n,e-(1<<n))}else t.write(1,0)}for(const n of r)T(t,n.code)}const P={channel:null,weighted:null,fill:null},z=3,G=5,O=q(4),k=Object.freeze({G:224,minLength:7,O:O}),j=q(0),R=257;function Z(t,n=0,e=1){return{k:t,offset:n,j:e,context:-1}}function B(t,n,e,r){return{R:t,Z:n,left:e,right:r}}function Y(t,n){const e=(r,o)=>{if(r===o)return n?t[r].B:t[r];const s=r+o>>1;return B(n,n?t[s].Y:s,e(s+1,o),e(r,s))};return e(0,t.length-1)}function D(t){return Y(t,0)}function F(t,n){const e=[n],r=[],o=[];for(const t of e){if(t.left){r.push(t.R+1,s(t.Z)),e.push(t.left,t.right);continue}t.context=o.length,o.push(t);const n=1===t.j?0:31-Math.clz32(t.j&-t.j);r.push(0,t.k,s(t.offset),n,(t.j>>n)-1)}const c=new Uint32Array(64);for(const t of r)X(j,t,c);const l=C(c);_(t,{_:new Uint8Array(6),P:[{config:j,code:l}]});for(const n of r)N(t,l,j,n);return o}function Q(t,n){const e=[[3,0],[6,8],[10,72],[13,1096]];if("rct"===n.type)t.write(2,0),t.o(e,n.D),t.o([[0,6],[2,0],[4,2],[6,10]],n.F??6);else if("palette"===n.type)t.write(2,1),t.o(e,n.D),t.o([[0,1],[0,3],[0,4],[13,1]],n.H),t.o([[8,0],[10,256],[12,1280],[16,5376]],n.K),t.o([[0,0],[8,1],[10,257],[16,1281]],n.V??0),t.write(4,n.k??0);else{if("squeeze"!==n.type)throw new Error("unknown transform "+n.type);{t.write(2,2);const r=n.W??[];t.o([[0,0],[4,1],[6,9],[8,41]],r.length);for(const n of r)t.write(1,n.$?1:0),t.write(1,n.tt?1:0),t.o(e,n.D),t.o([[0,1],[0,2],[0,3],[4,4]],n.H)}}}function H(t,{nt:n=!0,et:e=[]}={}){t.write(1,n?1:0),t.write(1,1),t.o([[0,0],[0,1],[4,2],[8,18]],e.length);for(const n of e)Q(t,n)}function K(t,n,e,r=t=>t.context,o=()=>j){const s=new Uint8Array(n.length+1);for(const t of n)s[t.context]=r(t)+1;const c=new Uint32Array(2);c[1]=1;const l=[{config:j,code:C(c)}],i=Math.max(...s);for(let t=0;t<i;t++)l.push({config:o(t),code:C(e[t])});return _(t,{N:k,_:s,P:l}),l}function V(t,n,e,r,o,c,l=!1){if(P.channel?.(t,n,e,r,o,c,l))return;const i=c.k,f=c.offset,a=c.j,u=c.config||j,h=O;let y=0;const p=(e,r=u,o=0)=>{t?N(t,n,r,e,o):l&&!o?n[e]++:X(r,e,n,l?n.length-33:o)},w=()=>{if(y){if(y>=8)p(0),p(y-7-1,h,224);else for(let t=0;t<y;t++)p(0);y=0}},d=(t,n)=>{const r=e[t];let o;1===a?o=r-n-f:(o=Math.round((r-n-f)/a),e[t]=n+f+o*a),0!==o?(w(),p(s(o))):y++};for(let t=0,n=0;t<o;t++)for(let o=0;o<r;o++,n++){let s;if(0===i)s=0;else{const c=o?e[n-1]:t?e[n-r]:0,l=t?e[n-r]:c;if(1===i)s=c;else if(2===i)s=l;else if(3===i)s=(c+l)/2|0;else{const f=c+l-(o&&t?e[n-r-1]:c);if(5===i){const t=c<l?c:l,n=c<l?l:c;s=f<t?t:f>n?n:f}else{if(4!==i)throw new Error("predictor "+i+" is not coded here");s=Math.abs(f-c)<Math.abs(f-l)?c:l}}}d(n,s)}w()}const W=[q(0),q(4),q(4,1,1),q(3,0,1)];function $(t){const n=t.length-33,r=[0,0,0];let o,s;for(const l of W){const i=new Uint32Array(R);let f=0;for(let e=0;e<n;e++)t[e]&&(L(l,e,r),i[r[0]]+=t[e],f+=t[e]*r[1]);for(let e=0;e<33;e++)i[224+e]=t[n+e],f+=t[n+e]*Math.max(0,e-12);const a=C(i),u=new e(128);E(u,l),T(u,a);let h=u.u+f+(1===a.S?1:5+c(a.S-1));for(let t=0;t<i.length;t++)i[t]&&(h+=i[t]*a.v[t]);const y={config:l,rt:i,ot:h,extra:f};o||(o=y),(!s||h<s.ot)&&(s=y)}return[o,s]}const tt=(t,n,e,r)=>e?r?t[n]+256*t[n+3]:t[n]:t[n]+256*t[n+1]+65536*t[n+2]+(r?16777216*t[n+3]:0);function nt(t,n,e,{palette:r=!0}={}){const o=n*e;let s=!0,c=!0;for(let n=0,e=0;e<o&&(255===t[n+3]||(s=!1,c))&&(t[n]===t[n+1]&&t[n]===t[n+2]||(c=!1,s));e++,n+=4);const l=c?1:3,i=!s,f=l+(i?1:0),a=n=>tt(t,n,c,i),u=new Map;let h=null;for(let t=0,n=0;r&&n<o;n++,t+=4){const n=a(t);if(0!==n&&!u.has(n)&&(u.set(n,1),u.size>=2048))break}if(r&&u.size<2048){const t=[...u.keys()],n=(t,n)=>t>>>8*n&255,e=t=>(.299*n(t,0)+.587*n(t,1)+.114*n(t,2)+.01)*(4===f?n(t,3):1);t.sort((t,n)=>e(t)-e(n)),h={colours:[0,...t],byte:n}}return{colour:l,alpha:i,channels:f,palette:h}}function et({channels:t,alpha:n,palette:e},r){const o=t-(n?1:0)==1,s=e&&new Map(e.map((t,n)=>[t,n]));return(c,l,i,f,a,u,h)=>{if(r&&!e&&t>=3)r.fill(c,l,i,f,a,u,h);else if(e||!P.fill?.(l,i,f,a,u,h,t,c))for(let r=0;r<h;r++){let h=4*((a+r)*i+f),y=r*u;for(let r=0;r<u;r++,h+=4,y++)if(e)c[0][y]=s.get(tt(l,h,o,n));else if(t>=3){const n=l[h],e=l[h+1],r=l[h+2],o=n-r,s=r+(o>>1),i=e-s;c[0][y]=s+(i>>1),c[1][y]=o,c[2][y]=i,4===t&&(c[3][y]=l[h+3])}else c[0][y]=l[h],2===t&&(c[1][y]=l[h+3])}}}function rt(t,n){const{leaves:r,picture:o,C:s}=t,c=et(t,n),l=o.map(()=>new Int16Array(65536));return(t,n,i,f,a,u,h)=>{if(c(l,t,n,i,f,a,u),!s)return void o.forEach((t,n)=>V(null,h[t],l[n],a,u,r[t],!0));const y=h||new e(a*u*o.length+64);return h||H(y,{nt:!0,et:[]}),o.forEach((t,n)=>V(y,s[t],l[n],a,u,r[t])),h?void 0:y.finish()}}function*ot(t,n,e,{shape:o=nt(t,n,e),colorSpace:s,rct:c,pooled:l}={}){let i,f;const a=o.palette?[o,{...o,palette:null}]:[o];for(let o=0;o<a.length;o++)try{const f=yield*r(st(t,n,e,a[o],s,c,l),o,a.length);(!i||f.length<i.length)&&(i=f)}catch(t){if("JXL_SIZE"!==t.code)throw t;f=t}if(!i)throw f;return i}function*st(t,n,r,o,s,c,l){const{channels:i,alpha:f,palette:a}=o,u=w(n,r),h=u.p*u.A,b=a?2:i,m=Array.from({length:b},()=>Z(G)),U=D(m),I={channels:i,alpha:f,palette:a&&a.colours,rct:c?.type,leaves:m,picture:a?[u.U?1:0]:m.map((t,n)=>n)},S=et(I,c),v=Array.from({length:i},()=>new Int16Array(1024)),x=t=>d(u,n,r,t);let q=null;if(a){const t=a.colours.length;q=new Int16Array(t*i),a.colours.forEach((n,e)=>{for(let r=0;r<i;r++)q[r*t+e]=a.byte(n,r)})}if(!a){const o=t=>{const n=C(t),r=new e(128);T(r,n);let o=r.u;for(let e=0;e<t.length;e++)t[e]&&(o+=t[e]*(n.v[e]+Math.max(0,e<224?e-1:e-236)));return o},s=Math.min(n,32),c=Math.min(r,32),l=[G,z].map(t=>({k:t,rt:m.map(()=>new Uint32Array(R))}));for(const e of[0,.5,1]){S(v,t,n,Math.floor((n-s)*e),Math.floor((r-c)*e),s,c);for(const t of l)for(let n=0;n<i;n++)V(null,t.rt[n],v[n],s,c,Z(t.k))}m.forEach((t,n)=>{const e=l.map(t=>o(t.rt[n])),r=e[1]<e[0]?1:0;t.k=l[r].k})}const E=a?[{type:"palette",D:0,H:i,K:a.colours.length}]:i>=3&&0!==c?.type?[{type:"rct",D:0,F:c?.type??6}]:[];let L=m.map(()=>new Uint32Array(33+(a?4096:1024)));q&&V(null,L[0],q,a.colours.length,i,m[0],!0);const X=rt(I,c);yield*A({pooled:l,kind:"plan",setup:{...I,sizes:L.map(t=>t.length)},at:t=>(t+1)/(2*h),stop:()=>!1},h,e=>X(t,n,...x(e),L),(t,n)=>M(L,n));const J=L.map($),N=J.reduce((t,n)=>t+n[0].ot-n[1].ot,0)>27*(u.U?1:h+1)+8?1:0;m.forEach((t,n)=>{t.config=J[n][N].config}),L=J.map(t=>t[N].rt);const _=new e(256);y(_,n,r,o.colour,o.alpha,{colorSpace:s}),p(_,{alpha:o.alpha});const P=new e(4096);P.write(1,1),P.write(1,1);const O=K(P,F(P,U),L,t=>m.indexOf(t),t=>m[t].config),k={...I,C:m.map((t,n)=>O[n+1]?.code)},j=rt(k,c);H(P,{nt:!0,et:E}),q&&V(P,k.C[0],q,a.colours.length,i,m[0]);const B=[];if(u.U)j(t,n,0,0,n,r,P),yield 1,B.push(P.finish());else{B.push(P.finish());for(let t=0;t<u.M*u.m+1;t++)B.push(new Uint8Array(0));const e=B.length,r=(t,n)=>{B[e+t]=n};yield*A({pooled:l,kind:"plan",setup:k,at:t=>(h+t+1)/(2*h),stop:()=>!1},h,e=>r(e,j(t,n,...x(e))),r)}return g(_,B)}const ct=(t,n)=>t+n+(t>n?1:0)>>1;function lt(t,n,e){const r=t>=n&&n>=e?1:t<=n&&n<=e?-1:0;if(!r)return 0;let o=(4*(t*=r)-3*(e*=r)-(n*=r)+6)/12|0;return o-(1&o)>2*(t-n)&&(o=2*(t-n)+1),o+(1&o)>2*(n-e)&&(o=2*(n-e)),r*o}function it(t,n){const{w:e,h:r,data:o}=t,s=n?e:r,c=s+1>>1,l=s-c,i=n?c:e,f=n?r:c,a=n?l:e,u=n?r:l,h=new Int16Array(i*f),y=new Int16Array(a*u),p=n?1:e;for(let t=0;t<f;t++)for(let r=0;r<i;r++){const c=n?r:t,f=n?t*e+2*r:2*t*e+r;if(c===l){h[t*i+r]=o[f];continue}const u=o[f],w=o[f+p],d=ct(u,w),A=c+1<l?ct(o[f+2*p],o[f+3*p]):1&s?o[f+2*p]:d;h[t*i+r]=d,y[t*a+r]=u-w-lt(c?o[f-p]:d,d,A)}const w=(e,r,o)=>({w:r,h:o,st:t.st+ +n,ct:t.ct+!n,data:e});return[w(h,i,f),w(y,a,u)]}function ft(t){const n=[],e=t.length;let r=t[0].w,o=t[0].h;for(e>2&&t[1].w===r&&t[1].h===o&&(n.push({$:!0,tt:!1,D:1,H:2}),n.push({$:!1,tt:!1,D:1,H:2})),!(r>o)&&o>8&&(n.push({$:!1,tt:!0,D:0,H:e}),o=o+1>>1);r>8||o>8;)r>8&&(n.push({$:!0,tt:!0,D:0,H:e}),r=r+1>>1),o>8&&(n.push({$:!1,tt:!0,D:0,H:e}),o=o+1>>1);return n}const at=1024,ut=8192;function*ht(t,n,r,{quality:o=90,shape:s=nt(t,n,r,{palette:!1}),colorSpace:c}={}){const l=function(t){return t>=100?0:t>=30?.1+.09*(100-t):53/3e3*t*t-1.15*t+25}(o);if(!(l>0))throw new Error("lossy encoding needs a quality below 100");const{colour:i,alpha:f,channels:a}=s,u=n*r,h=Array.from({length:a},()=>new Int16Array(u));for(let n=0,e=0;e<u;e++,n+=4){if(3===i){const r=t[n],o=t[n+1],s=t[n+2],c=r-s,l=s+(c>>1),i=o-l;h[0][e]=l+(i>>1),h[1][e]=c,h[2][e]=i}else h[0][e]=t[n];f&&(h[a-1][e]=t[n+3])}const d=h.map((t,e)=>({w:n,h:r,st:0,ct:0,data:t,component:3===i?e:0===e?0:3})),A=1===n&&r>at&&3===i,M=A?ft(d).filter(t=>!t.$):1!==n&&1!==r||3!==i?[]:ft(d),b=function(t,n=ft(t)){const e=t.map(t=>({...t,level:0,lt:!1}));for(const t of n){const n=t.D+t.H-1,r=t.tt?n+1:e.length;for(let o=t.D;o<=n;o++){const[n,s]=it(e[o],t.$),c=e[o].level+1;e[o]={...n,level:c,lt:e[o].lt,component:e[o].component},e.splice(r+(o-t.D),0,{...s,level:c,lt:!0,component:e[o].component})}}return e}(d,M.length?M:void 0),m=t=>t.lt?0:G,U=t=>function(t,n,e,r){let o=Math.min(16,n+e);if(o>0&&o--,3===t)return 1;const s=.25*function(t){let n=1;for(let e=0;e<24;e++)n=(4*n+t/(n*n*n*n))/5;return t*n}(r),c=1<<o,l=1===t||2===t?.35*s*Math.max(.5,1024/c):.35*s*1.1*(163.84/c);return Math.max(1,Math.floor(l))}(t.component,t.st+(A&&t.component>0&&t.component<3?1:0),t.ct,l),I=[...3===i?[{type:"rct",D:0,F:6}]:[],{type:"squeeze",W:M}],S=w(n,r,at),v=S.M*S.m,x=S.p*S.A;let C=0;for(;C<b.length&&b[C].w<=at&&b[C].h<=at;)C++;const T=(t,n,e,r)=>{const o=n>>t.st,s=e>>t.ct;return{x:o,y:s,w:Math.min(t.w,o+(r>>t.st))-o,h:Math.min(t.h,s+(r>>t.ct))-s}},q=[{index:0,Y:0,it:[]}];for(let t=0;t<C;t++)q[0].it.push({c:t,rect:{x:0,y:0,w:b[t].w,h:b[t].h}});if(!S.U){for(let t=0;t<v;t++){const n=t%S.M,e=t/S.M|0,r={index:1+t,Y:1+v+t,it:[]};for(let t=C;t<b.length;t++){const o=b[t];if(Math.min(o.st,o.ct)<3)continue;const s=T(o,n*ut,e*ut,ut);s.w>0&&s.h>0&&r.it.push({c:t,rect:s})}q.push(r)}for(let t=0;t<x;t++){const n=t%S.p,e=t/S.p|0,r={index:2+v+t,Y:1+3*v+17+t,it:[]};for(let t=C;t<b.length;t++){const o=b[t];if(Math.min(o.st,o.ct)>2)continue;const s=T(o,n*at,e*at,at);s.w>0&&s.h>0&&r.it.push({c:t,rect:s})}q.push(r)}}for(const t of q)for(const n of t.it){const t=b[n.c];n.ft=Z(m(t),0,U(t)),n.ft.channel=n.c}const E=q.filter(t=>t.it.length),L=1===E.length?D(E[0].it.map(t=>t.ft)):function(t){return Y(t,1)}(E.map(t=>({Y:t.Y,B:D(t.it.map(t=>t.ft))}))),X=new Int16Array(1048576),J=t=>{const n=b[t.c],e=t.rect;if(e.w===n.w&&e.h===n.h)return n.data;for(let t=0;t<e.h;t++)X.set(n.data.subarray((e.y+t)*n.w+e.x,(e.y+t)*n.w+e.x+e.w),t*e.w);return X},N=[...new Set(q.flatMap(t=>t.it.map(t=>t.c)))].sort((t,n)=>t-n),_=new Map(N.map((t,n)=>[t,n])),P=N.map(()=>new Uint32Array(R)),z=1+2*q.length;let O=1;yield O/z;for(const t of q){for(const n of t.it)V(null,P[_.get(n.c)],J(n),n.rect.w,n.rect.h,n.ft);yield++O/z}const k=new e(256);y(k,n,r,i,f,{colorSpace:c}),p(k,{alpha:f,shift:n>256||r>256?3:1});const j=Array.from({length:S.U?1:2+v+x},()=>null),B=j[0]=new e(65536);B.write(1,1),B.write(1,1);const Q=K(B,F(B,L),P,t=>_.get(t.channel));H(B,{nt:!0,et:I});for(const t of q){let n=j[t.index];n||(n=j[t.index]=new e(4096),t.it.length&&H(n,{nt:!0,et:[]}));for(const e of t.it)V(n,Q[_.get(e.c)+1].code,J(e),e.rect.w,e.rect.h,e.ft);yield++O/z}return g(k,function(t){return t.map(t=>t?t.finish():new Uint8Array(0))}(j))}const yt=[-500,-392,-255,-191,-127,-95,-63,-47,-31,-23,-15,-11,-7,-4,-3,-1,0,1,3,5,7,11,15,23,31,47,63,95,127,191,255,392,500],pt=Int8Array.from({length:1003},(t,n)=>yt.filter(t=>t<n-501).length),wt=Int32Array.from({length:64},(t,n)=>Math.floor(16777216/(n+1))),dt=(t,n)=>{const e=Math.max(0,26-Math.clz32(t+1));return 4+(n*wt[t>>e]>>e)},At=[12,13].map(t=>Int32Array.from({length:2048},(n,e)=>dt(e,t))),Mt=(t,n)=>t<2048?At[n-12][t]:dt(t,n),gt=new Int32Array(yt.length+1);let bt;function mt(t,n,e,r,o,c=0,l=gt,i,f){if(P.weighted?.(t,n,e,r,o,c,l,i,f))return;const a=r+2,u=bt&&bt[0].length>=2*a?bt:Array.from({length:6},(t,n)=>new Int32Array(n<5?2*a:8));bt=null;for(const t of u)t.fill(0);const[h,y,p,w,d,A]=u;let M=0;const g=(e,r,o=j,s=0)=>{t?N(t,n[e],o,r,s):X(o,r,n[e],s)},b=()=>{if(M){if(M>k.minLength)g(A[0],0),g(A[1],M-k.minLength-1,k.O,k.G);else for(let t=0;t<M;t++)g(A[t],0);M=0}};for(let t=0,n=0;t<o;t++){const o=1&t?0:a,u=1&t?a:0;for(let a=0;a<r;a++,n++){const m=a?e[n-1]:t?e[n-r]:0,U=t?e[n-r]:m,I=a+1<r&&t?e[n-r+1]:U,S=u+a,v=a<r-1?S+1:S,x=a?S-1:S;let C=Mt(h[S]+h[v]+h[x],13),T=Mt(y[S]+y[v]+y[x],12),q=Mt(p[S]+p[v]+p[x],12),E=Mt(w[S]+w[v]+w[x],12);const L=8*U,X=8*m,J=8*I,N=a?d[o+a-1]:0,_=d[S],P=d[x],z=d[v],G=_+N;let O=N;Math.abs(_)>Math.abs(O)&&(O=_),Math.abs(P)>Math.abs(O)&&(O=P),Math.abs(z)>Math.abs(O)&&(O=z);const k=l[pt[O<-501?0:O>501?1002:O+501]];f&&(f[n]=O);const j=X+J-L,R=L-(16*(G+z)>>5),Z=X-(10*(G+P)>>5),B=L-(7*(P+_+z)>>5),Y=27-Math.clz32(C+T+q+E);C>>=Y,T>>=Y,q>>=Y,E>>=Y;const D=C+T+q+E;let F=Math.floor(((D>>1)-1+j*C+R*T+Z*q+B*E)*wt[D-1]/16777216);if((_^N|_^P)<=0){const t=Math.min(X,J,L),n=Math.max(X,J,L);F=F<t?t:F>n?n:F}const Q=e[n],H=Q-(F+3>>3)-c;i?i[n]=s(H):0===H?(M<8&&(A[M]=k),M++):(b(),g(k,s(H)));const K=8*Q,V=Math.abs(j-K)+3>>3,W=Math.abs(R-K)+3>>3,$=Math.abs(Z-K)+3>>3,tt=Math.abs(B-K)+3>>3;d[o+a]=F-K,h[o+a]=V,y[o+a]=W,p[o+a]=$,w[o+a]=tt,h[u+a+1]+=V,y[u+a+1]+=W,p[u+a+1]+=$,w[u+a+1]+=tt}}b(),bt=u}const Ut=t=>Math.max(0,t<224?t-1:t-236),It=t=>{const n=C(t),r=new e(128);T(r,n);let o=r.u;for(let e=0;e<t.length;e++)t[e]&&(o+=t[e]*(n.v[e]+Ut(e)));return o};function St(t,n,e,r,o){const c=new Uint32Array(n*e);if(6===r)return mt(null,null,t,n,e,0,void 0,c,o),c;for(let o=0,l=0;o<e;o++)for(let e=0;e<n;e++,l++){const i=e?t[l-1]:o?t[l-n]:0,f=o?t[l-n]:i,a=e&&o?t[l-n-1]:i,u=3===r?(i+f)/2|0:Math.max(Math.min(i,f),Math.min(Math.max(i,f),i+f-a));c[l]=s(t[l]-u)}return c}function vt(t,n,e=1){const r=Array.from({length:e},()=>new Uint32Array(R)),o=[],s=(t,e,s=0)=>{const c=n?n[t]:0;o.push(e,s,c),X(s?k.O:j,e,r[c],s)};for(let n=0;n<t.length;){let e=1;if(!t[n])for(;n+e<t.length&&!t[n+e];)e++;if(s(n,t[n]),e>k.minLength)s(n+1,e-1-k.minLength,k.G);else for(let t=1;t<e;t++)s(n+t,0);n+=e}return{rt:r,it:o}}function xt(t,n,e,r,o){const s=vt(t,Uint8Array.from(n,t=>{let n=0,e=o.length;for(;n<e;){const r=n+e>>1;t>o[r]?n=r+1:e=r}return n}),o.length+1),c=s.rt.length,l=s.rt.map(t=>t.some(t=>t)),i=new Float64Array(c+1).fill(1/0),f=new Uint8Array(c+1);i[0]=0;for(let t=1;t<=c;t++){const n=new Uint32Array(R);let e=0;for(let r=t-1;r>=0;r--){if(l[r]){for(let t=0;t<R;t++)n[t]+=s.rt[r][t];e=It(n)}const o=i[r]+e+24;o<i[t]&&(i[t]=o,f[t]=r)}}const a=[];for(let t=c;t;t=f[t])a.unshift([f[t],t]);const u=a.map(()=>Z(e)),h=new Uint8Array(c),y=a.map(([t,n],e)=>{const r=new Uint32Array(R);for(let o=t;o<n;o++){h[o]=e;for(let t=0;t<R;t++)r[t]+=s.rt[o][t]}return r});for(let t=2;t<s.it.length;t+=3)s.it[t]=h[s.it[t]];const p=(t,n)=>{if(t===n)return u[t];const e=t+n>>1;return B(r,o[a[e][1]-1],p(e+1,n),p(t,e))};return{leaves:u,B:p(0,a.length-1),rt:y,it:s.it}}const Ct=[-127,-31,-7,-1,0,1,7,31,127],Tt=[-191,-127,-63,-31,-7,-1,0,7,31,63,127,191,255];function qt(t,n,e,r){const o=new Int32Array(n*e);for(let s=0,c=0;s<e;s++)for(let e=0;e<n;e++,c++){const l=e?t[c-1]:s?t[c-n]:0,i=s?t[c-n]:l,f=e&&s?t[c-n-1]:l;o[c]=9===r?l+i-f:l-f}return o}function Et(t){const n=new e(512),r=K(n,F(n,t.B),t.rt,n=>t.leaves.indexOf(n));let o=n.u;return t.rt.forEach((t,n)=>{const{v:e}=r[n+1].code;for(let n=0;n<t.length;n++)o+=t[n]*((e[n]||0)+Ut(n))}),o}function Lt(t,n,e,r){return t.map(t=>{let o;for(const s of[5,3,6]){const c=6===s?new Int32Array(n*e):null,l=St(t,n,e,s,c),i=Z(s),f=[{...vt(l),leaves:[i],B:i}];if(c&&f.push(xt(l,c,s,15,Ct)),r>=6&&5===s)for(const r of[9,10]){const o=qt(t,n,e,r),c=9===r?Tt:Ct;f.push(xt(l,o,s,r,c))}for(const t of f){const n=Et(t);(!o||n<o.ot)&&(o={...t,ot:n})}}return o})}function Xt(t,n){const e=n.flatMap(t=>t.leaves),r=K(t,F(t,D(n.map(t=>t.B))),n.flatMap(t=>t.rt),t=>e.indexOf(t));return()=>{for(let o=0;o<n.length;o++){const{it:s}=n[o],c=n[o].leaves.map(t=>r[e.indexOf(t)+1].code);for(let n=0;n<s.length;n+=3){const e=s[n+1];N(t,c[s[n+2]],e?k.O:j,s[n],e)}}}}function*Jt(t,n,r,o,s,c=4,l=!1,i){const{channels:a}=o,u=w(n,r),h=u.p*u.A,M=l?o.palette:null;if(l&&!M)return null;const b={channels:a,alpha:o.alpha,palette:M&&M.colours,rung:c},m=new e(256);y(m,n,r,o.colour,o.alpha,{colorSpace:s}),p(m,{alpha:o.alpha});const U=M?[{type:"palette",D:0,H:a,K:M.colours.length}]:a>=3?[{type:"rct",D:0,F:6}]:[];let I;if(M){const t=M.colours.length,n=new Int16Array(t*a);M.colours.forEach((e,r)=>{for(let o=0;o<a;o++)n[o*t+r]=M.byte(e,o)}),I=Lt([n],t,a,c)}const S=new e(4096),v=[];let x=0;const C=t=>{x+=t.length,f(x),v.push(t)};if(S.write(1,1),S.write(1,1),u.U){const e=Array.from({length:M?1:a},()=>new Int16Array(65536));et(b)(e,t,n,0,0,n,r);const o=Xt(S,[...I||[],...Lt(e,n,r,c)]);return H(S,{et:U}),o(),C(S.finish()),(yield 1)?null:g(m,v)}let T;if(I)T=Xt(S,I);else{const t=Array.from({length:a},()=>Z(5));K(S,F(S,D(t)),t.map(()=>new Uint32Array(R)),n=>t.indexOf(n))}H(S,{et:U}),T&&T(),C(S.finish());for(let t=0;t<u.M*u.m+1;t++)v.push(new Uint8Array(0));const q=function(t){const n=et(t),r=Array.from({length:t.palette?1:t.channels},()=>new Int16Array(65536));return(o,s,c,l,i,f)=>{n(r,o,s,c,l,i,f);const a=new e(i*f*r.length+256);return H(a,{nt:!1}),Xt(a,Lt(r,i,f,t.rung))(),a.finish()}}(b);return null===(yield*A({pooled:i,kind:"local",setup:b,at:t=>(t+1)/h,stop:()=>!0},h,e=>C(q(t,n,...d(u,n,r,e))),(t,n)=>C(n)))?null:g(m,v)}function Nt(t,n){const e=Math.floor(t/7),r=t%7,o=e%3,s=(e+1+Math.floor(e/3))%3,c=(e+2-Math.floor(e/3))%3;return{type:t,fill(t,e,l,i,f,a,u){for(let h=0;h<u;h++)for(let u=0,y=h*a,p=4*((f+h)*l+i);u<a;u++,y++,p+=4){const l=e[p+o],i=e[p+s],f=e[p+c];if(6===r){const n=l-f,e=f+(n>>1),r=i-e;t[0][y]=e+(r>>1),t[1][y]=n,t[2][y]=r}else t[0][y]=l,t[1][y]=i-(r>>1==1?l:r>>1==2?l+f>>1:0),t[2][y]=f-(1&r?l:0);4===n&&(t[3][y]=e[p+3])}}}}const _t=t=>null===t||("object"==typeof t?t.hurried:t);function Pt(n,s,c,l,f){const{quality:a,colorSpace:u}=function(t={},n=100){if(null===t||"object"!=typeof t)throw i("JXL_INPUT","Options are an object: {quality, colorSpace}.");if(void 0!==t.quality&&(n=t.quality),"number"!=typeof n||!Number.isFinite(n)||n<1||n>100)throw i("JXL_INPUT","Quality is a number from 1 to 100.");const e=void 0===t.colorSpace?"srgb":t.colorSpace;if("srgb"!==e&&"display-p3"!==e)throw i("JXL_INPUT","The colour space is srgb or display-p3.");return{quality:n,colorSpace:e}}(l),h=void 0===l?.effort?1:l.effort;if(!Number.isInteger(h)||h<1||h>9)throw i("JXL_INPUT","Effort is a whole number from 1 to 9.");return function(n,e,r,o){if(function(n,e,r=t){if(!Number.isInteger(n)||!Number.isInteger(e)||n<1||e<1)throw i("JXL_INPUT","A picture is at least one pixel wide and high, in whole pixels.");if(n>r.edge||e>r.edge)throw i("JXL_DIMENSIONS","A picture is at most "+r.edge+" pixels on a side.");if(n*e>r.pixels)throw i("JXL_DIMENSIONS","A picture is at most "+r.pixels.toLocaleString("en-US")+" pixels.")}(e,r,o),!(n instanceof Uint8Array||n instanceof Uint8ClampedArray))throw i("JXL_INPUT","Pixels are a Uint8Array or Uint8ClampedArray of RGBA bytes.");if(n.length!==e*r*4)throw i("JXL_INPUT","Pixels are width * height * 4 bytes: straight (not premultiplied) RGBA, row by row.")}(n,s,c),function*(t,n,s,c,l,i,f){const a=nt(t,n,s);if(c<100){if(!a.palette)return yield*ht(t,n,s,{quality:c,shape:a,colorSpace:l});const e=yield*r(ot(t,n,s,{shape:a,colorSpace:l}),0,2);let o;try{o=yield*r(ht(t,n,s,{quality:c,shape:a,colorSpace:l}),1,2)}catch(t){if("JXL_SIZE"!==t.code&&(!(t instanceof RangeError)||t.code))throw t;o=e}return e.length<=o.length?e:o}if(i<2)return yield*ot(t,n,s,{shape:a,colorSpace:l,pooled:f});let u=yield*r(ot(t,n,s,{shape:a,colorSpace:l,pooled:f}),0,2);const h=a.palette?{...a,palette:null}:a;if(i>=4){const r=[Zt(t,n,s,h,l,3,f)];a.palette&&r.push(Jt(t,n,s,a,l,4,!0,f)),i>=6&&(r.push(Jt(t,n,s,a,l,6,!1,f)),a.palette&&r.push(Jt(t,n,s,a,l,6,!0,f))),r.push(function*(t,n,r,o,s,c){if(3!==o.colour||n*r<4096)return null;const l=Math.min(n,32),i=Math.min(r,32),f=Array.from({length:o.channels},()=>new Int16Array(l*i)),a=[6,...Array.from({length:42},(t,n)=>n).filter(t=>6!==t)];let u;for(let s=0;s<a.length;s++){const c=Nt(a[s],o.channels),h=[5,3].map(t=>({k:t,rt:Array.from({length:3},()=>new Uint32Array(1057))}));for(let e=0;e<3;e++){c.fill(f,t,n,Math.floor((n-l)*e/2),Math.floor((r-i)*e/2),l,i);for(const t of h)for(let n=0;n<3;n++)V(null,t.rt[n],f[n],l,i,Z(t.k),!0)}const y=new e(32);c.type&&Q(y,{type:"rct",D:0,F:c.type});let p=y.u;for(let t=0;t<3;t++)p+=Math.min(...h.map(n=>$(n.rt[t])[1].ot));if((!u||p<u.ot)&&(u={rct:c,ot:p}),yield(s+1)/(4*a.length))return null}if(6===u.rct.type)return null;const h=ot(t,n,r,{shape:{...o,palette:null},colorSpace:s,rct:u.rct,pooled:c});let y,p;for(;!(y=h.next(p)).done;){const t=y.value,n="number"==typeof t;if(p=yield n?.25+.75*t:{...t,at:n=>.25+.75*t.at(n),stop:n=>t.at(n)<1},n?p&&t<1:!p)return null}return y.value}(t,n,s,a,l,f));for(let t=0;t<r.length;t++)try{let n,e,s=!1;for(;!(n=r[t].next(e)).done;)s=_t(e=yield o(n.value,n=>.5+(t+n)/(2*r.length)));if(n.value&&n.value.length<u.length&&(u=n.value),s)return u}catch(t){if("JXL_SIZE"!==t.code&&(!(t instanceof RangeError)||t.code))throw t}return u}try{const e=yield*r(Zt(t,n,s,h,l,i,f),1,2);e&&e.length<u.length&&(u=e)}catch(t){if("JXL_SIZE"!==t.code&&(!(t instanceof RangeError)||t.code))throw t}return u}(n,s,c,a,u,h,f&&a>=100&&!w(s,c).U)}const zt=t=>Math.max(0,t<224?t-1:t-236);function Gt(t){const n=C(t),r=new e(128);T(r,n);let o=r.u;for(let e=0;e<t.length;e++)t[e]&&(o+=t[e]*(n.v[e]+zt(e)));return o}const Ot=t=>{const n=new Uint32Array(R);for(const e of t)for(let t=0;t<R;t++)n[t]+=e[t];return n},kt=yt.length+1,jt=Int32Array.from({length:kt},(t,n)=>n);function Rt(t){const{channels:n,first:r,plans:o}=t,s=et(t),c=r?.map(t=>Z(t)),l=Array.from({length:n},()=>new Int16Array(65536));return(t,r,i,f,a,u,h)=>{if(s(l,t,r,i,f,a,u),!o){for(let t=0;t<n;t++)V(null,h[t],l[t],a,u,c[t]),mt(null,h.slice(n+t*kt,n+(t+1)*kt),l[t],a,u,0,jt);return}const y=h||new e(a*u*n+64);return h||H(y,{nt:!0,et:[]}),o.forEach(({ft:t,C:n,ut:e},r)=>{6===t.k?mt(y,n,l[r],a,u,0,e):V(y,n[0],l[r],a,u,t)}),h?void 0:y.finish()}}function*Zt(t,n,r,o,s,c,l){const{channels:i}=o,f=w(n,r),a=f.p*f.A,u={channels:i,alpha:o.alpha,palette:null},h=et(u),b=Array.from({length:i},()=>new Int16Array(1024)),m=t=>d(f,n,r,t),U=Math.min(n,32),I=Math.min(r,32),S=[G,z].map(t=>({k:t,rt:b.map(()=>new Uint32Array(R))}));for(const e of[0,.5,1]){h(b,t,n,Math.floor((n-U)*e),Math.floor((r-I)*e),U,I);for(const t of S)for(let n=0;n<i;n++)V(null,t.rt[n],b[n],U,I,Z(t.k))}const v=b.map((t,n)=>Z(S[Gt(S[1].rt[n])<Gt(S[0].rt[n])?1:0].k)),x=kt,C=b.map(()=>new Uint32Array(R)),T=b.map(()=>Array.from({length:x},()=>new Uint32Array(R))),q=[...C,...T.flat()],E={...u,first:v.map(t=>t.k)},L=Rt(E);if(null===(yield*A({pooled:l,kind:"search",setup:{...E,sizes:q.map(t=>t.length)},at:t=>(t+1)/(2*a),stop:()=>!0},a,e=>L(t,n,...m(e),q),(t,n)=>M(q,n))))return null;const X=b.map((t,n)=>{const e={ht:Gt(C[n]),leaves:[v[n]],rt:[C[n]],cuts:[]},r=Ot(T[n]),o=Gt(r);return o<e.ht?{ht:o,leaves:[Z(6)],rt:[r],cuts:[]}:e}),J=c<3?X:X.map((t,n)=>{const e=T[n].map(t=>t.some(t=>t)),r=new Float64Array(x+1).fill(1/0),o=new Int32Array(x+1);r[0]=0;for(let t=1;t<=x;t++){const s=new Uint32Array(R);let c=0;for(let l=t-1;l>=0;l--){if(e[l]){const t=T[n][l];for(let n=0;n<R;n++)s[n]+=t[n];c=Gt(s)}const i=r[l]+c+24;i<r[t]&&(r[t]=i,o[t]=l)}}if(!(r[x]<t.ht))return t;const s=[];for(let t=x;t>0;t=o[t])s.unshift([o[t],t]);return{ht:r[x],leaves:s.map(()=>Z(6)),rt:s.map(([t,e])=>Ot(T[n].slice(t,e))),cuts:s.slice(0,-1).map(([,t])=>yt[t-1]),ut:Int32Array.from({length:x},(t,n)=>s.findIndex(([t,e])=>n>=t&&n<e))}}),N=[X,J].filter((t,n)=>n?t.some((t,n)=>t!==X[n]):t.some((t,n)=>t.leaves[0]!==v[n]));if(!N.length)return null;const _=t=>({B:D(t.map(t=>((t,n)=>{const e=(r,o)=>{if(r===o)return t[r];const s=r+o>>1;return B(15,n[s],e(s+1,o),e(r,s))};return e(0,t.length-1)})(t.leaves,t.cuts))),leaves:t.flatMap(t=>t.leaves),rt:t.flatMap(t=>t.rt)}),P=t=>{const{B:n,leaves:r,rt:o}=_(t),s=new e(4096),c=K(s,F(s,n),o,t=>r.indexOf(t));let l=s.u;return o.forEach((t,n)=>{const{v:e}=c[n+1].code;for(let n=0;n<t.length;n++)t[n]&&(l+=t[n]*(e[n]+zt(n)))}),l};let O=N;if(N.length>1){const[t,n]=N.map(P),e=27*(f.U?1:a+1)+8;n+e<=t?O=[N[1]]:t+e<=n?O=[N[0]]:n<t&&(O=[N[1],N[0]])}let k=0,j=!1,Y=null;for(const t of O){const n=yield*Q(t);if(!n)return Y;if((!Y||n.length<Y.length||n.length===Y.length&&t===N[0])&&(Y=n),j)return Y}return Y;function*Q(c){const{B:h,leaves:w,rt:d}=_(c),M=i>=3?[{type:"rct",D:0,F:6}]:[],b=new e(256);y(b,n,r,o.colour,o.alpha,{colorSpace:s}),p(b,{alpha:o.alpha});const U=new e(4096);U.write(1,1),U.write(1,1);const I=K(U,F(U,h),d,t=>w.indexOf(t));H(U,{nt:!0,et:M});const S={...u,plans:c.map(t=>({ft:t.leaves[0],C:t.leaves.map(t=>I[w.indexOf(t)+1].code),ut:t.ut}))},v=Rt(S),x=[];if(f.U)v(t,n,0,0,n,r,U),j=yield.5+ ++k/(2*O.length*a),x.push(U.finish());else{x.push(U.finish());for(let t=0;t<f.M*f.m+1;t++)x.push(new Uint8Array(0));const e=k,r=x.length,o=(t,n)=>{x[r+t]=n};if(j=yield*A({pooled:l,kind:"search",setup:S,at:t=>.5+(e+t+1)/(2*O.length*a),stop:t=>t+1<a},a,e=>o(e,v(t,n,...m(e))),o),null===j)return null;k+=a}return g(b,x)}}function Bt(t,n,e,r){return function(t){let n;for(;!(n=t.next()).done;);return n.value}(Yt(t,n,e,r))}function Yt(t,n,e,r){return function(t){const n=function*(){let e,r;for(;!(e=a(()=>t.next(n.hurry))).done;)yield r=e.value;return r<1&&(yield 1),n.bytes=function(t){return f(t.length),t}(e.value)}();return n.bytes=null,n.hurry=!1,n}(Pt(t,n,e,r))}export{t as LIMITS,Bt as encode,Yt as encodeSteps};
package/effort.mjs CHANGED
@@ -5,18 +5,16 @@
5
5
  // 2. the specification's self-correcting (weighted) predictor, one context per channel;
6
6
  // 3. the weighted predictor with its channel's tokens split by the predictor's own error, neighbouring intervals of
7
7
  // libjxl's cut points merged wherever a shared prefix code costs less.
8
+ // 4. palette indices with local trees and histograms, the predictor and error intervals learned per group;
9
+ // also a sampled search over all 42 reversible colour transforms, accepted only after a smaller complete stream;
10
+ // 6. direct and palette planes with splits on the unclamped gradient and west-minus-northwest difference.
8
11
  // A lossy request is effort 1's. Above effort 1 an exact picture's job spends its first half (fractions up to 0.5)
9
12
  // writing effort 1's stream and its second searching, so a caller's clock can tell the search's own pace; `hurry`
10
13
  // ends the search at its next step with the smallest stream written so far. Every choice is integer arithmetic: the
11
14
  // same input and options write the same bytes everywhere.
12
- import {LIMITS, BitWriter, complete, part} from './bits.mjs';
13
- import {writeImageHeader, writeModularFrameHeader, groupLayout, assembleCodestream, GROUP_DIM} from './frame.mjs';
14
- import {buildCode, writePrefixCode} from './prefix.mjs';
15
- import {AVERAGE_PREDICTOR, GRADIENT_PREDICTOR, ALPHABET, leaf, split, channelTree, writeTree, writeModularHeader, writeChannelHistograms, codeChannel} from './modular.mjs';
16
- import {inspectPixels, losslessSteps} from './lossless.mjs';
17
- import {lossySteps} from './lossy.mjs';
18
- import {WEIGHTED_PREDICTOR, WEIGHTED_PROPERTY, WEIGHTED_CUTS, codeWeighted} from './weighted.mjs';
19
- import {fault, admitOptions, admitPixels, job} from './admit.mjs';
15
+ import {LIMITS, complete} from './bits.mjs';
16
+ import {job} from './admit.mjs';
17
+ import {effortJob} from './effort-job.mjs';
20
18
 
21
19
  export {LIMITS};
22
20
 
@@ -24,194 +22,4 @@ export function encode(data, width, height, options) { return complete(encodeSte
24
22
 
25
23
  // The options as every door reads them, and the effort, which this door alone reads (the core, one rung, does not): a
26
24
  // whole number from 1 to 9, 1 when absent.
27
- export function encodeSteps(data, width, height, options) {
28
- const {quality, colorSpace} = admitOptions(options), effort = options?.effort === undefined ? 1 : options.effort;
29
- if (!Number.isInteger(effort) || effort < 1 || effort > 9) throw fault('JXL_INPUT', 'Effort is a whole number from 1 to 9.');
30
- admitPixels(data, width, height);
31
- return job(effortSteps(data, width, height, quality, colorSpace, effort));
32
- }
33
-
34
- // Effort 1 is the core's work (index.mjs), step for step; the rungs run after it and keep a smaller stream if they
35
- // find one. A search that runs out of memory leaves effort 1's stream standing.
36
- function* effortSteps(data, width, height, quality, colorSpace, effort) {
37
- const shape = inspectPixels(data, width, height);
38
- if (quality < 100) {
39
- if (!shape.palette) return yield* lossySteps(data, width, height, {quality, shape, colorSpace});
40
- const exact = yield* part(losslessSteps(data, width, height, {shape, colorSpace}), 0, 2);
41
- let bytes;
42
- try { bytes = yield* part(lossySteps(data, width, height, {quality, shape, colorSpace}), 1, 2); }
43
- catch (error) { if (!(error instanceof RangeError) || error.code) throw error; bytes = exact; }
44
- return exact.length <= bytes.length ? exact : bytes;
45
- }
46
- if (effort < 2) return yield* losslessSteps(data, width, height, {shape, colorSpace});
47
- let best = yield* part(losslessSteps(data, width, height, {shape, colorSpace}), 0, 2);
48
- try {
49
- const bytes = yield* part(searchSteps(data, width, height, shape.palette ? {...shape, palette: null} : shape, colorSpace, effort), 1, 2);
50
- if (bytes && bytes.length < best.length) best = bytes;
51
- } catch (error) { if (!(error instanceof RangeError) || error.code) throw error; }
52
- return best;
53
- }
54
-
55
- // A token's raw bits: a residual token s above zero carries s - 1 of them, an LZ77 length token above 235 s - 236.
56
- const raw = s => Math.max(0, s < 224 ? s - 1 : s - 236);
57
- // A histogram's complete cost in bits: its prefix code's header and every token's code and raw bits.
58
- function cost(freqs) {
59
- const code = buildCode(freqs), writer = new BitWriter(128);
60
- writePrefixCode(writer, code);
61
- let bits = writer.bitLength;
62
- for (let s = 0; s < freqs.length; s++) if (freqs[s]) bits += freqs[s] * (code.lengths[s] + raw(s));
63
- return bits;
64
- }
65
- const sum = histograms => { const out = new Uint32Array(ALPHABET); for (const h of histograms) for (let s = 0; s < ALPHABET; s++) out[s] += h[s]; return out; };
66
-
67
- // The direct plan of lossless.mjs (YCoCg, 256-pixel groups), every channel counted over the whole picture under effort
68
- // 1's predictor (chosen by samples, as the core chooses it) and under the weighted one; each rung's plan takes every
69
- // channel's cheapest, and the plans are written the cheapest way. Nothing written (null) when no plan leaves effort 1.
70
- function* searchSteps(rgba, width, height, shape, colorSpace, effort) {
71
- const {channels} = shape, layout = groupLayout(width, height), groups = layout.groupsX * layout.groupsY;
72
- const planes = Array.from({length: channels}, () => new Int16Array(GROUP_DIM * GROUP_DIM));
73
- const fill = (x0, y0, w, h) => {
74
- for (let y = 0; y < h; y++) {
75
- let i = ((y0 + y) * width + x0) * 4, at = y * w;
76
- for (let x = 0; x < w; x++, i += 4, at++) {
77
- if (channels >= 3) {
78
- const r = rgba[i], g = rgba[i + 1], b = rgba[i + 2];
79
- const co = r - b, tmp = b + (co >> 1), cg = g - tmp;
80
- planes[0][at] = tmp + (cg >> 1); planes[1][at] = co; planes[2][at] = cg;
81
- if (channels === 4) planes[3][at] = rgba[i + 3];
82
- } else { planes[0][at] = rgba[i]; if (channels === 2) planes[1][at] = rgba[i + 3]; }
83
- }
84
- }
85
- };
86
- const group = (g, visit) => {
87
- const x0 = g % layout.groupsX * GROUP_DIM, y0 = (g / layout.groupsX | 0) * GROUP_DIM, w = Math.min(GROUP_DIM, width - x0), h = Math.min(GROUP_DIM, height - y0);
88
- fill(x0, y0, w, h);
89
- visit(w, h);
90
- };
91
- // Effort 1's predictor per channel: three 32-pixel samples priced under gradient and average, as the core does.
92
- const sw = Math.min(width, 32), sh = Math.min(height, 32);
93
- const sampled = [GRADIENT_PREDICTOR, AVERAGE_PREDICTOR].map(predictor => ({predictor, freqs: planes.map(() => new Uint32Array(ALPHABET))}));
94
- for (const fraction of [0, 0.5, 1]) {
95
- fill(Math.floor((width - sw) * fraction), Math.floor((height - sh) * fraction), sw, sh);
96
- for (const candidate of sampled) for (let c = 0; c < channels; c++) codeChannel(null, candidate.freqs[c], planes[c], sw, sh, leaf(candidate.predictor));
97
- }
98
- const first = planes.map((_, c) => leaf(sampled[cost(sampled[1].freqs[c]) < cost(sampled[0].freqs[c]) ? 1 : 0].predictor));
99
- // Every channel counted under effort 1's predictor and under the weighted one, its tokens kept by error interval.
100
- // A step is a group of the counting pass (the first half of the search's fractions) or of a plan's writing (the
101
- // second half, shared by the plans written), so the pace of the steps holds whether one plan is written or two.
102
- const contexts = WEIGHTED_CUTS.length + 1, identity = Int32Array.from({length: contexts}, (_, k) => k);
103
- const firstCounts = planes.map(() => new Uint32Array(ALPHABET)), intervals = planes.map(() => Array.from({length: contexts}, () => new Uint32Array(ALPHABET)));
104
- let done = 0;
105
- for (let g = 0; g < groups; g++) {
106
- group(g, (w, h) => {
107
- for (let c = 0; c < channels; c++) {
108
- codeChannel(null, firstCounts[c], planes[c], w, h, first[c]);
109
- codeWeighted(null, intervals[c], planes[c], w, h, 0, identity);
110
- }
111
- });
112
- if (yield ++done / (2 * groups)) return null;
113
- }
114
- // Rung 2: each channel's cheaper of effort 1's predictor and the weighted one in one context.
115
- const rung2 = planes.map((_, c) => {
116
- const plan = {cost: cost(firstCounts[c]), leaves: [first[c]], freqs: [firstCounts[c]], cuts: []};
117
- const whole = sum(intervals[c]), single = cost(whole);
118
- return single < plan.cost ? {cost: single, leaves: [leaf(WEIGHTED_PREDICTOR)], freqs: [whole], cuts: []} : plan;
119
- });
120
- // Rung 3: or its intervals grouped into runs of neighbours, the grouping of least cost found exactly by dynamic
121
- // programming. best[j] is the least cost of intervals 0..j-1 grouped, `from[j]` where its last group begins; an
122
- // interval no token reaches leaves the merged cost as it was.
123
- const rung3 = effort < 3 ? rung2 : rung2.map((plan, c) => {
124
- const filled = intervals[c].map(h => h.some(v => v));
125
- const best = new Float64Array(contexts + 1).fill(Infinity), from = new Int32Array(contexts + 1);
126
- best[0] = 0;
127
- for (let j = 1; j <= contexts; j++) {
128
- const merged = new Uint32Array(ALPHABET);
129
- let bits = 0;
130
- for (let i = j - 1; i >= 0; i--) {
131
- if (filled[i]) { const h = intervals[c][i]; for (let s = 0; s < ALPHABET; s++) merged[s] += h[s]; bits = cost(merged); }
132
- // Every group is a leaf of the tree and an entry of the context map: 24 bits more, so an interval no token
133
- // reaches joins its neighbour.
134
- const price = best[i] + bits + 24;
135
- if (price < best[j]) { best[j] = price; from[j] = i; }
136
- }
137
- }
138
- if (!(best[contexts] < plan.cost)) return plan;
139
- const groupsOf = [];
140
- for (let j = contexts; j > 0; j = from[j]) groupsOf.unshift([from[j], j]);
141
- return {cost: best[contexts], leaves: groupsOf.map(() => leaf(WEIGHTED_PREDICTOR)), freqs: groupsOf.map(([i, j]) => sum(intervals[c].slice(i, j))), cuts: groupsOf.slice(0, -1).map(([, j]) => WEIGHTED_CUTS[j - 1]),
142
- contextOf: Int32Array.from({length: contexts}, (_, k) => groupsOf.findIndex(([i, j]) => k >= i && k < j))};
143
- });
144
- const candidates = [rung2, rung3].filter((plans, k) => k ? plans.some((plan, c) => plan !== rung2[c]) : plans.some((plan, c) => plan.leaves[0] !== first[c]));
145
- if (!candidates.length) return null;
146
- // The tree: one subtree per channel on the channel property, and inside a split channel a balanced tree on the
147
- // weighted predictor's property, values above a cut to the left.
148
- const byError = (leaves, cuts) => {
149
- const build = (lo, hi) => { if (lo === hi) return leaves[lo]; const mid = (lo + hi) >> 1; return split(WEIGHTED_PROPERTY, cuts[mid], build(mid + 1, hi), build(lo, mid)); };
150
- return build(0, leaves.length - 1);
151
- };
152
- const assemble = plans => ({tree: channelTree(plans.map(plan => byError(plan.leaves, plan.cuts))), leaves: plans.flatMap(plan => plan.leaves), freqs: plans.flatMap(plan => plan.freqs)});
153
- // A plan's price in bits: its tree and histograms as written, and every token's code and raw bits. Two plans' streams
154
- // differ by their prices and at most 27 bits a section more (a section's padding, and its size's field in the table
155
- // of contents, 12 to 32 bits) and a byte: a plan that far cheaper is written alone, closer plans both.
156
- const price = plans => {
157
- const {tree, leaves, freqs} = assemble(plans), w = new BitWriter(4096);
158
- const histograms = writeChannelHistograms(w, writeTree(w, tree), freqs, l => leaves.indexOf(l));
159
- let bits = w.bitLength;
160
- freqs.forEach((f, i) => { const {lengths} = histograms[i + 1].code; for (let s = 0; s < f.length; s++) if (f[s]) bits += f[s] * (lengths[s] + raw(s)); });
161
- return bits;
162
- };
163
- let chosen = candidates;
164
- if (candidates.length > 1) {
165
- const [a, b] = candidates.map(price), margin = 27 * (layout.single ? 1 : groups + 1) + 8;
166
- if (b + margin <= a) chosen = [candidates[1]];
167
- else if (a + margin <= b) chosen = [candidates[0]];
168
- }
169
- let written = 0;
170
- const next = () => 0.5 + ++written / (2 * chosen.length * groups);
171
- let smallest = null;
172
- for (const plans of chosen) {
173
- const bytes = yield* write(plans);
174
- if (!bytes) return smallest;
175
- if (!smallest || bytes.length < smallest.length) smallest = bytes;
176
- }
177
- return smallest;
178
-
179
- // A plan's stream, a group per step; null when hurried.
180
- function* write(plans) {
181
- const {tree, leaves, freqs} = assemble(plans);
182
- const transforms = channels >= 3 ? [{type: 'rct', beginC: 0, rctType: 6}] : [];
183
- const header = new BitWriter(256);
184
- writeImageHeader(header, width, height, shape.colour, shape.alpha, {colorSpace});
185
- writeModularFrameHeader(header, {alpha: shape.alpha});
186
- const global = new BitWriter(4096);
187
- global.write(1, 1); // default DC quantisation
188
- global.write(1, 1); // a global tree
189
- const histograms = writeChannelHistograms(global, writeTree(global, tree), freqs, l => leaves.indexOf(l));
190
- writeModularHeader(global, {useGlobalTree: true, transforms});
191
- const codes = plans.map(plan => plan.leaves.map(l => histograms[leaves.indexOf(l) + 1].code));
192
- const code = (w, c, width, height) => {
193
- const plan = plans[c];
194
- if (plan.leaves[0].predictor === WEIGHTED_PREDICTOR) codeWeighted(w, codes[c], planes[c], width, height, 0, plan.contextOf);
195
- else codeChannel(w, codes[c][0], planes[c], width, height, plan.leaves[0]);
196
- };
197
- const sections = [];
198
- if (layout.single) {
199
- group(0, (w, h) => { for (let c = 0; c < channels; c++) code(global, c, w, h); });
200
- if (yield next()) return null;
201
- sections.push(global.finish());
202
- } else {
203
- sections.push(global.finish());
204
- for (let i = 0; i < layout.dcGroupsX * layout.dcGroupsY + 1; i++) sections.push(new Uint8Array(0));
205
- for (let g = 0; g < groups; g++) {
206
- group(g, (w, h) => {
207
- const section = new BitWriter(w * h * channels + 64);
208
- writeModularHeader(section, {useGlobalTree: true, transforms: []});
209
- for (let c = 0; c < channels; c++) code(section, c, w, h);
210
- sections.push(section.finish());
211
- });
212
- if (yield next()) return null;
213
- }
214
- }
215
- return assembleCodestream(header, sections);
216
- }
217
- }
25
+ export function encodeSteps(data, width, height, options) { return job(effortJob(data, width, height, options)); }