### Install Exifr using npm Source: https://github.com/mikekovarik/exifr/blob/master/README.md Install the Exifr package using npm for Node.js projects. ```bash npm install exifr ``` -------------------------------- ### Importing Exifr using CommonJS Source: https://github.com/mikekovarik/exifr/blob/master/index.html Example of how to import and use Exifr in a Node.js environment using the CommonJS module system. ```javascript const exifr = require('exifr') async function run () { const exif = await exifr.parse(file) console.log(exif) } run() ``` -------------------------------- ### Basic Usage: Reading EXIF Data Source: https://github.com/mikekovarik/exifr/blob/master/index.html Demonstrates how to read EXIF data from an image file using Exifr. This is a fundamental example for getting started. ```javascript import exifr from 'exifr' const exif = await exifr.parse(file) console.log(exif) ``` -------------------------------- ### Importing Exifr using ES Modules Source: https://github.com/mikekovarik/exifr/blob/master/index.html Example of how to import and use Exifr in an environment that supports ES Modules, such as modern browsers or Node.js with module support. ```javascript import exifr from 'exifr' async function run () { const exif = await exifr.parse(file) console.log(exif) } run() ``` -------------------------------- ### XMP XML to JSON Parsing Example Source: https://github.com/mikekovarik/exifr/blob/master/README.md Demonstrates how Exifr's minimalistic XML parser transforms a given XMP structure into a JSON object, illustrating rules for attributes, simple tags, and arrays. ```xml Mike Kovařík Some string here jpeg xmptiffiptc ``` ```js { name: 'Exifr', // attribute belonging to the same namespace author: 'Mike Kovařík', // simple tag of the namespace description: {lang: 'en-us', value: 'Some string here'}, // tag with attrs and value becomes object formats: 'jpeg', // single item array is unwrapped segments: ['xmp', 'tiff', 'iptc'] // array as usual } ``` -------------------------------- ### Image Thumbnail Extraction Example Source: https://github.com/mikekovarik/exifr/blob/master/examples/thumbnail.html This JavaScript code snippet demonstrates the process of extracting a thumbnail from an image using the Exifr library. It handles image loading, thumbnail extraction, and displays image dimensions and extraction time. It also includes error handling for files without thumbnails. ```javascript function promiseImg(img) { if (img.naturalWidth !== 0) { return Promise.resolve() } else { return new Promise((resolve, reject) => { img.onload = resolve img.onerror = reject }) } } var promiseTimeout = millis => new Promise(resolve => setTimeout(resolve, millis)) let original = document.querySelector("#original") let thumbnail = document.querySelector("#thumbnail") let originalDesc = document.querySelector("#original-desc") let thumbnailDesc = document.querySelector("#thumbnail-desc") processFile('../test/fixtures/IMG_20180725_163423.jpg') async function processFile(arg) { let url if (arg instanceof Blob) url = URL.createObjectURL(arg) else url = arg original.src = url await promiseImg(original) // original image loaded, extract thumb let t0 = performance.now() thumbnail.src = await exifr.thumbnailUrl(original) console.log('original ', original.src) console.log('thumbnail', thumbnail.src) let t1 = performance.now() // thumb extracted printImgInfo(original, originalDesc) try { await promiseTimeout() // needed for reloading after selecting another img await promiseImg(thumbnail) printImgInfo(thumbnail, thumbnailDesc, `extracted in ${Math.round(t1 - t0)} ms`) } catch (err) { printImgInfo(thumbnail, thumbnailDesc, `The file has no thumbnail`) } } function printImgInfo(img, pre, ...lines) { if (img.naturalWidth > 0 && img.naturalHeight > 0) { pre.innerHTML = [ `width: ${img.naturalWidth}`, `height: ${img.naturalHeight}`, ...lines ].join('\n') } else { pre.innerHTML = lines.join('\n') } } document.querySelector('input[type="file"]').addEventListener('change', async e => { processFile(e.target.files[0]) }) ``` -------------------------------- ### Extracting Full TIFF Segment Source: https://github.com/mikekovarik/exifr/blob/master/index.html This example demonstrates how to extract the entire TIFF segment from an image file, which contains all IFD blocks and other related data. ```javascript import exifr from 'exifr' const exif = await exifr.tiff(file) console.log(exif) ``` -------------------------------- ### Extracting Thumbnail Image Data Source: https://github.com/mikekovarik/exifr/blob/master/README.md Provides examples for obtaining the thumbnail image data as a buffer or as an object URL for direct use in browsers. ```javascript let thumbBuffer = await exifr.thumbnail(file) // or get object URL (browser only) img.src = await exifr.thumbnailUrl(file) ``` -------------------------------- ### Extract Image Rotation Data Source: https://github.com/mikekovarik/exifr/blob/master/README.md Use this snippet to get rotation instructions for an image. It provides angle, mirroring, and dimension swap information, crucial for handling browser autorotation quirks. ```javascript let r = await exifr.rotation(image) if (r.css) { img.style.transform = `rotate(${r.deg}deg) scale(${r.scaleX}, ${r.scaleY})` } ``` -------------------------------- ### Demo Initialization and Event Listeners Source: https://github.com/mikekovarik/exifr/blob/master/examples/legacy.html Sets up event listeners for three demo buttons and initializes the first demo on page load. It also includes logic to clear the output before running a demo if the `clear` argument is true. ```javascript document.getElementById('demo1').addEventListener('click', runDemo1) document.getElementById('demo2').addEventListener('click', runDemo2) document.getElementById('demo3').addEventListener('click', runDemo3) function runDemo1(clear) { if (clear) $output.innerHTML = 'parsing file' parseFile('../test/fixtures/IMG_20180725_163423-tiny.jpg') } function runDemo2(clear) { if (clear) $output.innerHTML = 'extracting depth map' extractDepthMap('../test/fixtures/xmp depth map.jpg', {xmp: true, mergeOutput: false, multiSegment: true}) } function runDemo3(clear) { if (clear) $output.innerHTML = 'parsing file' parseFile('../test/fixtures/IMG_20180725_163423-tiny.jpg', {tiff: false, icc: true, multiSegment: true}) } // load demo file first runDemo1(false) ``` -------------------------------- ### Instantiate and Use Exifr Class Source: https://github.com/mikekovarik/exifr/blob/master/README.md Shows how to manually instantiate the Exifr class for efficient simultaneous parsing of metadata and thumbnail extraction. Remember to close the file handle in Node.js if read in chunked mode. ```javascript let exr = new Exifr(options) await exr.read(file) let output = await exr.parse() let buffer = await exr.extractThumbnail() await exr.file?.close?.() ``` -------------------------------- ### Initialize Exifr and Event Listeners Source: https://github.com/mikekovarik/exifr/blob/master/benchmark/gps-dnd.html Imports the Exifr library and sets up event listeners for file drops and input changes to handle image processing. It targets HTML elements for logging and file input. ```javascript import exifr from '../src/bundles/full.mjs' import {gpsOnlyOptions, Exifr} from '../src/bundles/full.mjs' let $log = document.querySelector('#log') let memUsed = 0 let dropzone = document.body dropzone.addEventListener('dragenter', e => e.preventDefault()) dropzone.addEventListener('dragover', e => e.preventDefault()) dropzone.addEventListener('drop', e => { e.preventDefault() handleFiles(e.dataTransfer.files) }) document.querySelector('input[type="file"]').addEventListener('change', e => { e.preventDefault() handleFiles(e.target.files) }) ``` -------------------------------- ### Customizing Exifr Build Source: https://github.com/mikekovarik/exifr/blob/master/index.html Shows how to create a custom build of Exifr by importing only specific components like file readers, segment parsers, and dictionaries. This can reduce bundle size. ```javascript import parse from 'exifr/src/parsers/parse' import readBlob from 'exifr/src/readers/blob' import dictionary from 'exifr/src/dictionaries/exiftool' const exif = await parse(file, { fileReader: readBlob, dictionary: dictionary }) console.log(exif) ``` -------------------------------- ### Basic Exifr Parsing Source: https://github.com/mikekovarik/exifr/blob/master/README.md Demonstrates two ways to parse EXIF data: directly from a file path or by providing a file buffer. ```javascript // exifr reads the file from disk, only a few hundred bytes. exifr.parse('./myimage.jpg') .then(output => console.log('Camera:', output.Make, output.Model)) // Or read the file on your own and feed the buffer into exifr. fs.readFile('./myimage.jpg') .then(exifr.parse) .then(output => console.log('Camera:', output.Make, output.Model)) ``` -------------------------------- ### Import Exifr in Node.js (CommonJS and ESM) Source: https://github.com/mikekovarik/exifr/blob/master/README.md Demonstrates how to import Exifr in Node.js environments using both CommonJS and ES Module syntax. The 'full' bundle is used by default. ```javascript // Modern Node.js can import CommonJS import exifr from 'exifr' // => exifr/dist/full.umd.cjs // Explicily import ES Module import exifr from 'exifr/dist/full.esm.mjs' // to use ES Modules // CommonJS, old Node.js var exifr = require('exifr') // => exifr/dist/full.umd.cjs ``` -------------------------------- ### Include Exifr in Browsers (ESM, UMD, Legacy) Source: https://github.com/mikekovarik/exifr/blob/master/README.md Shows how to include Exifr in web pages using different script formats. The 'lite' bundle is recommended for browsers. ```html ``` -------------------------------- ### Import Exifr using named exports Source: https://github.com/mikekovarik/exifr/blob/master/README.md Illustrates an alternative way to import Exifr using named exports, although the default export is recommended. ```javascript import * as exifr from 'exifr' ``` -------------------------------- ### UMD Integration in Browser Source: https://github.com/mikekovarik/exifr/blob/master/README.md Shows how to use Exifr in a browser environment by including the UMD build via a script tag. Parses EXIF data from an image element. ```html ``` -------------------------------- ### Main Script: Spawn Worker and Handle Messages Source: https://github.com/mikekovarik/exifr/blob/master/examples/worker.html Spawns a Web Worker to process an image file and logs the time taken and EXIF data received. Ensure 'worker.js' is in the same directory. ```javascript let worker = new Worker('worker.js') let pre = document.querySelector('pre') function log(string) { pre.innerText += string + '\n' } log("main script spawned worker") let t1 = performance.now() worker.postMessage('../test/fixtures/IMG_20180725_163423.jpg') worker.onmessage = e => { let t2 = performance.now() log(`${(t2 - t1).toFixed(1)} ms`) log('main script received exif from worker') log('-------------------------------------------------------') log(JSON.stringify(e.data, null, 2)) } ``` -------------------------------- ### Parse Sidecar Files with Exifr Source: https://github.com/mikekovarik/exifr/blob/master/README.md Demonstrates how to parse sidecar metadata files like .xmp or .icc. The third argument can optionally specify the segment type for performance. ```javascript exifr.sidecar('./img_1234.icc') ``` ```javascript exifr.sidecar('./img_1234.icc', {translateKeys: false}) ``` ```javascript exifr.sidecar('./img_1234.colorprofile', {translateKeys: false}, 'icc') ``` -------------------------------- ### Using Base64 String as Input Source: https://github.com/mikekovarik/exifr/blob/master/index.html Demonstrates how to use a Base64 encoded image string as input for Exifr parsing. Useful when images are stored as strings rather than files. ```javascript import exifr from 'exifr' const exif = await exifr.parse(base64String) console.log(exif) ``` -------------------------------- ### Exifr Benchmark: Overall Performance Comparison Source: https://github.com/mikekovarik/exifr/blob/master/README.md This benchmark compares the average time taken by Exifr, exifreader, and exiftool to process a large number of photos. Exifr shows superior performance. ```text 2036 photos (in total 22GB): lib | average | all files --------------------------------- exifr | 2.5ms | 5s <--- !!! exifreader | 9.5ms | 19.5s exiftool | 76ms | 154s ``` -------------------------------- ### Import Map Configuration for Exifr Tests Source: https://github.com/mikekovarik/exifr/blob/master/test/index.html Defines import map for test dependencies. Ensure you are using a compatible browser and have necessary flags enabled. ```json { "imports": { "chai": "./empty.mjs", "path": "./empty.mjs", "express": "./empty.mjs", "child_process": "./empty.mjs", "util": "./empty.mjs", "fs": "./empty.mjs" } } ``` -------------------------------- ### Exifr Benchmark: Chunked vs. Whole File Reading Source: https://github.com/mikekovarik/exifr/blob/master/README.md This benchmark demonstrates the performance difference between reading an entire file and reading only the necessary chunks for metadata extraction. Reading by chunks is significantly faster. ```text user reads file 8.4 ms exifr reads whole file 8.2 ms exifr reads file by chunks 0.5 ms <--- !!! only parsing, not reading 0.2 ms <--- !!! ``` -------------------------------- ### Reading EXIF Data with Options Source: https://github.com/mikekovarik/exifr/blob/master/index.html Shows how to parse EXIF data with specific options, such as including TIFF segments or sanitizing values. Useful for fine-tuning the parsing process. ```javascript import exifr from 'exifr' const exif = await exifr.parse(file, { tiff: { ifd0: true, exif: true, gps: true, interop: true, ifd1: true }, makerNote: true, userComment: true, xmp: true, icc: true, iptc: true, jfif: true, ihdr: true, mergeOutput: true, sanitize: true, reviveValues: true, translateKeys: true, translateValues: true, multiSegment: true }) console.log(exif) ``` -------------------------------- ### ESM Integration in Browser Source: https://github.com/mikekovarik/exifr/blob/master/README.md Demonstrates using Exifr in modern browsers with ES Modules. Parses EXIF data from multiple files selected via an input element. ```html ``` -------------------------------- ### Shortcut for Picking Specific TIFF Tags Source: https://github.com/mikekovarik/exifr/blob/master/README.md Shows how to use shortcuts to selectively extract specific tags from EXIF and GPS TIFF blocks. ```js // Only extract FNumber + ISO tags from EXIF and GPSLatitude + GPSLongitude from GPS { exif: true, gps: true, pick: ['FNumber', 'ISO', 'GPSLatitude', 0x0004] // 0x0004 is GPSLongitude } // is a shortcut for {exif: ['FNumber', 'ISO'], gps: ['GPSLatitude', 0x0004]} // which is another shortcut for {exif: {pick: ['FNumber', 'ISO']}, gps: {pick: ['GPSLatitude', 0x0004]}} ``` -------------------------------- ### Importing Modules for Custom HEIC/TIFF Build Source: https://github.com/mikekovarik/exifr/blob/master/README.md Import modules for parsing HEIC and TIFF files, extracting TIFF segment data, and using TIFF EXIF value dictionaries. This configuration avoids importing file readers, assuming data is provided as Uint8Array. ```javascript import * as exifr from 'exifr/src/core.mjs' import 'exifr/src/file-parsers/heic.mjs' import 'exifr/src/file-parsers/tiff.mjs' import 'exifr/src/segment-parsers/tiff.mjs' import 'exifr/src/dicts/tiff-exif-values.mjs' ``` -------------------------------- ### Exifr class Source: https://github.com/mikekovarik/exifr/blob/master/README.md Provides a class-based interface for instantiating Exifr, reading files, and parsing metadata or extracting thumbnails efficiently, especially when both operations are needed. ```APIDOC ## `Exifr` class ### Description Provides a class-based interface for instantiating Exifr, reading files, and parsing metadata or extracting thumbnails efficiently, especially when both operations are needed. ### Constructor - `new Exifr(options)`: Instantiates a new Exifr object with optional configuration. ### Methods - `.read(file)`: Loads the specified file into the Exifr instance. - `.parse()`: Parses the loaded file to extract EXIF data. - `.extractThumbnail()`: Extracts the embedded thumbnail from the loaded file. - `.file?.close?.()`: Closes the file handle if opened in chunked mode (Node.js specific). ### Usage Example ```js let exr = new Exifr(options) await exr.read(file) let output = await exr.parse() let buffer = await exr.extractThumbnail() await exr.file?.close?.() ``` ``` -------------------------------- ### Global Error Handler and Output Function Source: https://github.com/mikekovarik/exifr/blob/master/examples/legacy.html Sets up a global error handler to log issues and a function to print output to the DOM. Uses `var` for older browser compatibility. ```javascript var $output = document.querySelector('#output') var $reload = document.querySelector('#reload') window.onerror = function(message, source, lone, col, error) { console.log('ONERROR') var lines = [ '********************** ERROR **********************', 'message: ' + message, 'source: ' + source, 'lone: ' + lone, 'col: ' + col ] if (error) { lines.push('description: ' + error.description) lines.push('message: ' + error.message) lines.push('name: ' + error.name) lines.push('number: ' + error.number) lines.push(error.stack) } printOutput(lines) } function printOutput(lines) { $output.innerHTML += '\n' + lines.join('\n') + '\n\n' } ``` -------------------------------- ### parse(file[, options]) Source: https://github.com/mikekovarik/exifr/blob/master/README.md Parses EXIF data from a given file and returns an object containing the EXIF information. An optional options argument can be provided to customize the parsing behavior. ```APIDOC ## `parse(file[, options])` ### Description Parses EXIF data from a given file and returns an object containing the EXIF information. An optional options argument can be provided to customize the parsing behavior. ### Parameters #### Path Parameters - **file** (string | Buffer | ArrayBuffer | Uint8Array | DataView | Blob | File | img element) - Required - The input file to parse. Can be a file path, URL, Base64 string, Buffer, ArrayBuffer, Blob, File, or an element. - **options** (object) - Optional - Configuration options for parsing. ### Returns - `Promise` - A promise that resolves to an object containing the EXIF data, or undefined if parsing fails or no EXIF data is found. ``` -------------------------------- ### Custom Bundle without FsReader Source: https://github.com/mikekovarik/exifr/blob/master/README.md Alternatively, create a custom bundle around the 'core' build of Exifr and exclude 'FsReader' to avoid 'fs' module dependencies. ```javascript import { core } from 'exifr/src/core'; // ... create your bundle around core ``` -------------------------------- ### Importing Modules for Custom JPEG Build Source: https://github.com/mikekovarik/exifr/blob/master/README.md Import specific modules for handling JPEG files, extracting ICC data, and using ICC dictionaries. This is useful for reducing bundle size in browser environments. ```javascript // Core bundle has nothing in it import * as exifr from 'exifr/src/core.mjs' // Now we import what we need import 'exifr/src/file-readers/BlobReader.mjs' import 'exifr/src/file-parsers/jpeg.mjs' import 'exifr/src/segment-parsers/icc.mjs' import 'exifr/src/dicts/icc-keys.mjs' import 'exifr/src/dicts/icc-values.mjs' ``` -------------------------------- ### Exifr Tag Filtering with options.pick Source: https://github.com/mikekovarik/exifr/blob/master/README.md Use `options.pick` to specify an array of tags that should be parsed. This enables their respective blocks and disables others, optimizing parsing by stopping once all requested tags are found. ```javascript {pick: ['ExposureTime', 'FNumber', 'ISO']} ``` ```javascript {pick: ['ExposureTime', 'FNumber', 'ISO', 'GPSLatitude']} ``` ```javascript {gps: {pick: ['GPSLatitude', 0x0004]}} ``` -------------------------------- ### Running Exifr Tests with Mocha Source: https://github.com/mikekovarik/exifr/blob/master/test/index.html Initiates the Mocha test runner to execute the imported Exifr test modules. This is the final step to run the test suite. ```javascript mocha.run() ``` -------------------------------- ### Render GPS Coordinates on Google Map Source: https://github.com/mikekovarik/exifr/blob/master/benchmark/gps-dnd.html Initializes a Google Map and displays markers for each valid GPS coordinate extracted from the image files. It fits the map bounds to show all detected points. ```javascript function renderMap(coords) { let map = new google.maps.Map(document.querySelector('#map'), { navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL}, mapTypeControl: false, mapTypeId: google.maps.MapTypeId.ROADMAP }) coords = coords.filter(coord => coord) let points = coords.map(coord => new google.maps.LatLng(coord.latitude, coord.longitude)) var bounds = new google.maps.LatLngBounds() points.forEach(point => bounds.extend(point)) map.fitBounds(bounds) let markers = points.map(point => new google.maps.Marker({map, position: point})) } ``` -------------------------------- ### Image Orientation and Rotation Handling Source: https://github.com/mikekovarik/exifr/blob/master/examples/orientation.html This script processes image URLs to extract orientation and rotation data using Exifr. It then creates and displays images, canvases, and applies transformations to demonstrate different orientation handling techniques. ```javascript let table = document.querySelector('table') function createElement(name) { return document.createElement(name) } function createRow(name, subtitle, array) { let tr = createElement('tr') let head = createElement('td') head.innerHTML = `

