ExifReader

repository·main·Indexed 21 days ago

https://github.com/mattiasw/exifreader

A high-performance JavaScript library for parsing image files (JPEG, PNG, HEIC, etc.) and extracting Exif, IPTC, and XMP metadata. It supports both browser and Node.js environments, offering synchronous and asynchronous APIs to load files from buffers, local paths, or URLs. Key features include the ability to read only specific parts of a file using 'length: auto', support for compressed tags, and options to filter or expand metadata groups.

Tokens
10K
Snippets
38
Records
46
Agent score
76%

What's inside exifreader

  1. Understand GPS coordinate and altitude data

    main

    In Exif data, full GPS information is split into two tags for each direction:

    1. Coordinate value: GPSLatitude or GPSLongitude.
    2. Reference value: GPSLatitudeRef or GPSLongitudeRef.

    You must use the reference values to determine if the coordinate is North/South or East/West.

    Altitude:

    • GPSAltitude: The coordinate value.
    • GPSAltitudeRef: Specifies if the altitude is above sea level (positive) or below sea level (negative).

    Note: If you prefer pre-calculated values, refer to the GPS section of the documentation.

  2. Access GPS data with expanded options

    main
    When calling ExifReader.load with {expanded: true}, a gps group is added to the results. This group contains Latitude, Longitude, and Altitude. These values are signed: negative values indicate locations south of the equator, west of the Prime Meridian, or below sea level.
  3. How to expand tag groups

    main

    By default, Exif, IPTC, and XMP tags are grouped together. If a tag (like Orientation) exists in multiple groups, the first value (Exif) is overwritten by the second (XMP). To prevent this and keep the groups separate, set expanded: true in the options object.

    const tags = ExifReader.load(fileBuffer, {expanded: true});
  4. Use ExifReader in React Native

    main

    In React Native, import the library directly from the source path in node_modules. Since local device files must be loaded manually, convert the file to a buffer (e.g., using react-native-fs and base64-arraybuffer) before passing it to ExifReader.load.

    import RNFS from 'react-native-fs';
    import {decode} from 'base64-arraybuffer';
    import ExifReader from './node_modules/exifreader/src/exif-reader.js';
    
    const b64Buffer = await RNFS.readFile('YOUR IMAGE URI', 'base64')
    const fileBuffer = decode(b64Buffer)
    const tags = ExifReader.load(fileBuffer, {expanded: true});
  5. Automatically locate and extract metadata bytes using `length: 'auto'`

    main

    Use length: 'auto' to download or read only the minimum amount of data required to extract metadata. This is highly efficient for remote files or large local files.

    Requirements:

    • You must also set expanded: true and includeOffsets: true.
    • The return value is a Promise.

    Optimization Tip: For JPEGs from modern phones/DSLRs, use excludeTags: {mpf: true}. This prevents ExifReader from reading large embedded MPF sub-image previews, which can significantly speed up the process and save bandwidth.

    Output Properties (tags.metadataRange):

    • end: The exact byte count needed for the metadata.
    • buffer: The trimmed slice of bytes [0, end) containing the metadata.
    • fetched: The total bytes actually read (may be slightly more than end due to chunking).
    • requests: The number of IO calls performed.
    const tags = await ExifReader.load(url, {
        length: 'auto',
        expanded: true,
        includeOffsets: true,
        excludeTags: {mpf: true},  // skip embedded preview
    });
    
    console.log(tags.metadataRange.end);       // exact byte count needed
    console.log(tags.metadataRange.buffer);    // the trimmed metadata bytes
  6. Parse XMP tags in non-DOM environments (Node.js/Web Workers)

    main

    In environments without a native DOMParser (like Node.js), you must provide a third-party XML parser to support XMP tags. The parser must implement a parseFromString method compatible with the Web API DOMParser.

    It is recommended to use @xmldom/xmldom with the onErrorStopParsing option to avoid infinite loops with certain XML files. linkedom is an alternative but lacks this safety option.

    import {DOMParser, onErrorStopParsing} from '@xmldom/xmldom';
    // ...
    const tags = ExifReader.load(fileBuffer, {domParser: new DOMParser({onError: onErrorStopParsing})});
  7. Check Client and Node.js compatibility

    main

    Browser Support

    ExifReader requires the DataView API, which is supported in:

    • Chrome 9+
    • Firefox 15+
    • Internet Explorer 10+
    • Edge
    • Safari 5.1+
    • Opera 12.1+

    Node.js Support

    • Node.js 10+ is required if you need to parse XMP tags.
    • Earlier versions of Node.js will work for other metadata types.
  8. Best practices for tag processing and performance

    main

    Data Reliability

    • Use .value for logic: The description property of tags may change in minor updates (e.g., an Orientation value of 3 might be described as Rotate 180). To ensure your code doesn't break during updates, always use the value property for processing logic.
    • Text Decoding: Some text tags use TextDecoder. Ensure your environment (like Node.js) supports the specific encoding required for the tag.
    • Composite Tags: Values for composite tags may be inaccurate if the image has been resized.

    Performance Optimizations

    • Memory Management: maker_notes can be extremely large for certain manufacturers. If you are storing many tags, consider deleting the maker_notes property after parsing to save memory.
    • Partial File Reading: To speed up parsing, you can use the length option to only read the beginning of a file.
      • Reading the first 128 kB is often sufficient for regular Exif tags.
      • Warning: Limiting the length may exclude iptc, xmp, or even exif tags if they are located later in the file.
    • Exclude MPF for speed: For phone photos, excluding the Multi-Picture Format (mpf) can significantly increase speed, as modern JPEGs often embed large sub-image previews. Use excludeTags: {mpf: true} to skip these.
  9. Read only a specific part of a file

    main

    To avoid loading an entire file into memory, you can use the length option to limit how many bytes ExifReader reads. This is effective if you know the metadata is located near the beginning of the file.

    Supported IO inputs for length:

    1. Local files via Node.js fs.
    2. Remote files via URL (requires the server to support the Range header and correct CORS settings).
    3. Browser File objects.
    4. In-memory inputs (ArrayBuffer, Buffer, etc.)—though for these, the file is already in memory, length will simply return a trimmed slice in metadataRange.buffer.

    Warning: This option does not work if you pass an already loaded ArrayBuffer or Buffer and expect to save memory; the data is already resident in memory.

    // Load only the first 128 KiB
    const tags = await ExifReader.load(filename, {length: 128 * 1024});
  10. Access and use image thumbnails

    main

    Thumbnail data is available via tags['Thumbnail'].

    • In a Browser: Use tags['Thumbnail'].base64 to create a data URI for an <img> element.
    • In Node.js: Use tags['Thumbnail'].image (raw bytes) to write a new file using Buffer.
    // Browser usage
    imageElement.src = 'data:image/jpg;base64,' + tags['Thumbnail'].base64;
    
    // Node.js usage
    const fs = require('fs');
    fs.writeFileSync('/path/to/new/thumbnail.jpg', Buffer.from(tags['Thumbnail'].image));
  11. Build a custom ExifReader bundle

    main

    After configuring the exifreader object in your package.json, run the build command to generate the optimized bundle. You should run this command after every fresh installation or upgrade. It is recommended to add it to your prebuild script.

    # To install and build for the first time
    npm install exifreader
    npx exifreader build
    
    # To rebuild after changing configuration
    npx exifreader build