scalpel@labs: ~/glossary/image-dimension-probing.mdx5 sections

Image Dimension Probing

Dimension probing loads an image quietly in the background, with a new Image() object, to read its natural width and height when the page never rendered it. Lazy-loaded and off-screen images have no measured size until something loads them, so probing fills that gap.

extension: Scalpel Imagesupdated: 2026-08-14read_time: 3 min
less image-dimension-probing.mdx

Why it matters

Many modern pages lazy-load images. They don't load until the user scrolls into view. An image that's far down the page and never scrolled to has never rendered, so the browser cannot tell you its naturalWidth and naturalHeight. A size filter would then have to either drop every unrendered image or keep them all, because you don't know if they're large or tiny.

Probing loads them quietly in the background, outside the DOM, to measure them. You see the real dimensions in the filter without forcing the page to render a gallery that might never be seen.

How it works

When an image doesn't render on the page, the browser never loads its file or reads its metadata. A new Image() off-DOM load bypasses this. You create an image element, set its src to the target URL, wait for the load event, then read naturalWidth and naturalHeight. The image is never added to the page, and it doesn't interfere with rendering.

Probing can load many images at once, but it respects a concurrency limit (typically 4-6 simultaneous requests) so the browser doesn't spawn a hundred parallel downloads and choke the page. It also applies a timeout per image (usually 5-10 seconds) so a stuck image doesn't hang the scan. If an image times out or errors, its size stays unknown; you can then choose to include or exclude unknown sizes with a checkbox.

The order matters for efficiency. Scalpel Images probes largest images first, so big files, the ones most worth filtering, get measured quickly. Tiny images and thumbnails go last.

What does not matter

Whether the image is lazy-loaded via JavaScript or with the HTML5 loading="lazy" attribute doesn't matter. Both result in the same outcome: the browser hasn't loaded the file yet. A data-src attribute pointing at the real URL works just as well as a plain src.

Also, cross-origin images can be probed just like same-origin ones. The CORS rules apply to pixel access (which would be blocked if the image isn't CORS-cleared), but just loading the image and reading its dimensions works fine. The only catch is that if the server doesn't send CORS headers, some browsers might not even load the image. That's rare, and Scalpel Images treats it as a timeout.

The timing for probing doesn't affect the initial scan. Probing runs after the main image list is built, so the popup shows responsive images and rendered images immediately. Unrendered images appear with unknown dimensions, and as probes return, the badges update live.

Code example

Here's how you'd probe an unrendered image:

function probeImage(url, timeout = 10000) {
  return new Promise((resolve) => {
    const img = new Image();
    
    const timeoutId = setTimeout(() => {
      resolve({ width: 0, height: 0, error: 'timeout' });
    }, timeout);
    
    img.onload = () => {
      clearTimeout(timeoutId);
      resolve({ width: img.naturalWidth, height: img.naturalHeight });
    };
    
    img.onerror = () => {
      clearTimeout(timeoutId);
      resolve({ width: 0, height: 0, error: 'load failed' });
    };
    
    img.src = url;
  });
}

// Probe an image that never rendered
probeImage('https://example.com/large-image.jpg').then((result) => {
  console.log(`Dimensions: ${result.width}x${result.height}`);
});

To batch-probe with a concurrency limit:

async function batchProbe(urls, concurrency = 4) {
  const queue = [...urls];
  const results = new Map();
  let running = 0;

  const processQueue = async () => {
    while (queue.length > 0 && running < concurrency) {
      running++;
      const url = queue.shift();
      
      probeImage(url).then((result) => {
        results.set(url, result);
        running--;
        processQueue();
      });
    }
  };

  while (queue.length > 0 || running > 0) {
    await new Promise(resolve => setTimeout(resolve, 50));
  }
  
  return results;
}

How Scalpel Images shows it

In the popup, unrendered images first show with unknown dimensions. As probes complete, the size badges update in real time. You'll see a dimension badge appear as each image is measured. The "Include unknown sizes" checkbox at the bottom lets you decide whether to keep images that still haven't been measured when you're ready to download.

Sources