hyperframes 0.6.5 → 0.6.6

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.
@@ -0,0 +1,239 @@
1
+ import { createRequire as __hf_createRequire } from "node:module";
2
+ import { fileURLToPath as __hf_fileURLToPath } from "node:url";
3
+ import { dirname as __hf_dirname } from "node:path";
4
+ var require = __hf_createRequire(import.meta.url);
5
+ var __filename = __hf_fileURLToPath(import.meta.url);
6
+ var __dirname = __hf_dirname(__filename);
7
+
8
+ // ../producer/src/services/pngDecodeBlitWorker.ts
9
+ import { parentPort } from "worker_threads";
10
+
11
+ // ../engine/src/utils/alphaBlit.ts
12
+ import { inflateSync } from "zlib";
13
+ function paeth(a, b, c) {
14
+ const p = a + b - c;
15
+ const pa = Math.abs(p - a);
16
+ const pb = Math.abs(p - b);
17
+ const pc = Math.abs(p - c);
18
+ if (pa <= pb && pa <= pc) return a;
19
+ if (pb <= pc) return b;
20
+ return c;
21
+ }
22
+ function decodePngRaw(buf, caller) {
23
+ if (buf[0] !== 137 || buf[1] !== 80 || buf[2] !== 78 || buf[3] !== 71 || buf[4] !== 13 || buf[5] !== 10 || buf[6] !== 26 || buf[7] !== 10) {
24
+ throw new Error(`${caller}: not a PNG file`);
25
+ }
26
+ let pos = 8;
27
+ let width = 0;
28
+ let height = 0;
29
+ let bitDepth = 0;
30
+ let colorType = 0;
31
+ let interlace = 0;
32
+ let sawIhdr = false;
33
+ const idatChunks = [];
34
+ while (pos + 12 <= buf.length) {
35
+ const chunkLen = buf.readUInt32BE(pos);
36
+ const chunkType = buf.toString("ascii", pos + 4, pos + 8);
37
+ const chunkData = buf.subarray(pos + 8, pos + 8 + chunkLen);
38
+ if (chunkType === "IHDR") {
39
+ width = chunkData.readUInt32BE(0);
40
+ height = chunkData.readUInt32BE(4);
41
+ bitDepth = chunkData[8] ?? 0;
42
+ colorType = chunkData[9] ?? 0;
43
+ interlace = chunkData[12] ?? 0;
44
+ sawIhdr = true;
45
+ } else if (chunkType === "IDAT") {
46
+ idatChunks.push(Buffer.from(chunkData));
47
+ } else if (chunkType === "IEND") {
48
+ break;
49
+ }
50
+ pos += 12 + chunkLen;
51
+ }
52
+ if (!sawIhdr) {
53
+ throw new Error(`${caller}: PNG missing IHDR chunk`);
54
+ }
55
+ if (colorType !== 2 && colorType !== 6) {
56
+ throw new Error(`${caller}: unsupported color type ${colorType} (expected 2=RGB or 6=RGBA)`);
57
+ }
58
+ if (interlace !== 0) {
59
+ throw new Error(
60
+ `${caller}: Adam7-interlaced PNGs are not supported (interlace method ${interlace})`
61
+ );
62
+ }
63
+ const channels = colorType === 6 ? 4 : 3;
64
+ const bpp = channels * (bitDepth / 8);
65
+ const stride = width * bpp;
66
+ const compressed = Buffer.concat(idatChunks);
67
+ const decompressed = inflateSync(compressed);
68
+ const rawPixels = Buffer.allocUnsafe(height * stride);
69
+ const prevRow = new Uint8Array(stride);
70
+ const currRow = new Uint8Array(stride);
71
+ let srcPos = 0;
72
+ for (let y = 0; y < height; y++) {
73
+ const filterType = decompressed[srcPos++] ?? 0;
74
+ const rawRow = decompressed.subarray(srcPos, srcPos + stride);
75
+ srcPos += stride;
76
+ switch (filterType) {
77
+ case 0:
78
+ currRow.set(rawRow);
79
+ break;
80
+ case 1:
81
+ for (let x = 0; x < stride; x++) {
82
+ currRow[x] = (rawRow[x] ?? 0) + (x >= bpp ? currRow[x - bpp] ?? 0 : 0) & 255;
83
+ }
84
+ break;
85
+ case 2:
86
+ for (let x = 0; x < stride; x++) {
87
+ currRow[x] = (rawRow[x] ?? 0) + (prevRow[x] ?? 0) & 255;
88
+ }
89
+ break;
90
+ case 3:
91
+ for (let x = 0; x < stride; x++) {
92
+ const left = x >= bpp ? currRow[x - bpp] ?? 0 : 0;
93
+ const up = prevRow[x] ?? 0;
94
+ currRow[x] = (rawRow[x] ?? 0) + Math.floor((left + up) / 2) & 255;
95
+ }
96
+ break;
97
+ case 4:
98
+ for (let x = 0; x < stride; x++) {
99
+ const left = x >= bpp ? currRow[x - bpp] ?? 0 : 0;
100
+ const up = prevRow[x] ?? 0;
101
+ const upLeft = x >= bpp ? prevRow[x - bpp] ?? 0 : 0;
102
+ currRow[x] = (rawRow[x] ?? 0) + paeth(left, up, upLeft) & 255;
103
+ }
104
+ break;
105
+ default:
106
+ throw new Error(`${caller}: unknown filter type ${filterType} at row ${y}`);
107
+ }
108
+ rawPixels.set(currRow, y * stride);
109
+ prevRow.set(currRow);
110
+ }
111
+ return { width, height, bitDepth, colorType, rawPixels };
112
+ }
113
+ function decodePng(buf) {
114
+ const { width, height, bitDepth, colorType, rawPixels } = decodePngRaw(buf, "decodePng");
115
+ if (bitDepth !== 8) {
116
+ throw new Error(`decodePng: unsupported bit depth ${bitDepth} (expected 8)`);
117
+ }
118
+ const output = new Uint8Array(width * height * 4);
119
+ if (colorType === 6) {
120
+ output.set(rawPixels);
121
+ } else {
122
+ for (let i = 0; i < width * height; i++) {
123
+ output[i * 4 + 0] = rawPixels[i * 3 + 0] ?? 0;
124
+ output[i * 4 + 1] = rawPixels[i * 3 + 1] ?? 0;
125
+ output[i * 4 + 2] = rawPixels[i * 3 + 2] ?? 0;
126
+ output[i * 4 + 3] = 255;
127
+ }
128
+ }
129
+ return { width, height, data: output };
130
+ }
131
+ function buildSrgbToSignalLut(transfer) {
132
+ const lut = new Uint16Array(256);
133
+ const hlgA = 0.17883277;
134
+ const hlgB = 1 - 4 * hlgA;
135
+ const hlgC = 0.5 - hlgA * Math.log(4 * hlgA);
136
+ const pqM1 = 0.1593017578125;
137
+ const pqM2 = 78.84375;
138
+ const pqC1 = 0.8359375;
139
+ const pqC2 = 18.8515625;
140
+ const pqC3 = 18.6875;
141
+ const pqMaxNits = 1e4;
142
+ const sdrNits = 203;
143
+ for (let i = 0; i < 256; i++) {
144
+ if (transfer === "srgb") {
145
+ lut[i] = i * 257;
146
+ continue;
147
+ }
148
+ const v = i / 255;
149
+ const linear = v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
150
+ let signal;
151
+ if (transfer === "hlg") {
152
+ signal = linear <= 1 / 12 ? Math.sqrt(3 * linear) : hlgA * Math.log(12 * linear - hlgB) + hlgC;
153
+ } else {
154
+ const Lp = Math.max(0, linear * sdrNits / pqMaxNits);
155
+ const Lm1 = Math.pow(Lp, pqM1);
156
+ signal = Math.pow((pqC1 + pqC2 * Lm1) / (1 + pqC3 * Lm1), pqM2);
157
+ }
158
+ lut[i] = Math.min(65535, Math.round(signal * 65535));
159
+ }
160
+ return lut;
161
+ }
162
+ var SRGB_TO_SRGB_16 = buildSrgbToSignalLut("srgb");
163
+ var SRGB_TO_HLG = buildSrgbToSignalLut("hlg");
164
+ var SRGB_TO_PQ = buildSrgbToSignalLut("pq");
165
+ function getSrgbToSignalLut(transfer) {
166
+ if (transfer === "pq") return SRGB_TO_PQ;
167
+ if (transfer === "hlg") return SRGB_TO_HLG;
168
+ return SRGB_TO_SRGB_16;
169
+ }
170
+ function blitRgba8OverRgb48le(domRgba, canvas, width, height, transfer = "hlg") {
171
+ const pixelCount = width * height;
172
+ const lut = getSrgbToSignalLut(transfer);
173
+ for (let i = 0; i < pixelCount; i++) {
174
+ const da = domRgba[i * 4 + 3] ?? 0;
175
+ if (da === 0) {
176
+ continue;
177
+ } else if (da === 255) {
178
+ const r16 = lut[domRgba[i * 4 + 0] ?? 0] ?? 0;
179
+ const g16 = lut[domRgba[i * 4 + 1] ?? 0] ?? 0;
180
+ const b16 = lut[domRgba[i * 4 + 2] ?? 0] ?? 0;
181
+ canvas.writeUInt16LE(r16, i * 6);
182
+ canvas.writeUInt16LE(g16, i * 6 + 2);
183
+ canvas.writeUInt16LE(b16, i * 6 + 4);
184
+ } else {
185
+ const alpha = da / 255;
186
+ const invAlpha = 1 - alpha;
187
+ const hdrR = (canvas[i * 6 + 0] ?? 0) | (canvas[i * 6 + 1] ?? 0) << 8;
188
+ const hdrG = (canvas[i * 6 + 2] ?? 0) | (canvas[i * 6 + 3] ?? 0) << 8;
189
+ const hdrB = (canvas[i * 6 + 4] ?? 0) | (canvas[i * 6 + 5] ?? 0) << 8;
190
+ const domR = lut[domRgba[i * 4 + 0] ?? 0] ?? 0;
191
+ const domG = lut[domRgba[i * 4 + 1] ?? 0] ?? 0;
192
+ const domB = lut[domRgba[i * 4 + 2] ?? 0] ?? 0;
193
+ canvas.writeUInt16LE(Math.round(domR * alpha + hdrR * invAlpha), i * 6);
194
+ canvas.writeUInt16LE(Math.round(domG * alpha + hdrG * invAlpha), i * 6 + 2);
195
+ canvas.writeUInt16LE(Math.round(domB * alpha + hdrB * invAlpha), i * 6 + 4);
196
+ }
197
+ }
198
+ }
199
+
200
+ // ../producer/src/services/pngDecodeBlitWorker.ts
201
+ if (!parentPort) {
202
+ console.warn("[pngDecodeBlitWorker] no parentPort; module loaded on main thread");
203
+ } else {
204
+ parentPort.on("message", (msg) => {
205
+ const { png, pngOffset, pngLength, dest, destOffset, destLength, width, height, transfer } = msg;
206
+ const pngBuf = Buffer.from(png, pngOffset, pngLength);
207
+ const destBuf = Buffer.from(dest, destOffset, destLength);
208
+ try {
209
+ const decodeStart = Date.now();
210
+ const { data: rgba } = decodePng(pngBuf);
211
+ const decodeMs = Date.now() - decodeStart;
212
+ const blitStart = Date.now();
213
+ blitRgba8OverRgb48le(
214
+ rgba,
215
+ destBuf,
216
+ width,
217
+ height,
218
+ transfer
219
+ );
220
+ const blitMs = Date.now() - blitStart;
221
+ const reply = {
222
+ ok: true,
223
+ png,
224
+ dest,
225
+ decodeMs,
226
+ blitMs
227
+ };
228
+ parentPort.postMessage(reply, [png, dest]);
229
+ } catch (err) {
230
+ const reply = {
231
+ ok: false,
232
+ error: err instanceof Error ? err.message : String(err),
233
+ png,
234
+ dest
235
+ };
236
+ parentPort.postMessage(reply, [png, dest]);
237
+ }
238
+ });
239
+ }