Реалізація генерації мініатюр (Thumbnails) для зображень на сайті

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

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

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

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація генерації мініатюр (Thumbnails) для зображень на сайті
Середня
~2-3 робочих дні
Часті питання

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

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

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

  • 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

Генерація мініатюр зображень

Генерація мініатюр перетворює завантажені зображення на кілька розмірів для різних контекстів (список, карточка, повноразмірний перегляд) без втрати оригіналу.

Laravel: Intervention Image + черга

// Модель з автоматичною генерацією мініатюр
class Image extends Model
{
    const SIZES = [
        'thumb'  => [200, 200],
        'medium' => [600, 400],
        'large'  => [1200, 800],
    ];
}

// Job для асинхронної генерації
class GenerateImageThumbnails implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    public function __construct(private Image $image) {}

    public function handle(): void
    {
        $originalPath = Storage::disk('s3')->path($this->image->path);
        $img = \Intervention\Image\Facades\Image::make($originalPath);

        foreach (Image::SIZES as $size => [$width, $height]) {
            $resized = clone $img;
            $resized->fit($width, $height);  // crop по центру

            $thumbPath = str_replace('original/', "{$size}/", $this->image->path);
            Storage::disk('s3')->put($thumbPath, $resized->encode('webp', 85)->__toString());
        }

        $this->image->update(['processed' => true]);
    }
}

// Контроллер завантаження
public function store(Request $request): JsonResponse
{
    $path = Storage::disk('s3')->putFile('original', $request->file('image'));

    $image = Image::create([
        'path'       => $path,
        'user_id'    => auth()->id(),
        'processed'  => false,
    ]);

    GenerateImageThumbnails::dispatch($image);

    return response()->json(['id' => $image->id]);
}

Node.js: Sharp

Sharp — найшвидша бібліотека Node.js для обробки зображень (на базі libvips).

import sharp from 'sharp';
import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';

const SIZES = {
  thumb:  { width: 200, height: 200 },
  medium: { width: 600, height: 400 },
  large:  { width: 1200, height: 800 },
} as const;

async function generateThumbnails(s3Key: string): Promise<Record<string, string>> {
  const s3 = new S3Client({ region: 'eu-west-1' });

  // Завантажити оригінал
  const { Body } = await s3.send(new GetObjectCommand({
    Bucket: process.env.S3_BUCKET!,
    Key: s3Key,
  }));

  const buffer = Buffer.from(await (Body as any).transformToByteArray());

  const results: Record<string, string> = {};

  await Promise.all(
    Object.entries(SIZES).map(async ([name, { width, height }]) => {
      const thumbnail = await sharp(buffer)
        .resize(width, height, { fit: 'cover', position: 'centre' })
        .webp({ quality: 85 })
        .toBuffer();

      const thumbKey = s3Key.replace('original/', `${name}/`).replace(/\.[^.]+$/, '.webp');

      await s3.send(new PutObjectCommand({
        Bucket: process.env.S3_BUCKET!,
        Key: thumbKey,
        Body: thumbnail,
        ContentType: 'image/webp',
        CacheControl: 'public, max-age=31536000',
      }));

      results[name] = thumbKey;
    })
  );

  return results;
}

Ледаяча генерація через Glide (PHP)

Glide генерує мініатюри за запитом із підписаним URL:

// Маршрут для зображень
Route::get('/img/{path}', function (Request $request, string $path) {
    $server = League\Glide\ServerFactory::create([
        'source'    => Storage::disk('s3')->getDriver(),
        'cache'     => Storage::disk('local')->getDriver(),
        'cache_path_prefix' => '.cache',
        'base_url'  => '/img',
        'max_image_size' => 2000 * 2000,
    ]);

    // Перевірка підпису URL
    League\Glide\Signatures\SignatureFactory::create(config('app.key'))
        ->validateRequest('/img/' . $path, $request->all());

    return $server->getImageResponse($path, $request->all());
})->where('path', '.*');

// Генерація підписаного URL
$url = (new League\Glide\Urls\UrlBuilderFactory)
    ->create('/img', config('app.key'))
    ->getUrl('uploads/photo.jpg', ['w' => 400, 'h' => 300, 'fit' => 'crop']);

Формати та оптимізація

// Вибір формату за підтримкою браузером
const output = sharp(buffer)
  .resize(800)
  .toFormat(supportsAvif ? 'avif' : supportsWebp ? 'webp' : 'jpeg', {
    quality: supportsAvif ? 60 : supportsWebp ? 80 : 85,
  });

AVIF дає 50% економію відносно JPEG при тій же якості. WebP підтримується всіма сучасними браузерами. Для максимальної сумісності використовують <picture> з кількома форматами.

Терміни реалізації

Генерація мініатюр в черзі (Laravel Job або BullMQ Worker) із збереженням в S3: 2–3 дні. З ленивою генерацією через Glide та кешуванням CDN: 3–4 дні.