exiftool-vendored 36.0.0 → 37.0.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +64 -5
  2. package/CLAUDE.md +2 -1
  3. package/README.md +128 -35
  4. package/RELEASE.md +1 -1
  5. package/data/TagMetadata.json +10 -3
  6. package/dist/DateTime.d.ts +2 -2
  7. package/dist/DateTime.js +1 -1
  8. package/dist/DateTime.js.map +1 -1
  9. package/dist/ExifTool.d.ts +45 -8
  10. package/dist/ExifTool.dispose.spec.js +3 -3
  11. package/dist/ExifTool.dispose.spec.js.map +1 -1
  12. package/dist/ExifTool.js +54 -10
  13. package/dist/ExifTool.js.map +1 -1
  14. package/dist/ExifToolOptions.d.ts +15 -2
  15. package/dist/ExifToolOptions.js.map +1 -1
  16. package/dist/ExifToolVendoredTags.d.ts +11 -1
  17. package/dist/ExifToolVendoredTags.js +1 -1
  18. package/dist/ExifToolVendoredTags.js.map +1 -1
  19. package/dist/ExiftoolPath.js +1 -1
  20. package/dist/ExiftoolPath.js.map +1 -1
  21. package/dist/InvalidUtf8Bytes.d.ts +20 -0
  22. package/dist/InvalidUtf8Bytes.js +106 -0
  23. package/dist/InvalidUtf8Bytes.js.map +1 -0
  24. package/dist/InvalidUtf8Bytes.spec.d.ts +1 -0
  25. package/dist/InvalidUtf8Bytes.spec.js +75 -0
  26. package/dist/InvalidUtf8Bytes.spec.js.map +1 -0
  27. package/dist/InvalidUtf8Xml.spec.d.ts +1 -0
  28. package/dist/InvalidUtf8Xml.spec.js +156 -0
  29. package/dist/InvalidUtf8Xml.spec.js.map +1 -0
  30. package/dist/JSON.d.ts +1 -0
  31. package/dist/JSON.js +6 -1
  32. package/dist/JSON.js.map +1 -1
  33. package/dist/RawTags.d.ts +9 -2
  34. package/dist/ReadRawTask.d.ts +1 -0
  35. package/dist/ReadRawTask.js +16 -3
  36. package/dist/ReadRawTask.js.map +1 -1
  37. package/dist/ReadRawTask.spec.js +191 -0
  38. package/dist/ReadRawTask.spec.js.map +1 -1
  39. package/dist/ReadTask.js +24 -2
  40. package/dist/ReadTask.js.map +1 -1
  41. package/dist/ReadTask.spec.js +52 -0
  42. package/dist/ReadTask.spec.js.map +1 -1
  43. package/dist/TagEdit.d.ts +62 -0
  44. package/dist/TagEdit.js +224 -0
  45. package/dist/TagEdit.js.map +1 -0
  46. package/dist/TagEdit.spec.d.ts +1 -0
  47. package/dist/TagEdit.spec.js +863 -0
  48. package/dist/TagEdit.spec.js.map +1 -0
  49. package/dist/Tags.d.ts +56 -38
  50. package/dist/Tags.js +3 -3
  51. package/dist/Tags.js.map +1 -1
  52. package/dist/Tags.spec.js +8 -0
  53. package/dist/Tags.spec.js.map +1 -1
  54. package/dist/Timezones.js.map +1 -1
  55. package/dist/Utf8JsonFilter.d.ts +7 -0
  56. package/dist/Utf8JsonFilter.js +85 -0
  57. package/dist/Utf8JsonFilter.js.map +1 -0
  58. package/dist/WriteTask.d.ts +6 -0
  59. package/dist/WriteTask.js +58 -18
  60. package/dist/WriteTask.js.map +1 -1
  61. package/dist/WriteTask.spec.js +17 -0
  62. package/dist/WriteTask.spec.js.map +1 -1
  63. package/dist/update/mktags.js +19 -1
  64. package/dist/update/mktags.js.map +1 -1
  65. package/package.json +15 -47
package/CHANGELOG.md CHANGED
@@ -35,6 +35,65 @@ vendored versions of ExifTool match the version that they vendor.
35
35
 
36
36
  ## History
37
37
 
