Работа с изображениями на TypeScript: изменение размера (resize) и обрезка (crop)
В современной веб-разработке обработка изображений на стороне клиента — частая задача. TypeScript, благодаря строгой типизации и интеграции с современными API браузера, позволяет выполнять операции resize (изменение размера) и crop (обрезка) безопасно и эффективно. В этой статье мы разберём два подхода: использование нативного Canvas API и работу с серверными библиотеками sharp и jimp для Node.js.
1. Canvas API: клиентская обработка без зависимостей
Браузерный HTMLCanvasElement — самый лёгкий способ манипулировать изображениями. Он не требует установки дополнительных пакетов и работает в любом современном браузере.
1.1. Изменение размера (resize) через Canvas
Основная идея — нарисовать исходное изображение на canvas с новыми размерами, а затем экспортировать результат.
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;
}
// Рисуем изображение с новыми размерами
ctx.drawImage(source, 0, 0, targetWidth, targetHeight);
// Экспортируем в Blob (формат по умолчанию - PNG)
canvas.toBlob((blob) => {
if (blob) resolve(blob);
else reject(new Error('Failed to create blob'));
}, 'image/jpeg', 0.9); // можно указать формат и качество
});
}
Важно: При увеличении изображения (upscale) качество может ухудшиться — canvas использует билинейную интерполяцию. Для превью это приемлемо, для печати — нет.
1.2. Обрезка (crop) с координатами
Обрезка требует указать прямоугольную область исходного изображения.
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;
}
// Вырезаем фрагмент из исходного изображения
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');
});
}
Совет: Всегда проверяйте, что координаты x, y, width, height не выходят за границы исходного изображения, иначе canvas вернёт пустые области.
2. Серверная обработка: sharp и jimp
Если вы работаете в среде Node.js и TypeScript, библиотеки sharp (C++ native, высокая производительность) и jimp (чистый JS, кроссплатформенность) — стандартные решения.
2.1. Установка и импорт
// Установка
// npm install sharp
// npm install jimp
import sharp from 'sharp';
import Jimp from 'jimp';
2.2. Изменение размера (resize) с sharp
async function resizeWithSharp(
inputPath: string,
outputPath: string,
width: number,
height: number
): Promise<void> {
await sharp(inputPath)
.resize(width, height, {
fit: 'cover', // 'cover' - обрезает лишнее, 'contain' - вписывает
position: 'center' // точка отсчёта при обрезке
})
.toFile(outputPath);
}
Параметр fit определяет стратегию вписывания:
cover— масштабирует и обрезает, чтобы полностью заполнить заданные размеры;contain— вписывает изображение целиком, возможны пустые полосы;fill— искажает пропорции, растягивая до точных размеров.
2.3. Обрезка (crop) с sharp
async function cropWithSharp(
inputPath: string,
outputPath: string,
left: number,
top: number,
width: number,
height: number
): Promise<void> {
await sharp(inputPath)
.extract({ left, top, width, height })
.to