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 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,YAAY,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,WAAW,EACX,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
package/script/mod.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * @module @cross/image
4
+ *
5
+ * A pure JavaScript, dependency-free, cross-runtime image processing library.
6
+ * Supports reading, resizing, and saving common image formats (PNG, JPEG, WebP, GIF, TIFF, BMP, RAW).
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { Image } from "@cross/image";
11
+ *
12
+ * // Read an image
13
+ * const data = await Deno.readFile("input.png");
14
+ * const image = await Image.read(data);
15
+ *
16
+ * // Resize it
17
+ * image.resize({ width: 200, height: 200 });
18
+ *
19
+ * // Save as different format
20
+ * const output = await image.save("jpeg");
21
+ * await Deno.writeFile("output.jpg", output);
22
+ * ```
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.ASCIIFormat = exports.RAWFormat = exports.BMPFormat = exports.TIFFFormat = exports.GIFFormat = exports.WebPFormat = exports.JPEGFormat = exports.PNGFormat = exports.Image = void 0;
26
+ var image_js_1 = require("./src/image.js");
27
+ Object.defineProperty(exports, "Image", { enumerable: true, get: function () { return image_js_1.Image; } });
28
+ var png_js_1 = require("./src/formats/png.js");
29
+ Object.defineProperty(exports, "PNGFormat", { enumerable: true, get: function () { return png_js_1.PNGFormat; } });
30
+ var jpeg_js_1 = require("./src/formats/jpeg.js");
31
+ Object.defineProperty(exports, "JPEGFormat", { enumerable: true, get: function () { return jpeg_js_1.JPEGFormat; } });
32
+ var webp_js_1 = require("./src/formats/webp.js");
33
+ Object.defineProperty(exports, "WebPFormat", { enumerable: true, get: function () { return webp_js_1.WebPFormat; } });
34
+ var gif_js_1 = require("./src/formats/gif.js");
35
+ Object.defineProperty(exports, "GIFFormat", { enumerable: true, get: function () { return gif_js_1.GIFFormat; } });
36
+ var tiff_js_1 = require("./src/formats/tiff.js");
37
+ Object.defineProperty(exports, "TIFFFormat", { enumerable: true, get: function () { return tiff_js_1.TIFFFormat; } });
38
+ var bmp_js_1 = require("./src/formats/bmp.js");
39
+ Object.defineProperty(exports, "BMPFormat", { enumerable: true, get: function () { return bmp_js_1.BMPFormat; } });
40
+ var raw_js_1 = require("./src/formats/raw.js");
41
+ Object.defineProperty(exports, "RAWFormat", { enumerable: true, get: function () { return raw_js_1.RAWFormat; } });
42
+ var ascii_js_1 = require("./src/formats/ascii.js");
43
+ Object.defineProperty(exports, "ASCIIFormat", { enumerable: true, get: function () { return ascii_js_1.ASCIIFormat; } });
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,27 @@
1
+ import type { ASCIIOptions, ImageData, ImageFormat } from "../types.js";
2
+ /**
3
+ * ASCII format handler
4
+ * Converts images to ASCII art text representation
5
+ *
6
+ * Format structure:
7
+ * - Magic bytes (6 bytes): "ASCII\n" (0x41 0x53 0x43 0x49 0x49 0x0A)
8
+ * - Options line: "width:W charset:C aspectRatio:A invert:I\n"
9
+ * - ASCII art text (UTF-8 encoded)
10
+ *
11
+ * Note: This format is primarily for encoding (image to ASCII).
12
+ * Decoding reconstructs a basic grayscale approximation.
13
+ */
14
+ export declare class ASCIIFormat implements ImageFormat {
15
+ readonly name = "ascii";
16
+ readonly mimeType = "text/plain";
17
+ private readonly MAGIC_BYTES;
18
+ private readonly CHARSETS;
19
+ canDecode(data: Uint8Array): boolean;
20
+ decode(data: Uint8Array): Promise<ImageData>;
21
+ encode(imageData: ImageData, options?: ASCIIOptions): Promise<Uint8Array>;
22
+ /**
23
+ * Parse options from the options line
24
+ */
25
+ private parseOptions;
26
+ }
27
+ //# sourceMappingURL=ascii.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ascii.d.ts","sourceRoot":"","sources":["../../../src/src/formats/ascii.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAExE;;;;;;;;;;;GAWG;AACH,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,QAAQ,gBAAgB;IAEjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAOzB;IAGH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAOvB;IAEF,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO;IAcpC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IA+D5C,MAAM,CACJ,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,UAAU,CAAC;IAoDtB;;OAEG;IACH,OAAO,CAAC,YAAY;CA6BrB"}
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ASCIIFormat = void 0;
4
+ /**
5
+ * ASCII format handler
6
+ * Converts images to ASCII art text representation
7
+ *
8
+ * Format structure:
9
+ * - Magic bytes (6 bytes): "ASCII\n" (0x41 0x53 0x43 0x49 0x49 0x0A)
10
+ * - Options line: "width:W charset:C aspectRatio:A invert:I\n"
11
+ * - ASCII art text (UTF-8 encoded)
12
+ *
13
+ * Note: This format is primarily for encoding (image to ASCII).
14
+ * Decoding reconstructs a basic grayscale approximation.
15
+ */
16
+ class ASCIIFormat {
17
+ constructor() {
18
+ Object.defineProperty(this, "name", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: "ascii"
23
+ });
24
+ Object.defineProperty(this, "mimeType", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: "text/plain"
29
+ });
30
+ Object.defineProperty(this, "MAGIC_BYTES", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: new Uint8Array([
35
+ 0x41,
36
+ 0x53,
37
+ 0x43,
38
+ 0x49,
39
+ 0x49,
40
+ 0x0A,
41
+ ])
42
+ }); // "ASCII\n"
43
+ // Character sets ordered from darkest to lightest
44
+ Object.defineProperty(this, "CHARSETS", {
45
+ enumerable: true,
46
+ configurable: true,
47
+ writable: true,
48
+ value: {
49
+ simple: " .:-=+*#%@",
50
+ extended: " .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$",
51
+ blocks: " ░▒▓█",
52
+ detailed: " .`-_':,;^=+/\"|)\\<>)iv%xclrs{*}I?!][1taeo7zjLunT#JCwfy325Fh9kP6pqdbVOlS8X$KHEA4D3RZG0MQNWU&%B@",
53
+ }
54
+ });
55
+ }
56
+ canDecode(data) {
57
+ // Check if data starts with "ASCII\n"
58
+ if (data.length < 6) {
59
+ return false;
60
+ }
61
+ return data[0] === this.MAGIC_BYTES[0] &&
62
+ data[1] === this.MAGIC_BYTES[1] &&
63
+ data[2] === this.MAGIC_BYTES[2] &&
64
+ data[3] === this.MAGIC_BYTES[3] &&
65
+ data[4] === this.MAGIC_BYTES[4] &&
66
+ data[5] === this.MAGIC_BYTES[5];
67
+ }
68
+ decode(data) {
69
+ if (!this.canDecode(data)) {
70
+ throw new Error("Invalid ASCII art signature");
71
+ }
72
+ // Convert to string
73
+ const text = new TextDecoder().decode(data);
74
+ const lines = text.split("\n");
75
+ if (lines.length < 2) {
76
+ throw new Error("Invalid ASCII art format");
77
+ }
78
+ // Parse options from second line
79
+ const optionsLine = lines[1];
80
+ const options = this.parseOptions(optionsLine);
81
+ // Get ASCII art content (skip magic line and options line)
82
+ const artLines = lines.slice(2).filter((line) => line.length > 0);
83
+ if (artLines.length === 0) {
84
+ throw new Error("No ASCII art content found");
85
+ }
86
+ // Calculate dimensions
87
+ const height = artLines.length;
88
+ const width = Math.max(...artLines.map((line) => line.length));
89
+ // Convert ASCII art back to image data
90
+ const imageData = new Uint8Array(width * height * 4);
91
+ const charset = this.CHARSETS[options.charset] || this.CHARSETS.simple;
92
+ for (let y = 0; y < height; y++) {
93
+ const line = artLines[y];
94
+ for (let x = 0; x < width; x++) {
95
+ const char = x < line.length ? line[x] : " ";
96
+ const charIndex = charset.indexOf(char);
97
+ // Calculate brightness (0-255)
98
+ let brightness;
99
+ if (charIndex === -1) {
100
+ brightness = 0; // Unknown character = black
101
+ }
102
+ else {
103
+ brightness = Math.floor((charIndex / (charset.length - 1)) * 255);
104
+ }
105
+ if (options.invert) {
106
+ brightness = 255 - brightness;
107
+ }
108
+ const offset = (y * width + x) * 4;
109
+ imageData[offset] = brightness; // R
110
+ imageData[offset + 1] = brightness; // G
111
+ imageData[offset + 2] = brightness; // B
112
+ imageData[offset + 3] = 255; // A
113
+ }
114
+ }
115
+ return Promise.resolve({ width, height, data: imageData });
116
+ }
117
+ encode(imageData, options = {}) {
118
+ const { width: targetWidth = 80, charset = "simple", aspectRatio = 0.5, invert = false, } = options;
119
+ // Get character set
120
+ const chars = this.CHARSETS[charset] || this.CHARSETS.simple;
121
+ // Calculate target height based on aspect ratio
122
+ const { width: imgWidth, height: imgHeight, data } = imageData;
123
+ const targetHeight = Math.floor((imgHeight / imgWidth) * targetWidth * aspectRatio);
124
+ // Build ASCII art
125
+ const lines = [];
126
+ for (let y = 0; y < targetHeight; y++) {
127
+ let line = "";
128
+ for (let x = 0; x < targetWidth; x++) {
129
+ // Map to source pixel
130
+ const srcX = Math.floor((x / targetWidth) * imgWidth);
131
+ const srcY = Math.floor((y / targetHeight) * imgHeight);
132
+ const offset = (srcY * imgWidth + srcX) * 4;
133
+ // Calculate grayscale value
134
+ const r = data[offset];
135
+ const g = data[offset + 1];
136
+ const b = data[offset + 2];
137
+ const gray = Math.floor(0.299 * r + 0.587 * g + 0.114 * b);
138
+ // Map to character
139
+ const brightness = invert ? 255 - gray : gray;
140
+ const charIndex = Math.floor((brightness / 255) * (chars.length - 1));
141
+ line += chars[charIndex];
142
+ }
143
+ lines.push(line);
144
+ }
145
+ // Create output with magic bytes and options
146
+ const optionsLine = `width:${targetWidth} charset:${charset} aspectRatio:${aspectRatio} invert:${invert}`;
147
+ const content = `ASCII\n${optionsLine}\n${lines.join("\n")}`;
148
+ return Promise.resolve(new TextEncoder().encode(content));
149
+ }
150
+ /**
151
+ * Parse options from the options line
152
+ */
153
+ parseOptions(line) {
154
+ const defaults = {
155
+ charset: "simple",
156
+ invert: false,
157
+ };
158
+ if (!line)
159
+ return defaults;
160
+ const parts = line.split(" ");
161
+ const options = { ...defaults };
162
+ for (const part of parts) {
163
+ const [key, value] = part.split(":");
164
+ if (key === "charset" && value) {
165
+ if (["simple", "extended", "blocks", "detailed"].includes(value)) {
166
+ options.charset = value;
167
+ }
168
+ }
169
+ else if (key === "invert" && value) {
170
+ options.invert = value === "true";
171
+ }
172
+ }
173
+ return options;
174
+ }
175
+ }
176
+ exports.ASCIIFormat = ASCIIFormat;
@@ -0,0 +1,19 @@
1
+ import type { ImageData, ImageFormat } from "../types.js";
2
+ /**
3
+ * BMP format handler
4
+ * Implements a pure JavaScript BMP decoder and encoder
5
+ */
6
+ export declare class BMPFormat implements ImageFormat {
7
+ readonly name = "bmp";
8
+ readonly mimeType = "image/bmp";
9
+ canDecode(data: Uint8Array): boolean;
10
+ decode(data: Uint8Array): Promise<ImageData>;
11
+ encode(imageData: ImageData): Promise<Uint8Array>;
12
+ private readUint16LE;
13
+ private readUint32LE;
14
+ private readInt32LE;
15
+ private writeUint16LE;
16
+ private writeUint32LE;
17
+ private writeInt32LE;
18
+ }
19
+ //# sourceMappingURL=bmp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bmp.d.ts","sourceRoot":"","sources":["../../../src/src/formats/bmp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAiB,MAAM,aAAa,CAAC;AAKzE;;;GAGG;AACH,qBAAa,SAAU,YAAW,WAAW;IAC3C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,QAAQ,eAAe;IAEhC,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO;IAMpC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAwF5C,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IA8DjD,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,YAAY;CAGrB"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BMPFormat = void 0;
4
+ // Constants for unit conversions
5
+ const INCHES_PER_METER = 39.3701;
6
+ /**
7
+ * BMP format handler
8
+ * Implements a pure JavaScript BMP decoder and encoder
9
+ */
10
+ class BMPFormat {
11
+ constructor() {
12
+ Object.defineProperty(this, "name", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: "bmp"
17
+ });
18
+ Object.defineProperty(this, "mimeType", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: "image/bmp"
23
+ });
24
+ }
25
+ canDecode(data) {
26
+ // BMP signature: 'BM' (0x42 0x4D)
27
+ return data.length >= 2 &&
28
+ data[0] === 0x42 && data[1] === 0x4d;
29
+ }
30
+ decode(data) {
31
+ if (!this.canDecode(data)) {
32
+ throw new Error("Invalid BMP signature");
33
+ }
34
+ // Read BMP file header (14 bytes)
35
+ const _fileSize = this.readUint32LE(data, 2);
36
+ const dataOffset = this.readUint32LE(data, 10);
37
+ // Read DIB header (at least 40 bytes for BITMAPINFOHEADER)
38
+ const dibHeaderSize = this.readUint32LE(data, 14);
39
+ let width;
40
+ let height;
41
+ let bitDepth;
42
+ let compression;
43
+ const metadata = {};
44
+ if (dibHeaderSize >= 40) {
45
+ // BITMAPINFOHEADER or later
46
+ width = this.readInt32LE(data, 18);
47
+ height = this.readInt32LE(data, 22);
48
+ bitDepth = this.readUint16LE(data, 28);
49
+ compression = this.readUint32LE(data, 30);
50
+ // Read DPI information (pixels per meter)
51
+ const xPixelsPerMeter = this.readInt32LE(data, 38);
52
+ const yPixelsPerMeter = this.readInt32LE(data, 42);
53
+ if (xPixelsPerMeter > 0 && yPixelsPerMeter > 0) {
54
+ // Convert pixels per meter to DPI
55
+ metadata.dpiX = Math.round(xPixelsPerMeter / INCHES_PER_METER);
56
+ metadata.dpiY = Math.round(yPixelsPerMeter / INCHES_PER_METER);
57
+ metadata.physicalWidth = Math.abs(width) / metadata.dpiX;
58
+ metadata.physicalHeight = Math.abs(height) / metadata.dpiY;
59
+ }
60
+ }
61
+ else {
62
+ throw new Error("Unsupported BMP header format");
63
+ }
64
+ // Handle negative height (top-down bitmap)
65
+ const isTopDown = height < 0;
66
+ const absHeight = Math.abs(height);
67
+ // Only support uncompressed BMPs for now
68
+ if (compression !== 0) {
69
+ throw new Error(`Compressed BMP not supported (compression type: ${compression})`);
70
+ }
71
+ // Only support 24-bit and 32-bit BMPs
72
+ if (bitDepth !== 24 && bitDepth !== 32) {
73
+ throw new Error(`Unsupported bit depth: ${bitDepth}. Only 24 and 32-bit BMPs are supported.`);
74
+ }
75
+ // Calculate row size (must be multiple of 4 bytes)
76
+ const bytesPerPixel = bitDepth / 8;
77
+ const rowSize = Math.floor((bitDepth * width + 31) / 32) * 4;
78
+ // Read pixel data
79
+ const rgba = new Uint8Array(width * absHeight * 4);
80
+ for (let y = 0; y < absHeight; y++) {
81
+ const rowIndex = isTopDown ? y : (absHeight - 1 - y); // BMP stores bottom-to-top by default
82
+ const rowOffset = dataOffset + y * rowSize;
83
+ for (let x = 0; x < width; x++) {
84
+ const pixelOffset = rowOffset + x * bytesPerPixel;
85
+ const outIndex = (rowIndex * width + x) * 4;
86
+ // BMP stores pixels as BGR(A)
87
+ rgba[outIndex] = data[pixelOffset + 2]; // R
88
+ rgba[outIndex + 1] = data[pixelOffset + 1]; // G
89
+ rgba[outIndex + 2] = data[pixelOffset]; // B
90
+ rgba[outIndex + 3] = bitDepth === 32 ? data[pixelOffset + 3] : 255; // A
91
+ }
92
+ }
93
+ return Promise.resolve({
94
+ width,
95
+ height: absHeight,
96
+ data: rgba,
97
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
98
+ });
99
+ }
100
+ encode(imageData) {
101
+ const { width, height, data, metadata } = imageData;
102
+ // Calculate sizes
103
+ const bytesPerPixel = 4; // We'll encode as 32-bit RGBA
104
+ const rowSize = Math.floor((32 * width + 31) / 32) * 4;
105
+ const pixelDataSize = rowSize * height;
106
+ const fileSize = 14 + 40 + pixelDataSize; // File header + DIB header + pixel data
107
+ const result = new Uint8Array(fileSize);
108
+ // Calculate DPI values
109
+ let xPixelsPerMeter = 2835; // Default 72 DPI
110
+ let yPixelsPerMeter = 2835;
111
+ if (metadata?.dpiX && metadata.dpiX > 0) {
112
+ xPixelsPerMeter = Math.round(metadata.dpiX * INCHES_PER_METER);
113
+ }
114
+ if (metadata?.dpiY && metadata.dpiY > 0) {
115
+ yPixelsPerMeter = Math.round(metadata.dpiY * INCHES_PER_METER);
116
+ }
117
+ // BMP File Header (14 bytes)
118
+ result[0] = 0x42; // 'B'
119
+ result[1] = 0x4d; // 'M'
120
+ this.writeUint32LE(result, 2, fileSize); // File size
121
+ this.writeUint32LE(result, 6, 0); // Reserved
122
+ this.writeUint32LE(result, 10, 54); // Offset to pixel data (14 + 40)
123
+ // DIB Header (BITMAPINFOHEADER - 40 bytes)
124
+ this.writeUint32LE(result, 14, 40); // DIB header size
125
+ this.writeInt32LE(result, 18, width); // Width
126
+ this.writeInt32LE(result, 22, height); // Height (positive = bottom-up)
127
+ this.writeUint16LE(result, 26, 1); // Planes
128
+ this.writeUint16LE(result, 28, 32); // Bits per pixel
129
+ this.writeUint32LE(result, 30, 0); // Compression (0 = uncompressed)
130
+ this.writeUint32LE(result, 34, pixelDataSize); // Image size
131
+ this.writeInt32LE(result, 38, xPixelsPerMeter); // X pixels per meter
132
+ this.writeInt32LE(result, 42, yPixelsPerMeter); // Y pixels per meter
133
+ this.writeUint32LE(result, 46, 0); // Colors in palette
134
+ this.writeUint32LE(result, 50, 0); // Important colors
135
+ // Write pixel data (bottom-to-top, BGR(A) format)
136
+ let offset = 54;
137
+ for (let y = height - 1; y >= 0; y--) {
138
+ for (let x = 0; x < width; x++) {
139
+ const srcIndex = (y * width + x) * 4;
140
+ result[offset++] = data[srcIndex + 2]; // B
141
+ result[offset++] = data[srcIndex + 1]; // G
142
+ result[offset++] = data[srcIndex]; // R
143
+ result[offset++] = data[srcIndex + 3]; // A
144
+ }
145
+ // Add padding to make row size multiple of 4
146
+ const padding = rowSize - width * bytesPerPixel;
147
+ for (let p = 0; p < padding; p++) {
148
+ result[offset++] = 0;
149
+ }
150
+ }
151
+ return Promise.resolve(result);
152
+ }
153
+ readUint16LE(data, offset) {
154
+ return data[offset] | (data[offset + 1] << 8);
155
+ }
156
+ readUint32LE(data, offset) {
157
+ return data[offset] | (data[offset + 1] << 8) |
158
+ (data[offset + 2] << 16) | (data[offset + 3] << 24);
159
+ }
160
+ readInt32LE(data, offset) {
161
+ const value = this.readUint32LE(data, offset);
162
+ return value > 0x7fffffff ? value - 0x100000000 : value;
163
+ }
164
+ writeUint16LE(data, offset, value) {
165
+ data[offset] = value & 0xff;
166
+ data[offset + 1] = (value >>> 8) & 0xff;
167
+ }
168
+ writeUint32LE(data, offset, value) {
169
+ data[offset] = value & 0xff;
170
+ data[offset + 1] = (value >>> 8) & 0xff;
171
+ data[offset + 2] = (value >>> 16) & 0xff;
172
+ data[offset + 3] = (value >>> 24) & 0xff;
173
+ }
174
+ writeInt32LE(data, offset, value) {
175
+ this.writeUint32LE(data, offset, value < 0 ? value + 0x100000000 : value);
176
+ }
177
+ }
178
+ exports.BMPFormat = BMPFormat;
@@ -0,0 +1,40 @@
1
+ import type { ImageData, ImageFormat, MultiFrameImageData } from "../types.js";
2
+ /**
3
+ * GIF format handler
4
+ * Now includes pure-JS implementation with custom LZW compression/decompression
5
+ *
6
+ * Features:
7
+ * - LZW compression/decompression
8
+ * - Color quantization and palette generation for encoding
9
+ * - Interlacing support
10
+ * - Transparency support
11
+ * - Multi-frame animation support (decoding and encoding)
12
+ * - Falls back to runtime APIs when pure-JS fails
13
+ */
14
+ export declare class GIFFormat implements ImageFormat {
15
+ readonly name = "gif";
16
+ readonly mimeType = "image/gif";
17
+ supportsMultipleFrames(): boolean;
18
+ canDecode(data: Uint8Array): boolean;
19
+ decode(data: Uint8Array): Promise<ImageData>;
20
+ private extractMetadata;
21
+ encode(imageData: ImageData): Promise<Uint8Array>;
22
+ /**
23
+ * Decode all frames from an animated GIF
24
+ */
25
+ decodeFrames(data: Uint8Array): Promise<MultiFrameImageData>;
26
+ /**
27
+ * Encode multi-frame image data to animated GIF
28
+ * Note: Currently not implemented, will encode only first frame
29
+ */
30
+ encodeFrames(imageData: MultiFrameImageData, _options?: unknown): Promise<Uint8Array>;
31
+ private mapDisposalMethod;
32
+ private readUint16LE;
33
+ private decodeUsingRuntime;
34
+ private readDataSubBlocks;
35
+ private parseComment;
36
+ private parseXMP;
37
+ private injectMetadata;
38
+ private createCommentText;
39
+ }
40
+ //# sourceMappingURL=gif.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gif.d.ts","sourceRoot":"","sources":["../../../src/src/formats/gif.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EAEX,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAIrB;;;;;;;;;;;GAWG;AACH,qBAAa,SAAU,YAAW,WAAW;IAC3C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,QAAQ,eAAe;IAEhC,sBAAsB,IAAI,OAAO;IAIjC,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO;IAS9B,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IA2ClD,OAAO,CAAC,eAAe;IAwDjB,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IAyDvD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAkC5D;;;OAGG;IACH,YAAY,CACV,SAAS,EAAE,mBAAmB,EAC9B,QAAQ,CAAC,EAAE,OAAO,GACjB,OAAO,CAAC,UAAU,CAAC;IAkBtB,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,YAAY;YAIN,kBAAkB;IAqChC,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,YAAY;IAmCpB,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,cAAc;IAqDtB,OAAO,CAAC,iBAAiB;CAY1B"}