(Node) Get the Image Width and Height

Mar 12, 2024

TL;DR, follow the final code right away!

In a browser runtime, you can easily get the size of an image using the Image element. The following code can be run directly in the browser console.

const img = new Image();
img.onload = function () {
  console.log(img.width + 'x' + img.height);
  // 200x300
};
img.src = 'https://picsum.photos/200/300';

However, in the case of non-browser runtime like Node or Bun, you cannot use this Image element. Then how can you get the size of the image in this situation?

image-size

The open-source library image-size can easily solve this problem.

yarn add image-size

image-size is written with TypeScript.
Currently it operates only in the Node runtime in version 1, but It is expected to operate in the browser runtime in version 2. find out GitHub.

The basic operation is to extract image information from binary data of the image.

Different file formats have different binary structures and need to be handled separately, but since image-size supports many file formats (PNG, JPEG, GIF, WebP, HEIC, etc.) and automatically parses them, we can easily get the size of an image.

Local Images

If you want to get the size of an image in the local file system, you can get it right away by just passing the file path as an argument.

import sizeOf from 'image-size';
 
const dimension = sizeOf('public/og.png');
 
console.log(dimension);
// {
//   height: 720,
//   width: 1280,
//   type: "png",
// }

External Images

For external images, you can get the size of the image by obtaining binary data from the URL and providing it as an argument.

import sizeOf from 'image-size';
 
const res = await fetch('https://picsum.photos/200/300');
const buffer = new Uint8Array(await res.arrayBuffer());
const dimension = sizeOf(buffer);
 
console.log(dimension);
// {
//   height: 300,
//   orientation: 1,
//   width: 200,
//   type: "jpg",
// }

Inside image-size, parsing is done based on Uint8Array(8-bit unsigned integer array), so just provide it to them.

You can get the binary data(ArrayBuffer) through the arrayBuffer method of the fetch Response, and you can convert the binary data to a Uint8Array object through the constructor of Uint8Array.

Also, it is acceptable to write like below in the Node runtime.

// Buffer is a global variable in the Node runtime, but it is recommended to import and use it for easy reference.
import { Buffer } from 'node:buffer';
 
const buffer = Buffer.from(await res.arrayBuffer());

Final Code

If you look at the library code, you can see that it gets the image size by converting the local image into binary data as well.
So whether it is an internal image or an external image, if you convert them all into binary data and get the image size, you can write much a clean code.

import fs from 'node:fs/promises';
import sizeOf from 'image-size';
 
const getImageBuffer = async (src: string) => {
  const isExternalImage = src.startsWith('http');
 
  if (isExternalImage) {
    const res = await fetch(src);
    return new Uint8Array(await res.arrayBuffer());
  }
 
  const localSrc = `public/${src}`;
  const file = await fs.readFile(localSrc);
  return new Uint8Array(file);
};
 
export const getImageDimension = async (src: string) => {
  const buffer = await getImageBuffer(src);
  return sizeOf(buffer);
};

I wanted to prevent layout shift of the blog article by specifying the image size at the web application build time.
Try to get the size of the image without depending on the browser anymore.