exif-parser vs image-size vs image-type vs imageinfo
Image Metadata and Dimension Detection in Node.js
exif-parserimage-sizeimage-typeimageinfo

Image Metadata and Dimension Detection in Node.js

exif-parser, image-size, image-type, and imageinfo are Node.js utilities designed to inspect image files without fully decoding them. They serve distinct but overlapping roles: image-size extracts dimensions (width/height), image-type identifies the file format (JPEG, PNG, etc.) from buffers or streams, exif-parser reads EXIF metadata (camera settings, GPS, orientation), and imageinfo is a legacy tool that attempts to provide both dimensions and type. These libraries are essential for image upload validation, automatic orientation correction, and optimizing asset delivery in web applications.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
exif-parser0229-149 years ago-
image-size02,227378 kB45a year agoMIT
image-type04227.36 kB03 months agoMIT
imageinfo059-415 years ago-

Image Metadata and Dimension Detection: exif-parser vs image-size vs image-type vs imageinfo

When handling image uploads or processing assets in Node.js, you often need to know three things: what format is it, how big is it, and what metadata does it contain? The packages exif-parser, image-size, image-type, and imageinfo address these needs, but they solve different parts of the puzzle. Let's compare how they handle detection, performance, and API design.

📏 Getting Image Dimensions

image-size is the dedicated tool for reading width and height. It supports many formats (PNG, JPEG, GIF, SVG, etc.) and works with buffers or file paths.

import sizeOf from 'image-size';

const dimensions = sizeOf('images/batch/folder/image.png');
console.log(dimensions.width, dimensions.height);
// Output: 100 100

imageinfo also provides dimensions but uses a callback-based API typical of older Node.js libraries. It returns an object with width, height, and type.

import imageinfo from 'imageinfo';

const buffer = fs.readFileSync('image.png');
const info = imageinfo(buffer);

if (info.valid) {
  console.log(info.width, info.height);
}

exif-parser does not provide general image dimensions. It focuses strictly on EXIF data. If the EXIF data contains pixel dimensions, you can read them, but this is not reliable for all images.

// exif-parser: No direct dimension API
// You must parse EXIF tags which may or may not exist
const parser = require('exif-parser').create(buffer);
const tags = parser.parse();
// tags.tags.PixelXDimension might exist, but don't count on it

image-type does not provide dimensions. It only identifies the file format.

// image-type: No dimension support
// Only returns file type info

🔍 Detecting File Type

image-type is the most reliable for checking the actual file signature (magic numbers). It ignores file extensions, which is critical for security.

import imageType from 'image-type';

const buffer = fs.readFileSync('mystery-file');
const type = imageType(buffer);

if (type) {
  console.log(type.ext, type.mime);
  // Output: 'png', 'image/png'
}

image-size infers the type internally to determine dimensions but does not expose a clean type-detection API as its primary feature. You can access the type property from the result.

import sizeOf from 'image-size';

const dimensions = sizeOf('image.jpg');
console.log(dimensions.type);
// Output: 'jpg'

imageinfo returns the format type alongside dimensions in its result object.

import imageinfo from 'imageinfo';

const info = imageinfo(buffer);
console.log(info.format); 
// Output: 'PNG' or 'JPEG'

exif-parser does not detect file types. It assumes the input is a JPEG or TIFF containing EXIF data. Passing a PNG will result in empty or failed parsing.

// exif-parser: Assumes JPEG/TIFF
// No type detection mechanism
const parser = require('exif-parser').create(pngBuffer);
const result = parser.parse(); 
// Result will likely be empty or invalid

📷 Reading EXIF Metadata

exif-parser is the only package in this list designed specifically for EXIF data. It exposes tags like orientation, GPS, ISO, and shutter speed.

import exif from 'exif-parser';

const parser = exif.create(buffer);
parser.parse((err, result) => {
  if (err) throw err;
  console.log(result.tags.Make); // Camera brand
  console.log(result.tags.Orientation); // For auto-rotate
});

