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,1017 @@
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
+ // Standard JPEG quantization tables
9
+ const STANDARD_LUMINANCE_QUANT_TABLE = [
10
+ 16,
11
+ 11,
12
+ 10,
13
+ 16,
14
+ 24,
15
+ 40,
16
+ 51,
17
+ 61,
18
+ 12,
19
+ 12,
20
+ 14,
21
+ 19,
22
+ 26,
23
+ 58,
24
+ 60,
25
+ 55,
26
+ 14,
27
+ 13,
28
+ 16,
29
+ 24,
30
+ 40,
31
+ 57,
32
+ 69,
33
+ 56,
34
+ 14,
35
+ 17,
36
+ 22,
37
+ 29,
38
+ 51,
39
+ 87,
40
+ 80,
41
+ 62,
42
+ 18,
43
+ 22,
44
+ 37,
45
+ 56,
46
+ 68,
47
+ 109,
48
+ 103,
49
+ 77,
50
+ 24,
51
+ 35,
52
+ 55,
53
+ 64,
54
+ 81,
55
+ 104,
56
+ 113,
57
+ 92,
58
+ 49,
59
+ 64,
60
+ 78,
61
+ 87,
62
+ 103,
63
+ 121,
64
+ 120,
65
+ 101,
66
+ 72,
67
+ 92,
68
+ 95,
69
+ 98,
70
+ 112,
71
+ 100,
72
+ 103,
73
+ 99,
74
+ ];
75
+ const STANDARD_CHROMINANCE_QUANT_TABLE = [
76
+ 17,
77
+ 18,
78
+ 24,
79
+ 47,
80
+ 99,
81
+ 99,
82
+ 99,
83
+ 99,
84
+ 18,
85
+ 21,
86
+ 26,
87
+ 66,
88
+ 99,
89
+ 99,
90
+ 99,
91
+ 99,
92
+ 24,
93
+ 26,
94
+ 56,
95
+ 99,
96
+ 99,
97
+ 99,
98
+ 99,
99
+ 99,
100
+ 47,
101
+ 66,
102
+ 99,
103
+ 99,
104
+ 99,
105
+ 99,
106
+ 99,
107
+ 99,
108
+ 99,
109
+ 99,
110
+ 99,
111
+ 99,
112
+ 99,
113
+ 99,
114
+ 99,
115
+ 99,
116
+ 99,
117
+ 99,
118
+ 99,
119
+ 99,
120
+ 99,
121
+ 99,
122
+ 99,
123
+ 99,
124
+ 99,
125
+ 99,
126
+ 99,
127
+ 99,
128
+ 99,
129
+ 99,
130
+ 99,
131
+ 99,
132
+ 99,
133
+ 99,
134
+ 99,
135
+ 99,
136
+ 99,
137
+ 99,
138
+ 99,
139
+ 99,
140
+ ];
141
+ // Zigzag order for DCT coefficients
142
+ const ZIGZAG = [
143
+ 0,
144
+ 1,
145
+ 8,
146
+ 16,
147
+ 9,
148
+ 2,
149
+ 3,
150
+ 10,
151
+ 17,
152
+ 24,
153
+ 32,
154
+ 25,
155
+ 18,
156
+ 11,
157
+ 4,
158
+ 5,
159
+ 12,
160
+ 19,
161
+ 26,
162
+ 33,
163
+ 40,
164
+ 48,
165
+ 41,
166
+ 34,
167
+ 27,
168
+ 20,
169
+ 13,
170
+ 6,
171
+ 7,
172
+ 14,
173
+ 21,
174
+ 28,
175
+ 35,
176
+ 42,
177
+ 49,
178
+ 56,
179
+ 57,
180
+ 50,
181
+ 43,
182
+ 36,
183
+ 29,
184
+ 22,
185
+ 15,
186
+ 23,
187
+ 30,
188
+ 37,
189
+ 44,
190
+ 51,
191
+ 58,
192
+ 59,
193
+ 52,
194
+ 45,
195
+ 38,
196
+ 31,
197
+ 39,
198
+ 46,
199
+ 53,
200
+ 60,
201
+ 61,
202
+ 54,
203
+ 47,
204
+ 55,
205
+ 62,
206
+ 63,
207
+ ];
208
+ // Standard Huffman tables for DC coefficients (luminance)
209
+ const STD_DC_LUMINANCE_NRCODES = [
210
+ 0,
211
+ 0,
212
+ 1,
213
+ 5,
214
+ 1,
215
+ 1,
216
+ 1,
217
+ 1,
218
+ 1,
219
+ 1,
220
+ 0,
221
+ 0,
222
+ 0,
223
+ 0,
224
+ 0,
225
+ 0,
226
+ 0,
227
+ ];
228
+ const STD_DC_LUMINANCE_VALUES = [
229
+ 0,
230
+ 1,
231
+ 2,
232
+ 3,
233
+ 4,
234
+ 5,
235
+ 6,
236
+ 7,
237
+ 8,
238
+ 9,
239
+ 10,
240
+ 11,
241
+ ];
242
+ // Standard Huffman tables for AC coefficients (luminance)
243
+ const STD_AC_LUMINANCE_NRCODES = [
244
+ 0,
245
+ 0,
246
+ 2,
247
+ 1,
248
+ 3,
249
+ 3,
250
+ 2,
251
+ 4,
252
+ 3,
253
+ 5,
254
+ 5,
255
+ 4,
256
+ 4,
257
+ 0,
258
+ 0,
259
+ 1,
260
+ 0x7d,
261
+ ];
262
+ const STD_AC_LUMINANCE_VALUES = [
263
+ 0x01,
264
+ 0x02,
265
+ 0x03,
266
+ 0x00,
267
+ 0x04,
268
+ 0x11,
269
+ 0x05,
270
+ 0x12,
271
+ 0x21,
272
+ 0x31,
273
+ 0x41,
274
+ 0x06,
275
+ 0x13,
276
+ 0x51,
277
+ 0x61,
278
+ 0x07,
279
+ 0x22,
280
+ 0x71,
281
+ 0x14,
282
+ 0x32,
283
+ 0x81,
284
+ 0x91,
285
+ 0xa1,
286
+ 0x08,
287
+ 0x23,
288
+ 0x42,
289
+ 0xb1,
290
+ 0xc1,
291
+ 0x15,
292
+ 0x52,
293
+ 0xd1,
294
+ 0xf0,
295
+ 0x24,
296
+ 0x33,
297
+ 0x62,
298
+ 0x72,
299
+ 0x82,
300
+ 0x09,
301
+ 0x0a,
302
+ 0x16,
303
+ 0x17,
304
+ 0x18,
305
+ 0x19,
306
+ 0x1a,
307
+ 0x25,
308
+ 0x26,
309
+ 0x27,
310
+ 0x28,
311
+ 0x29,
312
+ 0x2a,
313
+ 0x34,
314
+ 0x35,
315
+ 0x36,
316
+ 0x37,
317
+ 0x38,
318
+ 0x39,
319
+ 0x3a,
320
+ 0x43,
321
+ 0x44,
322
+ 0x45,
323
+ 0x46,
324
+ 0x47,
325
+ 0x48,
326
+ 0x49,
327
+ 0x4a,
328
+ 0x53,
329
+ 0x54,
330
+ 0x55,
331
+ 0x56,
332
+ 0x57,
333
+ 0x58,
334
+ 0x59,
335
+ 0x5a,
336
+ 0x63,
337
+ 0x64,
338
+ 0x65,
339
+ 0x66,
340
+ 0x67,
341
+ 0x68,
342
+ 0x69,
343
+ 0x6a,
344
+ 0x73,
345
+ 0x74,
346
+ 0x75,
347
+ 0x76,
348
+ 0x77,
349
+ 0x78,
350
+ 0x79,
351
+ 0x7a,
352
+ 0x83,
353
+ 0x84,
354
+ 0x85,
355
+ 0x86,
356
+ 0x87,
357
+ 0x88,
358
+ 0x89,
359
+ 0x8a,
360
+ 0x92,
361
+ 0x93,
362
+ 0x94,
363
+ 0x95,
364
+ 0x96,
365
+ 0x97,
366
+ 0x98,
367
+ 0x99,
368
+ 0x9a,
369
+ 0xa2,
370
+ 0xa3,
371
+ 0xa4,
372
+ 0xa5,
373
+ 0xa6,
374
+ 0xa7,
375
+ 0xa8,
376
+ 0xa9,
377
+ 0xaa,
378
+ 0xb2,
379
+ 0xb3,
380
+ 0xb4,
381
+ 0xb5,
382
+ 0xb6,
383
+ 0xb7,
384
+ 0xb8,
385
+ 0xb9,
386
+ 0xba,
387
+ 0xc2,
388
+ 0xc3,
389
+ 0xc4,
390
+ 0xc5,
391
+ 0xc6,
392
+ 0xc7,
393
+ 0xc8,
394
+ 0xc9,
395
+ 0xca,
396
+ 0xd2,
397
+ 0xd3,
398
+ 0xd4,
399
+ 0xd5,
400
+ 0xd6,
401
+ 0xd7,
402
+ 0xd8,
403
+ 0xd9,
404
+ 0xda,
405
+ 0xe1,
406
+ 0xe2,
407
+ 0xe3,
408
+ 0xe4,
409
+ 0xe5,
410
+ 0xe6,
411
+ 0xe7,
412
+ 0xe8,
413
+ 0xe9,
414
+ 0xea,
415
+ 0xf1,
416
+ 0xf2,
417
+ 0xf3,
418
+ 0xf4,
419
+ 0xf5,
420
+ 0xf6,
421
+ 0xf7,
422
+ 0xf8,
423
+ 0xf9,
424
+ 0xfa,
425
+ ];
426
+ // Standard Huffman tables for DC coefficients (chrominance)
427
+ const STD_DC_CHROMINANCE_NRCODES = [
428
+ 0,
429
+ 0,
430
+ 3,
431
+ 1,
432
+ 1,
433
+ 1,
434
+ 1,
435
+ 1,
436
+ 1,
437
+ 1,
438
+ 1,
439
+ 1,
440
+ 0,
441
+ 0,
442
+ 0,
443
+ 0,
444
+ 0,
445
+ ];
446
+ const STD_DC_CHROMINANCE_VALUES = [
447
+ 0,
448
+ 1,
449
+ 2,
450
+ 3,
451
+ 4,
452
+ 5,
453
+ 6,
454
+ 7,
455
+ 8,
456
+ 9,
457
+ 10,
458
+ 11,
459
+ ];
460
+ // Standard Huffman tables for AC coefficients (chrominance)
461
+ const STD_AC_CHROMINANCE_NRCODES = [
462
+ 0,
463
+ 0,
464
+ 2,
465
+ 1,
466
+ 2,
467
+ 4,
468
+ 4,
469
+ 3,
470
+ 4,
471
+ 7,
472
+ 5,
473
+ 4,
474
+ 4,
475
+ 0,
476
+ 1,
477
+ 2,
478
+ 0x77,
479
+ ];
480
+ const STD_AC_CHROMINANCE_VALUES = [
481
+ 0x00,
482
+ 0x01,
483
+ 0x02,
484
+ 0x03,
485
+ 0x11,
486
+ 0x04,
487
+ 0x05,
488
+ 0x21,
489
+ 0x31,
490
+ 0x06,
491
+ 0x12,
492
+ 0x41,
493
+ 0x51,
494
+ 0x07,
495
+ 0x61,
496
+ 0x71,
497
+ 0x13,
498
+ 0x22,
499
+ 0x32,
500
+ 0x81,
501
+ 0x08,
502
+ 0x14,
503
+ 0x42,
504
+ 0x91,
505
+ 0xa1,
506
+ 0xb1,
507
+ 0xc1,
508
+ 0x09,
509
+ 0x23,
510
+ 0x33,
511
+ 0x52,
512
+ 0xf0,
513
+ 0x15,
514
+ 0x62,
515
+ 0x72,
516
+ 0xd1,
517
+ 0x0a,
518
+ 0x16,
519
+ 0x24,
520
+ 0x34,
521
+ 0xe1,
522
+ 0x25,
523
+ 0xf1,
524
+ 0x17,
525
+ 0x18,
526
+ 0x19,
527
+ 0x1a,
528
+ 0x26,
529
+ 0x27,
530
+ 0x28,
531
+ 0x29,
532
+ 0x2a,
533
+ 0x35,
534
+ 0x36,
535
+ 0x37,
536
+ 0x38,
537
+ 0x39,
538
+ 0x3a,
539
+ 0x43,
540
+ 0x44,
541
+ 0x45,
542
+ 0x46,
543
+ 0x47,
544
+ 0x48,
545
+ 0x49,
546
+ 0x4a,
547
+ 0x53,
548
+ 0x54,
549
+ 0x55,
550
+ 0x56,
551
+ 0x57,
552
+ 0x58,
553
+ 0x59,
554
+ 0x5a,
555
+ 0x63,
556
+ 0x64,
557
+ 0x65,
558
+ 0x66,
559
+ 0x67,
560
+ 0x68,
561
+ 0x69,
562
+ 0x6a,
563
+ 0x73,
564
+ 0x74,
565
+ 0x75,
566
+ 0x76,
567
+ 0x77,
568
+ 0x78,
569
+ 0x79,
570
+ 0x7a,
571
+ 0x82,
572
+ 0x83,
573
+ 0x84,
574
+ 0x85,
575
+ 0x86,
576
+ 0x87,
577
+ 0x88,
578
+ 0x89,
579
+ 0x8a,
580
+ 0x92,
581
+ 0x93,
582
+ 0x94,
583
+ 0x95,
584
+ 0x96,
585
+ 0x97,
586
+ 0x98,
587
+ 0x99,
588
+ 0x9a,
589
+ 0xa2,
590
+ 0xa3,
591
+ 0xa4,
592
+ 0xa5,
593
+ 0xa6,
594
+ 0xa7,
595
+ 0xa8,
596
+ 0xa9,
597
+ 0xaa,
598
+ 0xb2,
599
+ 0xb3,
600
+ 0xb4,
601
+ 0xb5,
602
+ 0xb6,
603
+ 0xb7,
604
+ 0xb8,
605
+ 0xb9,
606
+ 0xba,
607
+ 0xc2,
608
+ 0xc3,
609
+ 0xc4,
610
+ 0xc5,
611
+ 0xc6,
612
+ 0xc7,
613
+ 0xc8,
614
+ 0xc9,
615
+ 0xca,
616
+ 0xd2,
617
+ 0xd3,
618
+ 0xd4,
619
+ 0xd5,
620
+ 0xd6,
621
+ 0xd7,
622
+ 0xd8,
623
+ 0xd9,
624
+ 0xda,
625
+ 0xe2,
626
+ 0xe3,
627
+ 0xe4,
628
+ 0xe5,
629
+ 0xe6,
630
+ 0xe7,
631
+ 0xe8,
632
+ 0xe9,
633
+ 0xea,
634
+ 0xf2,
635
+ 0xf3,
636
+ 0xf4,
637
+ 0xf5,
638
+ 0xf6,
639
+ 0xf7,
640
+ 0xf8,
641
+ 0xf9,
642
+ 0xfa,
643
+ ];
644
+ class BitWriter {
645
+ constructor() {
646
+ Object.defineProperty(this, "buffer", {
647
+ enumerable: true,
648
+ configurable: true,
649
+ writable: true,
650
+ value: []
651
+ });
652
+ Object.defineProperty(this, "bitBuffer", {
653
+ enumerable: true,
654
+ configurable: true,
655
+ writable: true,
656
+ value: 0
657
+ });
658
+ Object.defineProperty(this, "bitCount", {
659
+ enumerable: true,
660
+ configurable: true,
661
+ writable: true,
662
+ value: 0
663
+ });
664
+ }
665
+ writeBits(value, length) {
666
+ this.bitBuffer = (this.bitBuffer << length) | value;
667
+ this.bitCount += length;
668
+ while (this.bitCount >= 8) {
669
+ this.bitCount -= 8;
670
+ const byte = (this.bitBuffer >> this.bitCount) & 0xff;
671
+ this.buffer.push(byte);
672
+ // Byte stuffing: insert 0x00 after 0xFF
673
+ if (byte === 0xff) {
674
+ this.buffer.push(0x00);
675
+ }
676
+ }
677
+ }
678
+ flush() {
679
+ if (this.bitCount > 0) {
680
+ const byte = (this.bitBuffer << (8 - this.bitCount)) & 0xff;
681
+ this.buffer.push(byte);
682
+ if (byte === 0xff) {
683
+ this.buffer.push(0x00);
684
+ }
685
+ }
686
+ this.bitBuffer = 0;
687
+ this.bitCount = 0;
688
+ }
689
+ getBytes() {
690
+ return new Uint8Array(this.buffer);
691
+ }
692
+ }
693
+ export class JPEGEncoder {
694
+ constructor(quality = 85) {
695
+ Object.defineProperty(this, "quality", {
696
+ enumerable: true,
697
+ configurable: true,
698
+ writable: true,
699
+ value: void 0
700
+ });
701
+ Object.defineProperty(this, "luminanceQuantTable", {
702
+ enumerable: true,
703
+ configurable: true,
704
+ writable: true,
705
+ value: []
706
+ });
707
+ Object.defineProperty(this, "chrominanceQuantTable", {
708
+ enumerable: true,
709
+ configurable: true,
710
+ writable: true,
711
+ value: []
712
+ });
713
+ Object.defineProperty(this, "dcLuminanceHuffman", {
714
+ enumerable: true,
715
+ configurable: true,
716
+ writable: true,
717
+ value: void 0
718
+ });
719
+ Object.defineProperty(this, "acLuminanceHuffman", {
720
+ enumerable: true,
721
+ configurable: true,
722
+ writable: true,
723
+ value: void 0
724
+ });
725
+ Object.defineProperty(this, "dcChrominanceHuffman", {
726
+ enumerable: true,
727
+ configurable: true,
728
+ writable: true,
729
+ value: void 0
730
+ });
731
+ Object.defineProperty(this, "acChrominanceHuffman", {
732
+ enumerable: true,
733
+ configurable: true,
734
+ writable: true,
735
+ value: void 0
736
+ });
737
+ this.quality = Math.max(1, Math.min(100, quality));
738
+ this.initQuantizationTables();
739
+ this.initHuffmanTables();
740
+ }
741
+ initQuantizationTables() {
742
+ const scaleFactor = this.quality < 50
743
+ ? 5000 / this.quality
744
+ : 200 - this.quality * 2;
745
+ for (let i = 0; i < 64; i++) {
746
+ let lumVal = Math.floor((STANDARD_LUMINANCE_QUANT_TABLE[i] * scaleFactor + 50) / 100);
747
+ let chromVal = Math.floor((STANDARD_CHROMINANCE_QUANT_TABLE[i] * scaleFactor + 50) / 100);
748
+ lumVal = Math.max(1, Math.min(255, lumVal));
749
+ chromVal = Math.max(1, Math.min(255, chromVal));
750
+ this.luminanceQuantTable[i] = lumVal;
751
+ this.chrominanceQuantTable[i] = chromVal;
752
+ }
753
+ }
754
+ initHuffmanTables() {
755
+ this.dcLuminanceHuffman = this.buildHuffmanTable(STD_DC_LUMINANCE_NRCODES, STD_DC_LUMINANCE_VALUES);
756
+ this.acLuminanceHuffman = this.buildHuffmanTable(STD_AC_LUMINANCE_NRCODES, STD_AC_LUMINANCE_VALUES);
757
+ this.dcChrominanceHuffman = this.buildHuffmanTable(STD_DC_CHROMINANCE_NRCODES, STD_DC_CHROMINANCE_VALUES);
758
+ this.acChrominanceHuffman = this.buildHuffmanTable(STD_AC_CHROMINANCE_NRCODES, STD_AC_CHROMINANCE_VALUES);
759
+ }
760
+ buildHuffmanTable(nrcodes, values) {
761
+ const codes = new Array(256).fill(0);
762
+ const sizes = new Array(256).fill(0);
763
+ let code = 0;
764
+ let valueIndex = 0;
765
+ for (let length = 1; length <= 16; length++) {
766
+ for (let i = 0; i < nrcodes[length]; i++) {
767
+ const value = values[valueIndex];
768
+ codes[value] = code;
769
+ sizes[value] = length;
770
+ code++;
771
+ valueIndex++;
772
+ }
773
+ code <<= 1;
774
+ }
775
+ return { codes, sizes };
776
+ }
777
+ encode(width, height, rgba, dpiX = 72, dpiY = 72) {
778
+ const output = [];
779
+ // SOI (Start of Image)
780
+ output.push(0xff, 0xd8);
781
+ // APP0 (JFIF marker)
782
+ this.writeAPP0(output, dpiX, dpiY);
783
+ // DQT (Define Quantization Tables)
784
+ this.writeDQT(output);
785
+ // SOF0 (Start of Frame - Baseline DCT)
786
+ this.writeSOF0(output, width, height);
787
+ // DHT (Define Huffman Tables)
788
+ this.writeDHT(output);
789
+ // SOS (Start of Scan)
790
+ this.writeSOS(output);
791
+ // Encode scan data
792
+ const scanData = this.encodeScan(width, height, rgba);
793
+ for (let i = 0; i < scanData.length; i++) {
794
+ output.push(scanData[i]);
795
+ }
796
+ // EOI (End of Image)
797
+ output.push(0xff, 0xd9);
798
+ return new Uint8Array(output);
799
+ }
800
+ writeAPP0(output, dpiX, dpiY) {
801
+ output.push(0xff, 0xe0); // APP0 marker
802
+ output.push(0x00, 0x10); // Length (16 bytes)
803
+ output.push(0x4a, 0x46, 0x49, 0x46, 0x00); // "JFIF\0"
804
+ output.push(0x01, 0x01); // Version 1.1
805
+ output.push(0x01); // Density units (1 = dots per inch)
806
+ output.push((dpiX >> 8) & 0xff, dpiX & 0xff); // X density
807
+ output.push((dpiY >> 8) & 0xff, dpiY & 0xff); // Y density
808
+ output.push(0x00, 0x00); // Thumbnail dimensions (none)
809
+ }
810
+ writeDQT(output) {
811
+ // Luminance table
812
+ output.push(0xff, 0xdb); // DQT marker
813
+ output.push(0x00, 0x43); // Length (67 bytes)
814
+ output.push(0x00); // Table 0, 8-bit precision
815
+ for (let i = 0; i < 64; i++) {
816
+ output.push(this.luminanceQuantTable[ZIGZAG[i]]);
817
+ }
818
+ // Chrominance table
819
+ output.push(0xff, 0xdb); // DQT marker
820
+ output.push(0x00, 0x43); // Length (67 bytes)
821
+ output.push(0x01); // Table 1, 8-bit precision
822
+ for (let i = 0; i < 64; i++) {
823
+ output.push(this.chrominanceQuantTable[ZIGZAG[i]]);
824
+ }
825
+ }
826
+ writeSOF0(output, width, height) {
827
+ output.push(0xff, 0xc0); // SOF0 marker
828
+ output.push(0x00, 0x11); // Length (17 bytes)
829
+ output.push(0x08); // Precision (8 bits)
830
+ output.push((height >> 8) & 0xff, height & 0xff); // Height
831
+ output.push((width >> 8) & 0xff, width & 0xff); // Width
832
+ output.push(0x03); // Number of components (3 = YCbCr)
833
+ // Y component
834
+ output.push(0x01); // Component ID
835
+ output.push(0x11); // Sampling factors (1x1)
836
+ output.push(0x00); // Quantization table 0
837
+ // Cb component
838
+ output.push(0x02); // Component ID
839
+ output.push(0x11); // Sampling factors (1x1)
840
+ output.push(0x01); // Quantization table 1
841
+ // Cr component
842
+ output.push(0x03); // Component ID
843
+ output.push(0x11); // Sampling factors (1x1)
844
+ output.push(0x01); // Quantization table 1
845
+ }
846
+ writeDHT(output) {
847
+ // DC Luminance
848
+ this.writeHuffmanTable(output, 0x00, STD_DC_LUMINANCE_NRCODES, STD_DC_LUMINANCE_VALUES);
849
+ // AC Luminance
850
+ this.writeHuffmanTable(output, 0x10, STD_AC_LUMINANCE_NRCODES, STD_AC_LUMINANCE_VALUES);
851
+ // DC Chrominance
852
+ this.writeHuffmanTable(output, 0x01, STD_DC_CHROMINANCE_NRCODES, STD_DC_CHROMINANCE_VALUES);
853
+ // AC Chrominance
854
+ this.writeHuffmanTable(output, 0x11, STD_AC_CHROMINANCE_NRCODES, STD_AC_CHROMINANCE_VALUES);
855
+ }
856
+ writeHuffmanTable(output, classId, nrcodes, values) {
857
+ output.push(0xff, 0xc4); // DHT marker
858
+ let length = 19;
859
+ for (let i = 1; i <= 16; i++) {
860
+ length += nrcodes[i];
861
+ }
862
+ output.push((length >> 8) & 0xff, length & 0xff); // Length
863
+ output.push(classId); // Class and ID
864
+ // Number of codes for each length
865
+ for (let i = 1; i <= 16; i++) {
866
+ output.push(nrcodes[i]);
867
+ }
868
+ // Values
869
+ let valueIndex = 0;
870
+ for (let i = 1; i <= 16; i++) {
871
+ for (let j = 0; j < nrcodes[i]; j++) {
872
+ output.push(values[valueIndex++]);
873
+ }
874
+ }
875
+ }
876
+ writeSOS(output) {
877
+ output.push(0xff, 0xda); // SOS marker
878
+ output.push(0x00, 0x0c); // Length (12 bytes)
879
+ output.push(0x03); // Number of components
880
+ // Y component
881
+ output.push(0x01); // Component ID
882
+ output.push(0x00); // DC table 0, AC table 0
883
+ // Cb component
884
+ output.push(0x02); // Component ID
885
+ output.push(0x11); // DC table 1, AC table 1
886
+ // Cr component
887
+ output.push(0x03); // Component ID
888
+ output.push(0x11); // DC table 1, AC table 1
889
+ output.push(0x00); // Start of spectral selection
890
+ output.push(0x3f); // End of spectral selection
891
+ output.push(0x00); // Successive approximation
892
+ }
893
+ encodeScan(width, height, rgba) {
894
+ const bitWriter = new BitWriter();
895
+ // Convert RGBA to YCbCr and encode MCUs
896
+ let dcY = 0, dcCb = 0, dcCr = 0;
897
+ const mcuWidth = Math.ceil(width / 8);
898
+ const mcuHeight = Math.ceil(height / 8);
899
+ for (let mcuY = 0; mcuY < mcuHeight; mcuY++) {
900
+ for (let mcuX = 0; mcuX < mcuWidth; mcuX++) {
901
+ const yBlock = new Array(64).fill(0);
902
+ const cbBlock = new Array(64).fill(0);
903
+ const crBlock = new Array(64).fill(0);
904
+ // Extract 8x8 block and convert RGB to YCbCr
905
+ for (let y = 0; y < 8; y++) {
906
+ for (let x = 0; x < 8; x++) {
907
+ const px = mcuX * 8 + x;
908
+ const py = mcuY * 8 + y;
909
+ if (px < width && py < height) {
910
+ const offset = (py * width + px) * 4;
911
+ const r = rgba[offset];
912
+ const g = rgba[offset + 1];
913
+ const b = rgba[offset + 2];
914
+ // RGB to YCbCr conversion
915
+ const yVal = 0.299 * r + 0.587 * g + 0.114 * b;
916
+ const cbVal = -0.168736 * r - 0.331264 * g + 0.5 * b + 128;
917
+ const crVal = 0.5 * r - 0.418688 * g - 0.081312 * b + 128;
918
+ yBlock[y * 8 + x] = yVal - 128; // Level shift
919
+ cbBlock[y * 8 + x] = cbVal - 128;
920
+ crBlock[y * 8 + x] = crVal - 128;
921
+ }
922
+ }
923
+ }
924
+ // Process Y, Cb, Cr blocks
925
+ dcY = this.encodeBlock(yBlock, this.luminanceQuantTable, dcY, this.dcLuminanceHuffman, this.acLuminanceHuffman, bitWriter);
926
+ dcCb = this.encodeBlock(cbBlock, this.chrominanceQuantTable, dcCb, this.dcChrominanceHuffman, this.acChrominanceHuffman, bitWriter);
927
+ dcCr = this.encodeBlock(crBlock, this.chrominanceQuantTable, dcCr, this.dcChrominanceHuffman, this.acChrominanceHuffman, bitWriter);
928
+ }
929
+ }
930
+ bitWriter.flush();
931
+ return Array.from(bitWriter.getBytes());
932
+ }
933
+ encodeBlock(block, quantTable, prevDC, dcTable, acTable, bitWriter) {
934
+ // Apply DCT
935
+ this.forwardDCT(block);
936
+ // Quantize and reorder to zigzag
937
+ const quantized = new Array(64);
938
+ for (let i = 0; i < 64; i++) {
939
+ const zigzagIndex = ZIGZAG[i];
940
+ quantized[i] = Math.round(block[zigzagIndex] / quantTable[zigzagIndex]);
941
+ }
942
+ // Encode DC coefficient
943
+ const dcDiff = quantized[0] - prevDC;
944
+ this.encodeDC(dcDiff, dcTable, bitWriter);
945
+ // Encode AC coefficients
946
+ this.encodeAC(quantized, acTable, bitWriter);
947
+ return quantized[0];
948
+ }
949
+ forwardDCT(block) {
950
+ // Simplified 2D DCT
951
+ const temp = new Array(64);
952
+ // 1D DCT on rows
953
+ for (let i = 0; i < 8; i++) {
954
+ const offset = i * 8;
955
+ for (let u = 0; u < 8; u++) {
956
+ let sum = 0;
957
+ for (let x = 0; x < 8; x++) {
958
+ sum += block[offset + x] * Math.cos(((2 * x + 1) * u * Math.PI) / 16);
959
+ }
960
+ const cu = u === 0 ? 1 / Math.sqrt(2) : 1;
961
+ temp[offset + u] = 0.5 * cu * sum;
962
+ }
963
+ }
964
+ // 1D DCT on columns
965
+ for (let j = 0; j < 8; j++) {
966
+ for (let v = 0; v < 8; v++) {
967
+ let sum = 0;
968
+ for (let y = 0; y < 8; y++) {
969
+ sum += temp[y * 8 + j] * Math.cos(((2 * y + 1) * v * Math.PI) / 16);
970
+ }
971
+ const cv = v === 0 ? 1 / Math.sqrt(2) : 1;
972
+ block[v * 8 + j] = 0.5 * cv * sum;
973
+ }
974
+ }
975
+ }
976
+ encodeDC(value, huffTable, bitWriter) {
977
+ const absValue = Math.abs(value);
978
+ let size = 0;
979
+ if (absValue > 0) {
980
+ size = Math.floor(Math.log2(absValue)) + 1;
981
+ }
982
+ // Write Huffman code for size
983
+ bitWriter.writeBits(huffTable.codes[size], huffTable.sizes[size]);
984
+ // Write magnitude
985
+ if (size > 0) {
986
+ const magnitude = value < 0 ? value + (1 << size) - 1 : value;
987
+ bitWriter.writeBits(magnitude, size);
988
+ }
989
+ }
990
+ encodeAC(block, huffTable, bitWriter) {
991
+ let zeroCount = 0;
992
+ for (let i = 1; i < 64; i++) {
993
+ const coef = block[i];
994
+ if (coef === 0) {
995
+ zeroCount++;
996
+ }
997
+ else {
998
+ // Write any pending zero runs
999
+ while (zeroCount >= 16) {
1000
+ bitWriter.writeBits(huffTable.codes[0xf0], huffTable.sizes[0xf0]);
1001
+ zeroCount -= 16;
1002
+ }
1003
+ const absCoef = Math.abs(coef);
1004
+ const size = Math.floor(Math.log2(absCoef)) + 1;
1005
+ const symbol = (zeroCount << 4) | size;
1006
+ bitWriter.writeBits(huffTable.codes[symbol], huffTable.sizes[symbol]);
1007
+ const magnitude = coef < 0 ? coef + (1 << size) - 1 : coef;
1008
+ bitWriter.writeBits(magnitude, size);
1009
+ zeroCount = 0;
1010
+ }
1011
+ }
1012
+ // Write EOB if there are trailing zeros
1013
+ if (zeroCount > 0) {
1014
+ bitWriter.writeBits(huffTable.codes[0x00], huffTable.sizes[0x00]);
1015
+ }
1016
+ }
1017
+ }