code icon Code

Image Metadata

Extract EXIF metadata from images

Source Code

import fs from "fs";
import path from "path";
import ExifParser from "exif-parser";

const [inputPath, outputPath] = process.argv.slice(2);

if (!inputPath || !outputPath) {
  console.error("Usage: inputPath outputPath");
  process.exit(1);
}

try {
  console.log(`Extracting image metadata: ${inputPath}...`);

  const buffer = fs.readFileSync(inputPath);
  const parser = ExifParser.create(buffer);
  const exifData = parser.parse();

  const result = {
    imageSize: exifData.imageSize || null,
    tags: {},
    gps: null,
  };

  // Extract useful tags
  const tags = exifData.tags || {};

  // Camera info
  if (tags.Make || tags.Model) {
    result.tags.camera = {
      make: tags.Make || null,
      model: tags.Model || null,
    };
  }

  // Date/time
  if (tags.DateTimeOriginal || tags.CreateDate || tags.ModifyDate) {
    result.tags.datetime = {
      original: tags.DateTimeOriginal ? new Date(tags.DateTimeOriginal * 1000).toISOString() : null,
      created: tags.CreateDate ? new Date(tags.CreateDate * 1000).toISOString() : null,
      modified: tags.ModifyDate ? new Date(tags.ModifyDate * 1000).toISOString() : null,
    };
  }

  // Camera settings
  if (tags.ExposureTime || tags.FNumber || tags.ISO) {
    result.tags.settings = {
      exposureTime: tags.ExposureTime || null,
      fNumber: tags.FNumber || null,
      iso: tags.ISO || tags.ISOSpeedRatings || null,
      focalLength: tags.FocalLength || null,
      flash: tags.Flash || null,
    };
  }

  // Image properties
  result.tags.image = {
    width: tags.ImageWidth || tags.ExifImageWidth || result.imageSize?.width || null,
    height: tags.ImageHeight || tags.ExifImageHeight || result.imageSize?.height || null,
    orientation: tags.Orientation || null,
    colorSpace: tags.ColorSpace || null,
  };

  // GPS coordinates
  if (tags.GPSLatitude && tags.GPSLongitude) {
    result.gps = {
      latitude: tags.GPSLatitude,
      longitude: tags.GPSLongitude,
      altitude: tags.GPSAltitude || null,
    };
  }

  // Software
  if (tags.Software) {
    result.tags.software = tags.Software;
  }

  // Include all raw tags for reference
  result.rawTags = tags;

  // Ensure output directory exists
  const dir = path.dirname(outputPath);
  if (dir && dir !== ".") {
    fs.mkdirSync(dir, { recursive: true });
  }

  fs.writeFileSync(outputPath, JSON.stringify(result, null, 2));

  console.log(`\nāœ“ Extracted image metadata`);
  if (result.imageSize) {
    console.log(`  Size: ${result.imageSize.width}x${result.imageSize.height}`);
  }
  if (result.tags.camera) {
    console.log(`  Camera: ${result.tags.camera.make || ""} ${result.tags.camera.model || ""}`);
  }
  if (result.tags.datetime?.original) {
    console.log(`  Date: ${result.tags.datetime.original}`);
  }
  if (result.gps) {
    console.log(`  GPS: ${result.gps.latitude}, ${result.gps.longitude}`);
  }
  console.log(`  Written to: ${outputPath}`);

  console.log(
    JSON.stringify({
      success: true,
      inputPath,
      outputPath,
      hasGps: !!result.gps,
      hasDateTime: !!result.tags.datetime,
      hasCamera: !!result.tags.camera,
    })
  );
} catch (error) {
  console.error("Error:", error.message);
  process.exit(1);
}