image-size does not read EXIF metadata. It stops after finding the dimension markers.

// image-size: No EXIF support
const dimensions = sizeOf('image.jpg');
// dimensions object has no EXIF tags

image-type does not read EXIF metadata. It only reads the file header signature.

// image-type: No EXIF support
const type = imageType(buffer);
// Returns only ext and mime

imageinfo does not read EXIF metadata. It focuses on basic structural info like size and format.

// imageinfo: No EXIF support
const info = imageinfo(buffer);
// No tags or metadata properties available

🌊 Stream Support

image-size supports streams, which is useful for large files where loading the whole buffer into memory is expensive.

import sizeOf from 'image-size';
import fs from 'fs';

const stream = fs.createReadStream('large-image.png');
sizeOf(stream, (err, dimensions) => {
  console.log(dimensions.width);
});

image-type also supports streams, allowing type detection without waiting for the full download.

import imageType from 'image-type';
import fs from 'fs';

const stream = fs.createReadStream('upload');
const type = await imageType.stream(stream);
console.log(type?.ext);

exif-parser works primarily with buffers. While you can pipe data into it, the API is designed around having the binary data available to parse tags.

// exif-parser: Buffer focused
const parser = exif.create(buffer);
// Stream support is not a primary feature

imageinfo expects a buffer. It does not have built-in stream handling.

// imageinfo: Buffer only
const info = imageinfo(buffer);
// Must read file fully before calling

⚠️ Maintenance and Status

image-size is actively maintained and widely used in production ecosystems. It receives updates for new formats and bug fixes.

image-type is also actively maintained and considered the standard for file type detection in the Node.js ecosystem.

exif-parser is stable but sees less frequent updates. It remains the go-to for pure JS EXIF parsing without native dependencies.

imageinfo is deprecated or effectively unmaintained. It has not seen significant updates in years. Using it introduces risk for security and compatibility.

📊 Summary Table

Featureimage-sizeimage-typeexif-parserimageinfo
Dimensions✅ Yes❌ No❌ No (indirect)✅ Yes
File Type✅ Yes (inferred)✅ Yes (primary)❌ No✅ Yes
EXIF Data❌ No❌ No✅ Yes❌ No
Stream Support✅ Yes✅ Yes⚠️ Limited❌ No
Status🟢 Active🟢 Active🟡 Stable🔴 Legacy

💡 The Big Picture

These tools are not direct competitors; they are complementary pieces of an image processing pipeline.

image-type should be your first line of defense. Use it to validate uploads before doing anything else. It ensures a file claiming to be a JPEG is actually a JPEG.

image-size is your standard for dimensions. Use it when you need to enforce aspect ratios or calculate storage needs. Its stream support makes it safe for large files.

exif-parser is your specialist for metadata. Use it when you need to auto-rotate images based on orientation tags or extract GPS data for mapping features.

imageinfo should be avoided. Its functionality is split better between image-size and image-type, both of which are more modern and reliable.

Final Thought: For a robust image upload handler, combine image-type (for security), image-size (for validation), and exif-parser (for orientation correction). Do not rely on a single legacy package to do it all.

How to Choose: exif-parser vs image-size vs image-type vs imageinfo

  • exif-parser:

    Choose exif-parser when you need to read EXIF metadata such as GPS coordinates, camera make/model, or orientation data. It is the specialized tool for metadata extraction and does not handle dimension detection or file type identification on its own. Use this alongside a dimension library if you need both size and metadata.

  • image-size:

    Choose image-size when your primary goal is to retrieve the width and height of an image file quickly. It supports a wide range of formats and works well with both buffers and file paths. It is the standard choice for validation logic where dimensions matter more than file type or metadata.

  • image-type:

    Choose image-type when you need to detect the actual file format from a buffer or stream, regardless of the file extension. It is ideal for security validation to ensure an uploaded file matches its claimed type. It does not provide dimensions or EXIF data.

  • imageinfo:

    Avoid imageinfo for new projects. It is a legacy package that combines dimension and type detection but lacks active maintenance and modern format support. Prefer image-size and image-type for better reliability, wider format coverage, and active community support.

