exiftool-vendored 30.2.0 → 30.3.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/CHANGELOG.md +24 -7
- package/CLAUDE.md +2 -1
- package/README.md +160 -453
- package/RELEASE.md +1 -2
- package/dist/DefaultExifToolOptions.js +2 -0
- package/dist/DefaultExifToolOptions.js.map +1 -1
- package/dist/ExifTool.d.ts +71 -28
- package/dist/ExifTool.js +109 -11
- package/dist/ExifTool.js.map +1 -1
- package/dist/ExifToolOptions.d.ts +14 -0
- package/dist/ExifToolOptions.js.map +1 -1
- package/dist/StrEnum.d.ts +1 -1
- package/dist/StrEnum.js +2 -4
- package/dist/StrEnum.js.map +1 -1
- package/dist/Tags.d.ts +12512 -2512
- package/dist/Tags.js +3 -3
- package/dist/Tags.js.map +1 -1
- package/dist/WriteTags.d.ts +3 -4
- package/package.json +25 -18
package/README.md
CHANGED
|
@@ -5,543 +5,250 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/exiftool-vendored)
|
|
6
6
|
[](https://github.com/photostructure/exiftool-vendored.js/actions/workflows/node.js.yml)
|
|
7
7
|
[](https://github.com/photostructure/exiftool-vendored.js/issues)
|
|
8
|
-
[](https://snyk.io/test/github/photostructure/exiftool-vendored.js?targetFile=package.json)
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## Installation & Quick Start
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
**Requirements**: Node.js Active LTS or Maintenance LTS versions only
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Expect [an order of magnitude faster performance](#performance) than other Node.js ExifTool modules.
|
|
17
|
-
|
|
18
|
-
Thanks to being based on [ExifTool](https://exiftool.org/), it's the state of the art in high quality metadata extraction for thousands of file types.
|
|
19
|
-
|
|
20
|
-
1. Best-effort extraction of
|
|
21
|
-
|
|
22
|
-
- **dates** with [correct timezone offset encoding](#dates)
|
|
23
|
-
- **latitudes & longitudes** as floats (where negative values indicate west or south of the meridian)
|
|
24
|
-
|
|
25
|
-
1. Support for
|
|
26
|
-
|
|
27
|
-
- [reading tags](https://photostructure.github.io/exiftool-vendored.js/classes/ExifTool.html#read)
|
|
28
|
-
- extracting embedded binaries, like [thumbnail](https://photostructure.github.io/exiftool-vendored.js/classes/ExifTool.html#extractThumbnail) and [preview](https://photostructure.github.io/exiftool-vendored.js/classes/ExifTool.html#extractPreview) images
|
|
29
|
-
- [writing tags](https://photostructure.github.io/exiftool-vendored.js/classes/ExifTool.html#write)
|
|
30
|
-
- [rescuing metadata](https://photostructure.github.io/exiftool-vendored.js/classes/ExifTool.html#rewriteAllTags)
|
|
31
|
-
|
|
32
|
-
1. **[Robust type definitions](#tags)** of the top 99.5% tags used by over 6,000
|
|
33
|
-
different camera makes and models (see an [example](https://photostructure.github.io/exiftool-vendored.js/interfaces/EXIFTags.html#CreateDate))
|
|
34
|
-
|
|
35
|
-
1. **Automated updates** to ExifTool ([as new versions come out
|
|
36
|
-
frequently](https://exiftool.org/history.html))
|
|
37
|
-
|
|
38
|
-
1. **Robust test coverage**, performed with on [macOS, Linux, and
|
|
39
|
-
Windows](https://github.com/photostructure/exiftool-vendored.js/actions?query=workflow%3A%22Node.js+CI%22)
|
|
40
|
-
|
|
41
|
-
## Installation
|
|
42
|
-
|
|
43
|
-
```sh
|
|
44
|
-
npm install --save exiftool-vendored
|
|
13
|
+
```bash
|
|
14
|
+
npm install exiftool-vendored
|
|
45
15
|
```
|
|
46
16
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
If anything doesn't work, the first thing to try is enabling the logger.
|
|
50
|
-
|
|
51
|
-
You can provide a [Logger implementation](https://photostructure.github.io/batch-cluster.js/interfaces/Logger.html) via [`ExifToolOptions.logger`](https://photostructure.github.io/exiftool-vendored.js/interfaces/ExifToolOptions.html#logger), or set the environment variable `NODE_DEBUG=exiftool-vendored`. [See the debuglog() documentation](https://nodejs.org/docs/latest/api/util.html#utildebuglogsection-callback) for more details.
|
|
52
|
-
|
|
53
|
-
### Regarding use within Electron
|
|
54
|
-
|
|
55
|
-
Due to how different every Electron application setup is, and how new versions
|
|
56
|
-
frequently have breaking changes, **do not ask for help by opening a github
|
|
57
|
-
issue on this project.**
|
|
58
|
-
|
|
59
|
-
Please seek help via StackOverflow, the Electron discord, or other channels.
|
|
60
|
-
|
|
61
|
-
### Electron-builder support
|
|
62
|
-
|
|
63
|
-
Add the following pattern to `electron-builder.yml`'s `asarUnpack`:
|
|
64
|
-
|
|
65
|
-
```yaml
|
|
66
|
-
- "node_modules/exiftool-vendored.*/**/*"
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
The default `exiftoolPath` implementation will detect `app.asar` in your `require`
|
|
70
|
-
path and replace it with `app.asar.unpacked` automatically.
|
|
71
|
-
|
|
72
|
-
### Electron-forge support
|
|
73
|
-
|
|
74
|
-
Version 25.0 of this library added experimental support for `electron-forge`:
|
|
75
|
-
add the following element to your `ForgeConfig.packagerConfig.extraResource`
|
|
76
|
-
string array, and things should "just work" **for the main process**.
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
"./node_modules/exiftool-vendored." +
|
|
80
|
-
(process.platform === "win32" ? "exe" : "pl");
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**If your main process forks any node subprocesses, `process.resourcesPath` _will
|
|
84
|
-
not be set_ in those subprocesses, and the default `exiftoolPath` won't work.**
|
|
85
|
-
|
|
86
|
-
If this is your case, you must provide a correct implementation of
|
|
87
|
-
[ExifToolOptions.exiftoolPath](https://photostructure.github.io/exiftool-vendored.js/interfaces/ExifToolOptions.html#exiftoolPath),
|
|
88
|
-
either by passing through `resourcesPath` via `process.env`, or some other
|
|
89
|
-
method.
|
|
90
|
-
|
|
91
|
-
### Installation notes
|
|
92
|
-
|
|
93
|
-
- `exiftool-vendored` provides an installation of ExifTool relevant for your
|
|
94
|
-
local platform through
|
|
95
|
-
[optionalDependencies](https://docs.npmjs.com/files/package.json#optionaldependencies).
|
|
96
|
-
|
|
97
|
-
- You shouldn't include either [exiftool-vendored.exe](https://github.com/photostructure/exiftool-vendored.exe) or
|
|
98
|
-
[exiftool-vendored.pl](https://github.com/photostructure/exiftool-vendored.pl) as direct dependencies to your project, unless you know
|
|
99
|
-
what you're doing.
|
|
100
|
-
|
|
101
|
-
- If you're installing on a minimal Linux distribution, you may need to install `perl`. On Alpine, run `apk add perl`.
|
|
102
|
-
|
|
103
|
-
- Node.js's `-slim` docker images don't include a working `perl` build. Use the non-slim image instead. [See the issue report for details.](https://github.com/photostructure/exiftool-vendored.js/issues/168)
|
|
104
|
-
|
|
105
|
-
- If the platform-correct vendor module (`exiftool-vendored.exe` or `exiftool-vendored.pl`) is not found, `exiftool` is searched for on your `PATH`. Note that _very_ old versions of `exiftool` are found on currently-supported Linux distributions which this library will not work correctly with.
|
|
106
|
-
|
|
107
|
-
## Upgrading
|
|
108
|
-
|
|
109
|
-
See the
|
|
110
|
-
[CHANGELOG](https://github.com/photostructure/exiftool-vendored.js/blob/main/CHANGELOG.md)
|
|
111
|
-
for breaking changes since you last updated.
|
|
112
|
-
|
|
113
|
-
### Major version bumps
|
|
114
|
-
|
|
115
|
-
I bump the major version if there's a **chance** existing code might be
|
|
116
|
-
affected.
|
|
117
|
-
|
|
118
|
-
I've been bit too many times by my code breaking when I pull in minor or patch
|
|
119
|
-
upgrades with other libraries. I think it's better to be pessimistic in code
|
|
120
|
-
change impact analysis: "over-promise and under-deliver" your breaking-code
|
|
121
|
-
changes.
|
|
122
|
-
|
|
123
|
-
When you upgrade to a new major version, please take a bit more care in
|
|
124
|
-
validating your own systems, but don't be surprised when everything still works.
|
|
125
|
-
|
|
126
|
-
## Usage
|
|
127
|
-
|
|
128
|
-
There are many configuration options to ExifTool, but all values have (more or
|
|
129
|
-
less sensible) defaults.
|
|
130
|
-
|
|
131
|
-
Those defaults have been used to create the
|
|
132
|
-
[`exiftool`](https://photostructure.github.io/exiftool-vendored.js/modules.html#exiftool) singleton.
|
|
133
|
-
Note that if you _don't_ use the default singleton, you don't need to `.end()`
|
|
134
|
-
it.
|
|
135
|
-
|
|
136
|
-
```js
|
|
137
|
-
// We're using the singleton here for convenience:
|
|
138
|
-
const exiftool = require("exiftool-vendored").exiftool;
|
|
139
|
-
|
|
140
|
-
// And to verify everything is working:
|
|
141
|
-
exiftool
|
|
142
|
-
.version()
|
|
143
|
-
.then((version) => console.log(`We're running ExifTool v${version}`));
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
If the default [ExifTool constructor
|
|
147
|
-
parameters](https://photostructure.github.io/exiftool-vendored.js/interfaces/ExifToolOptions.html)
|
|
148
|
-
wont' work for you, it's just a class that takes an options hash:
|
|
149
|
-
|
|
150
|
-
```js
|
|
151
|
-
const ExifTool = require("exiftool-vendored").ExifTool;
|
|
152
|
-
const exiftool = new ExifTool({ taskTimeoutMillis: 5000 });
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
You should only use the exported default `exiftool` singleton, or only create one instance of `ExifTool` as a singleton.
|
|
156
|
-
|
|
157
|
-
Remember to `.end()` whichever singleton you use.
|
|
158
|
-
|
|
159
|
-
### General API
|
|
160
|
-
|
|
161
|
-
`ExifTool.read()` returns a Promise to a [Tags](https://photostructure.github.io/exiftool-vendored.js/interfaces/Tags.html) instance. Note
|
|
162
|
-
that errors may be returned either by rejecting the promise, or for less
|
|
163
|
-
severe problems, via the `errors` field.
|
|
164
|
-
|
|
165
|
-
All other public ExifTool methods return `Promise<void>`, and will reject
|
|
166
|
-
the promise if the operation is not successful.
|
|
17
|
+
```javascript
|
|
18
|
+
import { exiftool } from "exiftool-vendored";
|
|
167
19
|
|
|
168
|
-
|
|
20
|
+
// Read metadata
|
|
21
|
+
const tags = await exiftool.read("photo.jpg");
|
|
22
|
+
console.log(`Camera: ${tags.Make} ${tags.Model}`);
|
|
23
|
+
console.log(`Taken: ${tags.DateTimeOriginal}`);
|
|
24
|
+
console.log(`Size: ${tags.ImageWidth}x${tags.ImageHeight}`);
|
|
169
25
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
digital camera makes and models, many from the [ExifTool metadata
|
|
176
|
-
repository](https://exiftool.org/sample_images.html) and <raw.pixls.us>.
|
|
177
|
-
|
|
178
|
-
Here are some example fields:
|
|
179
|
-
|
|
180
|
-
```ts
|
|
181
|
-
/** ★☆☆☆ ✔ Example: 200 */
|
|
182
|
-
ISO?: number
|
|
183
|
-
|
|
184
|
-
/** ★★★★ ✔ Example: 1920 */
|
|
185
|
-
ImageHeight?: number
|
|
186
|
-
|
|
187
|
-
/** ★★★★ ✔ Example: 1080 */
|
|
188
|
-
ImageWidth?: number
|
|
189
|
-
|
|
190
|
-
/** ★★★★ ✔ Example: "image/jpeg" */
|
|
191
|
-
MIMEType?: string
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
The stars represent how common that field has a value in the example corpus. ★★★★ fields are found in > 50% of the examples.
|
|
195
|
-
☆☆☆☆ fields are found in < 1% of examples.
|
|
196
|
-
|
|
197
|
-
The checkmark denotes if the field is found in "popular" cameras (like recent
|
|
198
|
-
Nikon, Canon, Sony, and Apple devices).
|
|
199
|
-
|
|
200
|
-
### Caveats with `Tags`
|
|
201
|
-
|
|
202
|
-
**The fields in `Tags` are not comprehensive.**
|
|
203
|
-
|
|
204
|
-
Just because a field is missing from the Tags interface **does not mean the
|
|
205
|
-
field doesn't exist in the returned object**. This library doesn't exclude
|
|
206
|
-
unknown fields, in other words. It's up to you and your code to look for other
|
|
207
|
-
fields you expect and cast to a more relevant interface.
|
|
208
|
-
|
|
209
|
-
### Logging and events
|
|
210
|
-
|
|
211
|
-
To enable trace, debug, info, warning, or error logging from this library and
|
|
212
|
-
the underlying `batch-cluster` library, provide a [Logger](https://photostructure.github.io/batch-cluster.js/interfaces/Logger.html) instance to the `ExifTool` constructor options.
|
|
213
|
-
|
|
214
|
-
ExifTool instances emits [many lifecycle and error events](https://photostructure.github.io/batch-cluster.js/interfaces/BatchClusterEvents.html#beforeEnd) via `batch-cluster`.
|
|
215
|
-
|
|
216
|
-
### Reading tags
|
|
217
|
-
|
|
218
|
-
```js
|
|
219
|
-
exiftool
|
|
220
|
-
.read("path/to/image.jpg")
|
|
221
|
-
.then((tags /*: Tags */) =>
|
|
222
|
-
console.log(
|
|
223
|
-
`Make: ${tags.Make}, Model: ${tags.Model}, Errors: ${tags.errors}`,
|
|
224
|
-
),
|
|
225
|
-
)
|
|
226
|
-
.catch((err) => console.error("Something terrible happened: ", err));
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Extracting embedded images
|
|
26
|
+
// Write metadata
|
|
27
|
+
await exiftool.write("photo.jpg", {
|
|
28
|
+
XPComment: "Amazing sunset!",
|
|
29
|
+
Copyright: "© 2024 Your Name",
|
|
30
|
+
});
|
|
230
31
|
|
|
231
|
-
Extract
|
|
232
|
-
|
|
233
|
-
when the image is extracted:
|
|
32
|
+
// Extract thumbnail
|
|
33
|
+
await exiftool.extractThumbnail("photo.jpg", "thumb.jpg");
|
|
234
34
|
|
|
235
|
-
|
|
236
|
-
|
|
35
|
+
// The singleton instance automatically cleans up on process exit by default.
|
|
36
|
+
// If you need immediate cleanup or have disabled registerExitHandlers:
|
|
37
|
+
// await exiftool.end();
|
|
237
38
|
```
|
|
238
39
|
|
|
239
|
-
|
|
40
|
+
## Why exiftool-vendored?
|
|
240
41
|
|
|
241
|
-
|
|
242
|
-
exiftool.extractPreview("path/to/image.jpg", "path/to/preview.jpg");
|
|
243
|
-
```
|
|
42
|
+
### ⚡ **Performance**
|
|
244
43
|
|
|
245
|
-
|
|
44
|
+
Order of magnitude faster than other Node.js ExifTool modules. Powers [PhotoStructure](https://photostructure.com) and [1,000+ other projects](https://github.com/photostructure/exiftool-vendored.js/network/dependents?package_id=UGFja2FnZS0xNjYxNjY2MQ%3D%3D).
|
|
246
45
|
|
|
247
|
-
|
|
248
|
-
exiftool.extractJpgFromRaw("path/to/image.cr2", "path/to/fromRaw.jpg");
|
|
249
|
-
```
|
|
46
|
+
### 🔧 **Robust**
|
|
250
47
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
48
|
+
- **Cross-platform**: macOS, Linux, Windows
|
|
49
|
+
- **Comprehensive**: Read, write, extract embedded images
|
|
50
|
+
- **Reliable**: Battle-tested with extensive test coverage
|
|
254
51
|
|
|
255
|
-
|
|
256
|
-
exiftool.extractBinaryTag("tagname", "path/to/file.exf", "path/to/dest.bin");
|
|
257
|
-
```
|
|
52
|
+
### 📚 **Developer-Friendly**
|
|
258
53
|
|
|
259
|
-
|
|
54
|
+
- **TypeScript**: Full type definitions for thousands of metadata fields
|
|
55
|
+
- **Smart dates**: Timezone-aware `ExifDateTime` classes
|
|
56
|
+
- **Auto-generated tags**: Based on 6,000+ real camera samples
|
|
260
57
|
|
|
261
|
-
|
|
262
|
-
documentation](https://exiftool.org/TagNames/index.html)
|
|
263
|
-
and look under the "Writable" column.
|
|
58
|
+
## Core Features
|
|
264
59
|
|
|
265
|
-
|
|
266
|
-
supported, the returned `Promise` will be rejected.
|
|
60
|
+
### Reading Metadata
|
|
267
61
|
|
|
268
|
-
|
|
62
|
+
```javascript
|
|
63
|
+
const tags = await exiftool.read("photo.jpg");
|
|
269
64
|
|
|
270
|
-
|
|
271
|
-
|
|
65
|
+
// Camera info
|
|
66
|
+
console.log(tags.Make, tags.Model, tags.LensModel);
|
|
272
67
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
```
|
|
68
|
+
// Capture settings
|
|
69
|
+
console.log(tags.ISO, tags.FNumber, tags.ExposureTime);
|
|
276
70
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
shortcut) to 4:56pm UTC on February 6, 2016:
|
|
71
|
+
// Location (if available)
|
|
72
|
+
console.log(tags.GPSLatitude, tags.GPSLongitude);
|
|
280
73
|
|
|
281
|
-
|
|
282
|
-
|
|
74
|
+
// Always check for parsing errors
|
|
75
|
+
if (tags.errors?.length > 0) {
|
|
76
|
+
console.warn("Metadata warnings:", tags.errors);
|
|
77
|
+
}
|
|
283
78
|
```
|
|
284
79
|
|
|
285
|
-
|
|
286
|
-
(TypeScript users: you'll need to cast to make this compile).
|
|
80
|
+
### Writing Metadata
|
|
287
81
|
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
|
|
82
|
+
```javascript
|
|
83
|
+
// Add keywords and copyright
|
|
84
|
+
await exiftool.write("photo.jpg", {
|
|
85
|
+
Keywords: ["sunset", "landscape"],
|
|
86
|
+
Copyright: "© 2024 Photographer Name",
|
|
87
|
+
"IPTC:CopyrightNotice": "© 2024 Photographer Name",
|
|
291
88
|
});
|
|
292
|
-
```
|
|
293
89
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
exiftool.write("path/to/file.jpg", { UserComment: null });
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
The above example removes any value associated with the `UserComment` tag.
|
|
301
|
-
|
|
302
|
-
### Partial Date Support
|
|
303
|
-
|
|
304
|
-
**NEW in v30.2.0:** XMP date tags now support partial dates (year-only or year-month):
|
|
305
|
-
|
|
306
|
-
```js
|
|
307
|
-
// Year-only dates
|
|
308
|
-
exiftool.write("path/to/file.jpg", { "XMP:CreateDate": 1980 });
|
|
309
|
-
// or
|
|
310
|
-
exiftool.write("path/to/file.jpg", {
|
|
311
|
-
"XMP:CreateDate": ExifDate.fromYear(1980),
|
|
90
|
+
// Update all date fields at once
|
|
91
|
+
await exiftool.write("photo.jpg", {
|
|
92
|
+
AllDates: "2024:03:15 14:30:00",
|
|
312
93
|
});
|
|
313
94
|
|
|
314
|
-
//
|
|
315
|
-
exiftool.write("
|
|
316
|
-
|
|
317
|
-
exiftool.write("path/to/file.jpg", { "XMP:CreateDate": "1980-08" });
|
|
318
|
-
// or
|
|
319
|
-
exiftool.write("path/to/file.jpg", {
|
|
320
|
-
"XMP:CreateDate": ExifDate.fromYearMonth("1980-08"),
|
|
95
|
+
// Delete tags
|
|
96
|
+
await exiftool.write("photo.jpg", {
|
|
97
|
+
UserComment: null,
|
|
321
98
|
});
|
|
322
99
|
```
|
|
323
100
|
|
|
324
|
-
|
|
325
|
-
tags](https://exiftool.org/TagNames/XMP.html) (like `XMP:CreateDate`,
|
|
326
|
-
`XMP:MetadataDate`). [EXIF tags](https://exiftool.org/TagNames/EXIF.html), like
|
|
327
|
-
`EXIF:CreateDate`, require **complete** (year, month, and day) dates. Always use
|
|
328
|
-
the group-prefixed tag names (e.g., `"XMP:CreateDate"`) when working with
|
|
329
|
-
partial dates.
|
|
330
|
-
|
|
331
|
-
### Always Beware: Timezones
|
|
101
|
+
### Extracting Images
|
|
332
102
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
103
|
+
```javascript
|
|
104
|
+
// Extract thumbnail
|
|
105
|
+
await exiftool.extractThumbnail("photo.jpg", "thumbnail.jpg");
|
|
336
106
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
section about [Dates](#dates) below for more information.
|
|
107
|
+
// Extract preview (larger than thumbnail)
|
|
108
|
+
await exiftool.extractPreview("photo.jpg", "preview.jpg");
|
|
340
109
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
You may find that some of your images have corrupt metadata and that writing
|
|
344
|
-
new dates, or editing the rotation information, for example, fails. ExifTool can
|
|
345
|
-
try to repair these images by rewriting all the metadata into a new file, along
|
|
346
|
-
with the original image content. See the
|
|
347
|
-
[documentation](https://exiftool.org/faq.html#Q20) for more
|
|
348
|
-
details about this functionality.
|
|
349
|
-
|
|
350
|
-
`rewriteAllTags` returns a void Promise that will be rejected if there are any
|
|
351
|
-
errors.
|
|
352
|
-
|
|
353
|
-
```js
|
|
354
|
-
exiftool.rewriteAllTags("problematic.jpg", "rewritten.jpg");
|
|
110
|
+
// Extract JPEG from RAW files
|
|
111
|
+
await exiftool.extractJpgFromRaw("photo.cr2", "processed.jpg");
|
|
355
112
|
```
|
|
356
113
|
|
|
357
|
-
|
|
114
|
+
## Understanding Tags
|
|
358
115
|
|
|
359
|
-
|
|
116
|
+
The `Tags` interface contains **thousands of metadata fields** from an auto-generated TypeScript file. Each tag uses a special notation:
|
|
360
117
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
1. Set the `EXIFTOOL_HOME` environment variable to the fully-qualified path that
|
|
365
|
-
contains your user configuration.
|
|
366
|
-
1. Specify the in the ExifTool constructor options:
|
|
118
|
+
```typescript
|
|
119
|
+
/** ★★★★ ✔ Example: 1920 */
|
|
120
|
+
ImageWidth?: number; // Very common, all cameras
|
|
367
121
|
|
|
368
|
-
|
|
369
|
-
|
|
122
|
+
/** ★☆☆☆ Example: "Custom" */
|
|
123
|
+
RareTag?: string; // Rare, <1% of files
|
|
370
124
|
```
|
|
371
125
|
|
|
372
|
-
|
|
126
|
+
- **★★★★** = Found in >50% of files (very common)
|
|
127
|
+
- **★☆☆☆** = Very rare, <1% of files
|
|
128
|
+
- **✔** = Found in popular cameras (Canon, Nikon, Sony, Apple)
|
|
373
129
|
|
|
374
|
-
**
|
|
130
|
+
**Important**: The interface isn't comprehensive - unknown fields may still exist in returned objects.
|
|
375
131
|
|
|
376
|
-
|
|
377
|
-
[`.end()`](https://photostructure.github.io/exiftool-vendored.js/classes/ExifTool.html#end)
|
|
378
|
-
on any used instance of `ExifTool` to allow `node` to exit gracefully.
|
|
132
|
+
📖 **[Complete Tags Documentation →](docs/TAGS.md)**
|
|
379
133
|
|
|
380
|
-
|
|
381
|
-
exiting due to the way Node.js streams
|
|
382
|
-
work](https://github.com/photostructure/exiftool-vendored.js/issues/106).
|
|
134
|
+
## Important Notes
|
|
383
135
|
|
|
384
|
-
|
|
385
|
-
attached to the child process cannot be `unref`'ed. (If there's a solution to
|
|
386
|
-
this, please post to the above issue!)
|
|
136
|
+
### ⏰ Dates & Timezones
|
|
387
137
|
|
|
388
|
-
|
|
138
|
+
Images rarely specify timezones. This library uses sophisticated heuristics:
|
|
389
139
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
and can be solved by adding an `after` block that shuts down the instance
|
|
394
|
-
of ExifTool that your tests are using:
|
|
140
|
+
1. **Explicit metadata** (TimeZoneOffset, OffsetTime)
|
|
141
|
+
2. **GPS location** → timezone lookup
|
|
142
|
+
3. **UTC timestamps** → calculate offset
|
|
395
143
|
|
|
396
|
-
```
|
|
397
|
-
|
|
144
|
+
```javascript
|
|
145
|
+
const dt = tags.DateTimeOriginal;
|
|
146
|
+
if (dt instanceof ExifDateTime) {
|
|
147
|
+
console.log("Timezone offset:", dt.tzoffset, "minutes");
|
|
148
|
+
console.log("Timezone:", dt.zone);
|
|
149
|
+
}
|
|
398
150
|
```
|
|
399
151
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
**The date metadata in all your images and videos are, most likely,
|
|
403
|
-
underspecified.**
|
|
404
|
-
|
|
405
|
-
Images and videos rarely specify a time zone in their dates. If all your files
|
|
406
|
-
were captured in your current time zone, defaulting to the local time zone is a
|
|
407
|
-
safe assumption, but if you have files that were captured in different parts of
|
|
408
|
-
the world, **this assumption will not be correct**. Parsing the same file in
|
|
409
|
-
different parts of the world result in different times for the same file.
|
|
410
|
-
|
|
411
|
-
Prior to version 7, heuristic 1 and 3 were applied.
|
|
152
|
+
📖 **[Date & Timezone Guide →](docs/DATES.md)**
|
|
412
153
|
|
|
413
|
-
|
|
414
|
-
highest-priority heuristic to return a value will be used as the timezone offset
|
|
415
|
-
for all datetime tags that don't already have a specified timezone.
|
|
154
|
+
### 🧹 Resource Cleanup
|
|
416
155
|
|
|
417
|
-
|
|
156
|
+
**Always call `.end()` on ExifTool instances** to prevent Node.js from hanging:
|
|
418
157
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
`DateTimeOriginal`, and if there are two values, the `ModifyDate` tag as well.
|
|
422
|
-
`OffsetTime`, `OffsetTimeOriginal`, and `OffsetTimeDigitized` are also
|
|
423
|
-
respected, if present (but are very rarely set).
|
|
158
|
+
```javascript
|
|
159
|
+
import { exiftool } from "exiftool-vendored";
|
|
424
160
|
|
|
425
|
-
|
|
161
|
+
// Use the singleton
|
|
162
|
+
const tags = await exiftool.read("photo.jpg");
|
|
426
163
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
### Heuristic 3: UTC timestamps
|
|
432
|
-
|
|
433
|
-
If `GPSDateTime` or `DateTimeUTC` is present, the delta with the dates found
|
|
434
|
-
within the file, as long as the delta is valid, is used as the timezone offset.
|
|
435
|
-
Deltas of > 14 hours are considered invalid.
|
|
436
|
-
|
|
437
|
-
### ExifDate and ExifDateTime
|
|
438
|
-
|
|
439
|
-
Because date-times have this optionally-set timezone, and some tags only specify
|
|
440
|
-
the date, this library returns classes that encode the date, the time of day, or
|
|
441
|
-
both, **with an optional timezone and an optional tzoffset**: `ExifDateTime` and
|
|
442
|
-
`ExifTime`. It's up to you, then, to determine what's correct for your
|
|
443
|
-
situation.
|
|
444
|
-
|
|
445
|
-
Note also that some smartphones record timestamps with microsecond precision
|
|
446
|
-
(not just milliseconds!), and both `ExifDateTime` and `ExifTime` have floating point
|
|
447
|
-
milliseconds.
|
|
448
|
-
|
|
449
|
-
## Tags
|
|
450
|
-
|
|
451
|
-
Official [EXIF](http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf) tag names
|
|
452
|
-
are [PascalCased](https://en.wikipedia.org/wiki/PascalCase), like
|
|
453
|
-
`AFPointSelected` and `ISO`. ("Fixing" the field names to be camelCase, would
|
|
454
|
-
result in ungainly `aFPointSelected` and `iSO` atrocities).
|
|
164
|
+
// Clean up when done
|
|
165
|
+
process.on("beforeExit", () => exiftool.end());
|
|
166
|
+
```
|
|
455
167
|
|
|
456
|
-
|
|
457
|
-
auto-generated by the `mktags` script, which parses through over 6,000 unique
|
|
458
|
-
camera make and model images, in large part sourced from the ExifTool site.
|
|
459
|
-
`mktags` groups tags, extracts their type, popularity, and example values such
|
|
460
|
-
that your IDE can autocomplete.
|
|
168
|
+
#### Automatic Cleanup with Disposable Interfaces
|
|
461
169
|
|
|
462
|
-
|
|
463
|
-
[MIMEType](https://photostructure.github.io/exiftool-vendored.js/interfaces/FileTags.html#MIMEType),
|
|
464
|
-
should be found in most files. Of the several thousand metadata tags, realize
|
|
465
|
-
less than 50 are found generally. You'll need to do your research to
|
|
466
|
-
determine which tags are valid for your uses.
|
|
170
|
+
For **TypeScript 5.2+** projects, use automatic resource management:
|
|
467
171
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
reasonable for safety.
|
|
172
|
+
```javascript
|
|
173
|
+
import { ExifTool } from "exiftool-vendored";
|
|
471
174
|
|
|
472
|
-
|
|
175
|
+
// Automatic synchronous cleanup
|
|
176
|
+
{
|
|
177
|
+
using et = new ExifTool();
|
|
178
|
+
const tags = await et.read("photo.jpg");
|
|
179
|
+
// ExifTool automatically cleaned up when block exits
|
|
180
|
+
}
|
|
473
181
|
|
|
474
|
-
|
|
182
|
+
// Automatic asynchronous cleanup (recommended)
|
|
183
|
+
{
|
|
184
|
+
await using et = new ExifTool();
|
|
185
|
+
const tags = await et.read("photo.jpg");
|
|
186
|
+
// ExifTool gracefully cleaned up when block exits
|
|
187
|
+
}
|
|
188
|
+
```
|
|
475
189
|
|
|
476
|
-
|
|
190
|
+
**Benefits:**
|
|
477
191
|
|
|
478
|
-
|
|
479
|
-
|
|
192
|
+
- **Guaranteed cleanup**: No leaked processes, even with exceptions
|
|
193
|
+
- **Timeout protection**: Automatic forceful cleanup if graceful shutdown hangs
|
|
194
|
+
- **Zero boilerplate**: No manual `.end()` calls needed
|
|
480
195
|
|
|
481
|
-
|
|
482
|
-
const str: string = JSON.stringify(tags);
|
|
196
|
+
### 🏷️ Tag Completeness
|
|
483
197
|
|
|
484
|
-
|
|
485
|
-
// instance, but you can cast it (unsafely...)
|
|
198
|
+
The `Tags` interface shows the most common fields, but ExifTool can extract many more. Cast to access unlisted fields:
|
|
486
199
|
|
|
487
|
-
|
|
200
|
+
```javascript
|
|
201
|
+
const tags = await exiftool.read("photo.jpg");
|
|
202
|
+
const customField = (tags as any).UncommonTag;
|
|
488
203
|
```
|
|
489
204
|
|
|
490
|
-
##
|
|
205
|
+
## Documentation
|
|
491
206
|
|
|
492
|
-
|
|
493
|
-
utilization is acceptable:
|
|
207
|
+
### 📚 **Guides**
|
|
494
208
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
209
|
+
- **[Installation Guide](docs/INSTALLATION.md)** - Electron, Docker, platform setup
|
|
210
|
+
- **[Usage Examples](docs/USAGE-EXAMPLES.md)** - Comprehensive API examples
|
|
211
|
+
- **[Date Handling](docs/DATES.md)** - Timezone complexities explained
|
|
212
|
+
- **[Tags Reference](docs/TAGS.md)** - Understanding the 2,500+ metadata fields
|
|
213
|
+
- **[Electron Integration](docs/ELECTRON.md)** - Electron-specific setup
|
|
498
214
|
|
|
499
|
-
|
|
500
|
-
[`minDelayBetweenSpawnMillis`](https://photostructure.github.io/batch-cluster.js/classes/BatchClusterOptions.html#minDelayBetweenSpawnMillis)
|
|
501
|
-
to 0
|
|
215
|
+
### 🔧 **Troubleshooting**
|
|
502
216
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
events](https://photostructure.github.io/batch-cluster.js/interfaces/BatchClusterEvents.html#noTaskData),
|
|
506
|
-
you need to bump the value up.
|
|
217
|
+
- **[Debugging Guide](docs/DEBUGGING.md)** - Debug logging and common issues
|
|
218
|
+
- **[Temporal Migration](docs/TEMPORAL-MIGRATION.md)** - Future JavaScript Temporal API
|
|
507
219
|
|
|
508
|
-
|
|
220
|
+
### 📖 **API Reference**
|
|
509
221
|
|
|
510
|
-
|
|
511
|
-
hierarchy of sample images and videos, and parses the results.
|
|
222
|
+
- **[TypeDoc Documentation](https://photostructure.github.io/exiftool-vendored.js/)** - Complete API reference
|
|
512
223
|
|
|
513
|
-
|
|
514
|
-
SSD can process 20+ files per second per thread, or 500+ files per second when
|
|
515
|
-
utilizing all CPU threads.
|
|
224
|
+
## Performance
|
|
516
225
|
|
|
517
|
-
|
|
226
|
+
The default singleton is throttled for stability. For high-throughput processing:
|
|
518
227
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
dramatically as well as reducing system load.
|
|
228
|
+
```javascript
|
|
229
|
+
import { ExifTool } from "exiftool-vendored";
|
|
522
230
|
|
|
523
|
-
|
|
231
|
+
const exiftool = new ExifTool({
|
|
232
|
+
maxProcs: 8, // More concurrent processes
|
|
233
|
+
minDelayBetweenSpawnMillis: 0, // Faster spawning
|
|
234
|
+
streamFlushMillis: 10, // Faster streaming
|
|
235
|
+
});
|
|
524
236
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
1); no more than `maxProcs` instances of `exiftool` will be spawned. If the
|
|
528
|
-
system is CPU constrained, however, you may want a smaller value. If you have
|
|
529
|
-
very fast disk IO, you may see a speed increase with larger values of
|
|
530
|
-
`maxProcs`, but note that each child process can consume 100 MB of RAM.
|
|
237
|
+
// Process many files efficiently
|
|
238
|
+
const results = await Promise.all(filePaths.map((file) => exiftool.read(file)));
|
|
531
239
|
|
|
532
|
-
|
|
240
|
+
await exiftool.end();
|
|
241
|
+
```
|
|
533
242
|
|
|
534
|
-
|
|
243
|
+
**Benchmarks**: 20+ files/second/thread, 500+ files/second using all CPU cores.
|
|
535
244
|
|
|
536
|
-
##
|
|
245
|
+
## Support & Community
|
|
537
246
|
|
|
538
|
-
- [
|
|
539
|
-
- [
|
|
540
|
-
- [
|
|
541
|
-
- [
|
|
542
|
-
- [David Randler](https://github.com/draity)
|
|
247
|
+
- **📋 Issues**: [GitHub Issues](https://github.com/photostructure/exiftool-vendored.js/issues)
|
|
248
|
+
- **📖 Changelog**: [CHANGELOG.md](CHANGELOG.md)
|
|
249
|
+
- **🔒 Security**: [SECURITY.md](SECURITY.md)
|
|
250
|
+
- **📄 License**: [MIT](LICENSE)
|
|
543
251
|
|
|
544
|
-
|
|
252
|
+
### Contributors 🎉
|
|
545
253
|
|
|
546
|
-
|
|
547
|
-
[CHANGELOG](https://github.com/mceachen/exiftool-vendored.js/blob/main/CHANGELOG.md) on github.
|
|
254
|
+
[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)
|