cross-image 0.1.2

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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +606 -0
  3. package/esm/mod.d.ts +33 -0
  4. package/esm/mod.d.ts.map +1 -0
  5. package/esm/mod.js +31 -0
  6. package/esm/package.json +3 -0
  7. package/esm/src/formats/ascii.d.ts +27 -0
  8. package/esm/src/formats/ascii.d.ts.map +1 -0
  9. package/esm/src/formats/ascii.js +172 -0
  10. package/esm/src/formats/bmp.d.ts +19 -0
  11. package/esm/src/formats/bmp.d.ts.map +1 -0
  12. package/esm/src/formats/bmp.js +174 -0
  13. package/esm/src/formats/gif.d.ts +40 -0
  14. package/esm/src/formats/gif.d.ts.map +1 -0
  15. package/esm/src/formats/gif.js +385 -0
  16. package/esm/src/formats/jpeg.d.ts +18 -0
  17. package/esm/src/formats/jpeg.d.ts.map +1 -0
  18. package/esm/src/formats/jpeg.js +414 -0
  19. package/esm/src/formats/png.d.ts +33 -0
  20. package/esm/src/formats/png.d.ts.map +1 -0
  21. package/esm/src/formats/png.js +544 -0
  22. package/esm/src/formats/raw.d.ts +23 -0
  23. package/esm/src/formats/raw.d.ts.map +1 -0
  24. package/esm/src/formats/raw.js +98 -0
  25. package/esm/src/formats/tiff.d.ts +58 -0
  26. package/esm/src/formats/tiff.d.ts.map +1 -0
  27. package/esm/src/formats/tiff.js +791 -0
  28. package/esm/src/formats/webp.d.ts +22 -0
  29. package/esm/src/formats/webp.d.ts.map +1 -0
  30. package/esm/src/formats/webp.js +403 -0
  31. package/esm/src/image.d.ts +124 -0
  32. package/esm/src/image.d.ts.map +1 -0
  33. package/esm/src/image.js +320 -0
  34. package/esm/src/types.d.ts +167 -0
  35. package/esm/src/types.d.ts.map +1 -0
  36. package/esm/src/types.js +1 -0
  37. package/esm/src/utils/gif_decoder.d.ts +42 -0
  38. package/esm/src/utils/gif_decoder.d.ts.map +1 -0
  39. package/esm/src/utils/gif_decoder.js +374 -0
  40. package/esm/src/utils/gif_encoder.d.ts +29 -0
  41. package/esm/src/utils/gif_encoder.d.ts.map +1 -0
  42. package/esm/src/utils/gif_encoder.js +226 -0
  43. package/esm/src/utils/jpeg_decoder.d.ts +39 -0
  44. package/esm/src/utils/jpeg_decoder.d.ts.map +1 -0
  45. package/esm/src/utils/jpeg_decoder.js +580 -0
  46. package/esm/src/utils/jpeg_encoder.d.ts +33 -0
  47. package/esm/src/utils/jpeg_encoder.d.ts.map +1 -0
  48. package/esm/src/utils/jpeg_encoder.js +1017 -0
  49. package/esm/src/utils/lzw.d.ts +43 -0
  50. package/esm/src/utils/lzw.d.ts.map +1 -0
  51. package/esm/src/utils/lzw.js +309 -0
  52. package/esm/src/utils/resize.d.ts +9 -0
  53. package/esm/src/utils/resize.d.ts.map +1 -0
  54. package/esm/src/utils/resize.js +52 -0
  55. package/esm/src/utils/tiff_lzw.d.ts +44 -0
  56. package/esm/src/utils/tiff_lzw.d.ts.map +1 -0
  57. package/esm/src/utils/tiff_lzw.js +306 -0
  58. package/esm/src/utils/webp_decoder.d.ts +39 -0
  59. package/esm/src/utils/webp_decoder.d.ts.map +1 -0
  60. package/esm/src/utils/webp_decoder.js +493 -0
  61. package/esm/src/utils/webp_encoder.d.ts +72 -0
  62. package/esm/src/utils/webp_encoder.d.ts.map +1 -0
  63. package/esm/src/utils/webp_encoder.js +627 -0
  64. package/package.json +41 -0
  65. package/script/mod.d.ts +33 -0
  66. package/script/mod.d.ts.map +1 -0
  67. package/script/mod.js +43 -0
  68. package/script/package.json +3 -0
  69. package/script/src/formats/ascii.d.ts +27 -0
  70. package/script/src/formats/ascii.d.ts.map +1 -0
  71. package/script/src/formats/ascii.js +176 -0
  72. package/script/src/formats/bmp.d.ts +19 -0
  73. package/script/src/formats/bmp.d.ts.map +1 -0
  74. package/script/src/formats/bmp.js +178 -0
  75. package/script/src/formats/gif.d.ts +40 -0
  76. package/script/src/formats/gif.d.ts.map +1 -0
  77. package/script/src/formats/gif.js +389 -0
  78. package/script/src/formats/jpeg.d.ts +18 -0
  79. package/script/src/formats/jpeg.d.ts.map +1 -0
  80. package/script/src/formats/jpeg.js +451 -0
  81. package/script/src/formats/png.d.ts +33 -0
  82. package/script/src/formats/png.d.ts.map +1 -0
  83. package/script/src/formats/png.js +548 -0
  84. package/script/src/formats/raw.d.ts +23 -0
  85. package/script/src/formats/raw.d.ts.map +1 -0
  86. package/script/src/formats/raw.js +102 -0
  87. package/script/src/formats/tiff.d.ts +58 -0
  88. package/script/src/formats/tiff.d.ts.map +1 -0
  89. package/script/src/formats/tiff.js +795 -0
  90. package/script/src/formats/webp.d.ts +22 -0
  91. package/script/src/formats/webp.d.ts.map +1 -0
  92. package/script/src/formats/webp.js +440 -0
  93. package/script/src/image.d.ts +124 -0
  94. package/script/src/image.d.ts.map +1 -0
  95. package/script/src/image.js +324 -0
  96. package/script/src/types.d.ts +167 -0
  97. package/script/src/types.d.ts.map +1 -0
  98. package/script/src/types.js +2 -0
  99. package/script/src/utils/gif_decoder.d.ts +42 -0
  100. package/script/src/utils/gif_decoder.d.ts.map +1 -0
  101. package/script/src/utils/gif_decoder.js +378 -0
  102. package/script/src/utils/gif_encoder.d.ts +29 -0
  103. package/script/src/utils/gif_encoder.d.ts.map +1 -0
  104. package/script/src/utils/gif_encoder.js +230 -0
  105. package/script/src/utils/jpeg_decoder.d.ts +39 -0
  106. package/script/src/utils/jpeg_decoder.d.ts.map +1 -0
  107. package/script/src/utils/jpeg_decoder.js +584 -0
  108. package/script/src/utils/jpeg_encoder.d.ts +33 -0
  109. package/script/src/utils/jpeg_encoder.d.ts.map +1 -0
  110. package/script/src/utils/jpeg_encoder.js +1021 -0
  111. package/script/src/utils/lzw.d.ts +43 -0
  112. package/script/src/utils/lzw.d.ts.map +1 -0
  113. package/script/src/utils/lzw.js +314 -0
  114. package/script/src/utils/resize.d.ts +9 -0
  115. package/script/src/utils/resize.d.ts.map +1 -0
  116. package/script/src/utils/resize.js +56 -0
  117. package/script/src/utils/tiff_lzw.d.ts +44 -0
  118. package/script/src/utils/tiff_lzw.d.ts.map +1 -0
  119. package/script/src/utils/tiff_lzw.js +311 -0
  120. package/script/src/utils/webp_decoder.d.ts +39 -0
  121. package/script/src/utils/webp_decoder.d.ts.map +1 -0
  122. package/script/src/utils/webp_decoder.js +497 -0
  123. package/script/src/utils/webp_encoder.d.ts +72 -0
  124. package/script/src/utils/webp_encoder.d.ts.map +1 -0
  125. package/script/src/utils/webp_encoder.js +631 -0
