---
title: "Валідація та конвертація HEIC зображень у Laravel"
url: https://laravelukraine.com/blog/validaciia-ta-konvertaciia-heic-zobrazen-u-laravel
date: 2026-08-08
source: https://laravel-news.com/laravel-heic-image-uploads?utm_medium=feed&utm_source=feedpress.me&utm_campaign=Feed%3A+laravelnews
---

# Валідація та конвертація HEIC зображень у Laravel

Кожен iPhone, проданий за останні кілька років, знімає у форматі HEIC за замовчуванням. Файл приблизно вдвічі менший за еквівалентний JPEG тієї ж якості, саме тому Apple перейшла на цей формат. Проте Chrome та Firefox не вміють рендерити HEIC. Застосунок, що приймає завантаження фото з телефонів, має десь це обробляти, і до недавнього часу компонент зображень Laravel не був тим місцем: HEIC файли відхилялися ще до того, як потрапляли до драйвера.

Laravel 13.24 приймає HEIC, HEIF та AVIF як вхідні дані, додає метод `toHeic()` для виводу та навчає правило валідації `image` розпізнавати всі три формати. У цій статті розглянемо, як приймати фото з телефону та віддавати його у форматі, зрозумілому для браузерів.

## Що потрібно вашому серверу

Декодування HEIC - це не те, що PHP робить самостійно. Воно надходить від HEIF делегата ImageMagick, побудованого на libheif, тому вам потрібне розширення Imagick з цим скомпільованим делегатом. Драйвер GD взагалі не може читати HEIC, незалежно від версії PHP.

Багато дистрибутивних пакетів постачають ImageMagick без HEIF делегата, тому перевірте, а не припускайте:

```
php -r "print_r(Imagick::queryFormats('HEI*'));"
```

Порожній масив означає, що розширення встановлено, але не може працювати з цими файлами. У Debian та Ubuntu делегат знаходиться в пакеті `libheif1`, а в macOS формула Homebrew `imagemagick` включає його. AVIF більш толерантний, оскільки GD теж може його декодувати, якщо PHP було зібрано з libavif.

Встановіть Intervention Image, якщо ще не зробили цього, оскільки він підтримує обидва драйвери:

```
composer require intervention/image:^4.0
```

## Валідація завантаження

Правило `image` перевіряє файл на відповідність фіксованому списку типів зображень, і цей список тепер включає `heic`, `heif` та `avif`:

```
$request->validate([
    'photo' => ['required', 'image', 'max:12288'],
]);
```

Нічого налаштовувати не потрібно. Фото, зняте на iPhone і завантажене прямо з камери, тепер проходить валідацію там, де раніше видавало помилку "The photo field must be an image."

Якщо ви хочете бути явними щодо того, які формати приймаєте, правило `mimes` приймає ті ж розширення:

```
'photo' => ['required', 'mimes:jpg,png,webp,heic', 'max:12288'],
```

Зауважте, що HEIC завантаження надходять з різними MIME типами залежно від клієнта, найпоширеніші - `image/heic` та `image/heif`. Правила `image` та `mimes` визначають тип із вмісту файлу, а не довіряють браузеру, тому обидва варіанти обробляються однаково.

## Конвертація під час завантаження

Прийняти файл - це лише половина справи. Якщо зберегти HEIC як є, більшість відвідувачів побачать зламане зображення. Рішення - конвертувати під час завантаження, що робиться кількома рядками через API зображень:

```
use App\Models\Photo;
use Illuminate\Http\Request;

public function store(Request $request)
{
    $request->validate([
        'photo' => ['required', 'image', 'max:12288'],
    ]);

    $path = $request->image('photo')
        ->usingImagick()
        ->orient()
        ->scale(width: 2000)
        ->toWebp()
        ->quality(80)
        ->store('photos');

    return Photo::create(['path' => $path]);
}
```

Два моменти варті уваги. `usingImagick()` тут тому, що драйвер за замовчуванням - GD, який не працює з HEIC. А `orient()` читає метадані орієнтації та повертає зображення відповідно, що важливіше для фото з телефонів, ніж для будь-чого іншого, оскільки портретний знімок зазвичай зберігається як горизонтальний кадр з прапорцем повороту.

Збережений файл автоматично отримує правильне розширення. `store()` будує хешоване ім'я файлу з вихідного формату, тому HEIC завантаження, конвертоване у WebP, потрапляє як `photos/{hash}.webp`.

## Видача AVIF з WebP фолбеком

Якщо ви хочете менший файл там, де це підтримується, згенеруйте обидва варіанти з одного джерела. Кожна трансформація повертає новий екземпляр, тому розгалуження не спричиняє витоку стану між ними:

```
$source = $request->image('photo')->usingImagick()->orient()->scale(width: 2000);

$avif = $source->toAvif()->quality(70)->storeAs('photos', "{$id}.avif");
$webp = $source->toWebp()->quality(80)->storeAs('photos', "{$id}.webp");
```

Потім дозвольте браузеру вибрати:

```
<picture>
    <source srcset="{{ Storage::url("photos/{$photo->id}.avif") }}" type="image/avif">
    <img src="{{ Storage::url("photos/{$photo->id}.webp") }}" alt="{{ $photo->caption }}">
</picture>
```

AVIF зазвичай на 20-30 відсотків менший за WebP при візуально порівнянній якості, ціною повільнішого кодування. Якщо ваші завантаження синхронні, цей час кодування з'являється в запиті, тому це гарний кандидат для черги завдань, коли ви обробляєте більше одного розміру.

## Запис HEIC

Вивід теж працює через `toHeic()` або `optimize('heic')`:

```
Image::fromPath(storage_path('app/photo.jpg'))
    ->usingImagick()
    ->toHeic()
    ->quality(80)
    ->store('photos');
```

Це вужчий випадок використання, ніж читання HEIC, але він трапляється: архів або експорт, який відкриватиметься на Apple пристроях, або конвеєр, що зберігає оригінальний формат під час обробки.

Псевдонім `heif` нормалізується до HEIC скрізь, тому `optimize('heif')` створює той самий вивід, що й `optimize('heic')`, файли зберігаються з канонічним розширенням `.heic`, а `mimeType()` повідомляє `image/heic`. `Image::extension()` також розпізнає псевдоніми MIME типів `image/x-heic` та `image/x-avif`, які надсилають деякі клієнти, відображаючи їх на `heic` та `avif` замість пропуску.

## Коли формат не підтримується

Якщо файл потрапляє до драйвера у форматі, який компонент не обробляє, ви отримуєте `ImageException` з типом у повідомленні:

```
The image format [image/tiff] is not supported.
```

Валідація спочатку правилом `image` ловить майже всі такі випадки, але виняток також з'явиться, коли HEIC файл потрапить до збірки Imagick без HEIF делегата. Це проблема розгортання, а не користувача, тому варто перевірити делегата на сервері як частину релізу, а не виявляти це зі звіту про помилку.

Для будь-чого старішого за 13.24 або коли вам потрібна конвертація поза Laravel, стаття про конвертацію HEIC у JPEG у PHP охоплює ручний підхід.

## Додаткове читання

- Практичний посібник з першокласної обробки зображень Laravel охоплює повний API трансформації та зберігання
- Домінантний колір зображення в Laravel добре поєднується з цим, оскільки конвертоване фото може безкоштовно нести колір-заповнювач
- Домінантний колір зображення та підтримка HEIC у Laravel 13.24 містить повні нотатки релізу
- Підтримка HEIC та AVIF була внесена [@riasvdv](https://github.com/riasvdv) у [#60922](https://github.com/laravel/framework/pull/60922)
