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,378 @@
1
+ "use strict";
2
+ /**
3
+ * Pure JavaScript GIF decoder implementation
4
+ * Supports GIF87a and GIF89a formats with LZW decompression
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.GIFDecoder = void 0;
8
+ const lzw_js_1 = require("./lzw.js");
9
+ class GIFDecoder {
10
+ constructor(data) {
11
+ Object.defineProperty(this, "data", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "pos", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ this.data = data;
24
+ this.pos = 0;
25
+ }
26
+ readByte() {
27
+ if (this.pos >= this.data.length) {
28
+ throw new Error("Unexpected end of GIF data");
29
+ }
30
+ return this.data[this.pos++];
31
+ }
32
+ readUint16LE() {
33
+ const low = this.readByte();
34
+ const high = this.readByte();
35
+ return low | (high << 8);
36
+ }
37
+ readBytes(count) {
38
+ if (this.pos + count > this.data.length) {
39
+ throw new Error("Unexpected end of GIF data");
40
+ }
41
+ const result = this.data.slice(this.pos, this.pos + count);
42
+ this.pos += count;
43
+ return result;
44
+ }
45
+ readColorTable(size) {
46
+ // Each color is 3 bytes (RGB)
47
+ return this.readBytes(size * 3);
48
+ }
49
+ readDataSubBlocks() {
50
+ const blocks = [];
51
+ while (true) {
52
+ const blockSize = this.readByte();
53
+ if (blockSize === 0)
54
+ break;
55
+ const blockData = this.readBytes(blockSize);
56
+ blocks.push(...blockData);
57
+ }
58
+ return new Uint8Array(blocks);
59
+ }
60
+ decode() {
61
+ // Verify GIF signature
62
+ const signature = this.readBytes(3);
63
+ const version = this.readBytes(3);
64
+ if (signature[0] !== 0x47 || signature[1] !== 0x49 || signature[2] !== 0x46 ||
65
+ (version[0] !== 0x38) ||
66
+ (version[1] !== 0x37 && version[1] !== 0x39) ||
67
+ (version[2] !== 0x61)) {
68
+ throw new Error("Invalid GIF signature");
69
+ }
70
+ // Read Logical Screen Descriptor
71
+ const width = this.readUint16LE();
72
+ const height = this.readUint16LE();
73
+ const packed = this.readByte();
74
+ const backgroundColorIndex = this.readByte();
75
+ const _aspectRatio = this.readByte();
76
+ const hasGlobalColorTable = (packed & 0x80) !== 0;
77
+ const _colorResolution = ((packed & 0x70) >> 4) + 1;
78
+ const _sortFlag = (packed & 0x08) !== 0;
79
+ const globalColorTableSize = 2 << (packed & 0x07);
80
+ let globalColorTable = null;
81
+ if (hasGlobalColorTable) {
82
+ globalColorTable = this.readColorTable(globalColorTableSize);
83
+ }
84
+ // Parse data stream
85
+ let imageWidth = 0;
86
+ let imageHeight = 0;
87
+ let imageLeft = 0;
88
+ let imageTop = 0;
89
+ let localColorTable = null;
90
+ let transparentColorIndex = null;
91
+ let interlaced = false;
92
+ while (this.pos < this.data.length) {
93
+ const separator = this.readByte();
94
+ if (separator === 0x21) {
95
+ // Extension
96
+ const label = this.readByte();
97
+ if (label === 0xf9) {
98
+ // Graphic Control Extension
99
+ const _blockSize = this.readByte();
100
+ const packed = this.readByte();
101
+ const hasTransparent = (packed & 0x01) !== 0;
102
+ const _delayTime = this.readUint16LE();
103
+ const transparentIndex = this.readByte();
104
+ const _terminator = this.readByte();
105
+ if (hasTransparent) {
106
+ transparentColorIndex = transparentIndex;
107
+ }
108
+ }
109
+ else {
110
+ // Skip other extensions
111
+ this.readDataSubBlocks();
112
+ }
113
+ }
114
+ else if (separator === 0x2c) {
115
+ // Image Descriptor
116
+ imageLeft = this.readUint16LE();
117
+ imageTop = this.readUint16LE();
118
+ imageWidth = this.readUint16LE();
119
+ imageHeight = this.readUint16LE();
120
+ const packed = this.readByte();
121
+ const hasLocalColorTable = (packed & 0x80) !== 0;
122
+ interlaced = (packed & 0x40) !== 0;
123
+ const localColorTableSize = 2 << (packed & 0x07);
124
+ if (hasLocalColorTable) {
125
+ localColorTable = this.readColorTable(localColorTableSize);
126
+ }
127
+ // Read image data
128
+ const minCodeSize = this.readByte();
129
+ const compressedData = this.readDataSubBlocks();
130
+ // Decompress using LZW
131
+ const decoder = new lzw_js_1.LZWDecoder(minCodeSize, compressedData);
132
+ const indexedData = decoder.decompress();
133
+ // Convert indexed to RGBA
134
+ const colorTable = localColorTable || globalColorTable;
135
+ if (!colorTable) {
136
+ throw new Error("No color table available");
137
+ }
138
+ return this.indexedToRGBA(indexedData, imageWidth, imageHeight, colorTable, transparentColorIndex, interlaced, width, height, imageLeft, imageTop, backgroundColorIndex);
139
+ }
140
+ else if (separator === 0x3b) {
141
+ // Trailer - end of GIF
142
+ break;
143
+ }
144
+ else if (separator === 0x00) {
145
+ // Skip null bytes
146
+ continue;
147
+ }
148
+ else {
149
+ throw new Error(`Unknown separator: 0x${separator.toString(16)}`);
150
+ }
151
+ }
152
+ throw new Error("No image data found in GIF");
153
+ }
154
+ /**
155
+ * Decode all frames from an animated GIF
156
+ * @returns Object with canvas dimensions and array of frames
157
+ */
158
+ decodeAllFrames() {
159
+ // Reset position
160
+ this.pos = 0;
161
+ // Verify GIF signature
162
+ const signature = this.readBytes(3);
163
+ const version = this.readBytes(3);
164
+ if (signature[0] !== 0x47 || signature[1] !== 0x49 || signature[2] !== 0x46 ||
165
+ (version[0] !== 0x38) ||
166
+ (version[1] !== 0x37 && version[1] !== 0x39) ||
167
+ (version[2] !== 0x61)) {
168
+ throw new Error("Invalid GIF signature");
169
+ }
170
+ // Read Logical Screen Descriptor
171
+ const width = this.readUint16LE();
172
+ const height = this.readUint16LE();
173
+ const packed = this.readByte();
174
+ const _backgroundColorIndex = this.readByte();
175
+ const _aspectRatio = this.readByte();
176
+ const hasGlobalColorTable = (packed & 0x80) !== 0;
177
+ // Color table size: 2^(n+1) where n is the 3 least significant bits
178
+ const globalColorTableSize = 2 << (packed & 0x07);
179
+ let globalColorTable = null;
180
+ if (hasGlobalColorTable) {
181
+ globalColorTable = this.readColorTable(globalColorTableSize);
182
+ }
183
+ const frames = [];
184
+ // Parse data stream for all frames
185
+ let transparentColorIndex = null;
186
+ let delayTime = 0;
187
+ let disposalMethod = 0;
188
+ while (this.pos < this.data.length) {
189
+ const separator = this.readByte();
190
+ if (separator === 0x21) {
191
+ // Extension
192
+ const label = this.readByte();
193
+ if (label === 0xf9) {
194
+ // Graphic Control Extension
195
+ const _blockSize = this.readByte();
196
+ const packed = this.readByte();
197
+ disposalMethod = (packed >> 2) & 0x07;
198
+ const hasTransparent = (packed & 0x01) !== 0;
199
+ delayTime = this.readUint16LE();
200
+ const transparentIndex = this.readByte();
201
+ const _terminator = this.readByte();
202
+ if (hasTransparent) {
203
+ transparentColorIndex = transparentIndex;
204
+ }
205
+ }
206
+ else {
207
+ // Skip other extensions
208
+ this.readDataSubBlocks();
209
+ }
210
+ }
211
+ else if (separator === 0x2c) {
212
+ // Image Descriptor
213
+ const imageLeft = this.readUint16LE();
214
+ const imageTop = this.readUint16LE();
215
+ const imageWidth = this.readUint16LE();
216
+ const imageHeight = this.readUint16LE();
217
+ const packed = this.readByte();
218
+ const hasLocalColorTable = (packed & 0x80) !== 0;
219
+ const interlaced = (packed & 0x40) !== 0;
220
+ // Color table size: 2^(n+1) where n is the 3 least significant bits
221
+ const localColorTableSize = 2 << (packed & 0x07);
222
+ let localColorTable = null;
223
+ if (hasLocalColorTable) {
224
+ localColorTable = this.readColorTable(localColorTableSize);
225
+ }
226
+ // Read image data
227
+ const minCodeSize = this.readByte();
228
+ const compressedData = this.readDataSubBlocks();
229
+ // Decompress using LZW
230
+ const decoder = new lzw_js_1.LZWDecoder(minCodeSize, compressedData);
231
+ const indexedData = decoder.decompress();
232
+ // Convert indexed to RGBA
233
+ const colorTable = localColorTable || globalColorTable;
234
+ if (!colorTable) {
235
+ throw new Error("No color table available");
236
+ }
237
+ // Deinterlace if necessary
238
+ const deinterlaced = interlaced
239
+ ? this.deinterlace(indexedData, imageWidth, imageHeight)
240
+ : indexedData;
241
+ // Create frame with just the image data (not full canvas)
242
+ const frameData = new Uint8Array(imageWidth * imageHeight * 4);
243
+ for (let y = 0; y < imageHeight; y++) {
244
+ for (let x = 0; x < imageWidth; x++) {
245
+ const srcIdx = y * imageWidth + x;
246
+ if (srcIdx >= deinterlaced.length)
247
+ continue;
248
+ const colorIndex = deinterlaced[srcIdx];
249
+ const dstIdx = (y * imageWidth + x) * 4;
250
+ if (transparentColorIndex !== null &&
251
+ colorIndex === transparentColorIndex) {
252
+ // Transparent pixel
253
+ frameData[dstIdx] = 0;
254
+ frameData[dstIdx + 1] = 0;
255
+ frameData[dstIdx + 2] = 0;
256
+ frameData[dstIdx + 3] = 0;
257
+ }
258
+ else {
259
+ // Copy color from color table
260
+ const colorOffset = colorIndex * 3;
261
+ if (colorOffset + 2 < colorTable.length) {
262
+ frameData[dstIdx] = colorTable[colorOffset];
263
+ frameData[dstIdx + 1] = colorTable[colorOffset + 1];
264
+ frameData[dstIdx + 2] = colorTable[colorOffset + 2];
265
+ frameData[dstIdx + 3] = 255;
266
+ }
267
+ }
268
+ }
269
+ }
270
+ frames.push({
271
+ width: imageWidth,
272
+ height: imageHeight,
273
+ left: imageLeft,
274
+ top: imageTop,
275
+ data: frameData,
276
+ delay: delayTime,
277
+ disposal: disposalMethod,
278
+ });
279
+ // Reset graphic control extension state
280
+ transparentColorIndex = null;
281
+ delayTime = 0;
282
+ disposalMethod = 0;
283
+ }
284
+ else if (separator === 0x3b) {
285
+ // Trailer - end of GIF
286
+ break;
287
+ }
288
+ else if (separator === 0x00) {
289
+ // Skip null bytes
290
+ continue;
291
+ }
292
+ else {
293
+ throw new Error(`Unknown separator: 0x${separator.toString(16)}`);
294
+ }
295
+ }
296
+ if (frames.length === 0) {
297
+ throw new Error("No image data found in GIF");
298
+ }
299
+ return {
300
+ width,
301
+ height,
302
+ frames,
303
+ };
304
+ }
305
+ indexedToRGBA(indexedData, imageWidth, imageHeight, colorTable, transparentColorIndex, interlaced, canvasWidth, canvasHeight, imageLeft, imageTop, backgroundColorIndex) {
306
+ // Create RGBA buffer for full canvas
307
+ const rgba = new Uint8Array(canvasWidth * canvasHeight * 4);
308
+ // Fill with background color
309
+ const bgR = colorTable[backgroundColorIndex * 3] || 0;
310
+ const bgG = colorTable[backgroundColorIndex * 3 + 1] || 0;
311
+ const bgB = colorTable[backgroundColorIndex * 3 + 2] || 0;
312
+ for (let i = 0; i < rgba.length; i += 4) {
313
+ rgba[i] = bgR;
314
+ rgba[i + 1] = bgG;
315
+ rgba[i + 2] = bgB;
316
+ rgba[i + 3] = 255;
317
+ }
318
+ // Deinterlace if necessary
319
+ const deinterlaced = interlaced
320
+ ? this.deinterlace(indexedData, imageWidth, imageHeight)
321
+ : indexedData;
322
+ // Copy image data to canvas
323
+ for (let y = 0; y < imageHeight; y++) {
324
+ for (let x = 0; x < imageWidth; x++) {
325
+ const srcIdx = y * imageWidth + x;
326
+ if (srcIdx >= deinterlaced.length)
327
+ continue;
328
+ const colorIndex = deinterlaced[srcIdx];
329
+ const canvasX = imageLeft + x;
330
+ const canvasY = imageTop + y;
331
+ if (canvasX >= canvasWidth || canvasY >= canvasHeight)
332
+ continue;
333
+ const dstIdx = (canvasY * canvasWidth + canvasX) * 4;
334
+ if (transparentColorIndex !== null && colorIndex === transparentColorIndex) {
335
+ // Transparent pixel
336
+ rgba[dstIdx + 3] = 0;
337
+ }
338
+ else {
339
+ // Copy color from color table
340
+ const colorOffset = colorIndex * 3;
341
+ if (colorOffset + 2 < colorTable.length) {
342
+ rgba[dstIdx] = colorTable[colorOffset];
343
+ rgba[dstIdx + 1] = colorTable[colorOffset + 1];
344
+ rgba[dstIdx + 2] = colorTable[colorOffset + 2];
345
+ rgba[dstIdx + 3] = 255;
346
+ }
347
+ }
348
+ }
349
+ }
350
+ return {
351
+ width: canvasWidth,
352
+ height: canvasHeight,
353
+ data: rgba,
354
+ };
355
+ }
356
+ deinterlace(data, width, height) {
357
+ const deinterlaced = new Uint8Array(data.length);
358
+ const passes = [
359
+ { start: 0, step: 8 }, // Pass 1: every 8th row, starting with row 0
360
+ { start: 4, step: 8 }, // Pass 2: every 8th row, starting with row 4
361
+ { start: 2, step: 4 }, // Pass 3: every 4th row, starting with row 2
362
+ { start: 1, step: 2 }, // Pass 4: every 2nd row, starting with row 1
363
+ ];
364
+ let srcIdx = 0;
365
+ for (const pass of passes) {
366
+ for (let y = pass.start; y < height; y += pass.step) {
367
+ for (let x = 0; x < width; x++) {
368
+ if (srcIdx >= data.length)
369
+ break;
370
+ const dstIdx = y * width + x;
371
+ deinterlaced[dstIdx] = data[srcIdx++];
372
+ }
373
+ }
374
+ }
375
+ return deinterlaced;
376
+ }
377
+ }
378
+ exports.GIFDecoder = GIFDecoder;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Pure JavaScript GIF encoder implementation
3
+ * Supports GIF89a format with LZW compression
4
+ */
5
+ export declare class GIFEncoder {
6
+ private width;
7
+ private height;
8
+ private data;
9
+ constructor(width: number, height: number, data: Uint8Array);
10
+ private writeBytes;
11
+ private writeUint16LE;
12
+ private writeString;
13
+ /**
14
+ * Quantize a color channel value to a specified number of levels
15
+ * @param value - The input color channel value (0-255)
16
+ * @param levels - Number of quantization levels minus 1 (e.g., 7 for 8 levels)
17
+ * @param step - Step size for quantization (e.g., 255/7)
18
+ * @returns Quantized integer value
19
+ */
20
+ private quantizeChannel;
21
+ /**
22
+ * Quantize RGBA image to 256 colors using median cut algorithm
23
+ */
24
+ private quantize;
25
+ private nextPowerOf2;
26
+ private getBitsPerColor;
27
+ encode(): Uint8Array;
28
+ }
29
+ //# sourceMappingURL=gif_encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gif_encoder.d.ts","sourceRoot":"","sources":["../../../src/src/utils/gif_encoder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAa;gBAEb,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU;IAM3D,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,WAAW;IAMnB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,OAAO,CAAC,QAAQ;IA6GhB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,eAAe;IAQvB,MAAM,IAAI,UAAU;CA+ErB"}
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ /**
3
+ * Pure JavaScript GIF encoder implementation
4
+ * Supports GIF89a format with LZW compression
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.GIFEncoder = void 0;
8
+ const lzw_js_1 = require("./lzw.js");
9
+ class GIFEncoder {
10
+ constructor(width, height, data) {
11
+ Object.defineProperty(this, "width", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "height", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ Object.defineProperty(this, "data", {
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true,
27
+ value: void 0
28
+ });
29
+ this.width = width;
30
+ this.height = height;
31
+ this.data = data;
32
+ }
33
+ writeBytes(output, bytes) {
34
+ output.push(...bytes);
35
+ }
36
+ writeUint16LE(output, value) {
37
+ output.push(value & 0xff);
38
+ output.push((value >> 8) & 0xff);
39
+ }
40
+ writeString(output, str) {
41
+ for (let i = 0; i < str.length; i++) {
42
+ output.push(str.charCodeAt(i));
43
+ }
44
+ }
45
+ /**
46
+ * Quantize a color channel value to a specified number of levels
47
+ * @param value - The input color channel value (0-255)
48
+ * @param levels - Number of quantization levels minus 1 (e.g., 7 for 8 levels)
49
+ * @param step - Step size for quantization (e.g., 255/7)
50
+ * @returns Quantized integer value
51
+ */
52
+ quantizeChannel(value, levels, step) {
53
+ // First round to get quantization level (0-levels)
54
+ // Then multiply by step size and round to ensure integer result
55
+ return Math.round(Math.round(value * levels / 255) * step);
56
+ }
57
+ /**
58
+ * Quantize RGBA image to 256 colors using median cut algorithm
59
+ */
60
+ quantize() {
61
+ // Simple quantization: collect unique colors and build palette
62
+ const colorMap = new Map();
63
+ const colors = [];
64
+ // Color quantization parameters for 8-bit palette (256 colors)
65
+ // R/G: 8 levels (0-7) using 3 bits, B: 4 levels (0-3) using 2 bits (8*8*4=256)
66
+ const RG_LEVELS = 7; // Max level for R/G (8 total levels: 0-7)
67
+ const B_LEVELS = 3; // Max level for B (4 total levels: 0-3)
68
+ const rgStep = 255 / RG_LEVELS; // Step size for R/G quantization
69
+ const bStep = 255 / B_LEVELS; // Step size for B quantization
70
+ // Collect unique colors
71
+ for (let i = 0; i < this.data.length; i += 4) {
72
+ const r = this.data[i];
73
+ const g = this.data[i + 1];
74
+ const b = this.data[i + 2];
75
+ const key = `${r},${g},${b}`;
76
+ if (!colorMap.has(key) && colors.length < 256) {
77
+ colorMap.set(key, colors.length);
78
+ colors.push({ r, g, b });
79
+ }
80
+ }
81
+ // Track if color reduction was applied
82
+ let useColorReduction = false;
83
+ // If we have too many colors, use simple color reduction
84
+ if (colors.length >= 256) {
85
+ // Downsample colors to 256 by reducing color depth
86
+ colorMap.clear();
87
+ colors.length = 0;
88
+ useColorReduction = true;
89
+ for (let i = 0; i < this.data.length; i += 4) {
90
+ // Reduce color depth: 3 bits for R/G channels, 2 bits for B channel
91
+ // This gives us 8 bits total = 256 possible colors
92
+ const r = this.quantizeChannel(this.data[i], RG_LEVELS, rgStep);
93
+ const g = this.quantizeChannel(this.data[i + 1], RG_LEVELS, rgStep);
94
+ const b = this.quantizeChannel(this.data[i + 2], B_LEVELS, bStep);
95
+ const key = `${r},${g},${b}`;
96
+ if (!colorMap.has(key)) {
97
+ if (colors.length < 256) {
98
+ colorMap.set(key, colors.length);
99
+ colors.push({ r, g, b });
100
+ }
101
+ }
102
+ }
103
+ }
104
+ // Pad to power of 2
105
+ const paletteSize = Math.max(2, this.nextPowerOf2(colors.length));
106
+ while (colors.length < paletteSize) {
107
+ colors.push({ r: 0, g: 0, b: 0 });
108
+ }
109
+ // Create palette
110
+ const palette = new Uint8Array(colors.length * 3);
111
+ for (let i = 0; i < colors.length; i++) {
112
+ palette[i * 3] = colors[i].r;
113
+ palette[i * 3 + 1] = colors[i].g;
114
+ palette[i * 3 + 2] = colors[i].b;
115
+ }
116
+ // Create indexed data
117
+ const indexed = new Uint8Array(this.width * this.height);
118
+ for (let i = 0, j = 0; i < this.data.length; i += 4, j++) {
119
+ let r = this.data[i];
120
+ let g = this.data[i + 1];
121
+ let b = this.data[i + 2];
122
+ // Apply color reduction if it was used for building the palette
123
+ if (useColorReduction) {
124
+ r = this.quantizeChannel(r, RG_LEVELS, rgStep);
125
+ g = this.quantizeChannel(g, RG_LEVELS, rgStep);
126
+ b = this.quantizeChannel(b, B_LEVELS, bStep);
127
+ }
128
+ const key = `${r},${g},${b}`;
129
+ // Try fast O(1) lookup first
130
+ if (colorMap.has(key)) {
131
+ indexed[j] = colorMap.get(key);
132
+ }
133
+ else {
134
+ // Fallback: find closest color in palette (shouldn't happen often)
135
+ let minDist = Infinity;
136
+ let bestIdx = 0;
137
+ for (let k = 0; k < colors.length; k++) {
138
+ const dr = r - colors[k].r;
139
+ const dg = g - colors[k].g;
140
+ const db = b - colors[k].b;
141
+ const dist = dr * dr + dg * dg + db * db;
142
+ if (dist < minDist) {
143
+ minDist = dist;
144
+ bestIdx = k;
145
+ }
146
+ }
147
+ indexed[j] = bestIdx;
148
+ }
149
+ }
150
+ return { palette, indexed };
151
+ }
152
+ nextPowerOf2(n) {
153
+ let power = 1;
154
+ while (power < n) {
155
+ power *= 2;
156
+ }
157
+ return power;
158
+ }
159
+ getBitsPerColor(paletteSize) {
160
+ let bits = 1;
161
+ while ((1 << bits) < paletteSize) {
162
+ bits++;
163
+ }
164
+ return Math.max(2, bits);
165
+ }
166
+ encode() {
167
+ const output = [];
168
+ // Quantize image
169
+ const { palette, indexed } = this.quantize();
170
+ const paletteSize = palette.length / 3;
171
+ const bitsPerColor = this.getBitsPerColor(paletteSize);
172
+ // Header
173
+ this.writeString(output, "GIF89a");
174
+ // Logical Screen Descriptor
175
+ this.writeUint16LE(output, this.width);
176
+ this.writeUint16LE(output, this.height);
177
+ // Packed field:
178
+ // - Global Color Table Flag (1 bit): 1
179
+ // - Color Resolution (3 bits): bitsPerColor - 1
180
+ // - Sort Flag (1 bit): 0
181
+ // - Size of Global Color Table (3 bits): bitsPerColor - 1
182
+ const packed = 0x80 | ((bitsPerColor - 1) << 4) | (bitsPerColor - 1);
183
+ output.push(packed);
184
+ // Background Color Index
185
+ output.push(0);
186
+ // Pixel Aspect Ratio
187
+ output.push(0);
188
+ // Global Color Table
189
+ // The GCT size is 2^(n+1) where n is the value in the packed field
190
+ // So we need to write that many colors, padding if necessary
191
+ const gctSize = 1 << bitsPerColor;
192
+ const paddedPalette = new Uint8Array(gctSize * 3);
193
+ paddedPalette.set(palette);
194
+ this.writeBytes(output, paddedPalette);
195
+ // Image Descriptor
196
+ output.push(0x2c); // Image Separator
197
+ // Image position and dimensions
198
+ this.writeUint16LE(output, 0); // Left
199
+ this.writeUint16LE(output, 0); // Top
200
+ this.writeUint16LE(output, this.width);
201
+ this.writeUint16LE(output, this.height);
202
+ // Packed field:
203
+ // - Local Color Table Flag (1 bit): 0
204
+ // - Interlace Flag (1 bit): 0
205
+ // - Sort Flag (1 bit): 0
206
+ // - Reserved (2 bits): 0
207
+ // - Size of Local Color Table (3 bits): 0
208
+ output.push(0);
209
+ // LZW Minimum Code Size
210
+ const minCodeSize = Math.max(2, bitsPerColor);
211
+ output.push(minCodeSize);
212
+ // Compress image data with LZW
213
+ const encoder = new lzw_js_1.LZWEncoder(minCodeSize);
214
+ const compressed = encoder.compress(indexed);
215
+ // Write compressed data in sub-blocks (max 255 bytes per block)
216
+ for (let i = 0; i < compressed.length; i += 255) {
217
+ const blockSize = Math.min(255, compressed.length - i);
218
+ output.push(blockSize);
219
+ for (let j = 0; j < blockSize; j++) {
220
+ output.push(compressed[i + j]);
221
+ }
222
+ }
223
+ // Block Terminator
224
+ output.push(0);
225
+ // Trailer
226
+ output.push(0x3b);
227
+ return new Uint8Array(output);
228
+ }
229
+ }
230
+ exports.GIFEncoder = GIFEncoder;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Basic baseline JPEG decoder implementation
3
+ * Supports baseline DCT JPEG images (the most common format)
4
+ *
5
+ * This is a simplified implementation that handles common JPEG files.
6
+ * For complex or non-standard JPEGs, the ImageDecoder API fallback is preferred.
7
+ */
8
+ export declare class JPEGDecoder {
9
+ private data;
10
+ private pos;
11
+ private width;
12
+ private height;
13
+ private components;
14
+ private qTables;
15
+ private dcTables;
16
+ private acTables;
17
+ private restartInterval;
18
+ private bitBuffer;
19
+ private bitCount;
20
+ constructor(data: Uint8Array);
21
+ decode(): Uint8Array;
22
+ private readMarker;
23
+ private readUint16;
24
+ private skipSegment;
25
+ private parseDQT;
26
+ private parseDHT;
27
+ private buildHuffmanTable;
28
+ private parseSOF;
29
+ private parseSOS;
30
+ private parseDRI;
31
+ private decodeScan;
32
+ private decodeBlock;
33
+ private decodeHuffman;
34
+ private readBit;
35
+ private receiveBits;
36
+ private idct;
37
+ private convertToRGB;
38
+ }
39
+ //# sourceMappingURL=jpeg_decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jpeg_decoder.d.ts","sourceRoot":"","sources":["../../../src/src/utils/jpeg_decoder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkGH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,QAAQ,CAAa;gBAEjB,IAAI,EAAE,UAAU;IAI5B,MAAM,IAAI,UAAU;IAwDpB,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,QAAQ;IAsBhB,OAAO,CAAC,QAAQ;IAgChB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,QAAQ;IAmChB,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,UAAU;IAiDlB,OAAO,CAAC,WAAW;IAiDnB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,OAAO;IA2Bf,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,IAAI;IAqCZ,OAAO,CAAC,YAAY;CAsGrB"}