Working with Images in TypeScript: Resize and Crop
In modern web development, client-side image processing is a common task. TypeScript, thanks to its strict typing and integration with modern browser APIs, allows you to perform resize and crop operations safely and efficiently. In this article, we will cover two approaches: using the native Canvas API and working with server-side libraries sharp and jimp for Node.js.
1. Canvas API: Client-Side Processing Without Dependencies
The browser's HTMLCanvasElement is the easiest way to manipulate images. It requires no additional packages and works in any modern browser.
1.1. Resizing via Canvas
The main idea is to draw the source image onto a canvas with new dimensions, then export the result.
function resizeImage( source: HTMLImageElement, targetWidth: number, targetHeight: number): Promise<Blob> { return new Promise((resolve, reject) => { const canvas = document.createElement('canvas'); canvas.width = targetWidth; canvas.height = targetHeight; const ctx = canvas.getContext('2d'); if (!ctx) { reject(new Error('Canvas context not supported')); return; } // Draw the image with new dimensions ctx.drawImage(source, 0, 0, targetWidth, targetHeight); // Export to Blob (default format is PNG) canvas.toBlob((blob) => { if (blob) resolve(blob); else reject(new Error('Failed to create blob')); }, 'image/jpeg', 0.9); // you can specify format and quality });}Important: When upscaling an image, quality may degrade — canvas uses bilinear interpolation. This is acceptable for previews, but not for printing.
1.2. Cropping with Coordinates
Cropping requires specifying a rectangular area of the source image.
function cropImage( source: HTMLImageElement, x: number, y: number, width: number, height: number): Promise<Blob> { return new Promise((resolve, reject) => { const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); if (!ctx) { reject(new Error('Canvas not supported')); return; } // Extract a fragment from the source image ctx.drawImage(source, x, y, width, height, 0, 0, width, height); canvas.toBlob((blob) => { if (blob) resolve(blob); else reject(new Error('Blob creation failed')); }, 'image/png'); });}Tip: Always check that the coordinates x, y, width, height do not exceed the boundaries of the source image, otherwise the canvas will return empty areas.
2. Server-Side Processing: sharp and jimp
If you are working in a Node.js and TypeScript environment, the libraries sharp (C++ native, high performance) and jimp (pure JS, cross-platform) are standard solutions.
2.1. Installation and Import
// Installation// npm install sharp// npm install jimp
import sharp from 'sharp';import Jimp from 'jimp';2.2. Resizing with sharp
async function resizeWithSharp( inputPath: string, outputPath: string, width: number, height: number): Promise<void> { await sharp(inputPath) .resize(width, height, { fit: 'cover', // 'cover' - crops excess, 'contain' - fits within position: 'center' // anchor point for cropping }) .toFile(outputPath);}The fit parameter defines the fitting strategy:
cover—