${name}

` if (subtitle) head.innerHTML += `

${subtitle}

` tr.append(head) for (let item of array) { let td = createElement('td') td.append(item) tr.append(td) } table.append(tr) } function createImg(url) { let img = createElement('img') img.src = url return img } let urls = [ '../test/fixtures/orientation/f1t.jpg', '../test/fixtures/orientation/f2t.jpg', '../test/fixtures/orientation/f3t.jpg', '../test/fixtures/orientation/f4t.jpg', '../test/fixtures/orientation/f5t.jpg', '../test/fixtures/orientation/f6t.jpg', '../test/fixtures/orientation/f7t.jpg', '../test/fixtures/orientation/f8t.jpg', ] let rawTransforms = [ {deg: 0, scaleX: 1, scaleY: 1}, {deg: 0, scaleX: -1, scaleY: 1}, {deg: 0, scaleX: -1, scaleY: -1}, {deg: 0, scaleX: 1, scaleY: -1}, {deg: 90, scaleX: 1, scaleY: -1}, {deg: 90, scaleX: -1, scaleY: -1}, {deg: 90, scaleX: -1, scaleY: 1}, {deg: 90, scaleX: 1, scaleY: 1}, ] ;(async function() { let orientationsPromises = urls.map(exifr.orientation) let rotationsPromises = urls.map(exifr.rotation) let orientations = await Promise.all(orientationsPromises) let rotations = await Promise.all(rotationsPromises) let images = urls.map(createImg) await Promise.all(images.map(img => new Promise(resolve => img.onload = resolve))) let raw = rawTransforms.map(rot => createRaw(urls[0], rot)) let rotated1 = images.map((img, i) => createRotatedCanvas(img, rotations[i])) let rotated2 = urls.map((url, i) => createRotatedImg(url, rotations[i])) createRow('orientation', 'standardized EXIF number', orientations) createRow('raw image', 'The way it looks in basic photo viewers or old browsers.', raw) createRow('unmodified <img>', 'The way browser renders it. May be autorotated in modern browsers.', images) createRow('rotated <canvas>', 'Using ctx.rotate() with ctx.drawImage() if rotation.canvas===true', rotated1) createRow('rotated with css', 'Using property transform:rotate() if rotation.css===true', rotated2) createRow('exifr.rotation()', 'Output of exifr describing if and how rotation should be handled depending on current browser.', rotations.map(rot => { rot = JSON.parse(JSON.stringify(rot)) rot.rad = Number(rot.rad.toFixed(3)) let json = Object.entries(rot).map(([key, val]) => `${key}: ${val}`).join('\n') let div = document.createElement('div') div.style.textAlign = 'left' div.style.whiteSpace = 'pre-wrap' div.style.fontSize = '10px' div.innerHTML = json return div })) })(); function createRaw(url, rot) { let img = createImg(url) img.style.transform = `rotate(${rot.deg}deg) scale(${rot.scaleX}, ${rot.scaleY})` return img } function createRotatedCanvas(img, rot) { let w = img.width let h = img.height // only swap width and height if the image is rotated 90 or 270 degrees // and if the browser doesn't do autorotation already if (rot.canvas && rot.dimensionSwapped) { w = img.height h = img.width } let canvas = document.createElement('canvas') canvas.width = w canvas.height = h let ctx = canvas.getContext('2d') // only rotate the image using canvas if browser doesn't do autorotation already if (rot.canvas) { ctx.translate(w / 2, h / 2) ctx.rotate(rot.rad) ctx.scale(rot.scaleX, rot.scaleY) ctx.drawImage(img, -img.width / 2, -img.height / 2, img.width, img.height) } else { ctx.drawImage(img, 0, 0) } return canvas } function createRotatedImg(url, rot) { let img = createImg(url) // only rotate the image using css if browser doesn't do autorotation already if (rot.css) img.style.transform = `rotate(${rot.deg}deg) scale(${rot.scaleX}, ${rot.scaleY})` return img } ``` -------------------------------- ### Handle Dropped or Selected Files Source: https://github.com/mikekovarik/exifr/blob/master/benchmark/gps-dnd.html Processes an array of files, calculates their total size, and initiates the parsing and measurement process. It then updates the log with the results. ```javascript async function handleFiles(files) { files = Array.from(files) let totalBytes = sum(files.map(f => f.size)) let [time, memory] = await parseAndMeasureImages(files) $log.innerHTML = [ `files: ${files.length} = ${(totalBytes / 1024 / 1024).toFixed(1)} MB`, `RAM used: ${(memory / 1024 / 1024).toFixed(1)} MB`, `parsed in: ${Math.floor(time)} ms (${(time / files.length).toFixed(1)} ms per file)`, ].join('\n') } ``` -------------------------------- ### sidecar(file[, options[, type]]) Source: https://github.com/mikekovarik/exifr/blob/master/README.md Parses a sidecar file (e.g., .xmp, .icc) which contains external metadata. An optional type argument can be provided for performance optimization. ```APIDOC ## `sidecar(file[, options[, type]])` ### Description Parses a sidecar file (e.g., .xmp, .icc) which contains external metadata. An optional type argument can be provided for performance optimization. ### Parameters #### Path Parameters - **file** (string | Buffer | ArrayBuffer | Uint8Array | DataView | Blob | File | img element) - Required - The input sidecar file to parse. - **options** (object) - Optional - Configuration options for parsing. - **type** (string) - Optional - The type of the sidecar file (e.g., 'icc', 'xmp'). ### Returns - `Promise` - A promise that resolves to an object containing the parsed sidecar data, or undefined if parsing fails. ``` -------------------------------- ### Exifr Default Options Configuration Source: https://github.com/mikekovarik/exifr/blob/master/README.md This object shows the default configuration for Exifr, including which segments and TIFF blocks are parsed by default, and various formatting and chunking options. ```javascript let defaultOptions = { // Segments (JPEG APP Segment, PNG Chunks, HEIC Boxes, etc...) tiff: true, xmp: false, icc: false, iptc: false, jfif: false, // (jpeg only) ihdr: false, // (png only) // Sub-blocks inside TIFF segment ifd0: true, // aka image ifd1: false, // aka thumbnail exif: true, gps: true, interop: false, // Other TIFF tags makerNote: false, userComment: false, // Filters skip: [], pick: [], // Formatters translateKeys: true, translateValues: true, reviveValues: true, sanitize: true, mergeOutput: true, silentErrors: true, // Chunked reader chunked: true, firstChunkSize: undefined, firstChunkSizeNode: 512, firstChunkSizeBrowser: 65536, // 64kb chunkSize: 65536, // 64kb chunkLimit: 5, httpHeaders: {}, } ``` -------------------------------- ### orientation(file) Source: https://github.com/mikekovarik/exifr/blob/master/README.md Extracts the orientation tag from the EXIF data of a given file, indicating how the image should be rotated. ```APIDOC ## `orientation(file)` ### Description Extracts the orientation tag from the EXIF data of a given file, indicating how the image should be rotated. ### Parameters #### Path Parameters - **file** (string | Buffer | ArrayBuffer | Uint8Array | DataView | Blob | File | img element) - Required - The input file to parse. ### Returns - `Promise` - A promise that resolves to a number representing the orientation, or undefined if not found. ``` -------------------------------- ### Importing Exifr Test Modules Source: https://github.com/mikekovarik/exifr/blob/master/test/index.html Imports various test modules for Exifr functionality. These are part of the test suite and require the import map to be correctly configured. ```javascript import './BufferView.spec.mjs' import './DynamicBufferView.spec.mjs' import './ChunkedReader.spec.mjs' import './reader.spec.mjs' import './formats/parser.spec.mjs' import './formats/jpeg.spec.mjs' import './formats/heic.spec.mjs' import './formats/avif.spec.mjs' import './formats/png.spec.mjs' import './options.spec.mjs' import './output-format.spec.mjs' import './highlevel/gps.spec.mjs' import './highlevel/orientation.spec.mjs' import './highlevel/thumb.spec.mjs' import './tiff.spec.mjs' import './jfif.spec.mjs' import './icc.spec.mjs' import './iptc.spec.mjs' import './xmp-segment.spec.mjs' import './xmp-parser-synthetic.spec.mjs' import './xmp-parser-fixtures.spec.mjs' import './fixtures.spec.mjs' import './issues.spec.mjs' import './webpack.spec.mjs' import './bundles.spec.mjs' ``` -------------------------------- ### Parse Specific Tags with options.pick Source: https://github.com/mikekovarik/exifr/blob/master/README.md To improve performance when processing many files, use `options.pick` to specify only the tags you need. Exifr will stop parsing once the last picked tag is found. ```javascript let {ISO, FNumber} = await exifr.parse(file, {exif: ['ISO', 'FNumber']}) ``` -------------------------------- ### Extracting Specific EXIF Tags Source: https://github.com/mikekovarik/exifr/blob/master/README.md Shows how to extract only certain tags like GPS coordinates, orientation, or specific fields. Also demonstrates disabling default TIFF parsing to focus on XMP. ```javascript // only GPS let {latitude, longitude} = await exifr.gps('./myimage.jpg') // only orientation let num = await exifr.orientation(blob) // only three tags let output = await exifr.parse(file, ['ISO', 'Orientation', 'LensModel']) // only XMP segment (and disabled TIFF which is enabled by default) let output = await exifr.parse(file, {tiff: false, xmp: true}) ``` -------------------------------- ### Parsing EXIF Data in a Web Worker Source: https://github.com/mikekovarik/exifr/blob/master/index.html Shows how to use Exifr within a web worker to perform EXIF parsing off the main thread, improving UI responsiveness for large files or many images. ```javascript const worker = new Worker('./examples/worker.js') worker.postMessage(file) ``` -------------------------------- ### Shortcut for Disabling TIFF Blocks Source: https://github.com/mikekovarik/exifr/blob/master/README.md Illustrates a shortcut configuration to enable specific interop tags while disabling all other TIFF blocks. ```js {interop: true, tiff: false} // is a shortcut for {interop: true, ifd0: false, exif: false, gps: false, ifd1: true} ``` -------------------------------- ### Creating a Custom GPS Dictionary Source: https://github.com/mikekovarik/exifr/blob/master/README.md Define a new dictionary for the GPS block by providing an array of tag codes and their corresponding string names. This allows for custom translation of GPS metadata keys. ```javascript // Create custom dictionary for GPS block import exifr from 'exifr' exifr.createDictionary(exifr.tagKeys, 'gps', [ [0x0001, 'LatitudeRef'], [0x0002, 'Latitude'], [0x0003, 'LongitudeRef'], [0x0004, 'Longitude'], ]) ``` -------------------------------- ### rotation(file) Source: https://github.com/mikekovarik/exifr/blob/master/README.md Extracts information needed to rotate an image based on its EXIF orientation data. Returns an object with rotation details and scaling factors. ```APIDOC ## `rotation(file)` ### Description Extracts information needed to rotate an image based on its EXIF orientation data. Returns an object with rotation details and scaling factors. ### Parameters #### Path Parameters - **file** (string | Buffer | ArrayBuffer | Uint8Array | DataView | Blob | File | img element) - Required - The input file to parse. ### Returns - `Promise` - A promise that resolves to an object with rotation properties (`deg`, `rad`, `scaleX`, `scaleY`, `dimensionSwapped`, `css`, `canvas`), or undefined if not found. ### Response Example ```json { "deg": 180, "rad": 3.141592653589793, "scaleX": 1, "scaleY": 1, "dimensionSwapped": false, "css": true, "canvas": true } ``` ``` -------------------------------- ### Extracting Thumbnail Data Source: https://github.com/mikekovarik/exifr/blob/master/index.html Demonstrates how to extract embedded thumbnail images from EXIF data. This is useful for displaying previews or smaller versions of images. ```javascript import exifr from 'exifr' const exif = await exifr.thumbnail(file) console.log(exif) ``` -------------------------------- ### exifr.sidecar Source: https://github.com/mikekovarik/exifr/blob/master/README.md Parses EXIF data from a sidecar file. ```APIDOC ## exifr.sidecar(file) ### Description Parses EXIF data from a sidecar file. ### Method `exifr.sidecar(file)` ### Parameters - **file**: (Buffer | Uint8Array | Blob | | string) - The input file in various formats. ### Returns - `object`: An object containing the parsed EXIF data from the sidecar file. ``` -------------------------------- ### exifr.orientation Source: https://github.com/mikekovarik/exifr/blob/master/README.md Parses only the orientation tag from a given file. ```APIDOC ## exifr.orientation(file) ### Description Parses only the orientation tag from the EXIF data of a given file. ### Method `exifr.orientation(file)` ### Parameters - **file**: (Buffer | Uint8Array | Blob | | string) - The input file in various formats. ### Returns - `number`: The orientation value. ``` -------------------------------- ### Cache Options Object for Multiple Parses Source: https://github.com/mikekovarik/exifr/blob/master/README.md When parsing multiple files with identical settings, cache the `options` object. This prevents Exifr from creating new `Options` instances repeatedly, improving performance. ```javascript let options = {exif: true, iptc: true} for (let file of files) exif.parse(file, options) ``` -------------------------------- ### Drag and Drop File Handling Source: https://github.com/mikekovarik/exifr/blob/master/examples/legacy.html Implements drag and drop functionality for the entire document body, allowing users to parse files by dropping them onto the page. It prevents default drag behaviors. ```javascript var dropzone = document.body function prevent(e) { e.preventDefault() } dropzone.addEventListener('dragenter', prevent) dropzone.addEventListener('dragover', prevent) dropzone.addEventListener('drop', function(e) { e.preventDefault() parseFile(e.dataTransfer.files[0]) }) ``` -------------------------------- ### Revive Values: False vs. True Source: https://github.com/mikekovarik/exifr/blob/master/README.md Compares the output of `reviveValues`. When `false`, dates are strings and some values are raw. When `true`, dates are converted to Date instances and other values are formatted for readability. ```json { GPSVersionID: [0x02, 0x02, 0x00, 0x00], ModifyDate: '2018:07:25 16:34:23', } ``` ```json { GPSVersionID: '2.2.0.0', ModifyDate: <Date instance: 2018-07-25T14:34:23.000Z>, } ``` -------------------------------- ### Exifr Tag Filtering with options.skip Source: https://github.com/mikekovarik/exifr/blob/master/README.md Use `options.skip` to specify an array of tags that should not be parsed. This is useful for excluding large or unnecessary tags like 'MakerNote'. ```javascript {skip: ['ImageWidth', 'Model', 'FNumber', 'GPSLatitude']} ``` ```javascript {exif: {skip: ['ImageUniqueID', 42033, 'SubSecTimeDigitized']}} ``` -------------------------------- ### thumbnail(file) Source: https://github.com/mikekovarik/exifr/blob/master/README.md Extracts an embedded thumbnail from an image file. Returns the thumbnail data as a Buffer or Uint8Array. ```APIDOC ## `thumbnail(file)` ### Description Extracts an embedded thumbnail from an image file. Returns the thumbnail data as a Buffer or Uint8Array. ### Parameters #### Path Parameters - **file** (string | Buffer | ArrayBuffer | Uint8Array | DataView | Blob | File | img element) - Required - The input file to parse. ### Returns - `Promise` - A promise that resolves to the thumbnail data, or undefined if not found. ``` -------------------------------- ### Use exifr.gps() for GPS Data Extraction Source: https://github.com/mikekovarik/exifr/blob/master/README.md For extracting only GPS coordinates, use the specialized `exifr.gps()` function. This is more efficient than parsing all metadata with `exifr.parse()` and enabling the GPS option. ```javascript exifr.gps(file) ``` -------------------------------- ### exifr.parse Source: https://github.com/mikekovarik/exifr/blob/master/README.md Parses EXIF data from a given file. It can parse specific blocks or tags based on the provided options. ```APIDOC ## exifr.parse(file, options) ### Description Parses IFD0, EXIF, and GPS blocks from a file. The `options` parameter can be used to parse all available data, only specified tags, or use custom parsing settings. ### Method `exifr.parse(file)` `exifr.parse(file, true)` `exifr.parse(file, ['Model', 'FNumber', ...])` `exifr.parse(file, {options})` ### Parameters - **file**: (Buffer | Uint8Array | Blob | | string) - The input file in various formats. - **options**: (boolean | string[] | object) - Optional. Specifies what segments and blocks to parse, filters tags, or custom settings. - `true`: Parses all available data. - `['Tag1', 'Tag2', ...]`: Parses only the specified tags. - `{options}`: Custom parsing settings. ### Returns - `object`: An object containing the parsed EXIF data. ``` -------------------------------- ### Exifr Parsing and Error Handling Source: https://github.com/mikekovarik/exifr/blob/master/examples/legacy.html Helper functions to print EXIF output and catch errors during Exifr parsing. The `parseFile` function handles general EXIF data, while `extractDepthMap` specifically processes depth map data. ```javascript function printExif(output) { $output.innerHTML += '\n' + JSON.stringify(output, null, 4) } function catchErrors(err) { console.log('UNCAUGHT') console.log(err) printOutput([ '********************** UNCAUGHT **********************', err.message, err.stack ]) } // first demo function parseFile(file, options) { exifr.parse(file, options) .then(printExif) .catch(catchErrors) } // second demo function extractDepthMap(file, options) { var img = document.createElement('img') exifr.parse(file, options) .then(function(output) { $output.innerHTML = '' var mime = output.GDepth.Mime var base64 = output.GDepth.Data img.width = 400 img.src = 'data:' + mime + ';base64,' + base64 $output.appendChild(img) }) .catch(catchErrors) } ``` -------------------------------- ### Merge Output: True vs. False Source: https://github.com/mikekovarik/exifr/blob/master/README.md Demonstrates the difference between merging all parsed segments into a single object (`mergeOutput: true`) and keeping them separate (`mergeOutput: false`). Use `mergeOutput: false` with caution, especially when `translateKeys` is also false or when parsing both IFD0 and IFD1, as numeric keys may collide. ```json { Make: 'Google', Model: 'Pixel', FNumber: 2, Country: 'Czech Republic', xmp: '<x:xmpmeta><rdf:Description>...' } ``` ```json { ifd0: { Make: 'Google', Model: 'Pixel' }, exif: { FNumber: 2 }, iptc: { Country: 'Czech Republic' }, xmp: '<x:xmpmeta><rdf:Description>...' } ``` -------------------------------- ### Customizing EXIF Tag Keys and Values Source: https://github.com/mikekovarik/exifr/blob/master/README.md Modify the translation dictionaries for EXIF tags by setting custom string names for keys and string descriptions for values. This allows for tailored output of EXIF metadata. ```javascript // Modify single tag's 0xa409 (Saturation) translation import exifr from 'exifr' let exifKeys = exifr.tagKeys.get('exif') let exifValues = exifr.tagValues.get('exif') exifKeys.set(0xa409, 'Saturation') exifValues.set(0xa409, { 0: 'Normal', 1: 'Low', 2: 'High' }) ``` -------------------------------- ### Web Worker Script for EXIF Parsing Source: https://github.com/mikekovarik/exifr/blob/master/README.md The content of the worker script (`worker.js`) that imports Exifr and parses messages received from the main thread. ```javascript // worker.js importScripts('./node_modules/exifr/dist/lite.umd.js') self.onmessage = async e => postMessage(await exifr.parse(e.data)) ``` -------------------------------- ### Webpack Ignore Comment Source: https://github.com/mikekovarik/exifr/blob/master/README.md Use the `webpackIgnore` magic comment to prevent Webpack from bundling the 'fs' module when importing 'exifr'. ```javascript import(/* webpackIgnore: true */ 'fs') ``` -------------------------------- ### Measure Image Parsing Performance Source: https://github.com/mikekovarik/exifr/blob/master/benchmark/gps-dnd.html Parses GPS data from multiple image files, measuring the time taken and the increase in JavaScript heap memory. It renders the map with the extracted coordinates. ```javascript async function parseAndMeasureImages(files) { memUsed = 0 let m1 = performance.memory.usedJSHeapSize let t1 = performance.now() let promises = files.map(exifr.gps).map(promise => promise.catch(() => {})) let coords = await Promise.all(promises) let m2 = performance.memory.usedJSHeapSize let t2 = performance.now() renderMap(coords) return [t2 - t1, m2 - m1] } ``` -------------------------------- ### exifr.rotation Source: https://github.com/mikekovarik/exifr/blob/master/README.md Provides information on how to rotate the photo based on its EXIF data. ```APIDOC ## exifr.rotation(file) ### Description Provides information on how to rotate the photo to its correct orientation based on the EXIF data. ### Method `exifr.rotation(file)` ### Parameters - **file**: (Buffer | Uint8Array | Blob | | string) - The input file in various formats. ### Returns - `object`: An object containing rotation information. ``` -------------------------------- ### Extracting GPS Data Source: https://github.com/mikekovarik/exifr/blob/master/index.html This snippet focuses on extracting only the GPS-related EXIF tags for fast retrieval. Ideal for applications that primarily need location data. ```javascript import exifr from 'exifr' const exif = await exifr.gps(file) console.log(exif) ``` -------------------------------- ### exifr.thumbnail Source: https://github.com/mikekovarik/exifr/blob/master/README.md Extracts the embedded thumbnail image from a file. ```APIDOC ## exifr.thumbnail(file) ### Description Extracts the embedded thumbnail image from the EXIF data of a given file. ### Method `exifr.thumbnail(file)` ### Parameters - **file**: (Buffer | Uint8Array | Blob | | string) - The input file in various formats. ### Returns - `Buffer | Uint8Array`: The binary data of the thumbnail. ```