Skip to main content

Command Palette

Search for a command to run...

Shrink Before You Send: Frontend Image Resizing for Faster and Cheaper Uploads

Updated
5 min read
Shrink Before You Send: Frontend Image Resizing for Faster and Cheaper Uploads
A

I’m a Frontend Software Engineer with 3+ years of experience building fast, scalable, and user-friendly web applications. I specialize in performance optimization, refactoring legacy code, and enhancing UI/UX, particularly in complex dashboard applications. I focus on improving load times and delivering smooth user experiences by collaborating closely with cross-functional teams.

Context

The Problem with Large Image Uploads

Modern web applications often handle large image uploads, especially from mobile devices that capture high-resolution photos by default. Uploading these full-sized images directly to the backend or sending them to an AI or LLM (Large Language Model) for visual processing leads to predictable issues:

  • Slow uploads

  • Overloaded backend systems

  • Increased LLM processing costs

Most use cases, such as profile pictures, product thumbnails, or AI inputs, do not require such massive files. Using a 4K source only adds latency and cost without any real benefit.

The Solution: Frontend Image Resizing

Frontend image resizing is a valuable technique that involves resizing and compressing images before they are sent to the backend. This approach can significantly reduce load times and cost without any noticeable drop in quality.


How It Works

The typical workflow looks like this

  1. User selects an image.

  2. The frontend resizes the image.

  3. The optimized image is uploaded to the backend.

  4. The backend sends it to an LLM or processing service.

  5. The response is returned faster and at a lower processing cost.

This optimization reduces the payload size, shortens upload duration, and minimizes downstream resource usage.


Approaches to Resizing

There are several options available, but here are the two main methods I recommend for resizing images within the browser:

1. Canvas (native)

The browser’s Canvas 2D API lets you draw an image at a smaller size and export a new Blob/File. No dependencies, minimal code, very fast for typical uploads.

When it shines

  • Screenshots, product photos, everyday camera images you’ll cap at ~768–1080px.

  • You want no bundle impact and simple maintenance.

Implementation

async function resizeWithCanvas(file: File, maxSide = 768, quality = 0.9): Promise<File> {
  const img = await fileToImage(file);

  // compute scaled dimensions keeping aspect ratio
  const scale = Math.min(maxSide / img.width, maxSide / img.height);
  const w = Math.round(img.width * scale);
  const h = Math.round(img.height * scale);

  const canvas = document.createElement('canvas');
  canvas.width = w; canvas.height = h;
  const ctx = canvas.getContext('2d')!;
  ctx.imageSmoothingEnabled = true;
  (ctx as any).imageSmoothingQuality = 'high';
  ctx.drawImage(img, 0, 0, w, h);

  const blob = await new Promise<Blob>(r => canvas.toBlob(b => r(b!), 'image/jpeg', quality));
  return new File([blob], file.name.replace(/\.[^.]+$/, '.jpg'), { type: 'image/jpeg' });
}

function fileToImage(file: File): Promise<HTMLImageElement> {
  return new Promise((res, rej) => {
    const img = new Image();
    img.onload = () => res(img);
    img.onerror = rej;
    img.src = URL.createObjectURL(file);
  });
}

2. Pica (library)

Pica is a high-quality re-sampler (using Lanczos3, with WASM/worker support). It's designed to provide better sharpness and fewer artifacts when significantly reducing the size of large images (e.g., 4000–6000px sources). It adds a small dependency, but the quality can be noticeably better on very large photos.

When it shines

  • DSLR-scale inputs or highly detailed textures where Canvas starts to look slightly soft.

  • Optionally runs in a Web Worker to prevent main-thread blocking.

Implementation

import pica from 'pica';

async function resizeWithPica(file: File, maxSide = 768, quality = 0.9): Promise<File> {
  const img = await fileToImage(file);
  const scale = Math.min(maxSide / img.width, maxSide / img.height);
  const w = Math.round(img.width * scale);
  const h = Math.round(img.height * scale);

  const canvas = document.createElement('canvas');
  canvas.width = w; canvas.height = h;

  const p = pica();
  await p.resize(img, canvas, { quality: 3, unsharpAmount: 80, unsharpRadius: 0.6, unsharpThreshold: 2 });
  const blob = await p.toBlob(canvas, 'image/jpeg', quality);
  return new File([blob], file.name.replace(/\.[^.]+$/, '.jpg'), { type: 'image/jpeg' });
}

function fileToImage(file: File): Promise<HTMLImageElement> {
  return new Promise((res, rej) => {
    const img = new Image();
    img.onload = () => res(img);
    img.onerror = rej;
    img.src = URL.createObjectURL(file);
  });
}

Comparison Overview

Both approaches achieve the same goal: reduce image dimensions and file size before upload. The main difference lies in quality vs. simplicity trade-offs.

CriterionCanvas (Native)Pica (Library)
SpeedVery fastSlightly slower
QualityExcellentMarginally sharper for 4K+ images
DependenciesNoneRequires library (~13.3 KB GZipped)
Ease of UseSimpleExtra configuration
Best ForLLM, profile, and thumbnail uploadsHigh-detail photography apps

Demo: Canvas vs Pica in Practice

Live Demo: web-image-resize.vercel.app

Source Code: github.com/abdrahmansoltan/web-image-resize

The demo compares both resizing approaches side by side with these Key findings:

  • Canvas consistently reduced image size by up to ~98% with minimal quality loss.

  • Pica delivered slightly sharper edges for very large photos but required additional setup.

  • For images under 1080px, differences were nearly imperceptible.


Findings and Conclusion

Expected Impact

  • Average image size: 2.8 MB → 350 KB

  • Upload duration: reduced by up to ~98%

  • Request time: reduced up to ~60%

  • Backend processing time: improved proportionally

  • LLM processing cost: reduced per pixel input

  • Image clarity: visually unchanged for standard use cases

Conclusion

Resizing images on the frontend is a simple yet powerful optimization that improves user experience and operational efficiency, especially for most applications, particularly those involving LLM inputs, profile pictures, or thumbnails.

Canvas API provides an ideal balance of performance, quality, and maintainability, as it’s native, fast, and introduce no dependencies. which is recommended for most cases.

Pica remains a valuable alternative for applications handling extremely detailed images (e.g., photography tools or high-resolution artwork).

Small optimization, significant results. Resize early, upload smart, and make every pixel count.

References