@@ -0,0 +1,584 @@
1
+ "use strict";
2
+ /**
3
+ * Basic baseline JPEG decoder implementation
4
+ * Supports baseline DCT JPEG images (the most common format)
5
+ *
6
+ * This is a simplified implementation that handles common JPEG files.
7
+ * For complex or non-standard JPEGs, the ImageDecoder API fallback is preferred.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.JPEGDecoder = void 0;
11
+ // JPEG markers
12
+ const EOI = 0xFFD9; // End of Image
13
+ const SOS = 0xFFDA; // Start of Scan
14
+ const DQT = 0xFFDB; // Define Quantization Table
15
+ const DHT = 0xFFC4; // Define Huffman Table
16
+ const SOF0 = 0xFFC0; // Start of Frame (Baseline DCT)
17
+ const SOF2 = 0xFFC2; // Start of Frame (Progressive DCT)
18
+ const DRI = 0xFFDD; // Define Restart Interval
19
+ // Zigzag order for DCT coefficients
20
+ const ZIGZAG = [
21
+ 0,
22
+ 1,
23
+ 8,
24
+ 16,
25
+ 9,
26
+ 2,
27
+ 3,
28
+ 10,
29
+ 17,
30
+ 24,
31
+ 32,
32
+ 25,
33
+ 18,
34
+ 11,
35
+ 4,
36
+ 5,
37
+ 12,
38
+ 19,
39
+ 26,
40
+ 33,
41
+ 40,
42
+ 48,
43
+ 41,
44
+ 34,
45
+ 27,
46
+ 20,
47
+ 13,
48
+ 6,
49
+ 7,
50
+ 14,
51
+ 21,
52
+ 28,
53
+ 35,
54
+ 42,
55
+ 49,
56
+ 56,
57
+ 57,
58
+ 50,
59
+ 43,
60
+ 36,
61
+ 29,
62
+ 22,
63
+ 15,
64
+ 23,
65
+ 30,
66
+ 37,
67
+ 44,
68
+ 51,
69
+ 58,
70
+ 59,
71
+ 52,
72
+ 45,
73
+ 38,
74
+ 31,
75
+ 39,
76
+ 46,
77
+ 53,
78
+ 60,
79
+ 61,
80
+ 54,
81
+ 47,
82
+ 55,
83
+ 62,
84
+ 63,
85
+ ];
86
+ class JPEGDecoder {
87
+ constructor(data) {
88
+ Object.defineProperty(this, "data", {
89
+ enumerable: true,
90
+ configurable: true,
91
+ writable: true,
92
+ value: void 0
93
+ });
94
+ Object.defineProperty(this, "pos", {
95
+ enumerable: true,
96
+ configurable: true,
97
+ writable: true,
98
+ value: 0
99
+ });
100
+ Object.defineProperty(this, "width", {
101
+ enumerable: true,
102
+ configurable: true,
103
+ writable: true,
104
+ value: 0
105
+ });
106
+ Object.defineProperty(this, "height", {
107
+ enumerable: true,
108
+ configurable: true,
109
+ writable: true,
110
+ value: 0
111
+ });
112
+ Object.defineProperty(this, "components", {
113
+ enumerable: true,
114
+ configurable: true,
115
+ writable: true,
116
+ value: []
117
+ });
118
+ Object.defineProperty(this, "qTables", {
119
+ enumerable: true,
120
+ configurable: true,
121
+ writable: true,
122
+ value: []
123
+ });
124
+ Object.defineProperty(this, "dcTables", {
125
+ enumerable: true,
126
+ configurable: true,
127
+ writable: true,
128
+ value: []
129
+ });
130
+ Object.defineProperty(this, "acTables", {
131
+ enumerable: true,
132
+ configurable: true,
133
+ writable: true,
134
+ value: []
135
+ });
136
+ Object.defineProperty(this, "restartInterval", {
137
+ enumerable: true,
138
+ configurable: true,
139
+ writable: true,
140
+ value: 0
141
+ });
142
+ Object.defineProperty(this, "bitBuffer", {
143
+ enumerable: true,
144
+ configurable: true,
145
+ writable: true,
146
+ value: 0
147
+ });
148
+ Object.defineProperty(this, "bitCount", {
149
+ enumerable: true,
150
+ configurable: true,
151
+ writable: true,
152
+ value: 0
153
+ });
154
+ this.data = data;
155
+ }
156
+ decode() {
157
+ // Verify JPEG signature
158
+ if (this.data.length < 2 || this.data[0] !== 0xFF || this.data[1] !== 0xD8) {
159
+ throw new Error("Invalid JPEG signature");
160
+ }
161
+ this.pos = 2;
162
+ // Parse markers
163
+ while (this.pos < this.data.length) {
164
+ const marker = this.readMarker();
165
+ if (marker === EOI) {
166
+ break;
167
+ }
168
+ else if (marker === SOS) {
169
+ this.parseSOS();
170
+ this.decodeScan();
171
+ break; // Stop after first scan for baseline JPEG
172
+ }
173
+ else if (marker === DQT) {
174
+ this.parseDQT();
175
+ }
176
+ else if (marker === DHT) {
177
+ this.parseDHT();
178
+ }
179
+ else if (marker === SOF0) {
180
+ this.parseSOF();
181
+ }
182
+ else if (marker === SOF2) {
183
+ throw new Error("Progressive JPEG not supported in pure JS decoder");
184
+ }
185
+ else if (marker === DRI) {
186
+ this.parseDRI();
187
+ }
188
+ else if (marker >= 0xFFE0 && marker <= 0xFFEF) {
189
+ // Skip APP markers
190
+ this.skipSegment();
191
+ }
192
+ else if (marker >= 0xFFC0 && marker <= 0xFFCF) {
193
+ // Other SOF markers
194
+ if (marker !== 0xFFC4 && marker !== 0xFFC8 && marker !== 0xFFCC) {
195
+ throw new Error(`Unsupported JPEG type: marker 0x${marker.toString(16)}`);
196
+ }
197
+ }
198
+ else {
199
+ // Skip unknown markers
200
+ if (this.pos < this.data.length) {
201
+ this.skipSegment();
202
+ }
203
+ }
204
+ }
205
+ if (this.width === 0 || this.height === 0) {
206
+ throw new Error("Failed to decode JPEG: invalid dimensions");
207
+ }
208
+ // Convert YCbCr to RGB
209
+ return this.convertToRGB();
210
+ }
211
+ readMarker() {
212
+ while (this.pos < this.data.length && this.data[this.pos] !== 0xFF) {
213
+ this.pos++;
214
+ }
215
+ if (this.pos >= this.data.length - 1) {
216
+ return EOI;
217
+ }
218
+ const byte1 = this.data[this.pos++];
219
+ let byte2 = this.data[this.pos++];
220
+ // Skip padding 0xFF bytes
221
+ while (byte2 === 0xFF && this.pos < this.data.length) {
222
+ byte2 = this.data[this.pos++];
223
+ }
224
+ return (byte1 << 8) | byte2;
225
+ }
226
+ readUint16() {
227
+ const value = (this.data[this.pos] << 8) | this.data[this.pos + 1];
228
+ this.pos += 2;
229
+ return value;
230
+ }
231
+ skipSegment() {
232
+ const length = this.readUint16();
233
+ this.pos += length - 2;
234
+ }
235
+ parseDQT() {
236
+ let length = this.readUint16() - 2;
237
+ while (length > 0) {
238
+ const info = this.data[this.pos++];
239
+ const tableId = info & 0x0F;
240
+ const precision = (info >> 4) & 0x0F;
241
+ if (precision !== 0) {
242
+ throw new Error("16-bit quantization tables not supported");
243
+ }
244
+ const table = new Array(64);
245
+ for (let i = 0; i < 64; i++) {
246
+ table[ZIGZAG[i]] = this.data[this.pos++];
247
+ }
248
+ this.qTables[tableId] = table;
249
+ length -= 65;
250
+ }
251
+ }
252
+ parseDHT() {
253
+ let length = this.readUint16() - 2;
254
+ while (length > 0) {
255
+ const info = this.data[this.pos++];
256
+ const tableId = info & 0x0F;
257
+ const tableClass = (info >> 4) & 0x0F;
258
+ const bits = new Array(16);
259
+ let numSymbols = 0;
260
+ for (let i = 0; i < 16; i++) {
261
+ bits[i] = this.data[this.pos++];
262
+ numSymbols += bits[i];
263
+ }
264
+ const huffVal = new Array(numSymbols);
265
+ for (let i = 0; i < numSymbols; i++) {
266
+ huffVal[i] = this.data[this.pos++];
267
+ }
268
+ const table = this.buildHuffmanTable(bits, huffVal);
269
+ if (tableClass === 0) {
270
+ this.dcTables[tableId] = table;
271
+ }
272
+ else {
273
+ this.acTables[tableId] = table;
274
+ }
275
+ length -= 17 + numSymbols;
276
+ }
277
+ }
278
+ buildHuffmanTable(bits, huffVal) {
279
+ const maxCode = new Array(16).fill(-1);
280
+ const minCode = new Array(16).fill(-1);
281
+ const valPtr = new Array(16).fill(-1);
282
+ const codes = new Map();
283
+ let code = 0;
284
+ let valIndex = 0;
285
+ for (let i = 0; i < 16; i++) {
286
+ if (bits[i] > 0) {
287
+ minCode[i] = code;
288
+ valPtr[i] = valIndex;
289
+ for (let j = 0; j < bits[i]; j++) {
290
+ codes.set((i << 16) | code, huffVal[valIndex]);
291
+ code++;
292
+ valIndex++;
293
+ }
294
+ maxCode[i] = code - 1;
295
+ code <<= 1;
296
+ }
297
+ else {
298
+ code <<= 1;
299
+ }
300
+ }
301
+ return { codes, maxCode, minCode, valPtr, huffVal };
302
+ }
303
+ parseSOF() {
304
+ const _length = this.readUint16();
305
+ const precision = this.data[this.pos++];
306
+ if (precision !== 8) {
307
+ throw new Error(`Unsupported precision: ${precision}`);
308
+ }
309
+ this.height = this.readUint16();
310
+ this.width = this.readUint16();
311
+ const numComponents = this.data[this.pos++];
312
+ if (numComponents !== 1 && numComponents !== 3) {
313
+ throw new Error(`Unsupported number of components: ${numComponents}`);
314
+ }
315
+ this.components = [];
316
+ for (let i = 0; i < numComponents; i++) {
317
+ const id = this.data[this.pos++];
318
+ const samplingFactor = this.data[this.pos++];
319
+ const qTable = this.data[this.pos++];
320
+ this.components.push({
321
+ id,
322
+ h: (samplingFactor >> 4) & 0x0F,
323
+ v: samplingFactor & 0x0F,
324
+ qTable,
325
+ dcTable: 0,
326
+ acTable: 0,
327
+ pred: 0,
328
+ blocks: [],
329
+ });
330
+ }
331
+ }
332
+ parseSOS() {
333
+ const _length = this.readUint16();
334
+ const numComponents = this.data[this.pos++];
335
+ for (let i = 0; i < numComponents; i++) {
336
+ const id = this.data[this.pos++];
337
+ const tables = this.data[this.pos++];
338
+ const component = this.components.find((c) => c.id === id);
339
+ if (component) {
340
+ component.dcTable = (tables >> 4) & 0x0F;
341
+ component.acTable = tables & 0x0F;
342
+ }
343
+ }
344
+ this.pos += 3; // Skip spectral selection and successive approximation
345
+ }
346
+ parseDRI() {
347
+ const _length = this.readUint16();
348
+ this.restartInterval = this.readUint16();
349
+ }
350
+ decodeScan() {
351
+ // Calculate MCU dimensions
352
+ const maxH = Math.max(...this.components.map((c) => c.h));
353
+ const maxV = Math.max(...this.components.map((c) => c.v));
354
+ const mcuWidth = Math.ceil(this.width / (8 * maxH));
355
+ const mcuHeight = Math.ceil(this.height / (8 * maxV));
356
+ // Initialize bit buffer
357
+ this.bitBuffer = 0;
358
+ this.bitCount = 0;
359
+ // Initialize blocks for each component
360
+ for (const component of this.components) {
361
+ const blocksAcross = Math.ceil(this.width * component.h / (8 * maxH));
362
+ const blocksDown = Math.ceil(this.height * component.v / (8 * maxV));
363
+ component.blocks = Array(blocksDown).fill(null).map(() => Array(blocksAcross).fill(null).map(() => new Array(64).fill(0)));
364
+ }
365
+ // Decode MCUs
366
+ try {
367
+ for (let mcuY = 0; mcuY < mcuHeight; mcuY++) {
368
+ for (let mcuX = 0; mcuX < mcuWidth; mcuX++) {
369
+ // Decode all components in this MCU
370
+ for (const component of this.components) {
371
+ for (let v = 0; v < component.v; v++) {
372
+ for (let h = 0; h < component.h; h++) {
373
+ const blockY = mcuY * component.v + v;
374
+ const blockX = mcuX * component.h + h;
375
+ if (blockY < component.blocks.length &&
376
+ blockX < component.blocks[0].length) {
377
+ this.decodeBlock(component, blockY, blockX);
378
+ }
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ }
385
+ catch (e) {
386
+ // If we run into issues during decoding, we may still have partial data
387
+ console.warn("JPEG decode warning:", e);
388
+ }
389
+ }
390
+ decodeBlock(component, blockY, blockX) {
391
+ const block = component.blocks[blockY][blockX];
392
+ // Decode DC coefficient
393
+ const dcTable = this.dcTables[component.dcTable];
394
+ if (!dcTable) {
395
+ throw new Error(`Missing DC table ${component.dcTable}`);
396
+ }
397
+ const dcLen = this.decodeHuffman(dcTable);
398
+ const dcDiff = dcLen > 0 ? this.receiveBits(dcLen) : 0;
399
+ component.pred += dcDiff;
400
+ block[0] = component.pred * this.qTables[component.qTable][0];
401
+ // Decode AC coefficients
402
+ const acTable = this.acTables[component.acTable];
403
+ if (!acTable) {
404
+ throw new Error(`Missing AC table ${component.acTable}`);
405
+ }
406
+ let k = 1;
407
+ while (k < 64) {
408
+ const rs = this.decodeHuffman(acTable);
409
+ const r = (rs >> 4) & 0x0F;
410
+ const s = rs & 0x0F;
411
+ if (s === 0) {
412
+ if (r === 15) {
413
+ k += 16;
414
+ }
415
+ else {
416
+ break; // EOB
417
+ }
418
+ }
419
+ else {
420
+ k += r;
421
+ if (k >= 64)
422
+ break;
423
+ block[ZIGZAG[k]] = this.receiveBits(s) *
424
+ this.qTables[component.qTable][ZIGZAG[k]];
425
+ k++;
426
+ }
427
+ }
428
+ // Perform IDCT
429
+ this.idct(block);
430
+ }
431
+ decodeHuffman(table) {
432
+ let code = 0;
433
+ for (let len = 0; len < 16; len++) {
434
+ code = (code << 1) | this.readBit();
435
+ if (table.minCode[len] !== -1 && code <= table.maxCode[len]) {
436
+ const index = table.valPtr[len] + (code - table.minCode[len]);
437
+ return table.huffVal[index];
438
+ }
439
+ }
440
+ throw new Error("Invalid Huffman code");
441
+ }
442
+ readBit() {
443
+ if (this.bitCount === 0) {
444
+ let byte = this.data[this.pos++];
445
+ // Handle byte stuffing (0xFF 0x00)
446
+ if (byte === 0xFF) {
447
+ const nextByte = this.data[this.pos];
448
+ if (nextByte === 0x00) {
449
+ this.pos++;
450
+ }
451
+ else if (nextByte >= 0xD0 && nextByte <= 0xD7) {
452
+ // Restart marker - reset DC predictors
453
+ this.pos++;
454
+ for (const component of this.components) {
455
+ component.pred = 0;
456
+ }
457
+ byte = this.data[this.pos++];
458
+ }
459
+ }
460
+ this.bitBuffer = byte;
461
+ this.bitCount = 8;
462
+ }
463
+ this.bitCount--;
464
+ return (this.bitBuffer >> this.bitCount) & 1;
465
+ }
466
+ receiveBits(n) {
467
+ let value = 0;
468
+ for (let i = 0; i < n; i++) {
469
+ value = (value << 1) | this.readBit();
470
+ }
471
+ // Convert from magnitude representation
472
+ if (value < (1 << (n - 1))) {
473
+ value = value - (1 << n) + 1;
474
+ }
475
+ return value;
476
+ }
477
+ idct(block) {
478
+ // Simplified 2D IDCT
479
+ // This is a basic implementation - not optimized
480
+ const temp = new Array(64);
481
+ // 1D IDCT on rows
482
+ for (let i = 0; i < 8; i++) {
483
+ const offset = i * 8;
484
+ for (let j = 0; j < 8; j++) {
485
+ let sum = 0;
486
+ for (let k = 0; k < 8; k++) {
487
+ const c = k === 0 ? 1 / Math.sqrt(2) : 1;
488
+ sum += c * block[offset + k] *
489
+ Math.cos((2 * j + 1) * k * Math.PI / 16);
490
+ }
491
+ temp[offset + j] = sum / 2;
492
+ }
493
+ }
494
+ // 1D IDCT on columns
495
+ for (let j = 0; j < 8; j++) {
496
+ for (let i = 0; i < 8; i++) {
497
+ let sum = 0;
498
+ for (let k = 0; k < 8; k++) {
499
+ const c = k === 0 ? 1 / Math.sqrt(2) : 1;
500
+ sum += c * temp[k * 8 + j] * Math.cos((2 * i + 1) * k * Math.PI / 16);
501
+ }
502
+ // Level shift and clamp
503
+ block[i * 8 + j] = Math.max(0, Math.min(255, Math.round(sum / 2 + 128)));
504
+ }
505
+ }
506
+ }
507
+ convertToRGB() {
508
+ const rgba = new Uint8Array(this.width * this.height * 4);
509
+ if (this.components.length === 1) {
510
+ // Grayscale
511
+ const y = this.components[0];
512
+ for (let row = 0; row < this.height; row++) {
513
+ for (let col = 0; col < this.width; col++) {
514
+ const blockRow = Math.floor(row / 8);
515
+ const blockCol = Math.floor(col / 8);
516
+ const blockY = row % 8;
517
+ const blockX = col % 8;
518
+ if (blockRow < y.blocks.length && blockCol < y.blocks[0].length) {
519
+ const value = y.blocks[blockRow][blockCol][blockY * 8 + blockX];
520
+ const offset = (row * this.width + col) * 4;
521
+ rgba[offset] = value;
522
+ rgba[offset + 1] = value;
523
+ rgba[offset + 2] = value;
524
+ rgba[offset + 3] = 255;
525
+ }
526
+ }
527
+ }
528
+ }
529
+ else {
530
+ // YCbCr to RGB
531
+ const [y, cb, cr] = this.components;
532
+ const maxH = Math.max(...this.components.map((c) => c.h));
533
+ const maxV = Math.max(...this.components.map((c) => c.v));
534
+ for (let row = 0; row < this.height; row++) {
535
+ for (let col = 0; col < this.width; col++) {
536
+ // Y component
537
+ const yBlockRow = Math.floor(row / 8);
538
+ const yBlockCol = Math.floor(col / 8);
539
+ const yBlockY = row % 8;
540
+ const yBlockX = col % 8;
541
+ let yVal = 0;
542
+ if (yBlockRow < y.blocks.length && yBlockCol < y.blocks[0].length) {
543
+ yVal = y.blocks[yBlockRow][yBlockCol][yBlockY * 8 + yBlockX];
544
+ }
545
+ // Cb and Cr components (may be subsampled)
546
+ // Scale pixel position by subsampling factor, then get block and within-block positions
547
+ const cbRow = Math.floor(row * cb.v / maxV);
548
+ const cbCol = Math.floor(col * cb.h / maxH);
549
+ const cbBlockRow = Math.floor(cbRow / 8);
550
+ const cbBlockCol = Math.floor(cbCol / 8);
551
+ const cbBlockY = cbRow % 8;
552
+ const cbBlockX = cbCol % 8;
553
+ let cbVal = 0;
554
+ if (cbBlockRow < cb.blocks.length && cbBlockCol < cb.blocks[0].length) {
555
+ cbVal = cb.blocks[cbBlockRow][cbBlockCol][cbBlockY * 8 + cbBlockX] -
556
+ 128;
557
+ }
558
+ const crRow = Math.floor(row * cr.v / maxV);
559
+ const crCol = Math.floor(col * cr.h / maxH);
560
+ const crBlockRow = Math.floor(crRow / 8);
561
+ const crBlockCol = Math.floor(crCol / 8);
562
+ const crBlockY = crRow % 8;
563
+ const crBlockX = crCol % 8;
564
+ let crVal = 0;
565
+ if (crBlockRow < cr.blocks.length && crBlockCol < cr.blocks[0].length) {
566
+ crVal = cr.blocks[crBlockRow][crBlockCol][crBlockY * 8 + crBlockX] -
567
+ 128;
568
+ }
569
+ // YCbCr to RGB conversion
570
+ const r = Math.max(0, Math.min(255, Math.round(yVal + 1.402 * crVal)));
571
+ const g = Math.max(0, Math.min(255, Math.round(yVal - 0.344136 * cbVal - 0.714136 * crVal)));
572
+ const b = Math.max(0, Math.min(255, Math.round(yVal + 1.772 * cbVal)));
573
+ const offset = (row * this.width + col) * 4;
574
+ rgba[offset] = r;
575
+ rgba[offset + 1] = g;
576
+ rgba[offset + 2] = b;
577
+ rgba[offset + 3] = 255;
578
+ }
579
+ }
580
+ }
581
+ return rgba;
582
+ }
583
+ }
584
+ exports.JPEGDecoder = JPEGDecoder;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Basic baseline JPEG encoder implementation
3
+ * Produces valid baseline DCT JPEG images
4
+ *
5
+ * This is a simplified implementation focusing on correctness over performance.
6
+ * For production use with better quality/size, the OffscreenCanvas API is preferred.
7
+ */
8
+ export declare class JPEGEncoder {
9
+ private quality;
10
+ private luminanceQuantTable;
11
+ private chrominanceQuantTable;
12
+ private dcLuminanceHuffman;
13
+ private acLuminanceHuffman;
14
+ private dcChrominanceHuffman;
15
+ private acChrominanceHuffman;
16
+ constructor(quality?: number);
17
+ private initQuantizationTables;
18
+ private initHuffmanTables;
19
+ private buildHuffmanTable;
20
+ encode(width: number, height: number, rgba: Uint8Array, dpiX?: number, dpiY?: number): Uint8Array;
21
+ private writeAPP0;
22
+ private writeDQT;
23
+ private writeSOF0;
24
+ private writeDHT;
25
+ private writeHuffmanTable;
26
+ private writeSOS;
27
+ private encodeScan;
28
+ private encodeBlock;
29
+ private forwardDCT;
30
+ private encodeDC;
31
+ private encodeAC;
32
+ }
33
+ //# sourceMappingURL=jpeg_encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jpeg_encoder.d.ts","sourceRoot":"","sources":["../../../src/src/utils/jpeg_encoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgrBH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,qBAAqB,CAAgB;IAC7C,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,kBAAkB,CAAgB;IAC1C,OAAO,CAAC,oBAAoB,CAAgB;IAC5C,OAAO,CAAC,oBAAoB,CAAgB;gBAEhC,OAAO,GAAE,MAAW;IAMhC,OAAO,CAAC,sBAAsB;IAqB9B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,iBAAiB;IAqBzB,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,IAAI,SAAK,EACT,IAAI,SAAK,GACR,UAAU;IAiCb,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,SAAS;IAwBjB,OAAO,CAAC,QAAQ;IAkChB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,QAAQ;IAsBhB,OAAO,CAAC,UAAU;IA2ElB,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,UAAU;IA8BlB,OAAO,CAAC,QAAQ;IAsBhB,OAAO,CAAC,QAAQ;CAqCjB"}