cross-image 0.1.4 → 0.2.0

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.
package/README.md CHANGED
@@ -1,121 +1,155 @@
1
- # @cross/image
2
-
3
- A pure JavaScript, dependency-free, cross-runtime image processing library for
4
- Deno, Node.js, and Bun.
5
-
6
- 📚 **[Full Documentation](https://cross-org.github.io/image/)**
7
-
8
- ## Features
9
-
10
- - 🚀 **Pure JavaScript** - No native dependencies
11
- - 🔌 **Pluggable formats** - Easy to extend with custom formats
12
- - 📦 **Cross-runtime** - Works on Deno, Node.js (18+), and Bun
13
- - 🎨 **Multiple formats** - PNG, JPEG, WebP, GIF, TIFF, BMP, and RAW support
14
- - ✂️ **Image manipulation** - Resize with multiple algorithms
15
- - 🔧 **Simple API** - Easy to use, intuitive interface
16
-
17
- ## Installation
18
-
19
- ### Deno
20
-
21
- ```ts
22
- import { Image } from "jsr:@cross/image";
23
- ```
24
-
25
- ### Node.js
26
-
27
- ```bash
28
- npx jsr add @cross/image
29
- ```
30
-
31
- ```ts
32
- import { Image } from "@cross/image";
33
- ```
34
-
35
- ### Bun
36
-
37
- ```bash
38
- bunx jsr add @cross/image
39
- ```
40
-
41
- ```ts
42
- import { Image } from "@cross/image";
43
- ```
44
-
45
- ## Quick Start
46
-
47
- ```ts
48
- import { Image } from "@cross/image";
49
-
50
- // Read an image (auto-detects format)
51
- const data = await Deno.readFile("input.png");
52
- const image = await Image.read(data);
53
-
54
- console.log(`Image size: ${image.width}x${image.height}`);
55
-
56
- // Resize the image
57
- image.resize({ width: 800, height: 600 });
58
-
59
- // Save in a different format
60
- const jpeg = await image.save("jpeg");
61
- await Deno.writeFile("output.jpg", jpeg);
62
- ```
63
-
64
- ## Supported Formats
65
-
66
- | Format | Pure-JS | Notes |
67
- | ------ | ----------- | ------------------------------- |
68
- | PNG | ✅ Full | Complete pure-JS implementation |
69
- | BMP | ✅ Full | Complete pure-JS implementation |
70
- | GIF | ✅ Full | Complete pure-JS implementation |
71
- | RAW | ✅ Full | Uncompressed RGBA |
72
- | ASCII | ✅ Full | Text-based ASCII art |
73
- | JPEG | ⚠️ Baseline | Pure-JS baseline DCT only |
74
- | WebP | ⚠️ Lossless | Pure-JS lossless VP8L |
75
- | TIFF | ⚠️ Basic | Pure-JS uncompressed + LZW |
76
-
77
- See the
78
- [full format support documentation](https://cross-org.github.io/image/formats.html)
79
- for detailed compatibility information.
80
-
81
- ## Documentation
82
-
83
- - **[API Reference](https://cross-org.github.io/image/api.html)** - Complete API
84
- documentation
85
- - **[Examples](https://cross-org.github.io/image/examples.html)** - Usage
86
- examples for common tasks
87
- - **[Format Support](https://cross-org.github.io/image/formats.html)** -
88
- Supported formats and specifications
89
- - **[JPEG Implementation](https://cross-org.github.io/image/jpeg-implementation.html)** -
90
- Technical details for JPEG
91
- - **[WebP Implementation](https://cross-org.github.io/image/webp-implementation.html)** -
92
- Technical details for WebP
93
-
94
- ## Development
95
-
96
- ### Running Tests
97
-
98
- ```bash
99
- deno test -A
100
- ```
101
-
102
- ### Linting and Formatting
103
-
104
- ```bash
105
- deno fmt --check
106
- deno lint
107
- ```
108
-
109
- ### Type Checking
110
-
111
- ```bash
112
- deno check mod.ts
113
- ```
114
-
115
- ## License
116
-
117
- MIT License - see LICENSE file for details.
118
-
119
- ## Contributing
120
-
121
- Contributions are welcome! Please feel free to submit a Pull Request.
1
+ # @cross/image
2
+
3
+ A pure JavaScript, dependency-free, cross-runtime image processing library for
4
+ Deno, Node.js, and Bun.
5
+
6
+ 📚 **[Full Documentation](https://cross-org.github.io/image/)**
7
+
8
+ ## Features
9
+
10
+ - 🚀 **Pure JavaScript** - No native dependencies
11
+ - 🔌 **Pluggable formats** - Easy to extend with custom formats
12
+ - 📦 **Cross-runtime** - Works on Deno, Node.js (18+), and Bun
13
+ - 🎨 **Multiple formats** - PNG, JPEG, WebP, GIF, TIFF, BMP, DNG, PAM, and PCX
14
+ support
15
+ - ✂️ **Image manipulation** - Resize, crop, composite, and more
16
+ - 🎛️ **Image processing** - Adjust brightness, contrast, saturation, exposure
17
+ - 🖌️ **Drawing operations** - Create, fill, and manipulate pixels
18
+ - 🔧 **Simple API** - Easy to use, intuitive interface
19
+
20
+ ## Installation
21
+
22
+ ### Deno
23
+
24
+ ```ts
25
+ import { Image } from "jsr:@cross/image";
26
+ ```
27
+
28
+ ### Node.js
29
+
30
+ ```bash
31
+ npx jsr add @cross/image
32
+ ```
33
+
34
+ ```ts
35
+ import { Image } from "@cross/image";
36
+ ```
37
+
38
+ ### Bun
39
+
40
+ ```bash
41
+ bunx jsr add @cross/image
42
+ ```
43
+
44
+ ```ts
45
+ import { Image } from "@cross/image";
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ### Deno
51
+
52
+ ```ts
53
+ import { Image } from "@cross/image";
54
+
55
+ // Decode an image (auto-detects format)
56
+ const data = await Deno.readFile("input.png");
57
+ const image = await Image.decode(data);
58
+
59
+ console.log(`Image size: ${image.width}x${image.height}`);
60
+
61
+ // Create a new blank image
62
+ const canvas = Image.create(800, 600, 255, 255, 255); // white background
63
+
64
+ // Composite the loaded image on top
65
+ canvas.composite(image, 50, 50);
66
+
67
+ // Apply image processing
68
+ canvas
69
+ .brightness(0.1)
70
+ .contrast(0.2)
71
+ .saturation(-0.1);
72
+
73
+ // Encode in a different format
74
+ const jpeg = await canvas.encode("jpeg");
75
+ await Deno.writeFile("output.jpg", jpeg);
76
+ ```
77
+
78
+ ### Node.js
79
+
80
+ ```ts
81
+ import { Image } from "cross-image";
82
+ import { readFile, writeFile } from "node:fs/promises";
83
+
84
+ // Read an image (auto-detects format)
85
+ const data = await readFile("input.png");
86
+ const image = await Image.read(data);
87
+
88
+ console.log(`Image size: ${image.width}x${image.height}`);
89
+
90
+ // Resize the image
91
+ image.resize({ width: 800, height: 600 });
92
+
93
+ // Save in a different format
94
+ const jpeg = await image.save("jpeg");
95
+ await writeFile("output.jpg", jpeg);
96
+ ```
97
+
98
+ ## Supported Formats
99
+
100
+ | Format | Pure-JS | Notes |
101
+ | ------ | ----------- | ------------------------------- |
102
+ | PNG | Full | Complete pure-JS implementation |
103
+ | BMP | ✅ Full | Complete pure-JS implementation |
104
+ | GIF | ✅ Full | Complete pure-JS implementation |
105
+ | RAW | ✅ Full | Uncompressed RGBA |
106
+ | ASCII | ✅ Full | Text-based ASCII art |
107
+ | JPEG | ⚠️ Baseline | Pure-JS baseline DCT only |
108
+ | WebP | ⚠️ Lossless | Pure-JS lossless VP8L |
109
+ | TIFF | ⚠️ Basic | Pure-JS uncompressed + LZW |
110
+
111
+ See the
112
+ [full format support documentation](https://cross-org.github.io/image/formats.html)
113
+ for detailed compatibility information.
114
+
115
+ ## Documentation
116
+
117
+ - **[API Reference](https://cross-org.github.io/image/api.html)** - Complete API
118
+ documentation
119
+ - **[Examples](https://cross-org.github.io/image/examples.html)** - Usage
120
+ examples for common tasks
121
+ - **[Format Support](https://cross-org.github.io/image/formats.html)** -
122
+ Supported formats and specifications
123
+ - **[JPEG Implementation](https://cross-org.github.io/image/jpeg-implementation.html)** -
124
+ Technical details for JPEG
125
+ - **[WebP Implementation](https://cross-org.github.io/image/webp-implementation.html)** -
126
+ Technical details for WebP
127
+
128
+ ## Development
129
+
130
+ ### Running Tests
131
+
132
+ ```bash
133
+ deno test -A
134
+ ```
135
+
136
+ ### Linting and Formatting
137
+
138
+ ```bash
139
+ deno fmt --check
140
+ deno lint
141
+ ```
142
+
143
+ ### Type Checking
144
+
145
+ ```bash
146
+ deno check mod.ts
147
+ ```
148
+
149
+ ## License
150
+
151
+ MIT License - see LICENSE file for details.
152
+
153
+ ## Contributing
154
+
155
+ Contributions are welcome! Please feel free to submit a Pull Request.
package/esm/mod.d.ts CHANGED
@@ -2,23 +2,45 @@
2
2
  * @module @cross/image
3
3
  *
4
4
  * A pure JavaScript, dependency-free, cross-runtime image processing library.
5
- * Supports reading, resizing, and saving common image formats (PNG, JPEG, WebP, GIF, TIFF, BMP, RAW).
5
+ * Supports decoding, resizing, and encoding common image formats (PNG, JPEG, WebP, GIF, TIFF, BMP, DNG, PAM, PCX).
6
+ * Includes image processing capabilities like compositing, level adjustments, and pixel manipulation.
6
7
  *
7
8
  * @example
8
9
  * ```ts
9
10
  * import { Image } from "@cross/image";
10
11
  *
11
- * // Read an image
12
+ * // Decode an image
12
13
  * const data = await Deno.readFile("input.png");
13
- * const image = await Image.read(data);
14
+ * const image = await Image.decode(data);
14
15
  *
15
- * // Resize it
16
- * image.resize({ width: 200, height: 200 });
16
+ * // Apply image processing
17
+ * image
18
+ * .resize({ width: 200, height: 200 })
19
+ * .brightness(0.1)
20
+ * .contrast(0.2);
17
21
  *
18
- * // Save as different format
19
- * const output = await image.save("jpeg");
22
+ * // Encode as different format
23
+ * const output = await image.encode("jpeg");
20
24
  * await Deno.writeFile("output.jpg", output);
21
25
  * ```
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { Image } from "@cross/image";
30
+ *
31
+ * // Create a blank canvas
32
+ * const canvas = Image.create(400, 300, 255, 255, 255);
33
+ *
34
+ * // Draw on it
35
+ * canvas.fillRect(50, 50, 100, 100, 255, 0, 0, 255);
36
+ *
37
+ * // Load and composite another image
38
+ * const overlay = await Image.decode(await Deno.readFile("logo.png"));
39
+ * canvas.composite(overlay, 10, 10, 0.8);
40
+ *
41
+ * // Save the result
42
+ * await Deno.writeFile("result.png", await canvas.encode("png"));
43
+ * ```
22
44
  */
23
45
  export { Image } from "./src/image.js";
24
46
  export type { ASCIIOptions, FrameMetadata, ImageData, ImageFormat, ImageFrame, ImageMetadata, MultiFrameImageData, ResizeOptions, WebPEncodeOptions, } from "./src/types.js";
@@ -28,6 +50,8 @@ export { WebPFormat } from "./src/formats/webp.js";
28
50
  export { GIFFormat } from "./src/formats/gif.js";
29
51
  export { type TIFFEncodeOptions, TIFFFormat } from "./src/formats/tiff.js";
30
52
  export { BMPFormat } from "./src/formats/bmp.js";
31
- export { RAWFormat } from "./src/formats/raw.js";
53
+ export { DNGFormat } from "./src/formats/dng.js";
54
+ export { PAMFormat } from "./src/formats/pam.js";
55
+ export { PCXFormat } from "./src/formats/pcx.js";
32
56
  export { ASCIIFormat } from "./src/formats/ascii.js";
33
57
  //# sourceMappingURL=mod.d.ts.map
package/esm/mod.js CHANGED
@@ -2,23 +2,45 @@
2
2
  * @module @cross/image
3
3
  *
4
4
  * A pure JavaScript, dependency-free, cross-runtime image processing library.
5
- * Supports reading, resizing, and saving common image formats (PNG, JPEG, WebP, GIF, TIFF, BMP, RAW).
5
+ * Supports decoding, resizing, and encoding common image formats (PNG, JPEG, WebP, GIF, TIFF, BMP, DNG, PAM, PCX).
6
+ * Includes image processing capabilities like compositing, level adjustments, and pixel manipulation.
6
7
  *
7
8
  * @example
8
9
  * ```ts
9
10
  * import { Image } from "@cross/image";
10
11
  *
11
- * // Read an image
12
+ * // Decode an image
12
13
  * const data = await Deno.readFile("input.png");
13
- * const image = await Image.read(data);
14
+ * const image = await Image.decode(data);
14
15
  *
15
- * // Resize it
16
- * image.resize({ width: 200, height: 200 });
16
+ * // Apply image processing
17
+ * image
18
+ * .resize({ width: 200, height: 200 })
19
+ * .brightness(0.1)
20
+ * .contrast(0.2);
17
21
  *
18
- * // Save as different format
19
- * const output = await image.save("jpeg");
22
+ * // Encode as different format
23
+ * const output = await image.encode("jpeg");
20
24
  * await Deno.writeFile("output.jpg", output);
21
25
  * ```
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { Image } from "@cross/image";
30
+ *
31
+ * // Create a blank canvas
32
+ * const canvas = Image.create(400, 300, 255, 255, 255);
33
+ *
34
+ * // Draw on it
35
+ * canvas.fillRect(50, 50, 100, 100, 255, 0, 0, 255);
36
+ *
37
+ * // Load and composite another image
38
+ * const overlay = await Image.decode(await Deno.readFile("logo.png"));
39
+ * canvas.composite(overlay, 10, 10, 0.8);
40
+ *
41
+ * // Save the result
42
+ * await Deno.writeFile("result.png", await canvas.encode("png"));
43
+ * ```
22
44
  */
23
45
  export { Image } from "./src/image.js";
24
46
  export { PNGFormat } from "./src/formats/png.js";
@@ -27,5 +49,7 @@ export { WebPFormat } from "./src/formats/webp.js";
27
49
  export { GIFFormat } from "./src/formats/gif.js";
28
50
  export { TIFFFormat } from "./src/formats/tiff.js";
29
51
  export { BMPFormat } from "./src/formats/bmp.js";
30
- export { RAWFormat } from "./src/formats/raw.js";
52
+ export { DNGFormat } from "./src/formats/dng.js";
53
+ export { PAMFormat } from "./src/formats/pam.js";
54
+ export { PCXFormat } from "./src/formats/pcx.js";
31
55
  export { ASCIIFormat } from "./src/formats/ascii.js";
@@ -0,0 +1,27 @@
1
+ import type { ImageData } from "../types.js";
2
+ import { TIFFFormat } from "./tiff.js";
3
+ /**
4
+ * DNG format handler
5
+ * Implements a basic Linear DNG (Digital Negative) writer.
6
+ * DNG is based on TIFF/EP. This implementation creates a valid DNG
7
+ * containing uncompressed linear RGB data (demosaiced).
8
+ */
9
+ export declare class DNGFormat extends TIFFFormat {
10
+ /** Format name identifier */
11
+ readonly name = "dng";
12
+ /** MIME type for DNG images */
13
+ readonly mimeType = "image/x-adobe-dng";
14
+ /**
15
+ * Check if the given data is a DNG image
16
+ * @param data Raw image data to check
17
+ * @returns true if data has DNG signature (TIFF signature + DNGVersion tag)
18
+ */
19
+ canDecode(data: Uint8Array): boolean;
20
+ /**
21
+ * Encode RGBA image data to DNG format (Linear DNG)
22
+ * @param imageData Image data to encode
23
+ * @returns Encoded DNG image bytes
24
+ */
25
+ encode(imageData: ImageData): Promise<Uint8Array>;
26
+ }
27
+ //# sourceMappingURL=dng.d.ts.map
@@ -0,0 +1,191 @@
1
+ import { TIFFFormat } from "./tiff.js";
2
+ /**
3
+ * DNG format handler
4
+ * Implements a basic Linear DNG (Digital Negative) writer.
5
+ * DNG is based on TIFF/EP. This implementation creates a valid DNG
6
+ * containing uncompressed linear RGB data (demosaiced).
7
+ */
8
+ export class DNGFormat extends TIFFFormat {
9
+ constructor() {
10
+ super(...arguments);
11
+ /** Format name identifier */
12
+ Object.defineProperty(this, "name", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: "dng"
17
+ });
18
+ /** MIME type for DNG images */
19
+ Object.defineProperty(this, "mimeType", {
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true,
23
+ value: "image/x-adobe-dng"
24
+ });
25
+ // Helper methods duplicated from TIFFFormat because they are protected/private there
26
+ // and we can't easily access them if they are private.
27
+ // Let's check TIFFFormat visibility.
28
+ // The read/write helpers were not exported in the previous read_file output.
29
+ }
30
+ /**
31
+ * Check if the given data is a DNG image
32
+ * @param data Raw image data to check
33
+ * @returns true if data has DNG signature (TIFF signature + DNGVersion tag)
34
+ */
35
+ canDecode(data) {
36
+ // DNG is a TIFF file, so it must have a TIFF signature
37
+ if (!super.canDecode(data)) {
38
+ return false;
39
+ }
40
+ // To be strictly a DNG, it should have the DNGVersion tag (0xC612 / 50706)
41
+ // However, scanning for tags in canDecode might be slow.
42
+ // For now, we rely on the fact that it's a TIFF-based format.
43
+ // If we want to be stricter, we would need to parse the IFD here.
44
+ // Let's do a quick check for the DNGVersion tag in the first few bytes if possible,
45
+ // but tags are in the IFD which can be anywhere.
46
+ // So we'll just check if it's a TIFF and maybe rely on extension or user intent.
47
+ // But wait, if we register both TIFF and DNG, who wins?
48
+ // The first one in the list.
49
+ // So we should probably implement a proper check if possible, or just accept that
50
+ // DNGs are TIFFs.
51
+ // For this implementation, we'll assume if it's a TIFF, it *could* be a DNG.
52
+ // But to distinguish, we really should check for DNGVersion.
53
+ // Let's try to find the DNGVersion tag (50706) in the first IFD.
54
+ try {
55
+ const isLittleEndian = data[0] === 0x49;
56
+ const ifdOffset = this.readUint32(data, 4, isLittleEndian);
57
+ // Safety check for offset
58
+ if (ifdOffset >= data.length)
59
+ return false;
60
+ const numEntries = this.readUint16(data, ifdOffset, isLittleEndian);
61
+ for (let i = 0; i < numEntries; i++) {
62
+ const entryOffset = ifdOffset + 2 + (i * 12);
63
+ if (entryOffset + 12 > data.length)
64
+ break;
65
+ const tag = this.readUint16(data, entryOffset, isLittleEndian);
66
+ if (tag === 50706) { // DNGVersion
67
+ return true;
68
+ }
69
+ }
70
+ }
71
+ catch {
72
+ return false;
73
+ }
74
+ return false;
75
+ }
76
+ /**
77
+ * Encode RGBA image data to DNG format (Linear DNG)
78
+ * @param imageData Image data to encode
79
+ * @returns Encoded DNG image bytes
80
+ */
81
+ async encode(imageData) {
82
+ const { width, height, data } = imageData;
83
+ // We'll create a Linear DNG (demosaiced RGB)
84
+ // This is very similar to a standard TIFF but with specific tags.
85
+ const result = [];
86
+ // Header (8 bytes)
87
+ // Little-endian byte order
88
+ result.push(0x49, 0x49); // "II"
89
+ result.push(0x2a, 0x00); // 42
90
+ // IFD offset (will be after header and pixel data)
91
+ const ifdOffset = 8 + data.length;
92
+ this.writeUint32LE(result, ifdOffset);
93
+ // Pixel data (Uncompressed RGBA)
94
+ for (let i = 0; i < data.length; i++) {
95
+ result.push(data[i]);
96
+ }
97
+ // IFD (Image File Directory)
98
+ const ifdStart = result.length;
99
+ // Tags we need for DNG:
100
+ // - NewSubfileType (254)
101
+ // - ImageWidth (256)
102
+ // - ImageHeight (257)
103
+ // - BitsPerSample (258)
104
+ // - Compression (259)
105
+ // - PhotometricInterpretation (262)
106
+ // - StripOffsets (273)
107
+ // - SamplesPerPixel (277)
108
+ // - RowsPerStrip (278)
109
+ // - StripByteCounts (279)
110
+ // - PlanarConfiguration (284)
111
+ // - ExtraSamples (338) - for Alpha
112
+ // - DNGVersion (50706)
113
+ // - UniqueCameraModel (50708)
114
+ const numEntries = 14;
115
+ this.writeUint16LE(result, numEntries);
116
+ // Calculate offsets for variable-length data
117
+ let dataOffset = ifdStart + 2 + numEntries * 12 + 4; // +4 for next IFD offset (0)
118
+ // 1. NewSubfileType (0x00FE) - 0 = Full resolution image
119
+ this.writeIFDEntry(result, 0x00FE, 4, 1, 0);
120
+ // 2. ImageWidth (0x0100)
121
+ this.writeIFDEntry(result, 0x0100, 4, 1, width);
122
+ // 3. ImageHeight (0x0101)
123
+ this.writeIFDEntry(result, 0x0101, 4, 1, height);
124
+ // 4. BitsPerSample (0x0102) - 8, 8, 8, 8
125
+ this.writeIFDEntry(result, 0x0102, 3, 4, dataOffset);
126
+ // Write the actual values later
127
+ const bitsPerSampleOffset = dataOffset;
128
+ dataOffset += 8; // 4 * 2 bytes
129
+ // 5. Compression (0x0103) - 1 = Uncompressed
130
+ this.writeIFDEntry(result, 0x0103, 3, 1, 1);
131
+ // 6. PhotometricInterpretation (0x0106) - 2 = RGB (Linear DNG)
132
+ // For Raw DNG it would be 32803 (CFA), but we are saving processed RGB data
133
+ this.writeIFDEntry(result, 0x0106, 3, 1, 2);
134
+ // 7. StripOffsets (0x0111)
135
+ this.writeIFDEntry(result, 0x0111, 4, 1, 8); // Pixel data starts at offset 8
136
+ // 8. SamplesPerPixel (0x0115) - 4 (RGBA)
137
+ this.writeIFDEntry(result, 0x0115, 3, 1, 4);
138
+ // 9. RowsPerStrip (0x0116)
139
+ this.writeIFDEntry(result, 0x0116, 4, 1, height);
140
+ // 10. StripByteCounts (0x0117)
141
+ this.writeIFDEntry(result, 0x0117, 4, 1, data.length);
142
+ // 11. PlanarConfiguration (0x011C) - 1 = Chunky
143
+ this.writeIFDEntry(result, 0x011C, 3, 1, 1);
144
+ // 12. ExtraSamples (0x0152) - 2 = Unassociated alpha
145
+ this.writeIFDEntry(result, 0x0152, 3, 1, 2); // 1 value, fits in offset field? No, it's SHORT (3), count 1. Value 2.
146
+ // Wait, writeIFDEntry puts value in offset field if count*type_size <= 4.
147
+ // SHORT is 2 bytes. 1 * 2 = 2 <= 4. So value goes in offset.
148
+ // 13. DNGVersion (0xC612 / 50706) - 1, 4, 0, 0
149
+ this.writeIFDEntry(result, 50706, 1, 4, 0x01040000);
150
+ // BYTE (1) count 4. 1*4=4. Fits.
151
+ // 1, 4, 0, 0 -> 0x01, 0x04, 0x00, 0x00.
152
+ // Little endian: 01 04 00 00.
153
+ // As uint32: 0x00000401? No, bytes are 1, 4, 0, 0.
154
+ // In file: 01 04 00 00.
155
+ // readUint32LE would read this as 0x00000401.
156
+ // So we pass 0x00000401?
157
+ // Let's verify writeIFDEntry logic in TIFFFormat (I can't see it but I assume it writes value directly if it fits).
158
+ // Actually, I need to check how writeIFDEntry works.
159
+ // Assuming it takes a number and writes it.
160
+ // 14. UniqueCameraModel (0xC614 / 50708) - "Cross Image DNG"
161
+ const modelName = "Cross Image DNG\0";
162
+ const modelNameBytes = new TextEncoder().encode(modelName);
163
+ this.writeIFDEntry(result, 50708, 2, modelNameBytes.length, dataOffset);
164
+ const modelNameOffset = dataOffset;
165
+ dataOffset += modelNameBytes.length;
166
+ // Next IFD offset (0)
167
+ this.writeUint32LE(result, 0);
168
+ // Write variable length data
169
+ // BitsPerSample data (8, 8, 8, 8)
170
+ // We need to write this at bitsPerSampleOffset
171
+ // But we are appending to result array.
172
+ // We calculated dataOffset relative to start of file?
173
+ // No, dataOffset was initialized to `ifdStart + 2 + numEntries * 12 + 4`.
174
+ // This is correct absolute offset.
175
+ // But we need to fill the gap between end of IFD and dataOffset?
176
+ // No, we are writing sequentially.
177
+ // Wait, `result` is an array of bytes.
178
+ // We wrote the IFD entries. Now we are at `ifdStart + 2 + numEntries * 12 + 4`.
179
+ // This matches `bitsPerSampleOffset`.
180
+ // Write BitsPerSample (8, 8, 8, 8)
181
+ this.writeUint16LE(result, 8);
182
+ this.writeUint16LE(result, 8);
183
+ this.writeUint16LE(result, 8);
184
+ this.writeUint16LE(result, 8);
185
+ // Write UniqueCameraModel string
186
+ for (let i = 0; i < modelNameBytes.length; i++) {
187
+ result.push(modelNameBytes[i]);
188
+ }
189
+ return new Uint8Array(result);
190
+ }
191
+ }
@@ -0,0 +1,43 @@
1
+ import type { ImageData, ImageFormat } from "../types.js";
2
+ /**
3
+ * PAM format handler
4
+ * Implements the Netpbm PAM (Portable Arbitrary Map) format.
5
+ * This is a standard uncompressed format supported by GIMP and other tools.
6
+ *
7
+ * Format structure:
8
+ * - Header (text):
9
+ * P7
10
+ * WIDTH <width>
11
+ * HEIGHT <height>
12
+ * DEPTH 4
13
+ * MAXVAL 255
14
+ * TUPLTYPE RGB_ALPHA
15
+ * ENDHDR
16
+ * - Data (binary):
17
+ * RGBA pixel data (width * height * 4 bytes)
18
+ */
19
+ export declare class PAMFormat implements ImageFormat {
20
+ /** Format name identifier */
21
+ readonly name = "pam";
22
+ /** MIME type for PAM images */
23
+ readonly mimeType = "image/x-portable-arbitrary-map";
24
+ /**
25
+ * Check if the given data is a PAM image
26
+ * @param data Raw image data to check
27
+ * @returns true if data has PAM signature
28
+ */
29
+ canDecode(data: Uint8Array): boolean;
30
+ /**
31
+ * Decode PAM image data to RGBA
32
+ * @param data Raw PAM image data
33
+ * @returns Decoded image data with RGBA pixels
34
+ */
35
+ decode(data: Uint8Array): Promise<ImageData>;
36
+ /**
37
+ * Encode RGBA image data to PAM format
38
+ * @param imageData Image data to encode
39
+ * @returns Encoded PAM image bytes
40
+ */
41
+ encode(imageData: ImageData): Promise<Uint8Array>;
42
+ }
43
+ //# sourceMappingURL=pam.d.ts.map