exiftool-vendored
    Preparing search index...

    Interface ExifToolOptions

    Options for the ExifTool constructor.

    Defaults are defined in DefaultExifToolOptions.

    interface ExifToolOptions {
        adjustTimeZoneIfDaylightSavings: (
            tags: Tags,
            tz: string,
        ) => Maybe<number>;
        asyncDisposalTimeoutMs?: number;
        backfillTimezones: boolean;
        checkPerl: boolean;
        cleanupChildProcs: boolean;
        cleanupChildProcsOnExit: boolean;
        defaultVideosToUTC: boolean;
        disposalTimeoutMs?: number;
        endGracefulWaitTimeMillis: number;
        exiftoolArgs: string[];
        exiftoolEnv: ProcessEnv;
        exiftoolPath:
            | string
            | Promise<string>
            | ((logger?: Logger) => string | Promise<string>);
        exitCommand?: string;
        fail: string | RegExp;
        forceWrite: boolean;
        geolocation: boolean;
        geoTz: (lat: number, lon: number) => Maybe<string>;
        groupNames: boolean;
        healthCheckCommand?: string;
        healthCheckIntervalMillis: number;
        ignoreMinorErrors: boolean;
        ignoreShebang: boolean;
        ignoreZeroZeroLatLon: boolean;
        imageHashType: false | "MD5" | "SHA256" | "SHA512";
        includeImageDataMD5: boolean | undefined;
        inferTimezoneFromDatestamps: boolean;
        inferTimezoneFromDatestampTags: (keyof Tags)[];
        inferTimezoneFromTimeStamp: boolean;
        isRetirementRequest?: (
            line: string,
            stream: "stderr" | "stdout",
        ) => boolean;
        keepUTCTime: boolean;
        killProcessGroup: boolean;
        logger: () => Logger;
        maxFailedTasksPerProcess: number;
        maxIdleMsPerProcess: number;
        maxProcAgeMillis: number;
        maxProcs: number;
        maxTasksPerProcess: number;
        minDelayBetweenSpawnMillis: number;
        numericTags: string[];
        onIdleIntervalMillis: number;
        pass: string | RegExp;
        pidCheckIntervalMillis: number;
        preferTimezoneInferenceFromGps: boolean;
        processFactory: () => ChildProcess | Promise<ChildProcess>;
        readArgs: string[];
        shouldIgnoreStderrLine?: (line: string) => boolean;
        spawnTimeoutMillis: number;
        streamFlushMillis: number;
        struct: 0 | 1 | 2 | "undef";
        taskRetries: number;
        taskTimeoutMillis: number;
        unrefStreams: boolean;
        useMWG: boolean;
        versionCommand: string;
        writeArgs: string[];
    }

    Hierarchy

    • BatchClusterOptions
    • BatchProcessOptions
    • ChildProcessFactory
      • ExifToolOptions
    Index
    adjustTimeZoneIfDaylightSavings: (tags: Tags, tz: string) => Maybe<number>

    The TimeZone tag normally represents the offset from UTC.

    Unfortunately, at least for some Nikon cameras, the TimeZone tag and the DaylightSavings tag must be taken into account to find the UTC offset.

    If you find other makes and models that need this treatment, please open a ticket on GitHub with example images or videos and we can update the default predicate.

    The return value is the number of minutes to adjust the timezone by.

    Returns 60 for Nikon cameras when DaylightSavings is true

    asyncDisposalTimeoutMs?: number

    Timeout in milliseconds for asynchronous disposal (using Symbol.asyncDispose). If graceful cleanup takes longer than this, forceful cleanup is requested. This is not a hard completion deadline.

    5000 (5 seconds)
    
    backfillTimezones: boolean

    Should we try to backfill timezones for date-times that don't have them? If set to true, and defaultVideosToUTC is also true, we'll try backfilling timezones for date-times that are UTC, as well.

    Setting this to false removes all timezone inference--only those date-times with an explicit offset will have a defined timezone.

    true
    
    checkPerl: boolean

    Should we check for a readable and executable perl file in $PATH? Set this to false if you know perl is installed.

    false on Windows, true elsewhere

    cleanupChildProcs: boolean

    Should batch-cluster try to clean up after spawned processes that don't shut down?

    Only disable this if you have another means of PID cleanup. BatchProcess.end() still rejects if that child is running 5 seconds after termination.

    Defaults to true.

    cleanupChildProcsOnExit: boolean

    When true, BatchCluster registers process.on("beforeExit") and process.on("exit") handlers to clean up child processes when the Node.js process exits.

    The beforeExit handler calls end(true) for graceful shutdown. The exit handler synchronously kills any remaining child processes.

    Set to false if you want to manage process cleanup yourself, or if you're experiencing issues with these handlers interfering with your application's exit behavior.

    Defaults to true.

    17.1.0

    defaultVideosToUTC: boolean

    Video file dates are assumed to be in UTC, rather than using timezone inference used in images. To disable this default, set this to false.

    disposalTimeoutMs?: number

    Timeout in milliseconds for synchronous disposal (using Symbol.dispose). If graceful cleanup takes longer than this, forceful cleanup is requested. This is not a hard completion deadline.

    1000 (1 second)
    
    endGracefulWaitTimeMillis: number

    When this.end() is called, or Node broadcasts the beforeExit event, this is the milliseconds spent waiting for currently running tasks to finish before sending kill signals to child processes.

    Setting this value to 0 means child processes will immediately receive a kill signal to shut down. Any pending requests may be interrupted. Must be >= 0. Defaults to 500ms.

    exiftoolArgs: string[]

    Args only passed to exiftool on launch. You probably don't need to change this from the default.

    ["-charset", "filename=utf8"]

    exiftoolEnv: ProcessEnv

    Environment variables passed to ExifTool (besides EXIFTOOL_HOME)

    {}

    exiftoolPath:
        | string
        | Promise<string>
        | ((logger?: Logger) => string | Promise<string>)

    Allows for non-standard paths to ExifTool.

    This must be the full path to exiftool, not just the directory.

    Path to vendored ExifTool binary
    
    exitCommand?: string

    Command to end the child batch process. If not provided (or undefined), stdin will be closed to signal to the child process that it may terminate, and if it does not shut down within endGracefulWaitTimeMillis, it will be SIGHUP'ed.

    fail: string | RegExp

    Expected text to print if a command fails. Cannot be blank. Strings will be interpreted as a regular expression fragment.

    forceWrite: boolean

    When writing an extracted tag to a file, this will overwrite an existing file instead of throwing an error. Enabling this option is equivalent to -w! in ExifTool.

    false
    
    geolocation: boolean

    When reading metadata, should we enable ExifTool's geolocation features? Note that this requires ExifTool version 12.78 or later.

    geoTz: (lat: number, lon: number) => Maybe<string>

    Override the default geo-to-timezone lookup service. Note that if geolocation is enabled, we'll use Tags.GeolocationTimeZone if it's not blank.

    If your implementation throws an error, ExifTool will consider that given latitude/longitude as invalid.

    Type Declaration

      • (lat: number, lon: number): Maybe<string>
      • Parameters

        • lat: number
        • lon: number

        Returns Maybe<string>

        if the given latitude and longitude are invalid.

    @photostructure/tz-lookup (consider geo-tz for more accuracy)

    const geotz = require("geo-tz")
    const { ExifTool } = require("exiftool-vendored")
    const exiftool = new ExifTool({ geoTz: (lat, lon) => geotz.find(lat, lon)[0] })
    groupNames: boolean

    Should ExifTool.read ask ExifTool for group-prefixed tag names (ExifTool's -G option)?

    When enabled, every tag that ExifTool emits is keyed by Group:TagName--like EXIF:Make, MakerNotes:MeteringMode, or ExifTool:Warning--which disambiguates tags that appear in several groups. Tags synthesized by this library remain bare: SourceFile, errors, warnings, zone, tz, tzSource, zoneSource, invalidUtf8Bytes, and the parsed and validated GPS tags (GPSLatitude, GPSLatitudeRef, GPSLongitude, GPSLongitudeRef).

    This is the recommended forward path for new integrations: see the "Group names" section of the README for the full output contract, and GroupedTags for the matching interface returned by ExifTool.read when this is true.

    Timezone and video-detection heuristics look up bare tag names via a last-wins degrouped view of the metadata, so they are approximations when the same tag name appears in several groups.

    Note: setting this on the ExifTool constructor changes the runtime shape of every read, but ExifTool.read's static return type only narrows to GroupedTags when groupNames: true is passed in the per-call options. When enabling it at construction, either pass { groupNames: true } to each read() call anyway, or annotate the result yourself.

    A -G in ExifToolOptions.readArgs behaves like groupNames: true at runtime (all parsing keys off the final argument list) but without the GroupedTags return type. An explicit groupNames: false does not strip a caller-supplied -G.

    false
    
    healthCheckCommand?: string

    If provided, and healthCheckIntervalMillis is greater than 0, or the previous task failed, this command will be sent to child processes.

    If the command outputs to stderr or returns a fail string, the process will be considered unhealthy and recycled. Lines discarded by shouldIgnoreStderrLine do not count as stderr output.

    healthCheckIntervalMillis: number

    If healthCheckCommand is set, how frequently should we check for unhealthy child processes?

    Set this to 0 to disable this feature.

    ignoreMinorErrors: boolean

    Should we ignore minor errors when reading metadata?

    true (ExifTool can be quite chatty)
    
    ignoreShebang: boolean

    ExifTool has a shebang line that assumes a valid perl is installed at /usr/bin/perl.

    Some environments may not include a valid /usr/bin/perl (like AWS Lambda), but perl may be available in your PATH some place else (like /opt/bin/perl), if you pull in a perl layer.

    When enabled, /usr/bin/perl (or, if that doesn't exist, the first perl in your PATH) is spawned directly, without a shell, with the ExifTool script as its first argument.

    true on systems without /usr/bin/perl, false otherwise

    ignoreZeroZeroLatLon: boolean

    Some software uses a GPS position of (0,0) as a synonym for "unset". If this option is true, and GPSLatitude and GPSLongitude are both 0, then those values will be returned, but the TZ will not be inferred from that location.

    If both this and geolocation are true, we will delete the Geolocation tags from the returned metadata object.

    imageHashType: false | "MD5" | "SHA256" | "SHA512"

    If defined, ExifTool will attempt to calculate an "ImageDataHash" tag value with a checksum of image data.

    Note that as of 2022-04-12, ExifTool supports JPEG, TIFF, PNG, CRW, CR3, MRW, RAF, X3F, IIQ, JP2, JXL, HEIC and AVIF images, MOV/MP4 videos, and some RIFF-based files such as AVI, WAV and WEBP.

    false (disabled, as it adds ~20ms of overhead to every read)
    
    includeImageDataMD5: boolean | undefined

    Use imageHashType instead.

    inferTimezoneFromDatestamps: boolean

    We always look at Tags.TimeZone, Tags.OffsetTime, Tags.TimeZoneOffset, Tags.OffsetTimeOriginal, Tags.OffsetTimeDigitized, and GPS metadata to infer the timezone.

    If these strategies fail, and this is enabled, we'll try to infer the timezone from non-UTC datestamps included in the inferTimezoneFromDatestampTags value.

    true
    
    inferTimezoneFromDatestampTags: (keyof Tags)[]

    This is the list of tag names that will be used to infer the timezone as a backstop, if no explicit timezone is found in metadata. Note that datestamps with UTC offsets are ignored, as they are frequently incorrectly set.

    This setting is only in play if inferTimezoneFromDatestamps is true.

    inferTimezoneFromTimeStamp: boolean

    Some cameras (Samsung Galaxy S7, for example) may not always include GPS metadata in photos if a fix can't be obtained. If this option is true, and GPS metadata is missing, we'll try to infer the timezone from the difference of the TimeStamp tag and the first defined tag value from inferTimezoneFromDatestampTags.

    This heuristic is pretty sketchy, and used as a last resort. You shouldn't enable it unless you have to.

    isRetirementRequest?: (line: string, stream: "stderr" | "stdout") => boolean

    Recognize a worker's request to retire after its current task settles. Called synchronously for complete stdout/stderr lines, without LF or CRLF. Return true to consume the entire line (including its line ending): it will not reach the task parser, pass/fail matching, taskData, noTaskData, stderr logging, or shouldIgnoreStderrLine. Return false to retain normal handling. Use an exact, reserved control line rather than ordinary log text.

    A match immediately prevents new tasks and health checks. The active task keeps receiving output and retains its normal timeout; the request itself neither resolves nor rejects it. Once idle, the worker is gracefully ended with reason retired. Repeated requests have no additional effect. Startup and idle workers can also request retirement. The worker should wait for the parent's exit command or stdin closure instead of exiting itself.

    For ordering, write the marker and then the task completion token through the same stdout writer. Both must end with a newline. The marker is consumed before completion is processed, even when both arrive in one chunk. Stderr requests have no ordering guarantee relative to stdout completion.

    Enabling this option buffers stdout and stderr into lines, independently of chunk boundaries. Stdout completion tokens must therefore end with a newline. Partial lines block new assignments; received fragments are flushed before task parsing or at EOF. Fragments without a pending owning task are also flushed after no more data arrives for streamFlushMillis, retaining normal stray-output handling. Idle retirement markers must finish within that interval. Fragments are never reassembled across a flush boundary. Unterminated fragments are ordinary output, never retirement requests. Lines longer than 64 * 1024 UTF-16 code units bypass recognition. If the callback throws, the worker is ended with stdout.error or stderr.error and its active task is rejected.

    Defaults to undefined, preserving existing stream handling.

    keepUTCTime: boolean

    Should ExifTool keep times that are stored as seconds since UTC epoch as UTC times? If false, ExifTool will use local time instead of UTC/Zulu.

    Note: when trying to validate this option, we could not find a single example that had a unixtime-encoded datetime, so this is likely irrelevant for most use cases and files.

    true (to avoid unintentionally adopting local timezones)
    
    killProcessGroup: boolean

    Should termination signal the child's entire process group, rather than just the child?

    This is only useful with a processFactory that spawns with detached: true, which makes each child its own process-group leader and lets batch-cluster also stop any grandchildren. ExifTool's default factory deliberately spawns non-detached children, so enabling this does nothing: signalling a group that doesn't exist fails, and batch-cluster then signals the child directly.

    false
    
    logger: () => Logger

    A BatchCluster instance and associated BatchProcess instances will share this Logger. Defaults to the Logger instance provided to setLogger().

    maxFailedTasksPerProcess: number

    How many task failures should retire an ExifTool process? Set to 0 to disable failure-count recycling.

    Leave this at 0 for ExifTool. A rejected task almost always means the file was bad--not found, unsupported, unwritable, or malformed--and not that ExifTool is sick. ExifTool in -stay_open mode emits {ready} after a per-file error and keeps working, so retiring it costs a respawn (and Perl interpreter startup) for every bad file. This counts failures over the process's entire lifetime, not consecutive ones, and ExifToolOptions.taskRetries defaults to 1, so a single unreadable file produces two failures: setting this to 2 would retire a process on its first bad file.

    Actually-sick processes are recycled by ExifToolOptions.taskTimeoutMillis, by stream errors, and by healthCheckCommand.

    0 (disabled)
    
    maxIdleMsPerProcess: number

    If a child process is idle for more than this value (in milliseconds), shut it down to reduce system resource consumption.

    A value of ~10 seconds to a couple minutes would be reasonable. Set this to 0 to disable this feature.

    maxProcAgeMillis: number

    Child processes will be recycled when they reach this age. A child that reaches this age while running a task will finish that task before being recycled.

    If non-zero, this value must not be less than spawnTimeoutMillis.

    Defaults to 5 minutes. Set to 0 to disable.

    maxProcs: number

    The maximum number of ExifTool child processes to spawn when load merits.

    Math.max(1, Math.floor(os.cpus().length / 4))

    maxTasksPerProcess: number

    The maximum number of requests a given ExifTool process will service before being retired.

    500
    
    minDelayBetweenSpawnMillis: number

    If maxProcs > 1, spawning new child processes to process tasks can slow down initial processing, and create unnecessary processes.

    Must be >= 0ms. Defaults to 1.5 seconds.

    numericTags: string[]

    Tag names (which can have '*' glob matchers) which you want numeric values, rather than ExifTool's "Print Conversion."

    If you're using tag values only for human consumption, you may want to leave this blank.

    Each entry must be a valid ExifTool tag reference; the read promise rejects entries containing whitespace, control characters, option delimiters, or value delimiters.

    ["*Duration*", "GPSAltitude", "GPSLatitude", "GPSLongitude", "GPSPosition", "GeolocationPosition", "Orientation"]

    onIdleIntervalMillis: number

    An interval timer is scheduled to do periodic maintenance of underlying child processes with this periodicity.

    2000 (2 seconds)
    
    pass: string | RegExp

    Expected text to print if a command passes. Cannot be blank. Strings will be interpreted as a regular expression fragment.

    pidCheckIntervalMillis: number

    Verify child processes are still running by checking the OS process table.

    Set this to 0 to disable this feature.

    preferTimezoneInferenceFromGps: boolean

    Timezone parsing requires a bunch of heuristics due to hardware and software companies not following metadata specifications similarly.

    If GPS metadata is trustworthy, set this to true to override explicit values assigned to TimezoneOffsetTagnames.

    Note that there are regions that have had their IANA timezone change over time--this will result in incorrect timezones.

    false
    
    processFactory: () => ChildProcess | Promise<ChildProcess>

    Factory function to spawn child processes.

    CRITICAL: If you spawn a child process and then reject the promise, YOU are responsible for killing the spawned process. BatchCluster cannot track processes that were never returned.

    Safe pattern:

    async function myFactory(): Promise<ChildProcess> {
    const proc = spawn("my-command", args);
    try {
    await someValidation(proc);
    return proc;
    } catch (error) {
    proc.kill(); // REQUIRED: Clean up before rejecting!
    throw error;
    }
    }

    Unsafe pattern (LEAKS PROCESSES):

    async function leakyFactory(): Promise<ChildProcess> {
    const proc = spawn("my-command", args);
    await someValidation(proc); // If this throws, proc is orphaned!
    return proc;
    }
    readArgs: string[]

    Any additional arguments that should be added by default to all read tasks, like ["-fast", "-api", "largefilesupport=1"]. The value provided to the ExifTool constructor can be overridden in the call to ExifTool.read.

    Security: entries are passed through to the underlying exiftool process verbatim. Never pass attacker-controlled strings here. The library rejects any entry containing \r, \n, or \0 as a defense-in-depth measure, but provides no other sanitization.

    JSON reads repair malformed UTF-8 with U+FFFD (�) independently of this array and preserve the original string bytes in Tags.invalidUtf8Bytes. If these arguments contain an explicit, non-empty ExifTool -api Filter=... option, that custom filter owns the complete output filtering pipeline and must perform any desired UTF-8 repair and byte capture itself.

    The marker appears only in string values; to render it as the pre-v37 ?, post-process with typeof value === "string" ? value.replace(/\uFFFD/g, "?") : value.

    ["-fast"]

    shouldIgnoreStderrLine?: (line: string) => boolean

    Called for each complete line written to stderr. Return true to discard that line before it is logged, associated with a task, or treated as taskless process output. The line ending is not included.

    Lines are assembled independently of stream chunk boundaries. An unterminated fragment is evaluated before its task is parsed, when no more stderr arrives for streamFlushMillis, or when the stream ends. With isRetirementRequest enabled, the quiet-period flush waits until the line's owning task is no longer pending. The worker is not assigned another task while a fragment is pending.

    Lines longer than 64 KiB bypass this callback and retain the normal stderr behavior. If this callback throws, its line is retained and the worker is ended with a stderr.error.

    Use this only for exact, known advisory lines. Every line for which this returns false retains the normal, potentially fatal stderr behavior. Defaults to undefined, which preserves the existing immediate handling of every stderr chunk without line buffering.

    spawnTimeoutMillis: number

    Spawning new ExifTool processes must not take longer than this before the child process is timed out and a new attempt is made. Be pessimistic here--windows can regularly take several seconds to spin up a process, thanks to antivirus shenanigans. This can't be set to a value less than 100ms.

    30000 (30 seconds)
    
    streamFlushMillis: number

    When a task's pass/fail token is detected on one stream (stdout or stderr), this is how long to wait for the other stream to flush before running the parser.

    Since stdout is typically line-buffered, it may arrive after stderr, so this value needs to be large enough for the OS to flush stdout.

    Note that this puts a hard lower limit on task latency for tasks whose token is found on stderr. If you set this too low, tasks may be erroneously resolved or rejected, and you'll see noTaskData events.

    Setting this to 0 will most likely result in internal errors (due to stream buffers not being associated to tasks that were just settled).

    struct: 0 | 1 | 2 | "undef"

    How should ExifTool handle nested structures?

    • 0 = Read/copy flattened tags
    • 1 = Read/copy structures
    • 2 = Read/copy both flattened and structured tags, but flag flattened tags as "unsafe" for copying
    • "undef" = Same as 0 for reading and 2 for copying
    taskRetries: number

    The number of times a task can error or timeout and be retried.

    1 (every task gets 2 chances)
    
    taskTimeoutMillis: number

    If requests to ExifTool take longer than this, presume the underlying process is dead and we should restart the task. This can't be set to a value less than 10ms, and really should be set to at more than a second unless taskRetries is sufficiently large or all writes will be to a fast local disk.

    30000 (30 seconds)
    
    unrefStreams: boolean

    When true, child process streams (stdin, stdout, stderr) are unreferenced so they don't prevent the parent Node.js process from exiting naturally.

    This allows scripts to exit without explicitly calling .end() on the BatchCluster instance. The child processes will be cleaned up automatically when the parent process exits.

    Set to false if you need the parent process to stay alive as long as child processes are running (legacy behavior prior to v17).

    Defaults to true.

    17.0.0

    useMWG: boolean

    Should ExifTool use MWG (Metadata Working Group) composite tags for reading and writing tags?

    ExifTool recommends this to be set to true. Note that this can result in many tag value differences from ExifTool.read, and makes ExifTool.write write to "synonymous" MWG tags automatically.

    This applies to every command the instance sends, and can't be set per call: ExifTool never unloads MWG, so once one command loads it, later commands on the same ExifTool process get MWG tags too. To use both, create two ExifTool instances.

    With useMWG: false, a command that references an MWG: tag (like a write() key of "MWG:Description") or passes -use MWG in readArgs or writeArgs still loads MWG for that command, and an -@ argument file or -p format file can too. After any such command, its ExifTool process is replaced before it runs another command.

    true
    
    versionCommand: string

    Low-overhead command to verify ExifTool has started correctly. Runs immediately after spawn and must complete within spawnTimeoutMillis before any tasks are assigned to the process.

    "-ver" (ExifTool version check)

    writeArgs: string[]

    Any additional arguments that should be added by default to all write tasks, like ["-overwrite_original"]. The value provided to the ExifTool constructor can be overridden in the call to ExifTool.write.

    Security: entries are passed through to the underlying exiftool process verbatim. Never pass attacker-controlled strings here. The library rejects any entry containing \r, \n, or \0 as a defense-in-depth measure, but provides no other sanitization.

    []