README for exif-parser

exif-parser

exif-parser is a parser for image metadata in the exif format, the most popular metadata format for jpeg and tiff images. It is written in pure javascript and has no external dependencies. It can also get the size of jpeg images and the size of the jpeg thumbnail embedded in the exif data. It can also extract the embedded thumbnail image.

Installing

npm install exif-parser

You can also build a browser bundle to include it with a <script> tag in a HTML document, like this:

git clone git@github.com:bwindels/exif-parser.git
cd exif-parser/
make build-browser-bundle

Built versions of the bundles are also available in the exif-parser-browser-bundles repo.

This will generate a dist/exif-parser-(version).js and dist/exif-parser-(version)-min.js file. These bundles expose the parser on the ExifParser global variable, which you would use like this:

var parser = window.ExifParser.create(arrayBuffer);

Creating a parser

To start parsing exif data, create a new parser like below. Note that the buffer you pass does not have to be the buffer for the full jpeg file. The exif section of a jpeg file has a maximum size of 65535 bytes and the section seems to always occur within the first 100 bytes of the file. So it is safe to only fetch the first 65635 bytes of a jpeg file and pass those to the parser.

The buffer you pass to create can be a node buffer or a DOM ArrayBuffer.

var parser = require('exif-parser').create(buffer);
var result = parser.parse();

Setting the flags

Before calling parse, you can set a number of flags on the parser, telling it how to behave while parsing.

Add fields in the binary format to result. Since these fields are mostly used for internal fields like Padding, you generally are not interested in these. If enabled, values for these fields will be a Buffer object in node or an ArrayBuffer in DOM environments (browsers).

parser.enableBinaryFields([boolean]), default false;

EXIF tags are organized into different sections, and to tell you the offset to other sections, EXIF uses certain tags. These tags don't tell you anything about the image, but are more for parsers to find out about all tags. Hence, these "pointer" fields are not included in the result tags field by default. Change this flag to include them nonetheless.

parser.enablePointers([boolean]), default false;

Resolve tags to their textual name, making result.tags a dictonary object instead of an array with the tag objects with no textual tag name.

parser.enableTagNames([boolean]), default true;

Read the image size while parsing.

parser.enableImageSize([boolean]), default true;

Read the EXIF tags. Could be useful to disable if you only want to read the image size.

parser.enableReturnTags([boolean]), default true;

EXIF values can be represented in a number of formats (fractions, degrees, arrays, ...) with different precision. Enabling this tries to cast values as much as possible to the appropriate javascript types like number, Date.

parser.enableSimpleValues([boolean]), default true;

working with the result

Getting the tags

the tags that were found while parsing are stored in result.tags unless you set parser.enableReturnTags(false). If parser.enableTagNames is set to true, result.tags will be an object with the key being the tag name and the value being the tag value. If parser.enableTagNames is set to false, result.tags will be an array of objects containing section, type and value properties.

Getting the image size

If parser.enableImageSize is set to true, result.getImageSize() will give you the image size as an object with width and height properties.

Getting the thumbnail

You can check if there is a thumbnail present in the exif data with result.hasThumbnail(). Exif supports thumbnails is jpeg and tiff format, though most are in jpeg format. You can check if there is a thumbnail present in a give format by passing the mime type: result.hasThumbnail("image/jpeg").

You can also get the image size of the thumbnail as an object with width and height properties: result.getThumbnailSize().

To get the node buffer or arraybuffer containing just the thumbnail, call result.getThumbnailBuffer()

Running the unit tests

Install nodeunit globally from npm if you haven't done so already. You can run the tests with nodeunit test/test-*.js.

Contributions

I welcome external contributions through pull requests. If you do so, please don't use regular expressions. I don't like them, and don't want to maintain a project where they are used. Also, when fixing a bug please provide a regression unit test if it makes sense.