Реалізація конвеєра обробки зображень (resize, crop, watermark, format conversion)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація конвеєра обробки зображень (resize, crop, watermark, format conversion)
Середня
~3-5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація конвейера обробки зображень (resize, crop, watermark, format conversion)

Image Processing Pipeline — автоматизована послідовність операцій над зображеннями: зміна розміру, обрізка, накладення водяного знака, конвертація форматів. Виконується при завантаженні або за запитом для оптимізації сховища і покращення швидкості завантаження.

Архітектура pipeline

Upload → Validation → Processing Queue → Transform → Storage → CDN
                                              ↓
                               resize → crop → watermark → convert → compress

Синхронний pipeline (при завантаженні)

// Node.js + Sharp
const sharp = require('sharp')
const path = require('path')

class ImagePipeline {
  constructor(config) {
    this.config = config
  }

  async process(inputBuffer, filename) {
    const ext = path.extname(filename).toLowerCase()
    const baseName = path.basename(filename, ext)
    const results = {}

    // Базова обробка
    const image = sharp(inputBuffer)
    const metadata = await image.metadata()

    // Конвертація в WebP для всіх форматів
    const webp = await this._toWebP(image.clone(), metadata)
    results.webp = webp

    // Генерація превью різних розмірів
    for (const [size, dims] of Object.entries(this.config.sizes)) {
      results[size] = await this._resize(image.clone(), dims)
      results[`${size}_webp`] = await this._resize(image.clone(), dims, 'webp')
    }

    // Водяний знак для публічних зображень
    if (this.config.watermark) {
      results.watermarked = await this._addWatermark(image.clone())
    }

    return results
  }

  async _resize(image, { width, height, fit = 'inside' }, format = null) {
    let processed = image.resize(width, height, {
      fit,
      withoutEnlargement: true,
      background: { r: 255, g: 255, b: 255, alpha: 1 }
    })

    if (format === 'webp') {
      processed = processed.webp({ quality: 85, effort: 4 })
    } else {
      processed = processed.jpeg({ quality: 85, mozjpeg: true })
    }

    return processed.toBuffer()
  }

  async _toWebP(image, metadata) {
    return image
      .webp({ quality: 85, effort: 4, smartSubsample: true })
      .toBuffer()
  }

  async _addWatermark(image) {
    const watermark = await sharp('./assets/watermark.png')
      .resize(200)
      .toBuffer()

    return image
      .composite([{
        input: watermark,
        gravity: 'southeast',
        blend: 'over'
      }])
      .toBuffer()
  }
}

const pipeline = new ImagePipeline({
  sizes: {
    thumbnail: { width: 150, height: 150, fit: 'cover' },
    medium: { width: 800, height: 600 },
    large: { width: 1920, height: 1080 },
  },
  watermark: true
})

Асинхронний pipeline через чергу

Для високого навантаження — обробка у фоні:

# tasks.py (Celery)
from celery import Celery
from PIL import Image
import io, boto3

app = Celery('image_tasks', broker='redis://redis:6379')

@app.task(bind=True, max_retries=3)
def process_image(self, image_id: int):
    try:
        # Завантажити вихідне зображення
        record = db.get_image(image_id)
        raw = s3.get_object(Bucket='uploads', Key=record.original_key)['Body'].read()

        img = Image.open(io.BytesIO(raw))

        # Нормалізувати EXIF-орієнтацію
        img = ImageOps.exif_transpose(img)

        # Конвертувати RGBA → RGB для JPEG
        if img.mode == 'RGBA':
            background = Image.new('RGB', img.size, (255, 255, 255))
            background.paste(img, mask=img.split()[3])
            img = background

        variants = {}
        for name, (w, h) in SIZES.items():
            resized = img.copy()
            resized.thumbnail((w, h), Image.LANCZOS)

            # Зберегти як WebP
            buf = io.BytesIO()
            resized.save(buf, 'WEBP', quality=85, method=6)
            buf.seek(0)

            key = f"processed/{image_id}/{name}.webp"
            s3.put_object(
                Bucket='media',
                Key=key,
                Body=buf,
                ContentType='image/webp',
                CacheControl='public, max-age=31536000'
            )
            variants[name] = key

        db.update_image_variants(image_id, variants)

    except Exception as exc:
        raise self.retry(exc=exc, countdown=60)

On-the-fly трансформація (imgproxy)

Альтернатива передгенерації — imgproxy: сервіс, який трансформує зображення за URL:

docker run -p 8080:8080 \
  -e IMGPROXY_KEY=YOUR_KEY \
  -e IMGPROXY_SALT=YOUR_SALT \
  -e IMGPROXY_MAX_SRC_RESOLUTION=50 \
  darthsim/imgproxy
import hmac, hashlib, base64

def sign_imgproxy_url(path: str, key: str, salt: str) -> str:
    encoded = base64.urlsafe_b64encode(
        hmac.new(
            bytes.fromhex(key),
            bytes.fromhex(salt) + path.encode(),
            hashlib.sha256
        ).digest()
    ).rstrip(b'=').decode()
    return encoded

# Формат URL: /SIGNATURE/resize:fit:WIDTH:HEIGHT:ENLARGE/format:webp/base64(URL)
source_url = base64.urlsafe_b64encode(b'https://storage.com/original/photo.jpg').decode()
path = f"/resize:fill:800:600:1/format:webp/{source_url}"
signature = sign_imgproxy_url(path, IMGPROXY_KEY, IMGPROXY_SALT)

image_url = f"https://img.company.com/{signature}{path}"

Термін виконання

Реалізація image processing pipeline з Sharp або imgproxy + інтеграція з S3 — 2–3 робочих дні.