Sharp — швидка обробка зображень без компромісів
Серверна обробка зображень стає вузьким місцем, коли користувачі завантажують RAW з камер або фото 12 Мп з телефону. Jimp споживає 200+ МБ на одне зображення, ImageMagick потребує системної установки та нестабільний під навантаженням. Ми стикалися з проектом, де 10 одночасних завантажень клали сервер через OOM. Рішення — Sharp на базі libvips. Він обробляє зображення потоково, без завантаження повного файлу в пам'ять, і в 4–5 разів швидше аналогів.
Чому Sharp швидше аналогів?
Sharp не тримає весь файл у пам'яті — він розбирає його по шматках, застосовує операції та одразу пише результат. Це дає вдвічі менше споживання пам'яті при тому ж навантаженні. Порівняйте з ImageMagick: той конвертує через тимчасові файли на диску, що уповільнює роботу у високонавантажених системах. У наших тестах Sharp обробив 1000 зображень (1920×1080 → 800px WebP) за 12 секунд — ImageMagick знадобилося 38 секунд.
| Бібліотека | Споживання пам'яті на 1 зображення | Час конвертації (1000 шт.) |
|---|---|---|
| Sharp | 20–30 МБ | 12 с |
| Jimp | 150–250 МБ | 45 с |
| ImageMagick | 100–150 МБ + I/O | 38 с |
Як Sharp захищає від decompression bomb?
Decompression bomb — зображення з величезними розмірами (наприклад, 100k×100k пікселів), яке при спробі завантаження виділяє всю пам'ять. Sharp дозволяє перевірити метадані до повного завантаження: викличте metadata() і відхиліть файл, якщо ширина × висота перевищує ліміт (наприклад, 50 Мп). Це запобігає OOM без зайвих витрат.
Як ми реалізуємо інтеграцію
На одному з проектів (інтернет-магазин одягу) потрібно було автоматично конвертувати завантажувані фото в WebP з кількома розмірами, зберігати EXIF для SEO і не допускати decompression bomb. Ми побудували пайплайн:
- Multer зберігає файл у пам'яті (buffer).
- Sharp читає метадані — якщо площа > 50 Мп, відхиляємо.
- Застосовуємо
.rotate()для автоматичного повороту за EXIF. - Через
clone()створюємо три гілки: thumbnail (150×150 cover), medium (800px), large (1920px). - Кожну гілку конвертуємо в WebP (quality 82, effort 4) і зберігаємо в S3.
- Повертаємо JSON з посиланнями.
Результат: час завантаження впав з 3 секунд до 0.8, сервер витримує 50 одночасних запитів.
Вибір формату: WebP чи AVIF?
| Формат | Ступінь стиснення (відносно JPEG) | Підтримка браузерами (2025) | Споживання CPU |
|---|---|---|---|
| WebP | ~30% менше JPEG | 96% | Помірне |
| AVIF | ~50% менше JPEG | 87% | Високе |
| JPEG XL | ~60% менше JPEG | 10% | Середнє |
Для більшості проектів WebP — оптимальний баланс. AVIF обирають, коли розмір критичний, а CPU не тисне.
Налаштування concurrency в продакшені
Sharp використовує всі ядра CPU за замовчуванням, що може перевантажити сервер. Рекомендуємо обмежити:
sharp.concurrency(2) // два потоки
Також використовуйте чергу через p-limit для контролю одночасних обробок, контролюючи concurrency.
Процес роботи
- Аналітика: вивчаємо поточний пайплайн, заміряємо навантаження, визначаємо цільові формати та роздільну здатність.
- Проектування: обираємо стратегію кешування (CDN, заголовки Cache-Control), налаштовуємо конвеєр з урахуванням вашого стеку (Express, S3, Cloudflare).
- Реалізація: пишемо код з обробкою помилок, захистом від decompression bomb, інтеграцією з Multer або busboy.
- Тестування: навантажувальний тест з 1000 зображень, перевірка всіх форматів і роздільних здатностей.
- Деплой: документація з розгортання, моніторинг (метрики часу обробки, пам'яті).
Терміни орієнтовно: від 2 до 5 робочих днів залежно від складності інтеграції (кількість форматів, S3, водяний знак). Вартість розраховується індивідуально після аудиту вашого проекту. Економія на серверних ресурсах — до 70% витрат на CPU та пам'ять.
Що входить у роботу
- Готовий пайплайн обробки зображень (resize, конвертація, водяний знак).
- Інтеграція з вашим веб-сервером (Express, Fastify, Next.js API routes).
- Документація з деплою та налаштування (змінні середовища, ліміти форків Sharp).
- Доступ до репозиторію з кодом.
- Гарантія підтримки протягом 2 тижнів після здачі.
Типові помилки при інтеграції
- Забули про concurrency: Sharp використовує всі ядра — в продакшені обмежте
sharp.concurrency(2)та чергу через p-limit. - Не перевіряєте формат через metadata: MIME-тип можна підробити. Sharp автоматично визначить реальний формат — використовуйте
meta.format. - Зберігаєте EXIF з GPS: при публічній публікації видаляйте метадані
.withMetadata(false), інакше витік координат.
Оцінимо ваш проект безкоштовно — просто надішліть поточний код обробки. Отримайте консультацію з оптимізації зображень без купівлі дорогих бібліотек.
// Пример конвейера с защитой от decompression bomb
async function safeProcess(buffer) {
try {
const meta = await sharp(buffer).metadata()
if (meta.width * meta.height > 50_000_000) {
throw new Error('Image too large: exceeds 50MP limit')
}
return await sharp(buffer)
.rotate()
.resize(2000, 2000, { fit: 'inside', withoutEnlargement: true })
.webp({ quality: 82 })
.toBuffer()
} catch (err) {
if (err.message.includes('Input buffer contains unsupported image format')) {
throw new TypeError('Unsupported image format')
}
throw err
}
}
Наш досвід: 10+ років у веб-розробці, 50+ проектів з інтеграцією Sharp. Гарантуємо сумісність з вашим стеком.







