### Basic Setup and Version Check Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/USAGE-EXAMPLES.md Demonstrates how to import and initialize exiftool-vendored.js and verify the installed ExifTool version. Includes optional graceful shutdown. ```javascript import { exiftool } from "exiftool-vendored"; // or: const { exiftool } = require("exiftool-vendored"); // Verify installation console.log(`ExifTool v${await exiftool.version()}`); // Optional: graceful shutdown (Node.js will exit naturally without this as of v35) await exiftool.end(); ``` -------------------------------- ### Docker Installation Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Example Dockerfile for using exiftool-vendored.js. It's recommended to use a full Node image and install Perl if using a slim image. ```dockerfile # Docker: use full Node image (includes Perl), not -slim FROM node:24 WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . CMD ["node", "index.js"] # If you must use slim images: # FROM node:24-slim # RUN apt-get update && apt-get install -y perl && rm -rf /var/lib/apt/lists/* ``` -------------------------------- ### Install Dependencies Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Installs project dependencies. Run this before other development commands. ```bash npm install ``` -------------------------------- ### Quick Start: Initialize ExifTool Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/CONFIGURATION.md Demonstrates basic initialization of ExifTool using the singleton or a custom instance with specific options. ```javascript import { ExifTool, Settings } from "exiftool-vendored"; // Use the singleton for simple cases import { exiftool } from "exiftool-vendored"; const tags = await exiftool.read("photo.jpg"); // Or create a custom instance const et = new ExifTool({ maxProcs: 4, taskTimeoutMillis: 30000, }); ``` -------------------------------- ### Quick Start: Read, Write, and Extract Metadata Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/README.md A basic example demonstrating how to read metadata from a JPG, write new metadata, and extract a thumbnail. Remember to call exiftool.end() when finished. ```javascript import { exiftool } from "exiftool-vendored"; // Read metadata const tags = await exiftool.read("photo.jpg"); console.log(`Camera: ${tags.Make} ${tags.Model}`); console.log(`Taken: ${tags.DateTimeOriginal}`); console.log(`Size: ${tags.ImageWidth}x${tags.ImageHeight}`); // Write metadata await exiftool.write("photo.jpg", { XPComment: "Amazing sunset!", Copyright: "© 2024 Your Name", }); // Extract thumbnail await exiftool.extractThumbnail("photo.jpg", "thumb.jpg"); await exiftool.end(); ``` -------------------------------- ### Example Dockerfile for application Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/INSTALLATION.md A sample Dockerfile for building an application that uses exiftool-vendored. ```dockerfile FROM node:24 WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . CMD ["node", "index.js"] ``` -------------------------------- ### Install exiftool-vendored with npm Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/INSTALLATION.md Install the exiftool-vendored package using npm. ```bash npm install exiftool-vendored ``` -------------------------------- ### Install Dependencies and Run Tests Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/RELEASE.md Standard commands for setting up the project locally, generating tags, and running pre-commit checks and tests. ```bash git clone this repo npm install npm run mktags ../test-images # < assumes `../test-images` has the full ExifTool sample image suite npm run precommit (look for lint or documentation generation issues) npm run test ``` -------------------------------- ### new ExifTool(options?) Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Create a custom ExifTool instance with fine-grained configuration. Instances are expensive to create; treat them as singletons. Each spawned process uses 10–50 MB RAM. This example shows configuration for high-throughput batch processing and timezone options. ```APIDOC ## new ExifTool(options?) ### Description Create a custom `ExifTool` instance with fine-grained configuration. Instances are expensive to create — treat them as singletons. Each spawned process uses 10–50 MB RAM. ### Usage ```javascript import { ExifTool } from "exiftool-vendored"; import { find } from "geo-tz"; // High-throughput batch processing instance const exiftool = new ExifTool({ maxProcs: 8, // Up to 8 concurrent ExifTool processes maxTasksPerProcess: 1000, // Retire each process after 1000 tasks taskTimeoutMillis: 60000, // 60s per task timeout spawnTimeoutMillis: 30000, // 30s for process startup // Timezone options backfillTimezones: true, // Infer missing timezones inferTimezoneFromDatestamps: true, // Use datestamp delta as fallback preferTimezoneInferenceFromGps: true, // Use geo-tz for higher-accuracy timezone lookups geoTz: (lat, lon) => find(lat, lon)[0], // Enable ExifTool's built-in geolocation enrichment (requires ExifTool 12.78+) geolocation: true, useMWG: true, // MWG composite tags (recommended) imageHashType: "SHA256", // Compute image content hash on every read defaultVideosToUTC: true, // Video dates assumed UTC asyncDisposalTimeoutMs: 30_000, // 30s timeout for await using cleanup }); // Verify it works console.log(await exiftool.version()); await exiftool.end(); ``` ``` -------------------------------- ### Install Perl on Debian/Ubuntu Minimal Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/INSTALLATION.md Install the perl package on Debian/Ubuntu minimal distributions. ```bash # Debian/Ubuntu minimal apt-get install perl ``` -------------------------------- ### Custom ExifTool Instance Configuration Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Create a custom ExifTool instance with fine-grained configuration options for high-throughput batch processing. This example demonstrates advanced settings for process management, timeouts, and timezone inference. ```javascript import { ExifTool } from "exiftool-vendored"; import { find } from "geo-tz"; // High-throughput batch processing instance const exiftool = new ExifTool({ maxProcs: 8, // Up to 8 concurrent ExifTool processes maxTasksPerProcess: 1000, // Retire each process after 1000 tasks taskTimeoutMillis: 60000, // 60s per task timeout spawnTimeoutMillis: 30000, // 30s for process startup // Timezone options backfillTimezones: true, // Infer missing timezones inferTimezoneFromDatestamps: true, // Use datestamp delta as fallback preferTimezoneInferenceFromGps: true, // Use geo-tz for higher-accuracy timezone lookups geoTz: (lat, lon) => find(lat, lon)[0], // Enable ExifTool's built-in geolocation enrichment (requires ExifTool 12.78+) geolocation: true, useMWG: true, // MWG composite tags (recommended) imageHashType: "SHA256", // Compute image content hash on every read defaultVideosToUTC: true, // Video dates assumed UTC asyncDisposalTimeoutMs: 30_000, // 30s timeout for await using cleanup }); // Verify it works console.log(await exiftool.version()); await exiftool.end(); ``` -------------------------------- ### Install Perl in a slim Docker image Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/INSTALLATION.md If using a slim Node.js Docker image, install perl manually. ```dockerfile FROM node:24-slim RUN apt-get update && apt-get install -y perl && rm -rf /var/lib/apt/lists/* ``` -------------------------------- ### Submit Custom Tasks with enqueueTask Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Provides a low-level API example for submitting custom `BatchCluster` tasks using `exiftool.enqueueTask`. This is useful for advanced use cases not covered by built-in methods. It also shows how to monitor and manage the ExifTool process pool. ```javascript import { ExifTool, ExifToolTask } from "exiftool-vendored"; const exiftool = new ExifTool(); // Monitor process pool health console.log("Pending tasks:", exiftool.pendingTasks); console.log("Busy processes:", exiftool.busyProcs); console.log("Spawned processes:", exiftool.spawnedProcs); console.log("Process IDs:", exiftool.pids); console.log("End counts:", exiftool.childEndCounts()); // Recycle all child processes (new ones spawn automatically) exiftool.closeChildProcesses(true); await exiftool.end(); ``` -------------------------------- ### Debug Logging Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Instructions and examples for enabling and configuring debug logging for the exiftool-vendored.js library. ```APIDOC ## Debug Logging ```bash # Enable via environment variable NODE_DEBUG=exiftool-vendored node your-script.js ``` ```javascript import { ExifTool } from "exiftool-vendored"; // Pass a custom logger to a specific instance const exiftool = new ExifTool({ logger: { trace: () => {}, debug: (msg) => console.log(`[DEBUG] ${msg}`), info: (msg) => console.log(`[INFO] ${msg}`), warn: (msg) => console.warn(`[WARN] ${msg}`), error: (msg) => console.error(`[ERROR] ${msg}`), }, }); ``` ``` -------------------------------- ### Install Perl on Alpine Linux Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/INSTALLATION.md Install the perl package on Alpine Linux distributions. ```bash # Alpine apk add perl ``` -------------------------------- ### Update Dependencies Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Updates project dependencies to their latest versions and installs them. ```bash npm run u ``` -------------------------------- ### Optimizing ExifTool for High-Throughput Processing Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/README.md Configure ExifTool with custom options like maxProcs, minDelayBetweenSpawnMillis, and streamFlushMillis for high-throughput processing. This setup is ideal for processing many files efficiently. ```javascript import { ExifTool } from "exiftool-vendored"; const exiftool = new ExifTool({ maxProcs: 8, // More concurrent processes minDelayBetweenSpawnMillis: 0, // Faster spawning streamFlushMillis: 10, // Faster streaming }); // Process many files efficiently const results = await Promise.all(filePaths.map((file) => exiftool.read(file))); await exiftool.end(); ``` -------------------------------- ### Library-wide Settings: Archaic Timezone Offsets Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/CONFIGURATION.md Configure global settings for exiftool-vendored.js, such as enabling historical timezone offsets. Includes an example of observing setting changes and resetting all settings. ```javascript import { Settings } from "exiftool-vendored"; // Enable historical timezone offsets for archival photos Settings.allowArchaicTimezoneOffsets.value = true; // Observe setting changes const unsubscribe = Settings.allowArchaicTimezoneOffsets.onChange( (oldValue, newValue) => console.log(`Changed: ${oldValue} -> ${newValue}`), ); // Reset all settings to defaults Settings.reset(); ``` -------------------------------- ### Run Release Process Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Initiates the release process for the library. Requires appropriate permissions. ```bash npm run release ``` -------------------------------- ### Configure Per-Instance ExifTool Options Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/README.md Create a new ExifTool instance with specific options like maxProcs, useMWG, or backfillTimezones. This allows for fine-grained control over individual ExifTool processes. ```javascript import { ExifTool } from "exiftool-vendored"; const exiftool = new ExifTool({ maxProcs: 8, // More concurrent processes useMWG: true, // Use Metadata Working Group tags backfillTimezones: true, // Infer missing timezones }); ``` -------------------------------- ### Synchronous Cleanup with 'using' Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/USAGE-EXAMPLES.md Shows how to use the 'using' keyword for automatic synchronous cleanup of ExifTool processes within a block scope. Also demonstrates processing multiple files with automatic cleanup. ```javascript import { ExifTool } from "exiftool-vendored"; // Block scope with automatic cleanup { using et = new ExifTool(); const tags = await et.read("photo.jpg"); console.log(`Camera: ${tags.Make} ${tags.Model}`); // ExifTool.end(false) called automatically when block exits } // Multiple files with automatic cleanup function processPhotos(filePaths) { using et = new ExifTool({ maxProcs: 4 }); return Promise.all( filePaths.map(async (file) => { const tags = await et.read(file); return { file, camera: `${tags.Make} ${tags.Model}` }; }), ); // Cleanup happens even if Promise.all() throws } ``` -------------------------------- ### JSDoc Annotations for Tags Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/TAGS.md JSDoc annotations provide metadata about each tag, including its frequency of occurrence, the groups it belongs to, and a representative example value. ```typescript /** * @frequency 🔥 ★★★★ (85%) * @groups EXIF, MakerNotes * @example 100 */ ISO?: number; /** * @frequency 🧊 ★★★☆ (23%) * @groups MakerNotes * @example "Custom lens data" */ LensSpec?: string; ``` -------------------------------- ### Build Documentation Only Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Generates TypeDoc documentation without serving it locally. Use for CI/CD pipelines. ```bash npm run docs:build ``` -------------------------------- ### Handling Missing Tag Values Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/TAGS.md Provides examples of safely checking for the existence of tags and using default values or fallbacks with the nullish coalescing operator (`??`) when tags might be missing. ```typescript const tags = await exiftool.read("photo.jpg"); // Safe checking if (tags.Make) { console.log(`Camera: ${tags.Make}`); } // With defaults const make = tags.Make ?? "Unknown"; const width = tags.ImageWidth ?? 0; // Nullish coalescing for fallbacks const timestamp = tags.DateTimeOriginal ?? tags.DateTime ?? tags.FileModifyDate; ``` -------------------------------- ### Generate TypeDoc Documentation Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Generates TypeDoc documentation and serves it locally for preview. Automatically deployed on push to main. ```bash npm run docs ``` -------------------------------- ### ExifTool Resource Management with `using` Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Demonstrates automatic resource management for ExifTool instances using TypeScript 5.2+ `using` and `await using` for automatic disposal. ```APIDOC ## `using` / `await using` — Automatic Disposal (TypeScript 5.2+) `ExifTool` implements both `Symbol.dispose` and `Symbol.asyncDispose` for automatic resource management. Requires `"target": "ES2022"` and `"lib": ["ES2022"]` in `tsconfig.json`. ### Async Disposal (Recommended) ```typescript import { ExifTool } from "exiftool-vendored"; async function processFiles(paths: string[]) { await using et = new ExifTool({ maxProcs: 8, asyncDisposalTimeoutMs: 30_000, // 30s timeout before forceful cleanup }); const results = []; for (const file of paths) { try { const tags = await et.read(file); await et.write(file, { Copyright: "© 2024 Acme Corp" }); results.push({ file, camera: `${tags.Make} ${tags.Model}`, success: true }); } catch (err) { results.push({ file, success: false, error: (err as Error).message }); } } return results; // ExifTool.end(true) called automatically here, even if an exception occurred } ``` ### Synchronous Disposal ```typescript import { ExifTool } from "exiftool-vendored"; // Synchronous disposal — fire-and-forget (initiates cleanup without waiting) { using et = new ExifTool({ disposalTimeoutMs: 2000 }); const tags = await et.read("photo.jpg"); console.log(tags.Make, tags.Model); // Cleanup initiated when block exits, timeout-protected } ``` ``` -------------------------------- ### Runtime Tag Descriptions with TagDescriptions Class Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/TAGS.md Shows how to import and use the `TagDescriptions` class to retrieve human-readable descriptions and documentation URLs for metadata tags at runtime. Includes preloading for synchronous access. ```typescript import { exiftool, TagDescriptions } from "exiftool-vendored"; const descriptions = new TagDescriptions(exiftool); // Preload during app initialization for sync access later await descriptions.preload(); // Sync lookup (instant if preloaded) const desc = descriptions.get("DateTimeOriginal"); // => { desc: "When a photo was taken...", see: "https://..." } // Or use async lookup (auto-loads if needed) const desc2 = await descriptions.getAsync("ISO"); ``` -------------------------------- ### Access Microsecond Precision in Timestamps Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/DATES.md ExifDateTime and ExifTime objects preserve sub-millisecond precision, including microseconds. Access the millisecond property to get floating-point values representing this precision. ```javascript const dt = tags.DateTimeOriginal; if (dt instanceof ExifDateTime) { // Floating point milliseconds include microsecond precision console.log("Milliseconds:", dt.millisecond); // e.g., 123.456 (123456 microseconds) } ``` -------------------------------- ### Asynchronous Cleanup with 'await using' Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/USAGE-EXAMPLES.md Illustrates automatic asynchronous cleanup of ExifTool processes using 'await using', including graceful shutdown with timeout protection. Also shows a function for batch processing with automatic cleanup. ```javascript import { ExifTool } from "exiftool-vendored"; // Graceful cleanup with timeout protection { await using et = new ExifTool(); const tags = await et.read("photo.jpg"); await et.write("photo.jpg", { XPComment: "Processed with exiftool-vendored, golly gee whiz it's neato", Copyright: "© 2024", }); // ExifTool.end(true) called automatically with timeout protection // If graceful cleanup times out, forceful cleanup is attempted } // Function with automatic cleanup async function batchProcessPhotos(filePaths) { await using et = new ExifTool({ maxProcs: 8, taskTimeoutMillis: 30000, }); const results = []; for (const file of filePaths) { try { const tags = await et.read(file); // Add copyright await et.write(file, { Copyright: "© 2025 Your Company", }); results.push({ file, success: true, camera: tags.Make }); } catch (error) { results.push({ file, success: false, error: error.message }); } } return results; // Automatic cleanup happens here, even with exceptions } ``` -------------------------------- ### ExifTool Singleton Usage Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Use the default pre-configured singleton ExifTool instance for most applications. This instance is optimized with a default `maxProcs` setting. Includes graceful shutdown handling for servers. ```javascript import { exiftool } from "exiftool-vendored"; // Confirm ExifTool version console.log(`ExifTool v${await exiftool.version()}`); // Output: ExifTool v13.57 // For servers/daemons: graceful shutdown on termination signals process.on("SIGINT", () => exiftool.end()); process.on("SIGTERM", () => exiftool.end()); ``` -------------------------------- ### Resource Cleanup: Manual Cleanup Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/CONFIGURATION.md Demonstrates manual resource cleanup for ExifTool instances using a try...finally block to ensure `.end()` is called. ```javascript const exiftool = new ExifTool(); try { const tags = await exiftool.read("photo.jpg"); } finally { await exiftool.end(); } ``` -------------------------------- ### Electron Builder Configuration (package.json) Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/ELECTRON.md Configure electron-builder to unpack exiftool-vendored from ASAR archives using package.json. ```json { "build": { "asarUnpack": ["node_modules/exiftool-vendored.*/**/*"] } } ``` -------------------------------- ### Electron Forge Configuration Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/ELECTRON.md Configure Electron Forge's packager to include the exiftool-vendored binary. ```javascript // forge.config.js module.exports = { packagerConfig: { extraResource: [ "./node_modules/exiftool-vendored." + (process.platform === "win32" ? "exe" : "pl"), ], }, }; ``` -------------------------------- ### Use a full Node.js Docker image Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/INSTALLATION.md Use a full Node.js Docker image that includes perl, which is required for exiftool-vendored. ```dockerfile # ✅ Good - includes perl FROM node:24 ``` ```dockerfile # ❌ Bad - missing perl FROM node:24-slim ``` -------------------------------- ### Parse and Write ExifDate Objects Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Shows how to parse EXIF date strings into ExifDate objects and how to write partial dates (year-only, year-month) to XMP tags. Note that EXIF tags require full dates. ```javascript import { ExifDate, exiftool } from "exiftool-vendored"; // Parse a full EXIF date string const d = ExifDate.from("2024:03:15"); console.log(d?.year, d?.month, d?.day); // 2024, 3, 15 // Write partial dates to XMP tags (EXIF tags require full dates) await exiftool.write("photo.jpg", { "XMP:CreateDate": ExifDate.fromYear(1985), // Year only "XMP:MetadataDate": ExifDate.fromYearMonth("1985-06"), // Year + month // Or using raw strings — both formats accepted: "XMP:DateCreated": "1985:06", "XMP:DateAcquired": 1985, }); ``` -------------------------------- ### Configure exiftool-vendored.js Settings Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Illustrates how to modify global settings for exiftool-vendored.js, such as enabling archaic timezone offsets, adjusting GPS timezone inference tolerance, and adding custom timezone abbreviation mappings. Includes how to observe setting changes and reset all settings to defaults. ```javascript import { Settings } from "exiftool-vendored"; // Enable archaic timezone offsets for historical photo archives Settings.allowArchaicTimezoneOffsets.value = true; // Enable Baker Island Time (UTC-12) — rarely needed Settings.allowBakerIslandTime.value = false; // Tighten GPS timezone inference tolerance (default: 30 minutes) Settings.maxValidOffsetMinutes.value = 15; // Add custom timezone abbreviation mappings Settings.tzAbbreviationOffsets.value = { CST: -6 * 60, // Central Standard Time IST: 5 * 60 + 30, // India Standard Time }; // Observe setting changes const unsubscribe = Settings.allowArchaicTimezoneOffsets.onChange( (oldValue, newValue) => console.log(`allowArchaicTimezoneOffsets: ${oldValue} → ${newValue}`), ); // Reset all settings to defaults Settings.reset(); unsubscribe(); // Stop listening ``` -------------------------------- ### Run All Tests Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Executes all unit and integration tests. Ensure compilation is done first. ```bash npm test ``` -------------------------------- ### Settings - Library-wide Configuration Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt The global `Settings` object allows for library-wide configuration, affecting all `ExifTool` instances. Changes are applied immediately. ```APIDOC ## `Settings` — Library-wide Configuration Global settings object that affects all `ExifTool` instances. Changes take effect immediately for all subsequent operations. ```javascript import { Settings } from "exiftool-vendored"; // Enable archaic timezone offsets for historical photo archives Settings.allowArchaicTimezoneOffsets.value = true; // Enable Baker Island Time (UTC-12) — rarely needed Settings.allowBakerIslandTime.value = false; // Tighten GPS timezone inference tolerance (default: 30 minutes) Settings.maxValidOffsetMinutes.value = 15; // Add custom timezone abbreviation mappings Settings.tzAbbreviationOffsets.value = { CST: -6 * 60, // Central Standard Time IST: 5 * 60 + 30, // India Standard Time }; // Observe setting changes const unsubscribe = Settings.allowArchaicTimezoneOffsets.onChange( (oldValue, newValue) => console.log(`allowArchaicTimezoneOffsets: ${oldValue} → ${newValue}`), ); // Reset all settings to defaults Settings.reset(); unsubscribe(); // Stop listening ``` ``` -------------------------------- ### Basic Exiftool Usage in Electron Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/ELECTRON.md Import and use exiftool-vendored for reading image tags in an Electron application. ```javascript import { exiftool } from "exiftool-vendored"; const tags = await exiftool.read("path/to/image.jpg"); ``` -------------------------------- ### Custom ExifTool Path Configuration Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/ELECTRON.md Configure a custom path for the ExifTool binary, adapting for development and packaged environments. ```javascript import { ExifTool } from "exiftool-vendored"; import path from "node:path"; const exiftool = new ExifTool({ exiftoolPath: (platform) => { if (process.env.NODE_ENV === "development") { const suffix = platform === "win32" ? "exe" : "pl"; return path.join( __dirname, "..", "node_modules", `exiftool-vendored.${suffix}`, "bin", "exiftool", ); } else { const resourcesPath = process.resourcesPath; const suffix = platform === "win32" ? "exe" : "pl"; return path.join( resourcesPath, "app.asar.unpacked", "node_modules", `exiftool-vendored.${suffix}`, "bin", "exiftool", ); } }, }); ``` -------------------------------- ### Error Handling with Disposable Interfaces Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/USAGE-EXAMPLES.md Demonstrates robust error handling when using disposable ExifTool interfaces, ensuring cleanup occurs even if exceptions are thrown during file processing. Includes specific handling for file not found errors. ```javascript import { ExifTool } from "exiftool-vendored"; async function robustProcessing(file) { try { await using et = new ExifTool(); const tags = await et.read(file); if (tags.errors?.length > 0) { console.warn(`Metadata warnings for ${file}:`, tags.errors); } return tags; } catch (error) { if (error.message.includes("ENOENT")) { throw new Error(`File not found: ${file}`); } throw error; } // ExifTool cleanup guaranteed, even with exceptions } ``` -------------------------------- ### Electron Builder Configuration (YAML) Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/ELECTRON.md Configure electron-builder to unpack exiftool-vendored from ASAR archives. ```yaml asarUnpack: - "node_modules/exiftool-vendored.*/**/*" ``` -------------------------------- ### Resource Cleanup: Disposables (TypeScript 5.2+) Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/CONFIGURATION.md Demonstrates automatic resource cleanup for ExifTool instances using TypeScript 5.2+ disposables. ```typescript { await using exiftool = new ExifTool(); const tags = await exiftool.read("photo.jpg"); } // Automatic cleanup ``` -------------------------------- ### Run Specific Test File Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Compiles the project and then runs tests from a specific file. Useful for focused testing. ```bash npm run compile && npx mocha dist/ExifTool.spec.js ``` -------------------------------- ### Writing Partial Dates to XMP Tags Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/DATES.md Demonstrates how to write year-only or year-and-month dates to XMP tags like XMP:CreateDate. It also shows the usage of the ExifDate helper for creating these partial dates. ```APIDOC ## Writing Partial Dates to XMP Tags ### Description Supports writing partial dates (year only, or year and month) to XMP tags. This functionality is available from v30.2.0 onwards. ### Method `exiftool.write(path, tags)` ### Parameters #### Path Parameters - **path** (string) - Required - The path to the image file. #### Request Body - **tags** (object) - Required - An object containing the tags to write. - **"XMP:CreateDate"** (number | string | ExifDate) - Required - Can be a year (number), a "YYYY:MM" or "YYYY-MM" string, or an `ExifDate` object created with `ExifDate.fromYear()` or `ExifDate.fromYearMonth()`. - **"XMP:MetadataDate"** (number | string | ExifDate) - Required - Similar to `XMP:CreateDate`, accepts year, year-month, or `ExifDate` object. ### Request Example ```javascript // Year only await exiftool.write("photo.jpg", { "XMP:CreateDate": 1980 }); // Year and month await exiftool.write("photo.jpg", { "XMP:CreateDate": "1980:08" }); // Using ExifDate helper import { ExifDate } from "exiftool-vendored"; await exiftool.write("photo.jpg", { "XMP:CreateDate": ExifDate.fromYear(1980), "XMP:MetadataDate": ExifDate.fromYearMonth("1980-08") }); ``` ### Important Note Partial dates are only supported for XMP tags. EXIF tags require complete date information. ``` -------------------------------- ### Running Tests with npm and npx Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/TDD.md Commands for compiling code, running all tests, targeting specific test files, and filtering tests by a pattern. Includes watch mode for TDD cycles. ```bash npm run compile # Always compile first npm test # Run all tests npx mocha dist/Foo.spec.js # Run specific file npx mocha 'dist/*.spec.js' --grep "pattern" # Filter by name ``` ```bash npm run compile:watch # Terminal 1 npx mocha dist/Foo.spec.js # Terminal 2 (re-run as needed) ``` -------------------------------- ### exiftool singleton Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt The default export is a pre-configured singleton ExifTool instance. Use this for most applications to avoid managing instance lifecycle. It confirms the ExifTool version and provides graceful shutdown on termination signals. ```APIDOC ## exiftool singleton ### Description The default export is a pre-configured singleton `ExifTool` instance with `maxProcs` set to 1/4 of available CPUs. Use this for most applications to avoid managing instance lifecycle. ### Usage ```javascript import { exiftool } from "exiftool-vendored"; // Confirm ExifTool version console.log(`ExifTool v${await exiftool.version()}`); // Output: ExifTool v13.57 // For servers/daemons: graceful shutdown on termination signals process.on("SIGINT", () => exiftool.end()); process.on("SIGTERM", () => exiftool.end()); ``` ``` -------------------------------- ### Configurable Disposal Timeouts Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/USAGE-EXAMPLES.md Shows how to configure custom timeouts for both synchronous and asynchronous disposal of ExifTool processes when using disposable interfaces. This allows fine-grained control over cleanup behavior. ```javascript import { ExifTool } from "exiftool-vendored"; // Custom timeout configuration { await using et = new ExifTool({ disposalTimeoutMs: 2000, // 2 seconds for sync disposal asyncDisposalTimeoutMs: 30000, // 30 seconds for async disposal }); // Your processing here const tags = await et.read("large-file.tiff"); } ``` -------------------------------- ### Serialize and Deserialize Metadata to JSON Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/USAGE-EXAMPLES.md Demonstrates reading metadata, serializing it to a JSON string, saving it to a file, and then deserializing it back into usable tag objects, preserving specific data types like ExifDateTime. ```javascript import { parseJSON, ExifDateTime } from "exiftool-vendored"; import { readFile, writeFile } from "node:fs/promises"; // Read and serialize const tags = await exiftool.read("photo.jpg"); const jsonString = JSON.stringify(tags); // Save to file or send over network await writeFile("metadata.json", jsonString); // Later, deserialize const savedJson = await readFile("metadata.json", "utf8"); const restoredTags = parseJSON(savedJson); // restoredTags has proper ExifDateTime objects restored console.log(restoredTags.DateTimeOriginal instanceof ExifDateTime); // true ``` -------------------------------- ### Parse and Use ExifDateTime Objects Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Demonstrates parsing EXIF or ISO datetime strings into timezone-aware ExifDateTime objects. Shows how to access raw values, ISO strings, JavaScript Date objects, timezone offsets, and milliseconds. Also illustrates JSON round-trip serialization and deserialization. ```javascript import { ExifDateTime } from "exiftool-vendored"; // Parse from EXIF or ISO string const dt = ExifDateTime.from("2024:03:15 14:30:00", "America/New_York"); if (dt != null) { console.log(dt.rawValue); // "2024:03:15 14:30:00" console.log(dt.toISOString()); // "2024-03-15T14:30:00.000-05:00" console.log(dt.toDate()); // JavaScript Date object console.log(dt.tzoffset); // -300 (minutes west of UTC) console.log(dt.zone); // "America/New_York" console.log(dt.millisecond); // 0 (microsecond precision if available) } ``` ```javascript // JSON round-trip — ExifDateTime instances survive serialization import { parseJSON } from "exiftool-vendored"; const tags = await exiftool.read("photo.jpg"); const json = JSON.stringify(tags); const restored = parseJSON(json); console.log(restored.DateTimeOriginal instanceof ExifDateTime); // true ``` -------------------------------- ### Enable Debug Logging for exiftool-vendored.js Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Shows two methods for enabling debug logging: using the `NODE_DEBUG` environment variable for general debugging, and passing a custom logger object with specific log levels to an `ExifTool` instance for more granular control. ```bash # Enable via environment variable NODE_DEBUG=exiftool-vendored node your-script.js ``` ```javascript import { ExifTool } from "exiftool-vendored"; // Pass a custom logger to a specific instance const exiftool = new ExifTool({ logger: { trace: () => {}, debug: (msg) => console.log(`[DEBUG] ${msg}`), info: (msg) => console.log(`[INFO] ${msg}`), warn: (msg) => console.warn(`[WARN] ${msg}`), error: (msg) => console.error(`[ERROR] ${msg}`), }, }); ``` -------------------------------- ### Automatic Disposal with `using` (TypeScript) Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Demonstrates automatic resource management for ExifTool instances using `using` (synchronous) and `await using` (asynchronous) in TypeScript 5.2+. ```typescript import { ExifTool } from "exiftool-vendored"; // Async disposal — recommended for production (waits for graceful shutdown) async function processFiles(paths: string[]) { await using et = new ExifTool({ maxProcs: 8, asyncDisposalTimeoutMs: 30_000, // 30s timeout before forceful cleanup }); const results = []; for (const file of paths) { try { const tags = await et.read(file); await et.write(file, { Copyright: "© 2024 Acme Corp" }); results.push({ file, camera: `${tags.Make} ${tags.Model}`, success: true }); } catch (err) { results.push({ file, success: false, error: (err as Error).message }); } } return results; // ExifTool.end(true) called automatically here, even if an exception occurred } // Synchronous disposal — fire-and-forget (initiates cleanup without waiting) { using et = new ExifTool({ disposalTimeoutMs: 2000 }); const tags = await et.read("photo.jpg"); console.log(tags.Make, tags.Model); // Cleanup initiated when block exits, timeout-protected } ``` -------------------------------- ### Run Tests Matching Pattern Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/CLAUDE.md Compiles the project and runs tests that match a specific pattern. Useful for isolating failing tests. ```bash npm run compile && npx mocha 'dist/*.spec.js' --grep "pattern" ``` -------------------------------- ### exiftool.enqueueTask(taskFactory, retriable?) - Custom Task Submission Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt A low-level API for submitting custom tasks to the ExifTool process pool, enabling advanced use cases not covered by built-in methods. ```APIDOC ## `exiftool.enqueueTask(taskFactory, retriable?)` — Custom Task Submission Low-level API for submitting custom `BatchCluster` tasks to the ExifTool process pool. Enables advanced use cases not covered by the built-in methods. ```javascript import { ExifTool, ExifToolTask } from "exiftool-vendored"; const exiftool = new ExifTool(); // Monitor process pool health console.log("Pending tasks:", exiftool.pendingTasks); console.log("Busy processes:", exiftool.busyProcs); console.log("Spawned processes:", exiftool.spawnedProcs); console.log("Process IDs:", exiftool.pids); console.log("End counts:", exiftool.childEndCounts()); // Recycle all child processes (new ones spawn automatically) exiftool.closeChildProcesses(true); await exiftool.end(); ``` ``` -------------------------------- ### Automatic Resource Cleanup with TypeScript 5.2+ Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/README.md Utilize the 'using' declaration for automatic synchronous or asynchronous cleanup of ExifTool instances, ensuring no leaked processes even with exceptions. Recommended for TypeScript 5.2+ projects. ```typescript import { ExifTool } from "exiftool-vendored"; // Automatic synchronous cleanup { using et = new ExifTool(); const tags = await et.read("photo.jpg"); // ExifTool automatically cleaned up when block exits } // Automatic asynchronous cleanup (recommended) { await using et = new ExifTool(); const tags = await et.read("photo.jpg"); // ExifTool gracefully cleaned up when block exits } ``` -------------------------------- ### Write Basic Metadata Tags Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/USAGE-EXAMPLES.md Adds or updates simple metadata tags like comments, copyright, and capture dates in an image file. ```javascript // Add comment and copyright await exiftool.write("photo.jpg", { XPComment: "Beautiful sunset", Copyright: "© 2024 Your Name", }); // Update capture date await exiftool.write("photo.jpg", { DateTimeOriginal: "2024:03:15 14:30:00", }); ``` -------------------------------- ### Writing Full Dates with Timezone Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/DATES.md Shows how to write a complete date and time with a timezone offset to a JPEG file using `exiftool.write`. It also demonstrates updating multiple date-related tags by using the `AllDates` property. ```javascript // Write complete date with timezone await exiftool.write("photo.jpg", { DateTimeOriginal: "2024:03:15 14:30:00+05:00", }); // Write date in multiple formats await exiftool.write("photo.jpg", { AllDates: "2024:03:15 14:30:00", // Updates DateTimeOriginal, DateTime, ModifyDate }); ``` -------------------------------- ### Per-instance Options: Enable Geolocation Features Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/CONFIGURATION.md Enable geolocation features for an ExifTool instance. Requires ExifTool version 12.78 or later. Demonstrates reading geolocation tags. ```javascript const exiftool = new ExifTool({ geolocation: true, // Requires ExifTool 12.78+ }); const tags = await exiftool.read("photo.jpg"); console.log(tags.GeolocationCity, tags.GeolocationCountryCode); ``` -------------------------------- ### exiftool.write(file, tags, options?) Source: https://context7.com/photostructure/exiftool-vendored.js/llms.txt Writes metadata tags to an existing file. It performs tag validation and whitespace encoding for safety. By default, it creates a backup file (`_original`), but this can be suppressed with `writeArgs: ['-overwrite_original']`. ```APIDOC ## `exiftool.write(file, tags, options?)` ### Description Write metadata tags to an existing file. Tag keys are validated before transmission; tag values are whitespace-encoded for safety. By default, a backup file (`_original`) is created — pass `writeArgs: ['-overwrite_original']` to suppress it. ### Method `write(file: string, tags: Record, options?: object): Promise<{ warnings: string[] }>` ### Parameters #### Path Parameters - **file** (string) - Required - The path to the image file. #### Tags - **tags** (object) - Required - An object where keys are metadata tag names and values are the data to write. #### Options - **options** (object) - Optional - Configuration options for writing metadata. - **writeArgs** (Array) - Optional - Arguments to pass to ExifTool for writing (e.g., `['-overwrite_original']`). ### Request Example ```javascript import { exiftool } from "exiftool-vendored"; // Basic metadata tagging await exiftool.write("photo.jpg", { XPComment: "Golden hour at the coast", Copyright: "© 2024 Jane Doe", Artist: "Jane Doe", Keywords: ["landscape", "ocean", "sunset"], }); // Write to specific metadata groups await exiftool.write("photo.jpg", { "IPTC:Keywords": "sunset, landscape, nature", "IPTC:CopyrightNotice": "© 2024 Jane Doe", "XMP:Title": "Sunset Over the Pacific", "XMP:Description": "Golden hour captured at Malibu Beach", "XMP:Creator": "Jane Doe", }); // Update all date fields simultaneously await exiftool.write("photo.jpg", { AllDates: "2024:03:15 14:30:00+05:00", // Sets DateTimeOriginal, CreateDate, ModifyDate TimeZoneOffset: "+05:00", }); // Set GPS coordinates await exiftool.write("photo.jpg", { GPSLatitude: 34.0195, GPSLongitude: -118.4912, GPSAltitude: 15, }); // Delete tags by setting to null await exiftool.write("photo.jpg", { UserComment: null, ImageDescription: null, "IPTC:Keywords": null, }); // Overwrite original in place (no backup) await exiftool.write("photo.jpg", { Artist: "Jane Doe" }, { writeArgs: ["-overwrite_original"], }); // Check result const result = await exiftool.write("photo.jpg", { Copyright: "© 2024" }); console.log(result); // { warnings: [] } on success ``` ### Response #### Success Response (Result Object) - **result** (object) - An object indicating the success of the write operation. - **warnings** (Array) - An array of any warnings generated during the write process. #### Response Example ```json { "warnings": [] } ``` ``` -------------------------------- ### Enable Debug Logging via Logger Option Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/DEBUGGING.md Configure the ExifTool constructor with a logger option. You can use console for basic logging or provide a custom logger object with debug, info, warn, and error methods. ```javascript import { ExifTool } from "exiftool-vendored"; const exiftool = new ExifTool({ logger: console }); ``` ```javascript import { ExifTool } from "exiftool-vendored"; const exiftool = new ExifTool({ logger: { debug: (msg) => console.log(`[DEBUG] ${msg}`), info: (msg) => console.log(`[INFO] ${msg}`), warn: (msg) => console.warn(`[WARN] ${msg}`), error: (msg) => console.error(`[ERROR] ${msg}`), }, }); ``` -------------------------------- ### IDE Autocomplete for Tags Source: https://github.com/photostructure/exiftool-vendored.js/blob/main/docs/TAGS.md Illustrates how to leverage IDE autocompletion to discover available tag names and their descriptions when working with the `tags` object. ```typescript const tags = await exiftool.read("photo.jpg"); tags. // <-- IDE shows all available tags with descriptions ```