Работа с изображениями в Node.js: resize и crop
В современной веб-разработке часто возникает необходимость обрабатывать изображения на серверной стороне: изменять размер, обрезать, конвертировать форматы. Node.js предлагает несколько мощных библиотек для этих задач. В этой статье мы разберём две самые популярные — Sharp (высокая производительность, основана на libvips) и Jimp (чистый JavaScript, не требует нативных зависимостей).
1. Установка и подготовка
Для начала создайте новый проект и установите одну из библиотек:
mkdir image-processor && cd image-processor
npm init -y
npm install sharp jimp
2. Изменение размера (resize) с Sharp
Sharp — это быстрая библиотека на C, которая отлично подходит для production. Она поддерживает потоковую обработку и автоматическое определение формата.
const sharp = require('sharp');
// Простой resize до ширины 300px (высота сохраняет пропорции)
sharp('input.jpg')
.resize(300)
.toFile('output-300.jpg')
.then(() => console.log('Готово!'))
.catch(err => console.error(err));
// Принудительный resize до точных размеров 200x200 (с искажением)
sharp('input.jpg')
.resize(200, 200, { fit: 'fill' })
.toFile('output-fill.jpg');
// Умный resize с сохранением пропорций (обрезка по центру)
sharp('input.jpg')
.resize(200, 200, { fit: 'cover', position: 'centre' })
.toFile('output-cover.jpg');
3. Обрезка (crop) с Sharp
Метод extract позволяет вырезать прямоугольную область изображения.
const sharp = require('sharp');
// Вырезаем область: left=100, top=50, width=400, height=300
sharp('input.jpg')
.extract({ left: 100, top: 50, width: 400, height: 300 })
.toFile('cropped.jpg')
.then(info => console.log('Обрезано:', info));
4. Работа с Jimp (чистый JavaScript)
Jimp работает медленнее Sharp, но не требует компиляции нативных модулей — идеально для простых задач или окружений без прав на установку системных пакетов.
const Jimp = require('jimp');
// resize до ширины 300px
Jimp.read('input.jpg')
.then(image => {
return image
.resize(300, Jimp.AUTO) // AUTO сохраняет пропорции
.writeAsync('output-jimp.jpg');
})
.then(() => console.log('Jimp resize готов'))
.catch(err => console.error(err));
// crop (обрезка) с координатами
Jimp.read('input.jpg')
.then(image => {
return image
.crop(100, 50, 400, 300) // x, y, width, height
.writeAsync('cropped-jimp.jpg');
})
.catch(err => console.error(err));
5. Комбинированный пример: resize + crop за один проход
Часто требуется сначала обрезать, а потом уменьшить. Sharp делает это эффективно благодаря внутреннему конвейеру:
const sharp = require('sharp');
sharp('input.jpg')
.extract({ left: 50, top: 30, width: 800, height: 600 })
.resize(400, 300, { fit: 'cover' })
.toFile('result.jpg')
.then(info => console.log('Итоговый размер:', info.width, 'x', info.height));
6. Сравнение Sharp vs Jimp
- Производительность: Sharp в 5-10 раз быстрее для больших файлов.
- Установка: Jimp не требует нативных зависимостей (просто npm install).
- Функции: Sharp поддерживает больше форматов (heif, tiff, avif) и продвинутые фильтры.
- Потоковая обработка: Sharp работает с потоками Node.js (pipe), Jimp — только с буферами.
- Рекомендация: Для высоконагруженных сервисов выбирайте Sharp. Для простых скриптов или учебных проектов — Jimp.
7. Работа с буфером (без сохранения в файл)
Часто изображения приходят через HTTP или хранятся в памяти. Обе библиотеки поддерживают работу с Buffer:
const sharp = require('sharp');
const fs = require('fs');
// Читаем файл в буфер
const inputBuffer = fs.readFileSync('input.jpg');
// Обрабатываем в памяти
sharp(inputBuffer)
.resize(150, 150)
.toBuffer()
.then(outputBuffer => {
// Отправляем buffer клиенту или сохраняем
fs.writeFileSync('thumb.jpg', outputBuffer);
});
8. Обработка ошибок и валидация
Всегда проверяйте, что файл существует и является изображением: