rapier-jxl 1.1.21 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -10
- package/ENCODER-COMPARISON.md +6 -6
- package/README.md +107 -39
- package/admit.mjs +60 -0
- package/ans.mjs +157 -0
- package/bits.mjs +30 -10
- package/coefficient-ans.mjs +26 -0
- package/coefficient-effort.mjs +62 -0
- package/effort-level.mjs +10 -0
- package/effort.d.mts +12 -0
- package/effort.min.mjs +2 -0
- package/effort.mjs +240 -0
- package/entropy.mjs +16 -1
- package/frame.mjs +20 -10
- package/index.d.mts +13 -17
- package/index.mjs +30 -83
- package/jfif.mjs +418 -0
- package/jpeg-ans.d.mts +3 -0
- package/jpeg-ans.min.mjs +2 -0
- package/jpeg-ans.mjs +9 -0
- package/jpeg-job.mjs +29 -0
- package/jpeg.d.mts +18 -2
- package/jpeg.min.mjs +2 -2
- package/jpeg.mjs +15 -382
- package/local.mjs +197 -0
- package/lossless.mjs +33 -21
- package/lossy.mjs +41 -16
- package/package.json +17 -8
- package/photo-ans.d.mts +3 -0
- package/photo-ans.min.mjs +2 -0
- package/photo-ans.mjs +9 -0
- package/photo-dct.mjs +83 -0
- package/photo-job.mjs +27 -0
- package/photo-quant.mjs +150 -0
- package/photo.d.mts +11 -3
- package/photo.min.mjs +2 -2
- package/photo.mjs +10 -73
- package/public/examples/browser.html +4 -2
- package/public/examples/worker.mjs +34 -9
- package/rapier-jxl.min.mjs +2 -2
- package/sizes.json +286 -76
- package/vardct.mjs +71 -14
- package/weighted.mjs +89 -0
- package/writer.mjs +17 -0
- package/lossless.d.mts +0 -3
- package/lossless.min.mjs +0 -2
package/photo-quant.mjs
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// The photo door's per-block AC quantisation candidate. DC and alpha keep their original coefficients/samples.
|
|
3
|
+
// Eight block candidates: the original, three rate/error roundings at its field, and four coarser/finer fields.
|
|
4
|
+
// An admitted candidate mutates the supplied coefficient planes, avoiding a second whole-picture allocation;
|
|
5
|
+
// callers keep the already-written previous stream before entering this search.
|
|
6
|
+
import {PHOTO_LIMITS, float16Bits} from './bits.mjs';
|
|
7
|
+
import {dctBlocks} from './photo-dct.mjs';
|
|
8
|
+
|
|
9
|
+
const FIELDS = [4, 4, 4, 4, 3, 2, 6, 8], BASE = 4;
|
|
10
|
+
const PENALTIES = [0, 0.125, 0.25, 0.5, 0.25, 0.25, 0.25, 0.25];
|
|
11
|
+
const BIASES = [0.9299455010825141, 0.945349926692846, 0.9500648966626563];
|
|
12
|
+
// The existing 40 MP photo envelope, including input, measured at about 10.5 bytes per pixel. This is a
|
|
13
|
+
// deterministic allocation estimate for optional work, not a promise about an engine's resident-set high water.
|
|
14
|
+
const QUANT_MEMORY_BUDGET = PHOTO_LIMITS.pixels * 10.5;
|
|
15
|
+
const unbiased = (q, c) => Math.abs(q) < 2 ? q * BIASES[c] : q - 0.145 / q;
|
|
16
|
+
|
|
17
|
+
// Only normal positive half floats are needed: the writer raises its matrix scale to avoid subnormal decoders.
|
|
18
|
+
function half(value) {
|
|
19
|
+
const bits = float16Bits(value);
|
|
20
|
+
let out = 1 + (bits & 1023) / 1024, exponent = (bits >> 10) - 15;
|
|
21
|
+
while (exponent < 0) { out /= 2; exponent++; }
|
|
22
|
+
while (exponent > 0) { out *= 2; exponent--; }
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Reconstruction model: squared RGB coefficient error across edge-replicated DCT8 blocks, before clipping and
|
|
27
|
+
// output rounding. The stored half-precision matrix and the default quantisation bias are included. The transform
|
|
28
|
+
// is orthonormal, so this is the full padded block's RGB sample error (Parseval); DC is unchanged. The source
|
|
29
|
+
// samples are encoded sRGB or Display P3 values, not linear-light values.
|
|
30
|
+
const rgbError = (y, cb, cr) => {
|
|
31
|
+
const r = y + 1.402 * cr, g = y - 0.344136286 * cb - 0.714136286 * cr, b = y + 1.772 * cb;
|
|
32
|
+
return r * r + g * g + b * b;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export function* quantisationSteps(data, jpeg, storedBytes = 0) {
|
|
36
|
+
const {width, height, components, quantScale} = jpeg, stride = components[0].stride, rows = components[0].rows;
|
|
37
|
+
const count = stride * rows, choices = FIELDS.length;
|
|
38
|
+
// Optional search stays inside the existing photo memory envelope. Account for its score tables, and reserve
|
|
39
|
+
// two completed streams plus a writer's capacities, finished sections and assembly (six stream limits total),
|
|
40
|
+
// with 16 MiB for metadata. The original door's 40 MP admission is unchanged; larger searches keep their floor.
|
|
41
|
+
const pixelsBytes = data.byteLength + components.reduce((bytes, c) => bytes + c.coeffs.byteLength, 0);
|
|
42
|
+
if (pixelsBytes + Math.max(count * (choices * 10 + 2) + storedBytes, 7 * PHOTO_LIMITS.bytes) > QUANT_MEMORY_BUDGET) return null;
|
|
43
|
+
const errors = new Float64Array(count * choices), rates = new Uint16Array(count * choices);
|
|
44
|
+
const transform = dctBlocks(data, width, height), quant = components.map(c => c.quant), coeffs = components.map(c => c.coeffs);
|
|
45
|
+
const steps = FIELDS.map(field => quant.map(table => Float64Array.from(table, q => q * half(BASE / (8 * 255 * quantScale)) * 8 * 255 / field)));
|
|
46
|
+
const trial = new Int16Array(192), delta = new Float64Array(3);
|
|
47
|
+
const values = new Int32Array(6), differences = new Float64Array(6), bitCosts = new Float64Array(6);
|
|
48
|
+
let baselineError = 0, baselineRate = 0;
|
|
49
|
+
const quantise = (sums, block, choice) => {
|
|
50
|
+
let error = 0, rate = 0;
|
|
51
|
+
const penalty = PENALTIES[choice] * quant[0][1] * quant[0][1] / (quantScale * quantScale);
|
|
52
|
+
for (let k = 1; k < 64; k++) {
|
|
53
|
+
if (!choice) {
|
|
54
|
+
for (let c = 0; c < 3; c++) {
|
|
55
|
+
const q = coeffs[c][block * 64 + k];
|
|
56
|
+
delta[c] = unbiased(q, c) * steps[choice][c][k] - sums[c * 64 + k];
|
|
57
|
+
if (q) rate += 2 + 2 * (32 - Math.clz32(Math.abs(q)));
|
|
58
|
+
}
|
|
59
|
+
error += rgbError(delta[0], delta[1], delta[2]);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
for (let c = 0; c < 3; c++) {
|
|
63
|
+
const source = sums[c * 64 + k], step = steps[choice][c][k], lo = Math.floor(source / step);
|
|
64
|
+
for (let n = 0; n < 2; n++) {
|
|
65
|
+
const q = lo + n;
|
|
66
|
+
values[2 * c + n] = q;
|
|
67
|
+
bitCosts[2 * c + n] = q ? 2 + 2 * (32 - Math.clz32(Math.abs(q))) : 0;
|
|
68
|
+
differences[2 * c + n] = q < -32768 || q > 32767 ? Infinity : unbiased(q, c) * step - source;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
let selected = 0, best = Infinity, selectedError = 0;
|
|
72
|
+
for (let i = 0; i < 8; i++) {
|
|
73
|
+
const current = rgbError(differences[i & 1], differences[2 + ((i >> 1) & 1)], differences[4 + (i >> 2)]);
|
|
74
|
+
const candidate = current + penalty * (bitCosts[i & 1] + bitCosts[2 + ((i >> 1) & 1)] + bitCosts[4 + (i >> 2)]);
|
|
75
|
+
if (candidate < best) { best = candidate; selected = i; selectedError = current; }
|
|
76
|
+
}
|
|
77
|
+
if (best === Infinity) return {error: Infinity, rate: 65535};
|
|
78
|
+
error += selectedError;
|
|
79
|
+
for (let c = 0; c < 3; c++) {
|
|
80
|
+
const q = values[2 * c + ((selected >> c) & 1)];
|
|
81
|
+
trial[c * 64 + k] = q;
|
|
82
|
+
if (q) rate += 2 + 2 * (32 - Math.clz32(Math.abs(q)));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {error, rate};
|
|
86
|
+
};
|
|
87
|
+
for (let by = 0; by < rows; by++) {
|
|
88
|
+
for (let bx = 0; bx < stride; bx++) {
|
|
89
|
+
const block = by * stride + bx, sums = transform(bx, by);
|
|
90
|
+
for (let choice = 0; choice < choices; choice++) {
|
|
91
|
+
const result = quantise(sums, block, choice), at = block * choices + choice;
|
|
92
|
+
errors[at] = result.error; rates[at] = result.rate;
|
|
93
|
+
if (!choice) { baselineError += result.error; baselineRate += result.rate; }
|
|
94
|
+
}
|
|
95
|
+
if ((block + 1) % 1024 === 0 || block + 1 === count) if (yield (block + 1) / (3 * count)) return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// A coefficient has at most 16 magnitude bits: the per-block proxy rate fits Uint16.
|
|
100
|
+
// The proxy rate only proposes a field map. Binary search finds the cheapest proxy reconstruction under the
|
|
101
|
+
// baseline error; the complete written stream, with the field map and all headers, still has to beat effort 1.
|
|
102
|
+
const selected = new Uint8Array(count);
|
|
103
|
+
let selectionPass = 0;
|
|
104
|
+
const select = function* (lambda, keep) {
|
|
105
|
+
let total = 0, rate = 0;
|
|
106
|
+
for (let block = 0; block < count; block++) {
|
|
107
|
+
const at = block * choices;
|
|
108
|
+
let chosen = 0, best = errors[at] + lambda * rates[at];
|
|
109
|
+
for (let choice = 1; choice < choices; choice++) {
|
|
110
|
+
const cost = errors[at + choice] + lambda * rates[at + choice];
|
|
111
|
+
if (cost < best) { best = cost; chosen = choice; }
|
|
112
|
+
}
|
|
113
|
+
total += errors[at + chosen]; rate += rates[at + chosen];
|
|
114
|
+
if (keep) selected[block] = chosen;
|
|
115
|
+
if ((block + 1) % 1024 === 0 || block + 1 === count) {
|
|
116
|
+
if (yield 1 / 3 + (selectionPass + (block + 1) / count) / 147) return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
selectionPass++;
|
|
120
|
+
return {error: total, rate};
|
|
121
|
+
};
|
|
122
|
+
let lo = 0, hi = Math.max(1, baselineError / Math.max(1, baselineRate));
|
|
123
|
+
for (let i = 0; i < 24; i++) {
|
|
124
|
+
const chosen = yield* select(hi, false);
|
|
125
|
+
if (!chosen) return null;
|
|
126
|
+
if (chosen.error > baselineError) break;
|
|
127
|
+
hi *= 2;
|
|
128
|
+
}
|
|
129
|
+
for (let i = 0; i < 24; i++) {
|
|
130
|
+
const mid = (lo + hi) / 2, chosen = yield* select(mid, false);
|
|
131
|
+
if (!chosen) return null;
|
|
132
|
+
if (chosen.error <= baselineError) lo = mid; else hi = mid;
|
|
133
|
+
}
|
|
134
|
+
const chosen = yield* select(lo, true);
|
|
135
|
+
if (!chosen || chosen.error > baselineError || chosen.rate >= baselineRate || !selected.some(choice => choice)) return null;
|
|
136
|
+
const quantFields = new Uint8Array(count);
|
|
137
|
+
for (let by = 0; by < rows; by++) {
|
|
138
|
+
for (let bx = 0; bx < stride; bx++) {
|
|
139
|
+
const block = by * stride + bx, choice = selected[block];
|
|
140
|
+
quantFields[block] = FIELDS[choice];
|
|
141
|
+
if (choice) {
|
|
142
|
+
quantise(transform(bx, by), block, choice);
|
|
143
|
+
for (let c = 0; c < 3; c++) for (let k = 1; k < 64; k++) coeffs[c][block * 64 + k] = trial[c * 64 + k];
|
|
144
|
+
}
|
|
145
|
+
if ((block + 1) % 1024 === 0 || block + 1 === count) if (yield 2 / 3 + (block + 1) / (3 * count)) return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {...jpeg, quantFieldBase: BASE, quantFields,
|
|
149
|
+
reconstructionError: {baseline: baselineError, candidate: chosen.error}};
|
|
150
|
+
}
|
package/photo.d.mts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
import type {Pixels, EncodeOptions, Limits} from './index.mjs';
|
|
2
|
+
import type {Pixels, EncodeOptions, Job, Limits} from './index.mjs';
|
|
3
|
+
export type {Pixels, Limits, EncodeOptions, ErrorCode, EncoderError, Job} from './index.mjs';
|
|
4
|
+
/** This door's limits, by its memory: the 16 MiB codestream, 40 million pixels, 16,384 on a side. */
|
|
3
5
|
export const LIMITS: Limits;
|
|
4
|
-
/** Photographs: DCT8 coefficients with exact alpha; quality 90 by default, 100 is exact.
|
|
5
|
-
|
|
6
|
+
/** Photographs: DCT8 coefficients with exact alpha; quality 90 by default, 100 is exact.
|
|
7
|
+
* Effort 1 is the default; 3 tries a cluster budget, 4 also a learned order, preserving reconstructed pixels.
|
|
8
|
+
* Effort 5 adds per-block quantisation within effort 1's unclipped RGB sample reconstruction-error
|
|
9
|
+
* model, retaining the preceding stream unless the complete candidate is smaller. Optional searches beyond their
|
|
10
|
+
* memory estimate keep the preceding stream; this door's input limits do not change with effort. */
|
|
11
|
+
export function encodePhoto(data: Pixels, width: number, height: number, options?: EncodeOptions): Uint8Array;
|
|
12
|
+
/** encodePhoto's work and bytes as steps; the call is admitted at once. */
|
|
13
|
+
export function encodePhotoSteps(data: Pixels, width: number, height: number, options?: EncodeOptions): Job;
|
package/photo.min.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! Rapier JXL
|
|
2
|
-
function t(t){return t>=0?2*t:2*-t-1}function n(t){return 31-Math.clz32(t)}function o(t){return t<=1?0:32-Math.clz32(t-1)}function r(t){if(0===t)return 0;const n=t<0?32768:0;if(!((t=Math.abs(t))<65520))throw new Error("half float out of range: "+t);let o=Math.floor(Math.log2(t)),r=t/2**o-1;o<-14&&(r=t/2**-14,o=-15);let e=Math.round(1024*r);return 1024===e&&(e=0,o++),n|o+15<<10|e}function e(t,n){const o=new Uint8Array(t.length),r=[];for(let n=0;n<t.length;n++)t[n]>0&&r.push(n);if(!r.length)return o;if(1===r.length)return o[r[0]]=1,o;for(let e=1;;e*=2){const s=r.map(n=>({w:Math.max(t[n],e),t:n,l:null,r:null})).sort((t,n)=>t.w-n.w||t.t-n.t),c=[];let f=0,i=0;const l=()=>f<s.length&&(i>=c.length||s[f].w<=c[i].w)?s[f++]:c[i++];for(;s.length-f+(c.length-i)>1;){const t=l(),n=l();c.push({w:t.w+n.w,t:-1,l:t,r:n})}const a=[[l(),0]];let h=0;for(;a.length;){const[t,n]=a.pop();t.t>=0?(o[t.t]=n,n>h&&(h=n)):a.push([t.l,n+1],[t.r,n+1])}if(h<=n)return o}}function s(t,n,o,r,e,s){const c=[];for(;c.push(r&e),r>>=s;)r--;for(let r=c.length-1;r>=0;r--)t.push(o),n.push(c[r])}function c(t,n){let o=0;for(let r=0;r<n;r++)o=o<<1|1&t,t>>=1;return o}function f(t){const n=new Uint32Array(17),o=new Uint32Array(17),r=new Uint16Array(t.length);for(const o of t)n[o]++;n[0]=0;for(let t=1,r=0;t<=16;t++)r=r+n[t-1]<<1,o[t]=r;for(let n=0;n<t.length;n++)t[n]&&(r[n]=c(o[t[n]]++,t[n]));return r}function i(t){const n=[];for(let o=0;o<t.length;o++)t[o]>0&&n.push(o);const o=n.length,r=n[o-1]+1||1,s=o<=4?new Uint8Array(r):e(t,15).subarray(0,r);let c=0;if(o<=4){n.sort((n,o)=>t[o]-t[n]||n-o),c=4===o&&t[n[0]]>t[n[2]]+t[n[3]]?1:0;const r=o<2?[0]:2===o?[1,1]:3===o?[1,2,2]:c?[1,2,3,3]:[2,2,2,2];n.forEach((t,n)=>{s[t]=r[n]}),n.sort((t,n)=>s[t]-s[n]||t-n)}return{o:r,i:s,u:f(s),M:o&&o<=4?n:null,p:c}}function l(t,o){if(o.o<=1)return;if(o.M){const r=n(o.o-1)+1;t.write(2,1),t.write(2,o.M.length-1);for(const n of o.M)t.write(r,n);return void(4===o.M.length&&t.write(1,o.p))}const r=o.i,c=[],i=[];let l=r.length-1;for(;l>0&&!r[l];)l--;let a=8;for(let t=0;t<=l;){const n=r[t];let o=1;for(;t+o<=l&&r[t+o]===n;)o++;let e=o;if(n&&n!==a&&(c.push(n),i.push(0),e--,a=n),e<3)for(let t=0;t<e;t++)c.push(n),i.push(0);else s(c,i,n?16:17,e-3,n?3:7,n?2:3);t+=o}const h=new Uint32Array(18);for(const t of c)h[t]++;let u=0;for(const t of h)t&&u++;1===u&&(h[c[0]?0:1]=h[c[0]]);const w=e(h,5),M=f(w);let y=18;for(;y>0&&!w[k[y-1]];)y--;t.write(2,0);for(let n=0;n<y;n++){const o=w[k[n]];t.write(z[o],B[o])}for(let n=0;n<c.length;n++){const o=c[n];t.write(w[o],M[o]),16===o?t.write(2,i[n]):17===o&&t.write(3,i[n])}}function a(t,n=0,o=0){return{split:t,A:n,m:o,U:1<<t}}function h(t,n,r=15){t.write(o(r+1),n.split),n.split!==r&&(t.write(o(n.split+1),n.A),t.write(o(n.split-n.A+1),n.m))}function u(t,o,r){if(o<t.U)return r[0]=o,r[1]=0,void(r[2]=0);const e=n(o),s=o-(1<<e),c=e-t.A-t.m;r[0]=t.U+(e-t.split<<t.A+t.m|s>>e-t.A<<t.m|s&(1<<t.m)-1),r[1]=c,r[2]=o>>t.m&(1<<c)-1}function w(t,n,o,r=0){u(t,n,F),o[r+F[0]]++}function M(t,n,o,r,e=0){u(o,r,F);const s=e+F[0];t.write(n.i[s],n.u[s]),F[1]&&t.write(F[1],F[2])}function y(t,n){let r=0;for(const t of n)r=Math.max(r,t);const e=r?o(r+1):0;if(e<=3){if(t.write(1,1),t.write(2,e),e)for(const o of n)t.write(e,o);return}t.write(1,0),t.write(1,0);const s=a(8),c=a(4),f=n.length>=64,l=new Uint32Array(f?257:r+1),h=[];for(let t=0;t<n.length;){let o=1;for(;f&&t+o<n.length&&n[t+o]===n[t];)o++;if(o>=8)h.push([n[t],o-1]),l[n[t]]++,w(c,o-1-7,l,224),t+=o;else{for(let r=0;r<o;r++)h.push([n[t],0]),l[n[t]]++;t+=o}}const u=i(l);if(!f){p(t,{I:new Uint8Array(1),J:[{config:s,code:u}]});for(const[n]of h)M(t,u,s,n);return}const y=new Uint32Array(1);y[0]=1,p(t,{L:{T:224,minLength:7,X:c},I:new Uint8Array([1,0]),J:[{config:a(0),code:i(y)},{config:s,code:u}]});for(const[n,o]of h)M(t,u,s,n),o&&M(t,u,c,o-7,224)}function p(t,{L:o=null,I:r,J:e}){t.write(1,o?1:0),o&&(t.G([[0,224],[0,512],[0,4096],[15,8]],o.T),t.G([[0,3],[0,4],[2,5],[8,9]],o.minLength),h(t,o.X,8)),r.length>1&&y(t,r),t.write(1,1);for(const n of e)h(t,n.config,15);for(const o of e){const r=o.code.o-1;if(r){const o=n(r);t.write(1,1),t.write(4,o),t.write(o,r-(1<<o))}else t.write(1,0)}for(const n of e)l(t,n.code)}function A(t,n=0,o=1){return{C:t,offset:n,O:o,context:-1}}function d(t){return function(t,n){const o=(r,e)=>{if(r===e)return n?t[r].N:t[r];const s=r+e>>1;return function(t,n,o,r){return{P:t,S:n,left:o,right:r}}(n,n?t[s]._:s,o(s+1,e),o(r,s))};return o(0,t.length-1)}(t,0)}function g(n,o){const r=[o],e=[],s=[];for(const n of r){if(n.left){e.push(n.P+1,t(n.S)),r.push(n.left,n.right);continue}n.context=s.length,s.push(n);const o=1===n.O?0:31-Math.clz32(n.O&-n.O);e.push(0,n.C,t(n.offset),o,(n.O>>o)-1)}const c=new Uint32Array(64);for(const t of e)w(Q,t,c);const f=i(c);p(n,{I:new Uint8Array(6),J:[{config:Q,code:f}]});for(const t of e)M(n,f,Q,t);return s}function m(t,n){const o=[[3,0],[6,8],[10,72],[13,1096]];if("rct"===n.type)t.write(2,0),t.G(o,n.q),t.G([[0,6],[2,0],[4,2],[6,10]],n.j??6);else if("palette"===n.type)t.write(2,1),t.G(o,n.q),t.G([[0,1],[0,3],[0,4],[13,1]],n.k),t.G([[8,0],[10,256],[12,1280],[16,5376]],n.B),t.G([[0,0],[8,1],[10,257],[16,1281]],n.F??0),t.write(4,n.C??0);else{if("squeeze"!==n.type)throw new Error("unknown transform "+n.type);{t.write(2,2);const r=n.R??[];t.G([[0,0],[4,1],[6,9],[8,41]],r.length);for(const n of r)t.write(1,n.Z?1:0),t.write(1,n.D?1:0),t.G(o,n.q),t.G([[0,1],[0,2],[0,3],[4,4]],n.k)}}}function b(t,{Y:n=!0,H:o=[]}={}){t.write(1,n?1:0),t.write(1,1),t.G([[0,0],[0,1],[4,2],[8,18]],o.length);for(const n of o)m(t,n)}function U(t,n,o,r=t=>t.context){const e=new Uint8Array(n.length+1);for(const t of n)e[t.context]=r(t)+1;const s=new Uint32Array(2);s[1]=1;const c=[{config:Q,code:i(s)}],f=Math.max(...e);for(let t=0;t<f;t++)c.push({config:Q,code:i(o[t])});return p(t,{L:Y,I:e,J:c}),c}function x(n,o,r,e,s,c){const f=c.C,i=c.offset,l=c.O,a=Q,h=D;let u=0;const y=(t,r=a,e=0)=>{n?M(n,o,r,t,e):w(r,t,o,e)},p=()=>{if(u){if(u>=8)y(0),y(u-7-1,h,224);else for(let t=0;t<u;t++)y(0);u=0}},A=(n,o)=>{const e=r[n];let s;1===l?s=e-o-i:(s=Math.round((e-o-i)/l),r[n]=o+i+s*l),0!==s?(p(),y(t(s))):u++};for(let t=0,n=0;t<s;t++)for(let o=0;o<e;o++,n++){let s;if(0===f)s=0;else{const c=o?r[n-1]:t?r[n-e]:0,i=t?r[n-e]:c;if(1===f)s=c;else if(2===f)s=i;else if(3===f)s=(c+i)/2|0;else{const l=c+i-(o&&t?r[n-e-1]:c);if(5===f){const t=c<i?c:i,n=c<i?i:c;s=l<t?t:l>n?n:l}else{if(4!==f)throw new Error("predictor "+f+" is not coded here");s=Math.abs(l-c)<Math.abs(l-i)?c:i}}}A(n,s)}p()}function I(t,n){t.G([[9,1],[13,1],[18,1],[30,1]],n)}function E(t,n,o,r,e,{xyb:s=!1,orientation:c=1}={}){t.write(16,2815),t.write(1,0),I(t,o),t.write(3,0),I(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),e?t.write(3,5):t.write(2,0),t.write(1,s?1:0),3===r?t.write(1,1):t.write(15,14100),f&&t.write(1,1),t.write(2,0),t.write(1,1),t.K()}function J(t,n){t.write(n?7:5,0),t.write(11,1)}function L(t,n){const o=n.map(t=>t.length);!function(t,n){t.write(1,0),t.K();for(const o of n)t.G([[10,0],[14,1024],[22,17408],[30,4211712]],o);t.K()}(t,o);const r=t.finish(),e=new Uint8Array(r.length+o.reduce((t,n)=>t+n,0));e.set(r);let s=r.length;for(const t of n)e.set(t,s),s+=t.length;return e}function T(t,n,o,{palette:r=!0}={}){const e=n*o;let s=!0,c=!0;for(let n=0,o=0;o<e&&(255===t[n+3]||(s=!1,c))&&(t[n]===t[n+1]&&t[n]===t[n+2]||(c=!1,s));o++,n+=4);const f=c?1:3,i=!s,l=f+(i?1:0),a=n=>c?i?t[n]+256*t[n+3]:t[n]:t[n]+256*t[n+1]+65536*t[n+2]+(i?16777216*t[n+3]:0),h=new Map;let u=null;for(let t=0,n=0;r&&n<e;n++,t+=4){const n=a(t);if(0!==n&&!h.has(n)&&(h.set(n,1),h.size>=2048))break}if(r&&h.size<2048){const t=[...h.keys()],n=(t,n)=>Math.floor(t/256**n)%256,o=t=>(.299*n(t,0)+.587*n(t,1)+.114*n(t,2)+.01)*(4===l?n(t,3):1);t.sort((t,n)=>o(t)-o(n));const r=new Map([[0,0]]);t.forEach((t,n)=>r.set(t,n+1)),u={colours:[0,...t],index:r,key:a,byte:n}}return{colour:f,alpha:i,channels:l,palette:u}}function X(t,n,o,r){const{channels:e,palette:s}=r,c=function(t,n){const o=Math.ceil(t/H),r=Math.ceil(n/H);return{V:o,W:r,$:Math.ceil(t/2048),tt:Math.ceil(n/2048),nt:1===o&&1===r}}(n,o),f=s?2:e,a=Array.from({length:f},()=>A(Z)),h=d(a),u=Array.from({length:f},()=>new Int16Array(65536)),w=(o,r,c,f)=>{for(let i=0;i<f;i++){let f=4*((r+i)*n+o),l=i*c;for(let n=0;n<c;n++,f+=4,l++)if(s)u[0][l]=s.index.get(s.key(f));else if(e>=3){const n=t[f],o=t[f+1],r=t[f+2],s=n-r,c=r+(s>>1),i=o-c;u[0][l]=c+(i>>1),u[1][l]=s,u[2][l]=i,4===e&&(u[3][l]=t[f+3])}else u[0][l]=t[f],2===e&&(u[1][l]=t[f+3])}};let M=null;if(s){const t=s.colours.length;M=new Int16Array(t*e),s.colours.forEach((n,o)=>{for(let r=0;r<e;r++)M[r*t+o]=s.byte(n,r)})}const y=t=>a[s?c.nt?1:0:t],p=s?1:e,m=t=>{for(let r=0;r<c.W;r++)for(let e=0;e<c.V;e++){const s=e*H,f=r*H,i=Math.min(H,n-s),l=Math.min(H,o-f);w(s,f,i,l),t(r*c.V+e,i,l)}};if(!s){const t=t=>{const n=i(t),o=new j(128);l(o,n);let r=o.ot;for(let o=0;o<t.length;o++)t[o]&&(r+=t[o]*(n.i[o]+Math.max(0,o<224?o-1:o-236)));return r},r=Math.min(n,32),s=Math.min(o,32),c=[Z,R].map(t=>({C:t,rt:a.map(()=>new Uint32Array(257))}));for(const t of[0,.5,1]){w(Math.floor((n-r)*t),Math.floor((o-s)*t),r,s);for(const t of c)for(let n=0;n<e;n++)x(null,t.rt[n],u[n],r,s,A(t.C))}a.forEach((n,o)=>{const r=c.map(n=>t(n.rt[o])),e=r[1]<r[0]?1:0;n.C=c[e].C})}const I=s?[{type:"palette",q:0,k:e,B:s.colours.length}]:e>=3?[{type:"rct",q:0,j:6}]:[],T=a.map(()=>new Uint32Array(257)),X=t=>T[a.indexOf(t)];M&&x(null,X(a[0]),M,s.colours.length,e,a[0]),m((t,n,o)=>{for(let t=0;t<p;t++)x(null,X(y(t)),u[t],n,o,y(t))});const G=new j(256);E(G,n,o,r.colour,r.alpha),function(t,{alpha:n}){t.write(9,8),n&&t.write(2,0),t.write(2,1),J(t,n)}(G,{alpha:r.alpha});const C=new j(4096);C.write(1,1),C.write(1,1);const O=g(C,h),N=U(C,O,T,t=>a.indexOf(t)),P=t=>N[a.indexOf(t)+1].code;b(C,{Y:!0,H:I}),M&&x(C,P(a[0]),M,s.colours.length,e,a[0]);const S=[];if(c.nt)m((t,n,o)=>{for(let t=0;t<p;t++)x(C,P(y(t)),u[t],n,o,y(t))}),S.push(C.finish());else{S.push(C.finish());for(let t=0;t<c.$*c.tt+1;t++)S.push(new Uint8Array(0));m((t,n,o)=>{const r=new j(n*o*p+64);b(r,{Y:!0,H:[]});for(let t=0;t<p;t++)x(r,P(y(t)),u[t],n,o,y(t));S.push(r.finish())})}return L(G,S)}function G(t,n="JXL_JPEG"){return Object.assign(new Error("JPEG: "+t),{code:n})}function C(t,n){return u(t,n,$),$[0]}function O(t){let n=0,o=0;for(const o of t)n+=o;for(const r of t)r&&(o+=r*Math.log2(n/r));return o}function N(t,n,o){const r=[];if(n>0){const o=new Uint32Array(2048);let e=0;for(const n of t)o[Math.min(2047,Math.max(0,n+1024))]++,e++;let s=0,c=e/(n+1);for(let t=0;t<2048&&r.length<n;t++)s+=o[t],s>c&&(r.push(t-1025),c=e*(r.length+1)/(n+1))}const e=r.length+1,s=new Uint8Array(39*e);for(let t=0;t<e;t++)for(let n=0;n<tt;n++)s[(0+n)*e+t]=t,s[(13+n)*e+t]=o?e:e+(t>>1),s[(26+n)*e+t]=o?e:e+(e-1>>1)+1+(t>>1);let c=0;for(const t of s)c=Math.max(c,t+1);return{thresholds:r,et:e,map:s,st:c,ct:t=>{let n=0;for(const o of r)t>o&&n++;return n},ft:(t,n)=>s[(t<2?1^t:2)*tt*e+n],it:(t,n)=>(Math.min(t,64)<8?Math.min(t,64):4+(Math.min(t,64)>>1))*c+n,lt:t=>37*c+458*t,ht:495*c}}function P(t,n,o){const r=n.map(()=>A(o)),e=r.map(()=>new Uint32Array(257));n.forEach((t,n)=>x(null,e[n],t.data,t.w,t.h,r[n])),b(t,{Y:!1,H:[]});const s=g(t,d(r)),c=U(t,s,e,t=>r.indexOf(t));n.forEach((n,o)=>x(t,c[o+1].code,n.data,n.w,n.h,r[o]))}function S(t,n,o,r){let e=0;return e+=t[n]*ct[r],e+=t[n+o]*ct[r+1],e+=t[n+2*o]*ct[r+2],e+=t[n+3*o]*ct[r+3],e+=t[n+4*o]*ct[r+4],e+=t[n+5*o]*ct[r+5],e+=t[n+6*o]*ct[r+6],e+=t[n+7*o]*ct[r+7],e}function _(n,e,s,c={}){if(null===c||"object"!=typeof c)throw st("JXL_INPUT","Options are an object: {quality}.");const f=void 0===c.quality?90:c.quality;if("number"!=typeof f||!Number.isFinite(f)||f<1||f>100)throw st("JXL_INPUT","Quality is a number from 1 to 100.");if(!Number.isInteger(e)||!Number.isInteger(s)||e<1||s<1)throw st("JXL_INPUT","A picture has positive whole pixel dimensions.");if(e>v.edge||s>v.edge||e*s>v.pixels)throw st("JXL_DIMENSIONS","The picture exceeds the JPEG XL pixel limits.");if(!(n instanceof Uint8Array||n instanceof Uint8ClampedArray)||n.length!==e*s*4)throw st("JXL_INPUT","Pixels are width * height * 4 straight RGBA bytes.");try{const c=f>=100?function(t,n,o,{shape:r=T(t,n,o)}={}){let e,s;for(const c of r.palette?[r,{...r,palette:null}]:[r])try{const r=X(t,n,o,c);(!e||r.length<e.length)&&(e=r)}catch(t){if("JXL_SIZE"!==t.code)throw t;s=t}if(!e)throw s;return e}(n,e,s):function(n){const{width:e,height:s,components:c,alpha:f}=n,l=1===c.length,a=n.quantScale||1,h=n.ycbcr||l,u=(l?[0,0,0]:h?[1,0,2]:[0,1,2]).map(t=>c[t]),w=t=>1===t?0:2===t?1:-1,A=u.map(t=>w(t.h)),d=u.map(t=>w(t.v));if(A.includes(-1)||d.includes(-1))throw G("sampling factors other than one or two");const g=Math.max(...A),m=Math.max(...d),b=t=>g-A[t],U=t=>m-d[t];if(!h&&(g||m))throw G("an RGB JPEG with subsampling");const x=Math.ceil(e/(8<<g))<<g,I=Math.ceil(s/(8<<m))<<m,T=Math.ceil(e/H),X=Math.ceil(s/H),C=T*X,S=Math.ceil(x/256),_=S*Math.ceil(I/256),v=1===C,q=(t,n,o)=>{const r=u[t];return l&&1!==t?-1:64*(o*r.stride+n)},k=t=>{let n=1024;for(;t%n;)n>>=1;return n},z=u.map(t=>h?1:t.quant[0]/k(t.quant[0])),B=u.map(t=>h?0:1024/k(t.quant[0])),F=new Int32Array(x*I);for(let t=0;t<I;t++)for(let n=0;n<x;n++)F[t*x+n]=u[1].coeffs[q(1,n,t)]*z[1]+B[1];const R=u[1].quant,D=(R[8]+R[16]+R[24]+R[32]+R[40])/a,Y=x*I,Q=Y<256?0:Math.max(1,Math.min(7,o(Y)-o(D)-7));let $=N(F,Q,l);const tt=new j(256);if(E(tt,e,s,l?1:3,!!f,{orientation:n.orientation}),tt.write(1,0),tt.write(2,0),tt.write(1,0),tt.write(2,2),tt.write(8,111),tt.write(1,h?1:0),h)for(let t=0;t<3;t++)tt.write(2,0===A[t]&&0===d[t]?0:1===A[t]&&1===d[t]?1:1===A[t]?2:3);tt.write(2,0),f&&tt.write(2,0),J(tt,f);const nt=[0,1,2].map(()=>new Int32Array(1024)),ot=(n,o)=>{const r=n%T*32,e=32*(n/T|0),s=Math.min(32,x-r),c=Math.min(32,I-e);for(let n=0;n<c;n++)for(let c=0;c<s;c++)for(const s of[1,0,2]){const f=b(s),i=U(s),l=c>>f,a=n>>i;if(l<<f!==c||a<<i!==n)continue;const h=q(s,(r>>f)+l,(e>>i)+a),w=u[s].coeffs;let M=0;if(h>=0)for(let t=1;t<64;t++)w[h+t]&&M++;const y=nt[s],p=0===l?0===a?32:y[32*(a-1)]:0===a?y[32*a+l-1]:y[32*(a-1)+l]+y[32*a+l-1]+1>>1;y[32*a+l]=M;const A=$.ft(s,$.ct(F[(e+n)*x+r+c]));o($.it(p,A),M);const d=$.lt(A);let g=M>4?0:1,m=M;for(let n=1;n<64&&m;n++){const r=w[h+rt[n]];o(d+et(m,n,g),t(r)),g=r?1:0,m-=g}}},st=t=>{$=t;const n=new W(t.ht);for(let t=0;t<C;t++)ot(t,(t,o)=>n.add(t,o));return function(t,{maxClusters:n=48,newClusterCost:o=320}={}){const r=[];for(let n=0;n<t.ht;n++)t.ut[n]>0&&r.push(n);r.sort((n,o)=>t.ut[o]-t.ut[n]);const e=[];for(const s of r){const r=t.wt([s],V),c=O(r);let f=-1,i=1/0;for(let t=0;t<e.length;t++){const n=e[t],o=new Uint32Array(64);for(let t=0;t<64;t++)o[t]=n.rt[t]+r[t];const s=O(o)-n.Mt-c;s<i&&(i=s,f=t)}if(f<0||e.length<n&&i>o)e.push({ht:[s],rt:r,Mt:c});else{const t=e[f];t.ht.push(s);for(let n=0;n<64;n++)t.rt[n]+=r[n];t.Mt=O(t.rt)}}e.length||e.push({ht:[],rt:new Uint32Array(64),Mt:0});const s=new Uint8Array(t.ht);let c=2*t.ht;const f=e.map((n,o)=>{for(const t of n.ht)s[t]=o;let r=K[0],e=1/0;for(const o of K){const s=t.yt(n.ht,o);s<e&&(e=s,r=o)}const f=i(t.wt(n.ht,r,128));return c+=e+3*f.o+40,{config:r,code:f}});return{I:s,J:f,write:(t,n,o)=>{const r=f[s[n]];M(t,r.code,r.config,o)},Mt:c}}(n)};let ct=st($);if(Q>0){const t=$,n=st(N(F,0,l));n.Mt<=ct.Mt?ct=n:$=t}const ft=Array.from({length:v?1:2+_+C},()=>null),it=t=>ft[v?0:t]||(ft[v?0:t]=new j(4096)),lt=it(0);lt.write(1,0);const at=(t,n)=>{const o=t*H,r=n*H,c=Math.min(H,e-o),i=Math.min(H,s-r),l=new Int32Array(c*i);for(let t=0;t<i;t++)for(let n=0;n<c;n++)l[t*c+n]=f[4*((r+t)*e+o+n)+3];return{w:c,h:i,data:l}};for(let t=0;t<3;t++)lt.write(16,r(u[t].quant[0]/z[t]/(2040*a)*128));lt.write(2,3),lt.write(16,57343),lt.write(2,1),lt.write(5,0),lt.write(1,0),lt.write(4,0),lt.write(4,$.thresholds.length);for(const n of $.thresholds)lt.G([[4,0],[8,16],[16,272],[32,65808]],t(n));lt.write(4,0),lt.write(4,0),y(lt,$.map),lt.write(1,0),lt.write(2,0),lt.write(16,0),lt.write(16,0),lt.write(8,128),lt.write(8,128),lt.write(1,0),f&&P(lt,[v?at(0,0):{w:0,h:0,data:new Int32Array(0)}],Z);for(let t=0;t<_;t++){const n=it(1+t),r=t%S*256,e=256*(t/S|0),s=Math.min(256,x-r),c=Math.min(256,I-e);n.write(2,0),P(n,[1,0,2].map(t=>{const n=s>>b(t),o=c>>U(t),f=new Int32Array(n*o),i=z[t],l=B[t];for(let s=0;s<o;s++)for(let o=0;o<n;o++){const c=q(t,(r>>b(t))+o,(e>>U(t))+s);f[s*n+o]=c<0?0:u[t].coeffs[c]*i+l}return{w:n,h:o,data:f}}),Z);const f=s*c,i=o(f);i&&n.write(i,f-1);const l=s+7>>3,a=c+7>>3;P(n,[{w:l,h:a,data:new Int32Array(l*a)},{w:l,h:a,data:new Int32Array(l*a)},{w:f,h:2,data:new Int32Array(2*f)},{w:s,h:c,data:new Int32Array(f)}],0)}const ht=it(1+_);ht.write(1,0),ht.write(3,7),ht.write(16,r(1/(2040*a))),P(ht,[0,1,2].map(t=>{const n=new Int32Array(64),o=u[t].quant;for(let t=0;t<8;t++)for(let r=0;r<8;r++)n[8*r+t]=o[8*t+r];return{w:8,h:8,data:n}}),Z);for(let t=1;t<17;t++)ht.write(3,0);C>1&&ht.write(o(C),0),ht.write(2,2),p(ht,{I:ct.I,J:ct.J});for(let t=0;t<C;t++){const n=it(2+_+t);ot(t,(t,o)=>ct.write(n,t,o)),f&&!v&&P(n,[at(t%T,Math.floor(t/T))],Z)}return L(tt,function(t){return t.map(t=>t?t.finish():new Uint8Array(0))}(ft))}(function(t,n,o,r){const e=Math.ceil(n/8),s=Math.ceil(o/8),c=r>=30?.1+.09*(100-r):53/3e3*r*r-1.15*r+25,f=[0,1,2].map(t=>({h:1,v:1,stride:e,rows:s,quant:Int32Array.from(ft,(n,o)=>Math.max(1,Math.round(16*c*(t?8:14)*(o?n:.5)))),coeffs:new Int16Array(e*s*64)})),i=new Float64Array(192),l=new Float64Array(64);for(let r=0;r<s;r++)for(let s=0;s<e;s++){for(let e=0;e<8;e++)for(let c=0;c<8;c++){const f=4*(Math.min(o-1,8*r+e)*n+Math.min(n-1,8*s+c)),l=t[f],a=t[f+1],h=t[f+2],u=8*e+c;i[u]=.299*l+.587*a+.114*h-128,i[64+u]=-.168735892*l-.331264108*a+.5*h,i[128+u]=.5*l-.418687589*a-.081312411*h}for(let t=0;t<3;t++){for(let n=0;n<8;n++)for(let o=0;o<8;o++)l[8*n+o]=S(i,64*t+8*n,1,8*o);const{coeffs:n,quant:o}=f[t],c=64*(r*e+s);for(let t=0;t<8;t++)for(let r=0;r<8;r++){const e=S(l,r,8,8*t),s=8*t+r;n[c+s]=Math.round(16*e/o[s])}}}let a=null;for(let n=3;n<t.length;n+=4)if(255!==t[n]){a=t;break}return{width:n,height:o,components:f,quantScale:16,ycbcr:!0,orientation:1,alpha:a}}(n,e,s,f));if(c.length>v.bytes)throw st("JXL_SIZE","The encoded picture exceeds 16 MiB.");return c}catch(t){if(t instanceof RangeError&&!t.code)throw st("JXL_MEMORY","Not enough memory for this picture.");throw t}}const v=Object.freeze({bytes:16777216,pixels:24e6,edge:16384}),q=Array.from({length:33},(t,n)=>2**n);class j{constructor(t=4096){this.bytes=new Uint8Array(t),this.at=0,this.At=0,this.pending=0}write(t,n){if(t>32||n<0||n>=(q[t]??2**t))throw new Error("bit write out of range: "+t+" bits, "+n);let o=this.At+n*(1<<this.pending),r=this.pending+t;this.at+5>=this.bytes.length&&this.grow();const e=this.bytes;for(;r>=8;)e[this.at++]=255&o,o=Math.floor(o/256),r-=8;this.At=o,this.pending=r}G(t,n){for(let o=0;o<4;o++){const[r,e]=t[o];if(n>=e&&n-e<2**r)return this.write(2,o),void(r&&this.write(r,n-e))}throw new Error("U32 value out of range: "+n)}K(){this.pending&&(this.at+1>=this.bytes.length&&this.grow(),this.bytes[this.at++]=this.At,this.At=0,this.pending=0)}get ot(){return 8*this.at+this.pending}grow(t=0){const n=v.bytes+64;if(this.at+t+16>n)throw Object.assign(new Error("The encoded picture exceeds 16 MiB."),{code:"JXL_SIZE"});const o=new Uint8Array(Math.min(n,Math.max(2*this.bytes.length,this.at+t+16)));o.set(this.bytes.subarray(0,this.at)),this.bytes=o}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.At)}finish(){const t=this.at+(this.pending?1:0),n=this.bytes.slice(0,t);return this.pending&&(n[this.at]=this.At),n}}const k=[1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15],z=[2,4,3,2,2,4],B=[0,7,3,2,1,15],F=[0,0,0],R=3,Z=5,D=a(4),Y=Object.freeze({T:224,minLength:7,X:D}),Q=a(0),H=256,K=[a(0),a(1),a(2),a(3),a(4),a(4,1,1),a(5,1,1),a(2,0,1),a(3,0,1)],V=a(4,1,1);class W{constructor(t){this.ht=t,this.small=new Uint32Array(64*t),this.dt=Array.from({length:t},()=>null),this.ut=new Float64Array(t)}add(t,n){if(this.ut[t]++,n<64)return void this.small[64*t+n]++;const o=this.dt[t]||(this.dt[t]=new Map);o.set(n,(o.get(n)||0)+1)}wt(t,n,o=64){const r=new Uint32Array(o);for(const o of t){const t=64*o;for(let o=0;o<64;o++)this.small[t+o]&&(r[C(n,o)]+=this.small[t+o]);const e=this.dt[o];if(e)for(const[t,o]of e)r[C(n,t)]+=o}return r}yt(t,o){let r=O(this.wt(t,o));for(const e of t){const t=64*e;for(let e=o.U;e<64;e++)this.small[t+e]&&(r+=this.small[t+e]*(n(e)-o.A-o.m));const s=this.dt[e];if(s)for(const[t,e]of s)r+=e*(n(t)-o.A-o.m)}return r}}const $=[0,0,0],tt=13,nt=[0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,23,23,24,24,24,24,25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,28,29,29,29,29,30,30,30,30],ot=[0,0,31,62,62,93,93,93,93,123,123,123,123,152,152,152,152,152,152,152,152,180,180,180,180,180,180,180,180,180,180,180,180,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206],rt=[0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63].map(t=>(7&t)<<3|t>>3),et=(t,n,o)=>2*(ot[t]+nt[n])+o,st=(t,n)=>Object.assign(new Error(n),{code:t}),ct=Float64Array.from({length:64},(t,n)=>(n<8?Math.SQRT1_2:1)*Math.cos((2*(7&n)+1)*(n>>3)*Math.PI/16)/2),ft=Float64Array.from({length:64},(t,n)=>1.3**Math.max(0,5*Math.hypot(7&n,n>>3)/Math.sqrt(98)-1));export{_ as encodePhotoRGBA,v as LIMITS};
|
|
1
|
+
/*! Rapier JXL 2.1.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,o){let r,e;for(;!(r=t.next(e)).done;)e=yield(n+r.value)/o;return r.value}function n(t){return t>=0?2*t:2*-t-1}function o(t){return 31-Math.clz32(t)}function r(t){return t<=1?0:32-Math.clz32(t-1)}function e(t){if(0===t)return 0;const n=t<0?32768:0;if(!((t=Math.abs(t))<65520))throw new Error("half float out of range: "+t);let o=0,r=t;for(;r>=2;)r/=2,o++;for(;r<1;)r*=2,o--;o<-14?(r=16384*t,o=-15):r-=1;let e=Math.round(1024*r);return 1024===e&&(e=0,o++),n|o+15<<10|e}function s(t){if(t>Q.bytes)throw W("JXL_SIZE","The encoded picture exceeds 16 MiB.")}function i(t){try{return t()}catch(t){if(t instanceof RangeError&&!t.code)throw W("JXL_MEMORY","Not enough memory for this picture.");throw t}}function c(t,n){t.t([[9,1],[13,1],[18,1],[30,1]],n)}function f(t,n,o,r,e,{xyb:s=!1,orientation:i=1,colorSpace:f}={}){t.write(16,2815),t.write(1,0),c(t,o),t.write(3,0),c(t,n),t.write(1,0);const l=1!==i;t.write(1,l?1:0),l&&t.write(6,i-1),t.write(4,8),e?t.write(3,5):t.write(2,0),t.write(1,s?1:0),3===r&&"display-p3"===f?t.write(21,903568):3===r?t.write(1,1):t.write(15,14100),l&&t.write(1,1),t.write(2,0),t.write(1,1),t.o()}function l(t,n){t.write(n?7:5,0),t.write(11,1)}function a(t,n){const o=n.map(t=>t.length);!function(t,n){t.write(1,0),t.o();for(const o of n)t.t([[10,0],[14,1024],[22,17408],[30,4211712]],o);t.o()}(t,o);const r=t.finish(),e=r.length+o.reduce((t,n)=>t+n,0);s(e);const i=new Uint8Array(e);i.set(r);let c=r.length;for(const t of n)i.set(t,c),c+=t.length;return i}function u(t,n){const o=new Uint8Array(t.length),r=[];for(let n=0;n<t.length;n++)t[n]>0&&r.push(n);if(!r.length)return o;if(1===r.length)return o[r[0]]=1,o;for(let e=1;;e*=2){const s=r.map(n=>({w:Math.max(t[n],e),i:n,l:null,r:null})).sort((t,n)=>t.w-n.w||t.i-n.i),i=[];let c=0,f=0;const l=()=>c<s.length&&(f>=i.length||s[c].w<=i[f].w)?s[c++]:i[f++];for(;s.length-c+(i.length-f)>1;){const t=l(),n=l();i.push({w:t.w+n.w,i:-1,l:t,r:n})}const a=[[l(),0]];let u=0;for(;a.length;){const[t,n]=a.pop();t.i>=0?(o[t.i]=n,n>u&&(u=n)):a.push([t.l,n+1],[t.r,n+1])}if(u<=n)return o}}function h(t,n,o,r,e,s){const i=[];for(;i.push(r&e),r>>=s;)r--;for(let r=i.length-1;r>=0;r--)t.push(o),n.push(i[r])}function y(t,n){let o=0;for(let r=0;r<n;r++)o=o<<1|1&t,t>>=1;return o}function w(t){const n=new Uint32Array(17),o=new Uint32Array(17),r=new Uint16Array(t.length);for(const o of t)n[o]++;n[0]=0;for(let t=1,r=0;t<=16;t++)r=r+n[t-1]<<1,o[t]=r;for(let n=0;n<t.length;n++)t[n]&&(r[n]=y(o[t[n]]++,t[n]));return r}function d(t){const n=[];for(let o=0;o<t.length;o++)t[o]>0&&n.push(o);const o=n.length,r=n[o-1]+1||1,e=o<=4?new Uint8Array(r):u(t,15).subarray(0,r);let s=0;if(o<=4){n.sort((n,o)=>t[o]-t[n]||n-o),s=4===o&&t[n[0]]>t[n[2]]+t[n[3]]?1:0;const r=o<2?[0]:2===o?[1,1]:3===o?[1,2,2]:s?[1,2,3,3]:[2,2,2,2];n.forEach((t,n)=>{e[t]=r[n]}),n.sort((t,n)=>e[t]-e[n]||t-n)}return{u:r,M:e,p:w(e),A:o&&o<=4?n:null,m:s}}function M(t,n){if(n.u<=1)return;if(n.A){const r=o(n.u-1)+1;t.write(2,1),t.write(2,n.A.length-1);for(const o of n.A)t.write(r,o);return void(4===n.A.length&&t.write(1,n.m))}const r=n.M,e=[],s=[];let i=r.length-1;for(;i>0&&!r[i];)i--;let c=8;for(let t=0;t<=i;){const n=r[t];let o=1;for(;t+o<=i&&r[t+o]===n;)o++;let f=o;if(n&&n!==c&&(e.push(n),s.push(0),f--,c=n),f<3)for(let t=0;t<f;t++)e.push(n),s.push(0);else h(e,s,n?16:17,f-3,n?3:7,n?2:3);t+=o}const f=new Uint32Array(18);for(const t of e)f[t]++;let l=0;for(const t of f)t&&l++;1===l&&(f[e[0]?0:1]=f[e[0]]);const a=u(f,5),y=w(a);let d=18;for(;d>0&&!a[tt[d-1]];)d--;t.write(2,0);for(let n=0;n<d;n++){const o=a[tt[n]];t.write(nt[o],ot[o])}for(let n=0;n<e.length;n++){const o=e[n];t.write(a[o],y[o]),16===o?t.write(2,s[n]):17===o&&t.write(3,s[n])}}function p(t,n=0,o=0){return{split:t,U:n,I:o,S:1<<t}}function A(t,n,o=15){t.write(r(o+1),n.split),n.split!==o&&(t.write(r(n.split+1),n.U),t.write(r(n.split-n.U+1),n.I))}function g(t,n,r){if(n<t.S)return r[0]=n,r[1]=0,void(r[2]=0);const e=o(n),s=n-(1<<e),i=e-t.U-t.I;r[0]=t.S+(e-t.split<<t.U+t.I|s>>e-t.U<<t.I|s&(1<<t.I)-1),r[1]=i,r[2]=n>>t.I&(1<<i)-1}function b(t,n,o,r=0){g(t,n,rt),o[r+rt[0]]++}function m(t,n,o,r,e=0){g(o,r,rt);const s=e+rt[0];t.write(n.M[s],n.p[s]),rt[1]&&t.write(rt[1],rt[2])}function U(t,n){let o=0;for(const t of n)o=Math.max(o,t);const e=o?r(o+1):0;if(e<=3){if(t.write(1,1),t.write(2,e),e)for(const o of n)t.write(e,o);return}t.write(1,0),t.write(1,0);const s=p(8),i=p(4),c=n.length>=64,f=new Uint32Array(c?257:o+1),l=[];for(let t=0;t<n.length;){let o=1;for(;c&&t+o<n.length&&n[t+o]===n[t];)o++;if(o>=8)l.push([n[t],o-1]),f[n[t]]++,b(i,o-1-7,f,224),t+=o;else{for(let r=0;r<o;r++)l.push([n[t],0]),f[n[t]]++;t+=o}}const a=d(f);if(!c){I(t,{L:new Uint8Array(1),J:[{config:s,code:a}]});for(const[n]of l)m(t,a,s,n);return}const u=new Uint32Array(1);u[0]=1,I(t,{T:{X:224,minLength:7,N:i},L:new Uint8Array([1,0]),J:[{config:p(0),code:d(u)},{config:s,code:a}]});for(const[n,o]of l)m(t,a,s,n),o&&m(t,a,i,o-7,224)}function I(t,{T:n=null,L:r,J:e}){t.write(1,n?1:0),n&&(t.t([[0,224],[0,512],[0,4096],[15,8]],n.X),t.t([[0,3],[0,4],[2,5],[8,9]],n.minLength),A(t,n.N,8)),r.length>1&&U(t,r),t.write(1,1);for(const n of e)A(t,n.config,15);for(const n of e){const r=n.code.u-1;if(r){const n=o(r);t.write(1,1),t.write(4,n),t.write(n,r-(1<<n))}else t.write(1,0)}for(const n of e)M(t,n.code)}function x(t,n=0,o=1){return{_:t,offset:n,C:o,context:-1}}function S(t){return function(t,n){const o=(r,e)=>{if(r===e)return n?t[r].O:t[r];const s=r+e>>1;return function(t,n,o,r){return{P:t,F:n,left:o,right:r}}(n,n?t[s].q:s,o(s+1,e),o(r,s))};return o(0,t.length-1)}(t,0)}function E(t,o){const r=[o],e=[],s=[];for(const t of r){if(t.left){e.push(t.P+1,n(t.F)),r.push(t.left,t.right);continue}t.context=s.length,s.push(t);const o=1===t.C?0:31-Math.clz32(t.C&-t.C);e.push(0,t._,n(t.offset),o,(t.C>>o)-1)}const i=new Uint32Array(64);for(const t of e)b(ft,t,i);const c=d(i);I(t,{L:new Uint8Array(6),J:[{config:ft,code:c}]});for(const n of e)m(t,c,ft,n);return s}function L(t,n){const o=[[3,0],[6,8],[10,72],[13,1096]];if("rct"===n.type)t.write(2,0),t.t(o,n.G),t.t([[0,6],[2,0],[4,2],[6,10]],n.j??6);else if("palette"===n.type)t.write(2,1),t.t(o,n.G),t.t([[0,1],[0,3],[0,4],[13,1]],n.k),t.t([[8,0],[10,256],[12,1280],[16,5376]],n.B),t.t([[0,0],[8,1],[10,257],[16,1281]],n.R??0),t.write(4,n._??0);else{if("squeeze"!==n.type)throw new Error("unknown transform "+n.type);{t.write(2,2);const r=n.Z??[];t.t([[0,0],[4,1],[6,9],[8,41]],r.length);for(const n of r)t.write(1,n.D?1:0),t.write(1,n.Y?1:0),t.t(o,n.G),t.t([[0,1],[0,2],[0,3],[4,4]],n.k)}}}function J(t,{H:n=!0,K:o=[]}={}){t.write(1,n?1:0),t.write(1,1),t.t([[0,0],[0,1],[4,2],[8,18]],o.length);for(const n of o)L(t,n)}function T(t,n,o,r=t=>t.context){const e=new Uint8Array(n.length+1);for(const t of n)e[t.context]=r(t)+1;const s=new Uint32Array(2);s[1]=1;const i=[{config:ft,code:d(s)}],c=Math.max(...e);for(let t=0;t<c;t++)i.push({config:ft,code:d(o[t])});return I(t,{T:ct,L:e,J:i}),i}function X(t,o,r,e,s,i){const c=i._,f=i.offset,l=i.C,a=ft,u=it;let h=0;const y=(n,r=a,e=0)=>{t?m(t,o,r,n,e):b(r,n,o,e)},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}},d=(t,o)=>{const e=r[t];let s;1===l?s=e-o-f:(s=Math.round((e-o-f)/l),r[t]=o+f+s*l),0!==s?(w(),y(n(s))):h++};for(let t=0,n=0;t<s;t++)for(let o=0;o<e;o++,n++){let s;if(0===c)s=0;else{const i=o?r[n-1]:t?r[n-e]:0,f=t?r[n-e]:i;if(1===c)s=i;else if(2===c)s=f;else if(3===c)s=(i+f)/2|0;else{const l=i+f-(o&&t?r[n-e-1]:i);if(5===c){const t=i<f?i:f,n=i<f?f:i;s=l<t?t:l>n?n:l}else{if(4!==c)throw new Error("predictor "+c+" is not coded here");s=Math.abs(l-i)<Math.abs(l-f)?i:f}}}d(n,s)}w()}function N(t,n,o,{palette:r=!0}={}){const e=n*o;let s=!0,i=!0;for(let n=0,o=0;o<e&&(255===t[n+3]||(s=!1,i))&&(t[n]===t[n+1]&&t[n]===t[n+2]||(i=!1,s));o++,n+=4);const c=i?1:3,f=!s,l=c+(f?1:0),a=n=>i?f?t[n]+256*t[n+3]:t[n]:t[n]+256*t[n+1]+65536*t[n+2]+(f?16777216*t[n+3]:0),u=new Map;let h=null;for(let t=0,n=0;r&&n<e;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,o=t=>(.299*n(t,0)+.587*n(t,1)+.114*n(t,2)+.01)*(4===l?n(t,3):1);t.sort((t,n)=>o(t)-o(n));const r=new Map([[0,0]]);t.forEach((t,n)=>r.set(t,n+1)),h={colours:[0,...t],index:r,key:a,byte:n}}return{colour:c,alpha:f,channels:l,palette:h}}function*_(t,n,o,r,e){const{channels:s,palette:i}=r,c=function(t,n,o=256){const r=Math.ceil(t/o),e=Math.ceil(n/o);return{V:r,W:e,$:Math.ceil(t/(8*o)),tt:Math.ceil(n/(8*o)),nt:1===r&&1===e}}(n,o),u=i?2:s,h=Array.from({length:u},()=>x(st)),y=S(h),w=Array.from({length:u},()=>new Int16Array(65536)),p=(o,r,e,c)=>{for(let f=0;f<c;f++){let c=4*((r+f)*n+o),l=f*e;for(let n=0;n<e;n++,c+=4,l++)if(i)w[0][l]=i.index.get(i.key(c));else if(s>=3){const n=t[c],o=t[c+1],r=t[c+2],e=n-r,i=r+(e>>1),f=o-i;w[0][l]=i+(f>>1),w[1][l]=e,w[2][l]=f,4===s&&(w[3][l]=t[c+3])}else w[0][l]=t[c],2===s&&(w[1][l]=t[c+3])}};let A=null;if(i){const t=i.colours.length;A=new Int16Array(t*s),i.colours.forEach((n,o)=>{for(let r=0;r<s;r++)A[r*t+o]=i.byte(n,r)})}const g=t=>h[i?c.nt?1:0:t],b=i?1:s,m=c.V*c.W,U=2*m,I=(t,r)=>{const e=t%c.V*$,s=(t/c.V|0)*$,i=Math.min($,n-e),f=Math.min($,o-s);p(e,s,i,f),r(i,f)};let L=0;if(!i){const t=t=>{const n=d(t),o=new V(128);M(o,n);let r=o.ot;for(let o=0;o<t.length;o++)t[o]&&(r+=t[o]*(n.M[o]+Math.max(0,o<224?o-1:o-236)));return r},r=Math.min(n,32),e=Math.min(o,32),i=[st,et].map(t=>({_:t,rt:h.map(()=>new Uint32Array(257))}));for(const t of[0,.5,1]){p(Math.floor((n-r)*t),Math.floor((o-e)*t),r,e);for(const t of i)for(let n=0;n<s;n++)X(null,t.rt[n],w[n],r,e,x(t._))}h.forEach((n,o)=>{const r=i.map(n=>t(n.rt[o])),e=r[1]<r[0]?1:0;n._=i[e]._})}const N=i?[{type:"palette",G:0,k:s,B:i.colours.length}]:s>=3?[{type:"rct",G:0,j:6}]:[],_=h.map(()=>new Uint32Array(257)),C=t=>_[h.indexOf(t)];A&&X(null,C(h[0]),A,i.colours.length,s,h[0]);for(let t=0;t<m;t++)I(t,(t,n)=>{for(let o=0;o<b;o++)X(null,C(g(o)),w[o],t,n,g(o))}),yield++L/U;const O=new V(256);f(O,n,o,r.colour,r.alpha,{colorSpace:e}),function(t,{alpha:n,shift:o=1}){t.write(9,8),n&&t.write(2,0),t.write(2,o),l(t,n)}(O,{alpha:r.alpha});const P=new V(4096);P.write(1,1),P.write(1,1);const F=E(P,y),q=T(P,F,_,t=>h.indexOf(t)),G=t=>q[h.indexOf(t)+1].code;J(P,{H:!0,K:N}),A&&X(P,G(h[0]),A,i.colours.length,s,h[0]);const v=[];if(c.nt)I(0,(t,n)=>{for(let o=0;o<b;o++)X(P,G(g(o)),w[o],t,n,g(o))}),yield 1,v.push(P.finish());else{v.push(P.finish());for(let t=0;t<c.$*c.tt+1;t++)v.push(new Uint8Array(0));for(let t=0;t<m;t++)I(t,(t,n)=>{const o=new V(t*n*b+64);J(o,{H:!0,K:[]});for(let r=0;r<b;r++)X(o,G(g(r)),w[r],t,n,g(r));v.push(o.finish())}),yield++L/U}return a(O,v)}function C(t,n,o,r){let e=0;return e+=t[n]*lt[r],e+=t[n+o]*lt[r+1],e+=t[n+2*o]*lt[r+2],e+=t[n+3*o]*lt[r+3],e+=t[n+4*o]*lt[r+4],e+=t[n+5*o]*lt[r+5],e+=t[n+6*o]*lt[r+6],e+=t[n+7*o]*lt[r+7],e}function O(t,n,o){const r=new Float64Array(192),e=new Float64Array(64),s=new Float64Array(192);return(i,c)=>{for(let e=0;e<8;e++)for(let s=0;s<8;s++){const f=4*(Math.min(o-1,8*c+e)*n+Math.min(n-1,8*i+s)),l=t[f],a=t[f+1],u=t[f+2],h=8*e+s;r[h]=.299*l+.587*a+.114*u-128,r[64+h]=-.168735892*l-.331264108*a+.5*u,r[128+h]=.5*l-.418687589*a-.081312411*u}for(let t=0;t<3;t++){for(let n=0;n<8;n++)for(let o=0;o<8;o++)e[8*n+o]=C(r,64*t+8*n,1,8*o);for(let n=0;n<8;n++)for(let o=0;o<8;o++)s[64*t+8*n+o]=C(e,o,8,8*n)}return s}}function*P(t,n,o,r,e){const s=Math.ceil(n/8),i=Math.ceil(o/8),c=r>=30?.1+.09*(100-r):53/3e3*r*r-1.15*r+25,f=[0,1,2].map(t=>({h:1,v:1,stride:s,rows:i,quant:Int32Array.from(at,(n,o)=>Math.max(1,Math.round(16*c*(t?18:10)*(o?n:.25)))),coeffs:new Int16Array(s*i*64)})),l=O(t,n,o),a=(t,n)=>{for(let o=t;o<n;o++)for(let t=0;t<s;t++){const n=l(t,o),r=64*(o*s+t);for(let t=0;t<3;t++)for(let o=0;o<64;o++)f[t].coeffs[r+o]=Math.round(16*n[64*t+o]/f[t].quant[o])}};for(let t=0;t<i;t+=32)a(t,Math.min(i,t+32)),yield Math.min(i,t+32)/i;let u=null;for(let n=3;n<t.length;n+=4)if(255!==t[n]){u=t;break}return{width:n,height:o,components:f,quantScale:16,ycbcr:!0,orientation:1,alpha:u,colorSpace:e}}function F(n,o,r,c,f){const{quality:l,colorSpace:a}=function(t={},n=100){if(null===t||"object"!=typeof t)throw W("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 W("JXL_INPUT","Quality is a number from 1 to 100.");const o=void 0===t.colorSpace?"srgb":t.colorSpace;if("srgb"!==o&&"display-p3"!==o)throw W("JXL_INPUT","The colour space is srgb or display-p3.");return{quality:n,colorSpace:o}}(c,90),u=function(t={}){if(null===t||"object"!=typeof t)throw W("JXL_INPUT","Options are an object.");const n=void 0===t.effort?1:t.effort;if(!Number.isInteger(n)||n<1||n>9)throw W("JXL_INPUT","Effort is a whole number from 1 to 9.");return n}(c);return function(t,n,o,r){if(function(t,n,o=Q){if(!Number.isInteger(t)||!Number.isInteger(n)||t<1||n<1)throw W("JXL_INPUT","A picture is at least one pixel wide and high, in whole pixels.");if(t>o.edge||n>o.edge)throw W("JXL_DIMENSIONS","A picture is at most "+o.edge+" pixels on a side.");if(t*n>o.pixels)throw W("JXL_DIMENSIONS","A picture is at most "+o.pixels.toLocaleString("en-US")+" pixels.")}(n,o,r),!(t instanceof Uint8Array||t instanceof Uint8ClampedArray))throw W("JXL_INPUT","Pixels are a Uint8Array or Uint8ClampedArray of RGBA bytes.");if(t.length!==n*o*4)throw W("JXL_INPUT","Pixels are width * height * 4 bytes: straight (not premultiplied) RGBA, row by row.")}(n,o,r,H),function(t){const n=function*(){let o,r;for(;!(o=i(()=>t.next(n.hurry))).done;)yield r=o.value;return r<1&&(yield 1),n.bytes=(s((e=o.value).length),e);var e}();return n.bytes=null,n.hurry=!1,n}(function*(n,o,r,s,i,c,f){if(s>=100)return yield*function*(n,o,r,{shape:e=N(n,o,r),colorSpace:s}={}){let i,c;const f=e.palette?[e,{...e,palette:null}]:[e];for(let e=0;e<f.length;e++)try{const c=yield*t(_(n,o,r,f[e],s),e,f.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}(n,o,r,{colorSpace:i});if(c<5)return yield*t(f(yield*t(P(n,o,r,s,i),0,2),c),1,2);const l=yield*t(P(n,o,r,s,i),0,4);let a=yield*t(f(l,4),1,4);if(yield.5)return a;try{const o=yield*t(function*(t,n,o=0){const{width:r,height:s,components:i,quantScale:c}=n,f=i[0].stride,l=i[0].rows,a=f*l,u=ut.length;if(t.byteLength+i.reduce((t,n)=>t+n.coeffs.byteLength,0)+Math.max(a*(10*u+2)+o,7*H.bytes)>wt)return null;const h=new Float64Array(a*u),y=new Uint16Array(a*u),w=O(t,r,s),d=i.map(t=>t.quant),M=i.map(t=>t.coeffs),p=ut.map(t=>d.map(n=>Float64Array.from(n,n=>n*function(t){const n=e(t);let o=1+(1023&n)/1024,r=(n>>10)-15;for(;r<0;)o/=2,r++;for(;r>0;)o*=2,r--;return o}(4/(2040*c))*8*255/t))),A=new Int16Array(192),g=new Float64Array(3),b=new Int32Array(6),m=new Float64Array(6),U=new Float64Array(6);let I=0,x=0;const S=(t,n,o)=>{let r=0,e=0;const s=ht[o]*d[0][1]*d[0][1]/(c*c);for(let i=1;i<64;i++){if(!o){for(let r=0;r<3;r++){const s=M[r][64*n+i];g[r]=dt(s,r)*p[o][r][i]-t[64*r+i],s&&(e+=2+2*(32-Math.clz32(Math.abs(s))))}r+=Mt(g[0],g[1],g[2]);continue}for(let n=0;n<3;n++){const r=t[64*n+i],e=p[o][n][i],s=Math.floor(r/e);for(let t=0;t<2;t++){const o=s+t;b[2*n+t]=o,U[2*n+t]=o?2+2*(32-Math.clz32(Math.abs(o))):0,m[2*n+t]=o<-32768||o>32767?1/0:dt(o,n)*e-r}}let c=0,f=1/0,l=0;for(let t=0;t<8;t++){const n=Mt(m[1&t],m[2+(t>>1&1)],m[4+(t>>2)]),o=n+s*(U[1&t]+U[2+(t>>1&1)]+U[4+(t>>2)]);o<f&&(f=o,c=t,l=n)}if(f===1/0)return{error:1/0,rate:65535};r+=l;for(let t=0;t<3;t++){const n=b[2*t+(c>>t&1)];A[64*t+i]=n,n&&(e+=2+2*(32-Math.clz32(Math.abs(n))))}}return{error:r,rate:e}};for(let t=0;t<l;t++)for(let n=0;n<f;n++){const o=t*f+n,r=w(n,t);for(let t=0;t<u;t++){const n=S(r,o,t),e=o*u+t;h[e]=n.error,y[e]=n.rate,t||(I+=n.error,x+=n.rate)}if(((o+1)%1024==0||o+1===a)&&(yield(o+1)/(3*a)))return null}const E=new Uint8Array(a);let L=0;const J=function*(t,n){let o=0,r=0;for(let e=0;e<a;e++){const s=e*u;let i=0,c=h[s]+t*y[s];for(let n=1;n<u;n++){const o=h[s+n]+t*y[s+n];o<c&&(c=o,i=n)}if(o+=h[s+i],r+=y[s+i],n&&(E[e]=i),((e+1)%1024==0||e+1===a)&&(yield 1/3+(L+(e+1)/a)/147))return null}return L++,{error:o,rate:r}};let T=0,X=Math.max(1,I/Math.max(1,x));for(let t=0;t<24;t++){const t=yield*J(X,!1);if(!t)return null;if(t.error>I)break;X*=2}for(let t=0;t<24;t++){const t=(T+X)/2,n=yield*J(t,!1);if(!n)return null;n.error<=I?T=t:X=t}const N=yield*J(T,!0);if(!N||N.error>I||N.rate>=x||!E.some(t=>t))return null;const _=new Uint8Array(a);for(let t=0;t<l;t++)for(let n=0;n<f;n++){const o=t*f+n,r=E[o];if(_[o]=ut[r],r){S(w(n,t),o,r);for(let t=0;t<3;t++)for(let n=1;n<64;n++)M[t][64*o+n]=A[64*t+n]}if(((o+1)%1024==0||o+1===a)&&(yield 2/3+(o+1)/(3*a)))return null}return{...n,quantFieldBase:4,quantFields:_,reconstructionError:{baseline:I,candidate:N.error}}}(n,l,a.byteLength),2,4);o&&(a=yield*t(f(o,4,a),3,4))}catch(t){if((!(t instanceof RangeError)||t.code)&&"JXL_SIZE"!==t.code)throw t}return a}(n,o,r,l,a,u,f))}function q(t,n){return g(t,n,bt),bt[0]}function G(t){let n=0;for(t>=2&&t<4294967296&&(n=31-Math.clz32(t),t*=mt[n]);t>=1.4142135623730951;)t/=2,n++;for(;t<.7071067811865476;)t*=2,n--;const o=(t-1)/(t+1),r=o*o;let e=o,s=o;for(let t=3;t<30;t+=2)s+=(e*=r)/t;return n+2.885390081777927*s}function v(t){let n=0,o=0;for(const o of t)n+=o;for(const r of t)r&&(o+=r*G(n/r));return o}function j(t,{maxClusters:n=48,newClusterCost:o=320}={}){const r=[];for(let n=0;n<t.et;n++)t.st[n]>0&&r.push(n);r.sort((n,o)=>t.st[o]-t.st[n]);const e=[];for(const s of r){const r=t.it([s],At),i=v(r);let c=-1,f=1/0;for(let t=0;t<e.length;t++){const n=e[t],o=new Uint32Array(64);for(let t=0;t<64;t++)o[t]=n.rt[t]+r[t];const s=v(o)-n.ct-i;s<f&&(f=s,c=t)}if(c<0||e.length<n&&f>o)e.push({et:[s],rt:r,ct:i});else{const t=e[c];t.et.push(s);for(let n=0;n<64;n++)t.rt[n]+=r[n];t.ct=v(t.rt)}}e.length||e.push({et:[],rt:new Uint32Array(64),ct:0});const s=new Uint8Array(t.et);let i=2*t.et;const c=e.map((n,o)=>{for(const t of n.et)s[t]=o;let r=pt[0],e=1/0;for(const o of pt){const s=t.ft(n.et,o);s<e&&(e=s,r=o)}const c=d(t.it(n.et,r,128));return i+=e+3*c.u+40,{config:r,code:c}});return{L:s,J:c,write:(t,n,o)=>{const r=c[s[n]];m(t,r.code,r.config,o)},ct:i}}function k(t,n="JXL_JPEG"){return Object.assign(new Error("JPEG: "+t),{code:n})}function z(t,n,o){const r=[];if(n>0){const o=new Uint32Array(2048);let e=0;for(const n of t)o[Math.min(2047,Math.max(0,n+1024))]++,e++;let s=0,i=e/(n+1);for(let t=0;t<2048&&r.length<n;t++)s+=o[t],s>i&&(r.push(t-1025),i=e*(r.length+1)/(n+1))}const e=r.length+1,s=new Uint8Array(39*e);for(let t=0;t<e;t++)for(let n=0;n<It;n++)s[(0+n)*e+t]=t,s[(13+n)*e+t]=o?e:e+(t>>1),s[(26+n)*e+t]=o?e:e+(e-1>>1)+1+(t>>1);let i=0;for(const t of s)i=Math.max(i,t+1);return{thresholds:r,lt:e,map:s,ut:i,ht:t=>{let n=0;for(const o of r)t>o&&n++;return n},yt:(t,n)=>s[(t<2?1^t:2)*It*e+n],wt:(t,n)=>(Math.min(t,64)<8?Math.min(t,64):4+(Math.min(t,64)>>1))*i+n,dt:t=>37*i+458*t,et:495*i}}function B(t,n,o){const r=n.map(()=>x(o)),e=r.map(()=>new Uint32Array(257));n.forEach((t,n)=>X(null,e[n],t.data,t.w,t.h,r[n])),J(t,{H:!1,K:[]});const s=E(t,S(r)),i=T(t,s,e,t=>r.indexOf(t));n.forEach((n,o)=>X(t,i[o+1].code,n.data,n.w,n.h,r[o]))}function*R(t,o={}){const{width:i,height:c,components:u,alpha:h}=t,y=1===u.length,w=t.quantScale||1;let M=t.quantFieldBase||1;for(;M/(2040*w)<1/16384;)M*=2;const A=t.ycbcr||y,g=y?[0,0,0]:A?[1,0,2]:[0,1,2],x=g.map(t=>u[t]),S=o.orders?g.map(t=>o.orders[t].map(t=>Et[t])):[Et,Et,Et],E=t=>1===t?0:2===t?1:-1,L=x.map(t=>E(t.h)),J=x.map(t=>E(t.v));if(L.includes(-1)||J.includes(-1))throw k("sampling factors other than one or two");const T=Math.max(...L),X=Math.max(...J),N=t=>T-L[t],_=t=>X-J[t];if(!A&&(T||X))throw k("an RGB JPEG with subsampling");const C=Math.ceil(i/(8<<T))<<T,O=Math.ceil(c/(8<<X))<<X,P=Math.ceil(i/$),F=Math.ceil(c/$),q=P*F,G=Math.ceil(C/256),v=G*Math.ceil(O/256),R=1===q,Z=(t,n,o)=>{const r=x[t];return y&&1!==t?-1:64*(o*r.stride+n)},D=t=>{let n=1024;for(;t%n;)n>>=1;return n},Y=x.map(t=>A?1:t.quant[0]/D(t.quant[0])),Q=x.map(t=>A?0:1024/D(t.quant[0])),H=new Int32Array(C*O);for(let t=0;t<O;t++)for(let n=0;n<C;n++)H[t*C+n]=x[1].coeffs[Z(1,n,t)]*Y[1]+Q[1];const K=x[1].quant,W=(K[8]+K[16]+K[24]+K[32]+K[40])/w,tt=C*O,nt=tt<256?0:Math.max(1,Math.min(7,r(tt)-r(W)-7));let ot=z(H,nt,y);const rt=new V(256);if(f(rt,i,c,y?1:3,!!h,{orientation:t.orientation,colorSpace:t.colorSpace}),rt.write(1,0),rt.write(2,0),rt.write(1,0),rt.write(2,2),rt.write(8,111),rt.write(1,A?1:0),A)for(let t=0;t<3;t++)rt.write(2,0===L[t]&&0===J[t]?0:1===L[t]&&1===J[t]?1:1===L[t]?2:3);rt.write(2,0),h&&rt.write(2,0),l(rt,h);const et=[0,1,2].map(()=>new Int32Array(1024)),it=(t,o)=>{const r=t%P*32,e=32*(t/P|0),s=Math.min(32,C-r),i=Math.min(32,O-e);for(let t=0;t<i;t++)for(let i=0;i<s;i++)for(const s of[1,0,2]){const c=N(s),f=_(s),l=i>>c,a=t>>f;if(l<<c!==i||a<<f!==t)continue;const u=Z(s,(r>>c)+l,(e>>f)+a),h=x[s].coeffs;let y=0;if(u>=0)for(let t=1;t<64;t++)h[u+t]&&y++;const w=et[s],d=0===l?0===a?32:w[32*(a-1)]:0===a?w[32*a+l-1]:w[32*(a-1)+l]+w[32*a+l-1]+1>>1;w[32*a+l]=y;const M=ot.yt(s,ot.ht(H[(e+t)*C+r+i]));o(ot.wt(d,M),y);const p=ot.dt(M);let A=y>4?0:1,g=y;for(let t=1;t<64&&g;t++){const r=h[u+S[s][t]];o(p+Lt(g,t,A),n(r)),A=r?1:0,g-=A}}},ct=(nt>0?3:2)*q+v;let ft=0;const lt=function*(t){ot=t;const n=new gt(t.et);for(let t=0;t<q;t++)it(t,(t,o)=>n.add(t,o)),yield++ft/ct;return(o.coding||j)(n,o.clusters)};let at=yield*lt(ot);if(nt>0){const t=ot,n=z(H,0,y),o=yield*lt(n);o.ct<=at.ct?at=o:ot=t}const ut=Array.from({length:R?1:2+v+q},()=>null),ht=t=>ut[R?0:t]||(ut[R?0:t]=new V(4096)),yt=new Uint32Array(ut.length);let wt=0;const dt=t=>{t=R?0:t;const n=Math.ceil(ut[t].ot/8);wt+=n-yt[t],yt[t]=n,s(wt)},Mt=ht(0);Mt.write(1,0);const pt=(t,n)=>{const o=t*$,r=n*$,e=Math.min($,i-o),s=Math.min($,c-r),f=new Int32Array(e*s);for(let t=0;t<s;t++)for(let n=0;n<e;n++)f[t*e+n]=h[4*((r+t)*i+o+n)+3];return{w:e,h:s,data:f}};for(let t=0;t<3;t++)Mt.write(16,e(x[t].quant[0]/Y[t]/(2040*w)*128));Mt.write(2,3),Mt.write(16,57343),Mt.write(2,1),Mt.write(5,0),Mt.write(1,0),Mt.write(4,0),Mt.write(4,ot.thresholds.length);for(const t of ot.thresholds)Mt.t([[4,0],[8,16],[16,272],[32,65808]],n(t));Mt.write(4,0),Mt.write(4,0),U(Mt,ot.map),Mt.write(1,0),Mt.write(2,0),Mt.write(16,0),Mt.write(16,0),Mt.write(8,128),Mt.write(8,128),Mt.write(1,0),h&&B(Mt,[R?pt(0,0):{w:0,h:0,data:new Int32Array(0)}],st),dt(0);for(let n=0;n<v;n++){const o=ht(1+n),e=n%G*256,s=256*(n/G|0),i=Math.min(256,C-e),c=Math.min(256,O-s);o.write(2,0),B(o,[1,0,2].map(t=>{const n=i>>N(t),o=c>>_(t),r=new Int32Array(n*o),f=Y[t],l=Q[t];for(let i=0;i<o;i++)for(let o=0;o<n;o++){const c=Z(t,(e>>N(t))+o,(s>>_(t))+i);r[i*n+o]=c<0?0:x[t].coeffs[c]*f+l}return{w:n,h:o,data:r}}),st);const f=i*c,l=r(f);l&&o.write(l,f-1);const a=i+7>>3,u=c+7>>3,h=new Int32Array(2*f).fill(M-1,f);if(t.quantFields)for(let n=0;n<c;n++)for(let o=0;o<i;o++)h[f+n*i+o]=t.quantFields[(s+n)*C+e+o]-1;B(o,[{w:a,h:u,data:new Int32Array(a*u)},{w:a,h:u,data:new Int32Array(a*u)},{w:f,h:2,data:h},{w:i,h:c,data:new Int32Array(f)}],M>1?st:0),dt(1+n),yield++ft/ct}const At=ht(1+v);At.write(1,0),At.write(3,7),At.write(16,e(M/(2040*w))),B(At,[0,1,2].map(t=>{const n=new Int32Array(64),o=x[t].quant;for(let t=0;t<8;t++)for(let r=0;r<8;r++)n[8*r+t]=o[8*t+r];return{w:8,h:8,data:n}}),st);for(let t=1;t<17;t++)At.write(3,0);if(q>1&&At.write(r(q),0),o.orders){At.t([[0,95],[0,19],[0,0],[13,0]],1);const t=[];for(const n of g){const r=Array.from({length:64},(t,n)=>n),e=o.orders[n].map(t=>{const n=r.indexOf(t);return r.splice(n,1),n});let s=64;for(;s>1&&!e[s-1];)s--;t.push(s-1,...e.slice(1,s))}const n=p(0),r=new Uint32Array(64);for(const o of t)b(n,o,r);const e=d(r);I(At,{L:new Uint8Array(8),J:[{config:n,code:e}]});for(const o of t)m(At,e,n,o)}else At.write(2,2);at.writeHistograms?at.writeHistograms(At):I(At,{L:at.L,J:at.J}),dt(1+v);for(let t=0;t<q;t++){const n=ht(2+v+t);it(t,(t,o)=>at.write(n,t,o)),at.flush&&at.flush(n),h&&!R&&B(n,[pt(t%P,Math.floor(t/P))],st),dt(2+v+t),yield++ft/ct}return a(rt,function(t){return t.map(t=>t?t.finish():new Uint8Array(0))}(ut))}function*Z(t,n,o){if(n<3&&!o)return yield*R(t);let r=o;try{const o=R(t);let e,s;for(;!(e=o.next()).done;)if(s=yield e.value/2,s&&r&&e.value<1)return o.return(),r;if((!r||e.value.length<r.length)&&(r=e.value),s||n<3)return r;const i=n<4?1:3,c=R(t,{clusters:{maxClusters:32,newClusterCost:160}});for(;!(e=c.next()).done;)if(s=yield.5+e.value/(2*i),s&&e.value<1)return c.return(),r;if(e.value.length<r.length&&(r=e.value),s||n<4)return r;const f=function*(t){const n=Ut.map(t=>(7&t)<<3|t>>3),o=t.map(()=>new Uint32Array(64)),r=t.reduce((t,n)=>t+n.coeffs.length,0);let e=0;for(let s=0;s<t.length;s++){const{coeffs:i}=t[s],c=o[s];for(let t=0;t<i.length;t+=65536){const o=Math.min(t+65536,i.length);for(let r=t;r<o;r+=64)for(let t=1;t<64;t++)i[r+n[t]]&&c[t]++;if(e+=o-t,yield e/r)return null}}return o.map(t=>[0,...Array.from({length:63},(t,n)=>n+1).sort((n,o)=>Math.floor(t[o]/8)-Math.floor(t[n]/8)||n-o)])}(t.components);for(;!(e=f.next()).done;)if(yield.5+(1+e.value)/6)return f.return(),r;const l=R(t,{orders:e.value});for(;!(e=l.next()).done;)if(s=yield.5+(2+e.value)/6,s&&e.value<1)return l.return(),r;return e.value.length<r.length?e.value:r}catch(t){if(!r||(!(t instanceof RangeError)||t.code)&&"JXL_SIZE"!==t.code)throw t;return r}}function D(t,n,o,r){return function(t){let n;for(;!(n=t.next()).done;);return n.value}(Y(t,n,o,r))}function Y(t,n,o,r){return F(t,n,o,r,Z)}const Q=Object.freeze({bytes:16777216,pixels:24e6,edge:16384}),H=Object.freeze({bytes:16777216,pixels:4e7,edge:16384}),K=[1];for(let t=1;t<=32;t++)K.push(2*K[t-1]);class V{constructor(t=4096){this.bytes=new Uint8Array(t),this.at=0,this.Mt=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 o=this.Mt+n*(1<<this.pending),r=this.pending+t;this.at+5>=this.bytes.length&&this.grow();const e=this.bytes;for(;r>=8;)e[this.at++]=255&o,o=Math.floor(o/256),r-=8;this.Mt=o,this.pending=r}t(t,n){for(let o=0;o<4;o++){const[r,e]=t[o];if(n>=e&&n-e<K[r])return this.write(2,o),void(r&&this.write(r,n-e))}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.Mt,this.Mt=0,this.pending=0)}get ot(){return 8*this.at+this.pending}grow(t=0){const n=Q.bytes+64;if(this.at+t+16>n)throw Object.assign(new Error("The encoded picture exceeds 16 MiB."),{code:"JXL_SIZE"});const o=new Uint8Array(Math.min(n,Math.max(2*this.bytes.length,this.at+t+16)));o.set(this.bytes.subarray(0,this.at)),this.bytes=o}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.Mt)}finish(){const t=this.at+(this.pending?1:0),n=this.bytes.slice(0,t);return this.pending&&(n[this.at]=this.Mt),n}}const W=(t,n)=>Object.assign(new Error(n),{code:t}),$=256,tt=[1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15],nt=[2,4,3,2,2,4],ot=[0,7,3,2,1,15],rt=[0,0,0],et=3,st=5,it=p(4),ct=Object.freeze({X:224,minLength:7,N:it}),ft=p(0),lt=Float64Array.of(.3535533905932738,.3535533905932738,.3535533905932738,.3535533905932738,.3535533905932738,.3535533905932738,.3535533905932738,.3535533905932738,.4903926402016152,.4157348061512726,.27778511650980114,.09754516100806417,-.0975451610080641,-.277785116509801,-.4157348061512727,-.4903926402016152,.46193976625564337,.19134171618254492,-.19134171618254486,-.46193976625564337,-.4619397662556434,-.19134171618254517,.191341716182545,.46193976625564326,.4157348061512726,-.0975451610080641,-.4903926402016152,-.2777851165098011,.2777851165098009,.4903926402016152,.09754516100806439,-.41573480615127256,.3535533905932738,-.35355339059327373,-.35355339059327384,.3535533905932737,.35355339059327384,-.35355339059327334,-.35355339059327356,.3535533905932733,.27778511650980114,-.4903926402016152,.09754516100806415,.4157348061512728,-.41573480615127256,-.09754516100806401,.4903926402016153,-.27778511650980076,.19134171618254492,-.4619397662556434,.46193976625564326,-.19134171618254495,-.19134171618254528,.46193976625564337,-.4619397662556432,.19134171618254478,.09754516100806417,-.2777851165098011,.4157348061512728,-.4903926402016153,.4903926402016152,-.4157348061512725,.27778511650980076,-.09754516100806429),at=Float64Array.from({length:64},(t,n)=>{const o=.26236426446749106*Math.max(0,5*Math.sqrt((7&n)*(7&n)+(n>>3)*(n>>3))/Math.sqrt(98)-1);let r=1,e=1;for(let t=1;t<30;t++)e+=r=r*o/t;return e}),ut=[4,4,4,4,3,2,6,8],ht=[0,.125,.25,.5,.25,.25,.25,.25],yt=[.9299455010825141,.945349926692846,.9500648966626563],wt=10.5*H.pixels,dt=(t,n)=>Math.abs(t)<2?t*yt[n]:t-.145/t,Mt=(t,n,o)=>{const r=t+1.402*o,e=t-.344136286*n-.714136286*o,s=t+1.772*n;return r*r+e*e+s*s},pt=[p(0),p(1),p(2),p(3),p(4),p(4,1,1),p(5,1,1),p(2,0,1),p(3,0,1)],At=p(4,1,1);class gt{constructor(t){this.et=t,this.small=new Uint32Array(64*t),this.At=Array.from({length:t},()=>null),this.st=new Float64Array(t)}add(t,n){if(this.st[t]++,n<64)return void this.small[64*t+n]++;const o=this.At[t]||(this.At[t]=new Map);o.set(n,(o.get(n)||0)+1)}it(t,n,o=64){const r=new Uint32Array(o);for(const o of t){const t=64*o;for(let o=0;o<64;o++)this.small[t+o]&&(r[q(n,o)]+=this.small[t+o]);const e=this.At[o];if(e)for(const[t,o]of e)r[q(n,t)]+=o}return r}ft(t,n){let r=v(this.it(t,n));for(const e of t){const t=64*e;for(let e=n.S;e<64;e++)this.small[t+e]&&(r+=this.small[t+e]*(o(e)-n.U-n.I));const s=this.At[e];if(s)for(const[t,e]of s)r+=e*(o(t)-n.U-n.I)}return r}}const bt=[0,0,0],mt=[1];for(let t=1;t<32;t++)mt.push(mt[t-1]/2);const Ut=[0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63],It=13,xt=[0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,23,23,24,24,24,24,25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,28,29,29,29,29,30,30,30,30],St=[0,0,31,62,62,93,93,93,93,123,123,123,123,152,152,152,152,152,152,152,152,180,180,180,180,180,180,180,180,180,180,180,180,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206],Et=Ut.map(t=>(7&t)<<3|t>>3),Lt=(t,n,o)=>2*(St[t]+xt[n])+o;export{H as LIMITS,D as encodePhoto,Y as encodePhotoSteps};
|
package/photo.mjs
CHANGED
|
@@ -1,74 +1,11 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// Photographic pixels through the
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const QUANT_SHAPE = Float64Array.from({length: 64}, (_, k) => 1.3 ** Math.max(0, Math.hypot(k & 7, k >> 3) * 5 / Math.sqrt(98) - 1));
|
|
13
|
-
|
|
14
|
-
// Eight terms in the original accumulation order, including the initial zero. The two separable passes
|
|
15
|
-
// share this fixed dot product without a loop or a changed floating-point sum.
|
|
16
|
-
function dot8(data, at, step, basis) {
|
|
17
|
-
let sum = 0;
|
|
18
|
-
sum += data[at] * COSINES[basis];
|
|
19
|
-
sum += data[at + step] * COSINES[basis + 1];
|
|
20
|
-
sum += data[at + 2 * step] * COSINES[basis + 2];
|
|
21
|
-
sum += data[at + 3 * step] * COSINES[basis + 3];
|
|
22
|
-
sum += data[at + 4 * step] * COSINES[basis + 4];
|
|
23
|
-
sum += data[at + 5 * step] * COSINES[basis + 5];
|
|
24
|
-
sum += data[at + 6 * step] * COSINES[basis + 6];
|
|
25
|
-
sum += data[at + 7 * step] * COSINES[basis + 7];
|
|
26
|
-
return sum;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function photoCoefficients(data, width, height, quality) {
|
|
30
|
-
const stride = Math.ceil(width / 8), rows = Math.ceil(height / 8), quantScale = 16;
|
|
31
|
-
const distance = quality >= 30 ? 0.1 + (100 - quality) * 0.09 : 53 / 3000 * quality * quality - 23 / 20 * quality + 25;
|
|
32
|
-
const components = [0, 1, 2].map(c => ({h: 1, v: 1, stride, rows,
|
|
33
|
-
quant: Int32Array.from(QUANT_SHAPE, (shape, k) => Math.max(1, Math.round(quantScale * distance * (c ? 8 : 14) * (k ? shape : 0.5)))),
|
|
34
|
-
coeffs: new Int16Array(stride * rows * 64)}));
|
|
35
|
-
const block = new Float64Array(192), intermediate = new Float64Array(64);
|
|
36
|
-
for (let by = 0; by < rows; by++) for (let bx = 0; bx < stride; bx++) {
|
|
37
|
-
// Edge replication gives a complete transform without inventing a dark border in a partial block.
|
|
38
|
-
for (let y = 0; y < 8; y++) for (let x = 0; x < 8; x++) {
|
|
39
|
-
const at = (Math.min(height - 1, by * 8 + y) * width + Math.min(width - 1, bx * 8 + x)) * 4;
|
|
40
|
-
const r = data[at], g = data[at + 1], b = data[at + 2], k = y * 8 + x;
|
|
41
|
-
block[k] = 0.299 * r + 0.587 * g + 0.114 * b - 128;
|
|
42
|
-
block[64 + k] = -0.168735892 * r - 0.331264108 * g + 0.5 * b;
|
|
43
|
-
block[128 + k] = 0.5 * r - 0.418687589 * g - 0.081312411 * b;
|
|
44
|
-
}
|
|
45
|
-
for (let c = 0; c < 3; c++) {
|
|
46
|
-
for (let y = 0; y < 8; y++) for (let u = 0; u < 8; u++) {
|
|
47
|
-
intermediate[y * 8 + u] = dot8(block, c * 64 + y * 8, 1, u * 8);
|
|
48
|
-
}
|
|
49
|
-
const {coeffs, quant} = components[c], offset = (by * stride + bx) * 64;
|
|
50
|
-
for (let v = 0; v < 8; v++) for (let u = 0; u < 8; u++) {
|
|
51
|
-
const sum = dot8(intermediate, u, 8, v * 8), k = v * 8 + u;
|
|
52
|
-
coeffs[offset + k] = Math.round(sum * quantScale / quant[k]);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
let alpha = null;
|
|
57
|
-
for (let i = 3; i < data.length; i += 4) if (data[i] !== 255) { alpha = data; break; }
|
|
58
|
-
return {width, height, components, quantScale, ycbcr: true, orientation: 1, alpha};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Photographs below quality 100; quality 100 delegates to the existing exact encoder. Alpha is always exact.
|
|
62
|
-
export function encodePhotoRGBA(data, width, height, options = {}) {
|
|
63
|
-
if (options === null || typeof options !== 'object') throw photoFault('JXL_INPUT', 'Options are an object: {quality}.');
|
|
64
|
-
const quality = options.quality === undefined ? 90 : options.quality;
|
|
65
|
-
if (typeof quality !== 'number' || !Number.isFinite(quality) || quality < 1 || quality > 100) throw photoFault('JXL_INPUT', 'Quality is a number from 1 to 100.');
|
|
66
|
-
if (!Number.isInteger(width) || !Number.isInteger(height) || width < 1 || height < 1) throw photoFault('JXL_INPUT', 'A picture has positive whole pixel dimensions.');
|
|
67
|
-
if (width > LIMITS.edge || height > LIMITS.edge || width * height > LIMITS.pixels) throw photoFault('JXL_DIMENSIONS', 'The picture exceeds the JPEG XL pixel limits.');
|
|
68
|
-
if (!(data instanceof Uint8Array) && !(data instanceof Uint8ClampedArray) || data.length !== width * height * 4) throw photoFault('JXL_INPUT', 'Pixels are width * height * 4 straight RGBA bytes.');
|
|
69
|
-
try {
|
|
70
|
-
const bytes = quality >= 100 ? encodeLossless(data, width, height) : encodeVarDCT(photoCoefficients(data, width, height, quality));
|
|
71
|
-
if (bytes.length > LIMITS.bytes) throw photoFault('JXL_SIZE', 'The encoded picture exceeds 16 MiB.');
|
|
72
|
-
return bytes;
|
|
73
|
-
} catch (error) { if (error instanceof RangeError && !error.code) throw photoFault('JXL_MEMORY', 'Not enough memory for this picture.'); throw error; }
|
|
74
|
-
}
|
|
2
|
+
// Photographic pixels through the carrier's VarDCT writer: sRGB to YCbCr, DCT8,
|
|
3
|
+
// quantisation, then entropy coding. Quality 90 by default; 100 is exact, including
|
|
4
|
+
// RGB below transparent alpha. Alpha is always exact, and the colour space is declared.
|
|
5
|
+
import {PHOTO_LIMITS, complete} from './bits.mjs';
|
|
6
|
+
import {photoJob} from './photo-job.mjs';
|
|
7
|
+
import {coefficientEffortSteps} from './coefficient-effort.mjs';
|
|
8
|
+
|
|
9
|
+
export {PHOTO_LIMITS as LIMITS};
|
|
10
|
+
export function encodePhoto(data, width, height, options) { return complete(encodePhotoSteps(data, width, height, options)); }
|
|
11
|
+
export function encodePhotoSteps(data, width, height, options) { return photoJob(data, width, height, options, coefficientEffortSteps); }
|
|
@@ -9,7 +9,9 @@ The result shows only in a browser that decodes JPEG XL; the size is reported ei
|
|
|
9
9
|
<p id="out"></p>
|
|
10
10
|
<img id="shown" alt="">
|
|
11
11
|
<script type="module">
|
|
12
|
-
import {encode
|
|
12
|
+
import {encode} from '../../index.mjs';
|
|
13
|
+
import {transcode} from '../../jpeg.mjs';
|
|
14
|
+
import {encodePhoto} from '../../photo.mjs';
|
|
13
15
|
const out = document.getElementById('out'), shown = document.getElementById('shown');
|
|
14
16
|
document.querySelector('input[type=file]').addEventListener('change', async event => {
|
|
15
17
|
const file = event.target.files[0];
|
|
@@ -27,7 +29,7 @@ document.querySelector('input[type=file]').addEventListener('change', async even
|
|
|
27
29
|
context.drawImage(image, 0, 0);
|
|
28
30
|
const {data, width, height} = context.getImageData(0, 0, image.width, image.height);
|
|
29
31
|
const quality = document.getElementById('lossy').checked ? Number(document.getElementById('q').value) : 100;
|
|
30
|
-
bytes = encode(data, width, height, {quality}); note = quality >= 100 ? 'lossless' : 'lossy, quality ' + quality;
|
|
32
|
+
bytes = quality >= 100 ? encode(data, width, height) : encodePhoto(data, width, height, {quality}); note = quality >= 100 ? 'lossless' : 'lossy, quality ' + quality;
|
|
31
33
|
}
|
|
32
34
|
const ms = Math.round(performance.now() - started);
|
|
33
35
|
out.textContent = `${file.name}: ${file.size.toLocaleString()} bytes in, ${bytes.length.toLocaleString()} bytes of JPEG XL out (${note}, ${ms} ms).`;
|
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// A complete worker around Rapier JXL: post {id, op: 'encode', data, width, height, quality} or
|
|
3
|
-
//
|
|
4
|
-
|
|
2
|
+
// A complete worker around Rapier JXL: post {id, op: 'encode' or 'photo', data, width, height, quality} or
|
|
3
|
+
// {id, op: 'transcode', jpeg}; receive {id, progress} while it works, then {id, ok: true, bytes, width, height,
|
|
4
|
+
// orientation} or {id, ok: false, code, message}. {id, op: 'abort'} ends a request between steps. 'encode' takes an
|
|
5
|
+
// effort (the effort door; 1, its default, writes the core's bytes) and a deadline in milliseconds: past it the search
|
|
6
|
+
// is hurried and answers with the smallest stream written so far, never larger than effort 1's. Bytes are transferred.
|
|
7
|
+
import {encodeSteps} from '../../effort.mjs';
|
|
8
|
+
import {transcodeSteps} from '../../jpeg.mjs';
|
|
9
|
+
import {encodePhotoSteps} from '../../photo.mjs';
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
const running = new Set();
|
|
12
|
+
const turn = () => new Promise(resolve => setTimeout(resolve));
|
|
13
|
+
|
|
14
|
+
self.onmessage = async event => {
|
|
15
|
+
const ask = event.data || {}, {id, op} = ask;
|
|
16
|
+
if (op === 'abort') { running.delete(id); return; }
|
|
8
17
|
try {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
18
|
+
const job = op === 'encode' ? encodeSteps(ask.data, ask.width, ask.height, {quality: ask.quality, effort: ask.effort})
|
|
19
|
+
: op === 'photo' ? encodePhotoSteps(ask.data, ask.width, ask.height, {quality: ask.quality})
|
|
20
|
+
: op === 'transcode' ? transcodeSteps(ask.jpeg)
|
|
21
|
+
: null;
|
|
22
|
+
if (!job) throw Object.assign(new Error('unknown op ' + op), {code: 'JXL_INPUT'});
|
|
23
|
+
running.add(id);
|
|
24
|
+
let shown = performance.now();
|
|
25
|
+
const hurryAt = ask.deadline >= 0 ? shown + ask.deadline : Infinity;
|
|
26
|
+
for (const done of job) {
|
|
27
|
+
if (performance.now() >= hurryAt) job.hurry = true;
|
|
28
|
+
// Every 50 ms the worker takes its messages (an abort among them) and reports progress; leaving is the cancel.
|
|
29
|
+
if (performance.now() - shown < 50) continue;
|
|
30
|
+
self.postMessage({id, progress: done});
|
|
31
|
+
await turn();
|
|
32
|
+
if (!running.has(id)) return;
|
|
33
|
+
shown = performance.now();
|
|
34
|
+
}
|
|
35
|
+
running.delete(id);
|
|
36
|
+
const out = {bytes: job.bytes, width: job.width ?? ask.width, height: job.height ?? ask.height, orientation: job.orientation ?? 1};
|
|
13
37
|
self.postMessage({id, ok: true, ...out}, [out.bytes.buffer]);
|
|
14
38
|
} catch (error) {
|
|
39
|
+
running.delete(id);
|
|
15
40
|
self.postMessage({id, ok: false, code: error.code || 'JXL_ERROR', message: String(error.message || error)});
|
|
16
41
|
}
|
|
17
42
|
};
|