38
+ ### v37.0.0
39
+
40
+ - 💔 **BREAKING: malformed UTF-8 in ExifTool JSON output is now marked with
41
+ Unicode replacement character U+FFFD (`�`) instead of ASCII question mark
42
+ (`?`).** For example, malformed bytes `dc 4b` previously surfaced as `?K`
43
+ and now surface as `�K`. This applies to both `read()` and `readRaw()`,
44
+ including scalar and list values and calls that override `readArgs`. Valid
45
+ Unicode and authored question marks are unchanged.
46
+ - The original malformed string bytes are available without rereading the
47
+ media through an optional sparse `invalidUtf8Bytes` sidecar. It mirrors tag
48
+ paths, uses numeric object keys for damaged list items, stores each leaf as
49
+ a `Uint8Array`, and is absent when no malformed strings were found:
50
+
51
+ ```js
52
+ const tags = await exiftool.read(file);
53
+ tags.City; // "�K"
54
+ tags.invalidUtf8Bytes?.City; // Uint8Array([0xdc, 0x4b])
55
+ ```
56
+
57
+ `exiftool-vendored` does not guess a legacy charset. Consumers may decode
58
+ only these captured bytes using camera, tag, locale, or user-specific
59
+ evidence while retaining the U+FFFD value as a deterministic fallback.
60
+
61
+ - Nested structures mirror the paths ExifTool returns for the selected
62
+ `struct` mode. XML element text, attribute values, CDATA, opaque XML string
63
+ values, and leaves parsed from embedded binary XML packets are supported.
64
+ The captured bytes are the extracted value after XML parsing, not the
65
+ original XML token. Malformed XML element and attribute names are outside
66
+ this mechanism: value filters never receive names, and ExifTool's JSON
67
+ output repairs or canonicalizes them before the library sees them.
68
+
69
+ - The change affects new metadata reads only. Upgrading does not rewrite
70
+ values that applications have already persisted. Applications that use
71
+ extracted metadata as identifiers, facets, or tags may want to rescan or
72
+ reindex existing files.
73
+ - Consumers may replace ambiguous `?` corruption heuristics with explicit
74
+ U+FFFD checks where their data flow preserves the marker. Whether to
75
+ reject, display, or retain a marked value remains application policy.
76
+ - To restore the previous rendering, replace the marker in the string values
77
+ you consume (it never appears in numbers, dates, or binary fields). This is
78
+ a one-way transform — the reverse is impossible once malformed bytes have
79
+ collapsed to `?`, which is why the marker is preserved by default:
80
+
81
+ ```js
82
+ typeof value === "string" ? value.replace(/\uFFFD/g, "?") : value;
83
+ ```
84
+
85
+ - Advanced callers that provide their own non-empty ExifTool
86
+ `-api Filter=...` through `readArgs` retain ownership of the complete
87
+ filtering pipeline. A custom filter must perform its own UTF-8 repair and
88
+ byte capture if those behaviors are desired; `invalidUtf8Bytes` will be
89
+ absent.
90
+
91
+ - 📦 Corrected resource-cleanup documentation to distinguish normal shutdown, non-blocking `using`, awaited `await using`, and best-effort disposal timeouts.
92
+
93
+ ### v36.1.0
94
+
95
+ - ✨ Added `ExifTool.editTags()` for validated exact list-value additions/removals, MWG Collection additions/predicate removals, and audited scalar or flattened person-name removals without replacing unrelated metadata. See the [usage examples](docs/USAGE-EXAMPLES.md#editing-individual-tag-values).
96
+
38
97
  ### v36.0.0
39
98
 
40
99
  - 🏚️ **Dropped Node.js 20 from the supported engines and CI matrix.** Node.js 20 ("Iron") has reached [end-of-life](https://github.com/nodejs/release#release-schedule), so the minimum supported runtime is now Node.js 22 (`engines.node` is `>=22`). The CI test matrix is now Node.js 22, 24, and 26.
@@ -152,7 +211,7 @@ vendored versions of ExifTool match the version that they vendor.
152
211
 
153
212
  **Previously**, even though child processes were unreferenced, the stdio streams kept the parent Node.js process alive, requiring explicit `.end()` calls.
154
213
 
155
- **Now**, stdio streams are unreferenced by default, so scripts can exit naturally without calling `.end()`. Child processes are cleaned up automatically when the parent exits.
214
+ **Now**, stdio streams are unreferenced by default, so scripts can exit naturally without calling `.end()`. During normal shutdown, child-process cleanup is attempted automatically. Exit cleanup was strengthened further in v35.2.0 and v35.10.1; abrupt termination such as `SIGKILL` cannot run cleanup handlers.
156
215
 
157
216
  To restore the previous behavior (parent process stays alive until `.end()` is called):
158
217
 
@@ -277,12 +336,12 @@ vendored versions of ExifTool match the version that they vendor.
277
336
 
278
337
  - ✨ Added **Disposable interface support** for automatic resource cleanup:
279
338
  - `ExifTool` now implements both `Disposable` and `AsyncDisposable` interfaces
280
- - Use `using et = new ExifTool()` for automatic synchronous cleanup (TypeScript 5.2+)
281
- - Use `await using et = new ExifTool()` for automatic asynchronous cleanup
339
+ - Use `using et = new ExifTool()` to initiate cleanup when a scope exits (TypeScript 5.2+)
340
+ - Use `await using et = new ExifTool()` to await asynchronous cleanup
282
341
  - Synchronous disposal initiates graceful cleanup with configurable timeout fallback
283
- - Asynchronous disposal provides robust cleanup with timeout protection
342
+ - Asynchronous disposal requests forceful cleanup after its configured timeout; the timeout is not a hard completion deadline
284
343
  - New options: `disposalTimeoutMs` (default: 1000ms) and `asyncDisposalTimeoutMs` (default: 5000ms)
285
- - Comprehensive error handling ensures disposal never throws or hangs
344
+ - Disposal errors are logged; asynchronous disposal may reject if cleanup fails
286
345
  - Maintains backward compatibility - existing `.end()` method unchanged
287
346
 
288
347
  - ✨ **Enhanced JSDoc annotations** for Tags interface with emoji-based visual hierarchy:
package/CLAUDE.md CHANGED
@@ -53,7 +53,8 @@ npm run release # Run release process (requires proper permissions)
53
53
  ## Important Notes
54
54
 
55
55
  - Always run `npm run compile` before testing
56
- - As of v35, `.end()` is optional for scripts (Node.js exits naturally), but recommended for long-running apps
56
+ - With default settings, `.end()` is optional after awaited script work, but it
57
+ should be awaited when cleanup must finish before the application continues or exits
57
58
  - Tag interfaces not comprehensive - less common tags may exist in returned objects
58
59
  - Uses batch processing with automatic process pool management
59
60
  - TypeScript union type limits require careful tag selection
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # exiftool-vendored
1
+ # 📸 exiftool-vendored
2
2
 
3
3
  **Fast, cross-platform [Node.js](https://nodejs.org/) access to [ExifTool](https://exiftool.org/). Built and supported by [PhotoStructure](https://photostructure.com).**
4
4
 
@@ -6,7 +6,7 @@
6
6
  [![Node.js CI](https://github.com/photostructure/exiftool-vendored.js/actions/workflows/build.yml/badge.svg)](https://github.com/photostructure/exiftool-vendored.js/actions/workflows/build.yml)
7
7
  [![GitHub issues](https://img.shields.io/github/issues/photostructure/exiftool-vendored.js.svg)](https://github.com/photostructure/exiftool-vendored.js/issues)
8
8
 
9
- ## Installation & Quick Start
9
+ ## 🚀 Installation & Quick Start
10
10
 
11
11
  **Requirements**: Node.js Active LTS or Maintenance LTS versions only
12
12
 
@@ -35,7 +35,7 @@ await exiftool.extractThumbnail("photo.jpg", "thumb.jpg");
35
35
  await exiftool.end();
36
36
  ```
37
37
 
38
- ## Why exiftool-vendored?
38
+ ## 🤔 Why exiftool-vendored?
39
39
 
40
40
  ### ⚡ **Performance**
41
41
 
@@ -53,7 +53,7 @@ Order of magnitude faster than other Node.js ExifTool modules. Powers [PhotoStru
53
53
  - **Smart dates**: Timezone-aware `ExifDateTime` classes
54
54
  - **Auto-generated tags**: Based on 10,000+ real camera samples
55
55
 
56
- ## Core Features
56
+ ## Core Features
57
57
 
58
58
  ### Reading Metadata
59
59
 
@@ -96,6 +96,10 @@ await exiftool.write("photo.jpg", {
96
96
  });
97
97
  ```
98
98
 
99
+ For targeted list-value and supported structured edits, use `editTags()`. See
100
+ [Editing Individual Tag Values](docs/USAGE-EXAMPLES.md#editing-individual-tag-values)
101
+ for examples, supported tags, and safety constraints.
102
+
99
103
  ### Extracting Images
100
104
 
101
105
  ```javascript
@@ -109,7 +113,7 @@ await exiftool.extractPreview("photo.jpg", "preview.jpg");
109
113
  await exiftool.extractJpgFromRaw("photo.cr2", "processed.jpg");
110
114
  ```
111
115
 
112
- ## Understanding Tags
116
+ ## 🏷️ Understanding Tags
113
117
 
114
118
  The `Tags` interface contains **thousands of metadata fields** from an auto-generated TypeScript file. Each tag has JSDoc annotations:
115
119
 
@@ -135,17 +139,86 @@ LensSpec?: string;
135
139
  - **@groups** = Metadata categories (EXIF, GPS, IPTC, XMP, etc.)
136
140
  - **@example** = Representative values
137
141
 
138
- ### Code defensively!
142
+ ## 🛡️ Code defensively!
143
+
144
+ The generated `Tags` interface is a deliberately bounded, best-effort model of
145
+ what ExifTool extracts.
146
+
147
+ ### Declared fields may be missing
148
+
149
+ Formats, cameras, and editing software write different subsets of metadata,
150
+ and later tools may strip fields. Treat every property as optional, even when
151
+ it is common for the files you currently handle.
152
+
153
+ ### Undeclared fields may be included
154
+
155
+ The interface favors the most common and useful fields. Without tag pruning,
156
+ TypeScript fails with `TS2590: Expression produces a union type that is too
157
+ complex to represent`.
139
158
 
140
- - No fields are guaranteed to be present.
141
- - Value types are not guaranteed -- assume strings may get in your numeric fields, and handle it gracefully.
142
- - There may very well be keys returned that are **not** in the `Tags` interface.
159
+ Rare, vendor-specific, and custom tags may still appear at runtime. If your app
160
+ needs arbitrary tags, intersect `Tags` with `Record<string, unknown>`; if a tag
161
+ would be useful to others, please open a PR to add it to the generated
162
+ interface.
163
+
164
+ ### Value types may vary
165
+
166
+ ExifTool may return unexpected representations for malformed, ambiguous, or
167
+ format-specific values. Validate values at runtime and handle strings in
168
+ nominally numeric fields gracefully.
143
169
 
144
170
  📖 **[Complete Tags Documentation →](docs/TAGS.md)**
145
171
 
146
- ## Important Notes
172
+ ## 🪤 Parsing gotchas
173
+
174
+ ### Timezones may be inferred
175
+
176
+ Media metadata often omits its timezone, so this library uses several heuristics
177
+ to infer one. See [Dates & Timezones](#timezones) for the inference order and
178
+ configuration options.
179
+
180
+ ### Malformed UTF-8 is marked and preserved
181
+
182
+ Malformed UTF-8 bytes are marked with the Unicode replacement character
183
+ U+FFFD, not ASCII `?`, so byte corruption stays distinguishable from
184
+ authored punctuation. The original bytes are preserved without another file
185
+ read in the sparse `invalidUtf8Bytes` sidecar:
147
186
 
148
- ### ⚙️ Configuration
187
+ ```ts
188
+ const tags = await exiftool.read(file);
189
+ tags.ImageDescription; // "Arch Enemy\rG�teborg, 19.07.2007"
190
+
191
+ const bytes = tags.invalidUtf8Bytes?.ImageDescription;
192
+ if (bytes instanceof Uint8Array) {
193
+ // Camera/tag-specific evidence identifies this Kodak value as MacRoman:
194
+ const recovered = new TextDecoder("macintosh").decode(bytes);
195
+ recovered; // "Arch Enemy\rGöteborg, 19.07.2007"
196
+ }
197
+ ```
198
+
199
+ The `macintosh` charset is justified by evidence for this specific Kodak
200
+ value; it is not a default for every damaged field.
201
+
202
+ Nested metadata mirrors the representation selected by ExifTool's `struct`
203
+ option. Extracted XML element text, attribute values, CDATA, and parsed
204
+ embedded XML values are captured at their returned paths. These are the
205
+ bytes of ExifTool's extracted value after XML parsing, not the original XML
206
+ token: entity spellings and CDATA delimiters are not retained. Value filters
207
+ never receive XML element or attribute _names_, and ExifTool's JSON output
208
+ repairs or canonicalizes malformed names before the library sees them, so
209
+ their exact bytes cannot be exposed by this sidecar.
210
+
211
+ The library deliberately does not guess a legacy charset: files assembled
212
+ over many years may contain several encodings, and readable alternatives are
213
+ not necessarily correct. Consumers can decode only the sidecar entries using
214
+ their own camera/tag/user context. An explicit custom ExifTool `Filter`
215
+ disables both built-in repair and byte capture. To restore the pre-v37
216
+ display, guard on the value type first:
217
+ `typeof value === "string" ? value.replace(/\uFFFD/g, "?") : value`.
218
+
219
+ ## ⚠️ Important Notes
220
+
221
+ ### Configuration
149
222
 
150
223
  exiftool-vendored provides two levels of configuration:
151
224
 
@@ -172,7 +245,9 @@ const exiftool = new ExifTool({
172
245
 
173
246
  📖 **[Complete Configuration Guide →](docs/CONFIGURATION.md)**
174
247
 
175
- ### ⏰ Dates & Timezones
248
+ <a id="timezones"></a>
249
+
250
+ ### Dates & Timezones
176
251
 
177
252
  Images rarely specify timezones. This library infers them using several heuristics:
178
253
 
@@ -190,53 +265,71 @@ if (dt instanceof ExifDateTime) {
190
265
 
191
266
  📖 **[Date & Timezone Guide →](docs/DATES.md)**
192
267
 
193
- ### 🧹 Resource Cleanup
268
+ ### Resource Cleanup
194
269
 
195
- As of v35, **Node.js will exit naturally** without calling `.end()` — child processes are cleaned up automatically when the parent exits.
270
+ With the default settings, ExifTool workers no longer keep Node.js alive after
271
+ awaited work finishes. During normal shutdown, the library attempts to clean up
272
+ workers automatically. Abrupt termination, such as `SIGKILL` or an operating-
273
+ system crash, cannot run cleanup handlers.
196
274
 
197
- For **long-running applications** (servers, daemons), calling `.end()` is still recommended for graceful shutdown:
275
+ Call and await `.end()` when cleanup must finish before your application
276
+ continues or exits. For servers and daemons, make this one part of the
277
+ application's complete shutdown procedure:
198
278
 
199
279
  ```javascript
200
280
  import { exiftool } from "exiftool-vendored";
201
281
 
202
- // For servers/daemons: graceful shutdown on termination signals
203
- process.on("SIGINT", () => exiftool.end());
204
- process.on("SIGTERM", () => exiftool.end());
282
+ async function shutdown(signal) {
283
+ try {
284
+ await closeApplicationResources(); // Server, sockets, database, etc.
285
+ await exiftool.end();
286
+ } finally {
287
+ // A signal listener disables Node's default termination behavior. Re-send
288
+ // the signal after cleanup so the process terminates normally.
289
+ process.kill(process.pid, signal);
290
+ }
291
+ }
292
+
293
+ process.once("SIGINT", (signal) => void shutdown(signal));
294
+ process.once("SIGTERM", (signal) => void shutdown(signal));
205
295
  ```
206
296
 
207
297
  #### Automatic Cleanup with Disposable Interfaces
208
298
 
209
- For **TypeScript 5.2+** projects, consider using automatic resource management:
299
+ For **TypeScript 5.2+** projects configured for explicit resource management,
300
+ you can bind an instance's lifecycle to a scope:
210
301
 
211
302
  ```javascript
212
303
  import { ExifTool } from "exiftool-vendored";
213
304
 
214
- // Automatic synchronous cleanup
305
+ // Starts cleanup when the scope exits, but does not wait for it
215
306
  {
216
307
  using et = new ExifTool();
217
308
  const tags = await et.read("photo.jpg");
218
- // ExifTool automatically cleaned up when block exits
309
+ // ExifTool cleanup is initiated when the block exits
219
310
  }
220
311
 
221
- // Automatic asynchronous cleanup (recommended)
312
+ // Waits for cleanup when the scope exits (recommended)
222
313
  {
223
314
  await using et = new ExifTool();
224
315
  const tags = await et.read("photo.jpg");
225
- // ExifTool gracefully cleaned up when block exits
316
+ // ExifTool cleanup is awaited when the block exits
226
317
  }
227
318
  ```
228
319
 
229
320
  **Benefits:**
230
321
 
231
- - **Guaranteed cleanup**: No leaked processes, even with exceptions
232
- - **Timeout protection**: Automatic forceful cleanup if graceful shutdown hangs
233
- - **Zero boilerplate**: No manual `.end()` calls needed
322
+ - **Scope-bound disposal**: Disposal runs on ordinary scope exit, including exceptions
323
+ - **Awaited cleanup**: `await using` waits for asynchronous disposal
324
+ - **Less boilerplate**: No manual `try`/`finally` cleanup block
234
325
 
235
326
  **Caution:**
236
327
 
237
- - **Operating-system startup lag**: Linux costs ~50-500ms to launch a new ExifTool process, but macOS can take several seconds (presumably due to Gatekeeper), and **Windows can take tens of seconds** due to antivirus shenanigans. Don't dispose your instance unless you're **really** done with it!
328
+ - **Operating-system startup lag**: Startup time varies widely with the OS,
329
+ hardware, and security software, and can take several seconds on some
330
+ systems. Don't dispose an instance until you're really done with it.
238
331
 
239
- ### 🏷️ Tag Completeness
332
+ ### Tag Completeness
240
333
 
241
334
  The `Tags` interface shows the most common fields, but ExifTool can extract many more. Cast to access unlisted fields:
242
335
 
@@ -245,9 +338,9 @@ const tags = await exiftool.read("photo.jpg");
245
338
  const customField = (tags as any).UncommonTag;
246
339
  ```
247
340
 
248
- ## Documentation
341
+ ## 📚 Documentation
249
342
 
250
- ### 📚 **Guides**
343
+ ### **Guides**
251
344
 
252
345
  - **[Installation Guide](docs/INSTALLATION.md)** - Electron, Docker, platform setup
253
346
  - **[Usage Examples](docs/USAGE-EXAMPLES.md)** - Comprehensive API examples
@@ -255,16 +348,16 @@ const customField = (tags as any).UncommonTag;
255
348
  - **[Tags Reference](docs/TAGS.md)** - Understanding the 2,500+ metadata fields
256
349
  - **[Electron Integration](docs/ELECTRON.md)** - Electron-specific setup
257
350
 
258
- ### 🔧 **Troubleshooting**
351
+ ### **Troubleshooting**
259
352
 
260
353
  - **[Debugging Guide](docs/DEBUGGING.md)** - Debug logging and common issues
261
354
  - **[Temporal Migration](docs/TEMPORAL-MIGRATION.md)** - Future JavaScript Temporal API
262
355
 
263
- ### 📖 **API Reference**
356
+ ### **API Reference**
264
357
 
265
358
  - **[TypeDoc Documentation](https://photostructure.github.io/exiftool-vendored.js/)** - Complete API reference
266
359
 
267
- ## Performance
360
+ ## Performance
268
361
 
269
362
  The default singleton is throttled for stability. For high-throughput processing:
270
363
 
@@ -285,13 +378,13 @@ await exiftool.end();
285
378
 
286
379
  **Benchmarks**: 20+ files/second/thread, 500+ files/second using all CPU cores.
287
380
 
288
- ## Support & Community
381
+ ## 🤝 Support & Community
289
382
 
290
383
  - **📋 Issues**: [GitHub Issues](https://github.com/photostructure/exiftool-vendored.js/issues)
291
384
  - **📖 Changelog**: [CHANGELOG.md](CHANGELOG.md)
292
385
  - **🔒 Security**: [SECURITY.md](SECURITY.md)
293
386
  - **📄 License**: [MIT](LICENSE)
294
387
 
295
- ### Contributors 🎉
388
+ ### Contributors
296
389
 
297
390
  [Matthew McEachen](https://github.com/mceachen), [Joshua Harris](https://github.com/Circuit8), [Anton Mokrushin](https://github.com/amokrushin), [Luca Ban](https://github.com/mesqueeb), [Demiurga](https://github.com/apolkingg8), [David Randler](https://github.com/draity)
package/RELEASE.md CHANGED
@@ -47,7 +47,7 @@ For development and testing:
47
47
  1. `git clone` this repo
48
48
  2. `npm install`
49
49
  3. `npm run mktags ../test-images` # < assumes `../test-images` has the full ExifTool sample image suite
50
- 4. `npm run precommit` (look for lint or documentation generation issues)
50
+ 4. `npm run all` (look for lint or documentation generation issues)
51
51
  5. `npm run test`
52
52
  6. Verify diffs are reasonable, `git commit` and `git push`
53
53
  7. Follow the Automatic Release steps above
@@ -7394,7 +7394,7 @@
7394
7394
  "FirmwareVersion": {
7395
7395
  "frequency": 0.07,
7396
7396
  "mainstream": true,
7397
- "groups": ["APP", "MakerNotes", "QuickTime"],
7397
+ "groups": ["APP", "MakerNotes", "QuickTime", "RAF"],
7398
7398
  "type": "string",
7399
7399
  "typed": true
7400
7400
  },
@@ -11899,7 +11899,7 @@
11899
11899
  "Location": {
11900
11900
  "frequency": 0.02,
11901
11901
  "mainstream": true,
11902
- "groups": ["MakerNotes"],
11902
+ "groups": ["Composite", "MakerNotes", "XMP"],
11903
11903
  "type": "string",
11904
11904
  "typed": true
11905
11905
  },
@@ -19753,7 +19753,7 @@
19753
19753
  },
19754
19754
  "Transform": {
19755
19755
  "frequency": 0.01,
19756
- "mainstream": false,
19756
+ "mainstream": true,
19757
19757
  "groups": ["MakerNotes"],
19758
19758
  "type": "string",
19759
19759
  "typed": true
@@ -21006,6 +21006,13 @@
21006
21006
  "type": "string",
21007
21007
  "typed": true
21008
21008
  },
21009
+ "invalidUtf8Bytes": {
21010
+ "frequency": 0,
21011
+ "mainstream": true,
21012
+ "groups": ["Library"],
21013
+ "type": "InvalidUtf8Bytes",
21014
+ "typed": true
21015
+ },
21009
21016
  "tz": {
21010
21017
  "frequency": 0,
21011
21018
  "mainstream": true,
@@ -1,4 +1,4 @@
1
- import { DateTime } from "luxon";
1
+ import { DateTime, DateTimeMaybeValid } from "luxon";
2
2
  import { ExifDate } from "./ExifDate";
3
3
  import { ExifDateTime } from "./ExifDateTime";
4
4
  import { ExifTime } from "./ExifTime";
@@ -8,7 +8,7 @@ export declare const SecondMs = 1000;
8
8
  export declare const MinuteMs: number;
9
9
  export declare const HourMs: number;
10
10
  export declare const DayMs: number;
11
- export type DateOrTime = ExifDateTime | ExifDate | ExifTime | DateTime;
11
+ export type DateOrTime = ExifDateTime | ExifDate | ExifTime | DateTimeMaybeValid;
12
12
  export declare function isDateOrTime(o: unknown): o is DateOrTime;
13
13
  export declare function dateTimeToExif(d: DateTime, opts?: {
14
14
  includeOffset?: boolean;
package/dist/DateTime.js CHANGED
@@ -33,7 +33,7 @@ function toExifString(d) {
33
33
  return dateTimeToExif(d);
34
34
  }
35
35
  else {
36
- return d?.toExifString?.();
36
+ return d?.toExifString();
37
37
  }
38
38
  }
39
39
  function hms(d, opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"DateTime.js","sourceRoot":"","sources":["../src/DateTime.ts"],"names":[],"mappings":";;;AAMA,sCAEC;AASD,oCAOC;AAED,wCASC;AAED,oCAMC;AAED,kBAOC;AApDD,iCAAiC;AACjC,yCAAsC;AACtC,iDAA8C;AAC9C,yCAAsC;AAGtC,SAAgB,aAAa,CAAC,EAAmB;IAC/C,OAAO,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC;AAC9B,CAAC;AAEY,QAAA,QAAQ,GAAG,IAAI,CAAC;AAChB,QAAA,QAAQ,GAAG,EAAE,GAAG,gBAAQ,CAAC;AACzB,QAAA,MAAM,GAAG,EAAE,GAAG,gBAAQ,CAAC;AACvB,QAAA,KAAK,GAAG,EAAE,GAAG,cAAM,CAAC;AAIjC,SAAgB,YAAY,CAAC,CAAU;IACrC,OAAO,CACL,CAAC,YAAY,2BAAY;QACzB,CAAC,YAAY,mBAAQ;QACrB,CAAC,YAAY,mBAAQ;QACrB,gBAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CACvB,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAC5B,CAAW,EACX,IAAiE;IAEjE,OAAO,CAAC,CAAC,QAAQ,CACf,kBAAkB;QAChB,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,CAAC,IAAI,EAAE,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAC9C,CAAC;AACJ,CAAC;AAED,SAAgB,YAAY,CAAC,CAAa;IACxC,IAAI,gBAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,EAAE,YAAY,EAAE,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,SAAgB,GAAG,CACjB,CAAW,EACX,IAAwC;IAExC,OAAO,CAAC,CAAC,QAAQ,CACf,UAAU,GAAG,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAChE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"DateTime.js","sourceRoot":"","sources":["../src/DateTime.ts"],"names":[],"mappings":";;;AAMA,sCAEC;AAUD,oCAOC;AAED,wCASC;AAED,oCAMC;AAED,kBAOC;AArDD,iCAAqD;AACrD,yCAAsC;AACtC,iDAA8C;AAC9C,yCAAsC;AAGtC,SAAgB,aAAa,CAAC,EAAmB;IAC/C,OAAO,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC;AAC9B,CAAC;AAEY,QAAA,QAAQ,GAAG,IAAI,CAAC;AAChB,QAAA,QAAQ,GAAG,EAAE,GAAG,gBAAQ,CAAC;AACzB,QAAA,MAAM,GAAG,EAAE,GAAG,gBAAQ,CAAC;AACvB,QAAA,KAAK,GAAG,EAAE,GAAG,cAAM,CAAC;AAKjC,SAAgB,YAAY,CAAC,CAAU;IACrC,OAAO,CACL,CAAC,YAAY,2BAAY;QACzB,CAAC,YAAY,mBAAQ;QACrB,CAAC,YAAY,mBAAQ;QACrB,gBAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CACvB,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAC5B,CAAW,EACX,IAAiE;IAEjE,OAAO,CAAC,CAAC,QAAQ,CACf,kBAAkB;QAChB,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,CAAC,IAAI,EAAE,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAC9C,CAAC;AACJ,CAAC;AAED,SAAgB,YAAY,CAAC,CAAa;IACxC,IAAI,gBAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAgB,GAAG,CACjB,CAAW,EACX,IAAwC;IAExC,OAAO,CAAC,CAAC,QAAQ,CACf,UAAU,GAAG,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAChE,CAAC;AACJ,CAAC"}
@@ -5,6 +5,7 @@ import { ExifToolTask, ExifToolTaskOptions } from "./ExifToolTask";
5
5
  import { PreviewTag } from "./PreviewTag";
6
6
  import { ReadRawTaskOptions } from "./ReadRawTask";
7
7
  import { ReadTaskOptions } from "./ReadTask";
8
+ import { TagEdit } from "./TagEdit";
8
9
  import { Tags } from "./Tags";
9
10
  import { WriteTags } from "./WriteTags";
10
11
  import { WriteTaskOptions, WriteTaskResult } from "./WriteTask";
@@ -44,6 +45,7 @@ export type { GeolocationTags } from "./GeolocationTags";
44
45
  export type { ICCProfileTags } from "./ICCProfileTags";
45
46
  export type { IPTCApplicationRecordTags as ApplicationRecordTags, IPTCApplicationRecordTags, } from "./IPTCApplicationRecordTags";
46
47
  export type { ImageDataHashTag } from "./ImageDataHashTag";
48
+ export type { InvalidUtf8Bytes } from "./InvalidUtf8Bytes";
47
49
  export type { Json, Literal } from "./JSON";
48
50
  export type { CollectionInfo, KeywordInfoStruct, KeywordStruct, MWGCollectionsTags, MWGKeywordTags, } from "./MWGTags";
49
51
  export type { Maybe, Nullable } from "./Maybe";
@@ -56,6 +58,8 @@ export type { UnsubscribeFunction } from "./Settings";
56
58
  export type { ShortcutTags } from "./ShortcutTags";
57
59
  export type { Struct } from "./Struct";
58
60
  export type { TagDescription, TagDescriptionsOptions } from "./TagDescriptions";
61
+ export { CollectionEditTagName, RegionNameEditTagName, TagEditAddTagNames, TagEditRemoveOnlyTagNames, TagEditTagNames, TagEditValueTagNames, } from "./TagEdit";
62
+ export type { AddCollectionEdit, AddTagEdit, CollectionPredicate, RemoveCollectionEdit, RemoveTagEdit, TagEdit, TagEditAddTagName, TagEditRemoveOnlyTagName, TagEditTagName, TagEditValueTagName, } from "./TagEdit";
59
63
  export type { APPTags, CompositeTags, EXIFTags, ExifToolTags, FileTags, FlashPixTags, IPTCTags, JFIFTags, MakerNotesTags, MetaTags, MPFTags, PanasonicRawTags, PhotoshopTags, PrintIMTags, QuickTimeTags, RAFTags, RIFFTags, Tags, XMPTags, } from "./Tags";
60
64
  export type { Version } from "./Version";
61
65
  export type { AdditionalWriteTags, EXIFStrictDateTags, ExpandedDateTags, GroupPrefixedTags, MutableTags, StructAppendTags, WritableGPSRefs, WriteTags, XMPPartialDateTags, } from "./WriteTags";
@@ -118,7 +122,9 @@ export declare class ExifTool {
118
122
  * use `readRaw`.** Note that the default is `["-fast"]`, so if you want
119
123
  * ExifTool to read the entire file for metadata, you should pass an empty
120
124
  * array as the second parameter. See https://exiftool.org/#performance for
121
- * more information about `-fast` and `-fast2`.
125
+ * more information about `-fast` and `-fast2`. The wrapper still adds its
126
+ * malformed UTF-8 repair/byte-capture filter unless these arguments provide
127
+ * a custom ExifTool `Filter`, in which case that filter owns both behaviors.
122
128
  *
123
129
  * @param options overrides to the default ExifTool options provided to the
124
130
  * ExifTool constructor.
@@ -145,9 +151,12 @@ export declare class ExifTool {
145
151
  * worse if you don't include `-fast` or `-fast2` (as the most expensive bits
146
152
  * are the perl interpreter and scanning the file on disk).
147
153
  *
148
- * @param options any additional arguments other than the file path. Note that
149
- * "-json", and the Windows unicode filename handler flags, "-charset
150
- * filename=utf8", will be added automatically.
154
+ * @param options read options, including any additional `readArgs` other than
155
+ * the file path. `-json`, the Windows Unicode filename handler flags,
156
+ * `-charset filename=utf8`, malformed UTF-8 repair with U+FFFD, and original
157
+ * malformed-string byte capture in `invalidUtf8Bytes` are added
158
+ * automatically. An explicit custom ExifTool `Filter` in `readArgs` replaces
159
+ * the wrapper's filter and owns both repair and byte capture.
151
160
  *
152
161
  * @return Note that the return value will be similar to `Tags`, but with no
153
162
  * date, time, or other rich type parsing that you get from `.read()`. The
@@ -210,6 +219,33 @@ export declare class ExifTool {
210
219
  * instead: move `writeArgs` into your `options` hash.
211
220
  */
212
221
  write(file: string, tags: WriteTags, writeArgs?: string[], options?: WriteTaskOptions): Promise<WriteTaskResult>;
222
+ /**
223
+ * Add or remove individual metadata values without replacing unrelated list
224
+ * items. Arguments are emitted in the provided order in one non-retriable
225
+ * ExifTool write command, but ExifTool applies removals before additions for
226
+ * the same tag.
227
+ *
228
+ * Tag names must be entries in {@link TagEditTagNames}. The primitive subset
229
+ * is {@link TagEditValueTagNames}; {@link TagEditAddTagNames} and
230
+ * {@link TagEditRemoveOnlyTagNames} distinguish add-capable lists from
231
+ * audited scalar and flattened structure fields. Structured values and
232
+ * predicates are supported only for the closed schemas explicitly typed by
233
+ * {@link TagEdit}. Each primitive operation accepts one non-empty, exactly
234
+ * preservable string value; repeat operations to preserve duplicate
235
+ * additions. A remove operation deletes every exact matching value. Values
236
+ * are literal text and HTML entity sequences are not decoded, unlike the
237
+ * legacy behavior of {@link ExifTool.write}.
238
+ *
239
+ * This API does not set, clear, or force-write empty tags. Continue using
240
+ * {@link ExifTool.write} for whole-tag writes and deletion with `null`.
241
+ *
242
+ * @param file an existing file or writable sidecar path
243
+ * @param edits one or more ordered add/remove operations
244
+ * @param options overrides to the configured write-task options. `-api` and
245
+ * `-sep`/`-separator` write arguments are rejected because they can alter
246
+ * edit semantics.
247
+ */
248
+ editTags(file: string, edits: readonly TagEdit[], options?: WriteTaskOptions): Promise<WriteTaskResult>;
213
249
  /**
214
250
  * This will strip `file` of all metadata tags. The original file (with the
215
251
  * name `${FILENAME}_original`) will be retained. Note that some tags, like
@@ -371,8 +407,8 @@ export declare class ExifTool {
371
407
  * This allows ExifTool instances to be automatically cleaned up when they go out of scope.
372
408
  *
373
409
  * Note: This is a synchronous disposal method that initiates graceful cleanup but doesn't
374
- * wait for completion. If graceful cleanup times out, forceful cleanup is attempted.
375
- * For guaranteed cleanup completion, use `await using` with the async disposal method instead.
410
+ * wait for completion. If graceful cleanup times out, forceful cleanup is requested.
411
+ * Use `await using` when the caller must wait for the cleanup attempt to settle.
376
412
  *
377
413
  * @example
378
414
  * ```typescript
@@ -388,8 +424,9 @@ export declare class ExifTool {
388
424
  * Implements the AsyncDisposable interface for automatic async cleanup with the `await using` keyword.
389
425
  * This allows ExifTool instances to be automatically cleaned up when they go out of scope.
390
426
  *
391
- * This method provides robust cleanup with timeout protection to prevent hanging.
392
- * If graceful cleanup times out, forceful cleanup is attempted automatically.
427
+ * This method waits for graceful cleanup. If the configured timeout elapses,
428
+ * forceful cleanup is requested. Cleanup is best-effort and the timeout is not
429
+ * a hard completion deadline.
393
430
  *
394
431
  * @example
395
432
  * ```typescript
@@ -83,7 +83,7 @@ describe("ExifTool disposal", () => {
83
83
  await et[Symbol.asyncDispose]();
84
84
  (0, chai_1.expect)(et.ended).to.be.true;
85
85
  });
86
- it("should handle timeout in async disposal gracefully", async () => {
86
+ it("should request forceful cleanup after an async disposal timeout", async () => {
87
87
  const et = new ExifTool_1.ExifTool();
88
88
  // Mock a slow .end() method by stubbing it
89
89
  const originalEnd = et.end.bind(et);
@@ -98,11 +98,11 @@ describe("ExifTool disposal", () => {
98
98
  }
99
99
  else {
100
100
  forcefulEndCalled = true;
101
- // Forceful cleanup should work quickly
101
+ // Model a forceful cleanup request that settles quickly
102
102
  return originalEnd(false);
103
103
  }
104
104
  };
105
- // The async dispose should timeout and attempt forceful cleanup
105
+ // The async disposer should request forceful cleanup after its timeout
106
106
  await et[Symbol.asyncDispose]();
107
107
  (0, chai_1.expect)(endCalled).to.be.true;
108
108
  (0, chai_1.expect)(forcefulEndCalled).to.be.true;
@@ -1 +1 @@
1
- {"version":3,"file":"ExifTool.dispose.spec.js","sourceRoot":"","sources":["../src/ExifTool.dispose.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ExifTool.dispose.spec.js","sourceRoot":"","sources":["../src/ExifTool.dispose.spec.ts"],"names":[],"mappings":"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"}