как проще всего обрезать фото пропорционально к примеру 200px по ширине перед сохранением?Laravel

public function store(Request $request) {
        $image = $request->file('image');
        //перед сохранением изменить размер пропорционально к примеру если было загружено 2000 на 1000px то по ширине к примеру сделать 200p а высота пропорционально чтобы уменьшилась
        if ($image) {
            $path_image = $image->store('uploads', 'public');
        }
}

спасибо!

Ответы (1 шт):

Автор решения: Алексей Лапин

PHP не умеет изменять размер существующего изображения. Но он умеет копировать кусок изображения с последующим изменением размера. С помощью этого лайфхака можно реализовать функцию resize().

/**
 * Resize of image
 *
 * @param int    $desiredWidth Ширина, до которой нужно обрезать
 * @param string $path         Путь до файла, которое нужно обрезать
 * @param string $destination  Путь до файла, куда сохранить получившееся изображение
 * @param int    $quality      Качество обрезанного изображения (в процентах)
 *
 * @return void
 * @throws Exception
 */
public function resize(int $desiredWidth, string $path, string $destination, int $quality = 80) 
{
    $binary = file_get_contents($path);
    $imageSize = !empty($binary) ? getimagesizefromstring($binary) : null;

    // Проверяем, что файл не пустой
    if (!$imageSize) {
        throw new Exception("Файл пустой");
    }

    // Получаем размер файла
    [0 => $width, 1 => $height] = $imageSize;

    // Создаем "виртуальное" изображение в памяти
    $sourceImage = imagecreatefromstring($binary);

    // Если файл больше, чем нам нужно, то обрезаем
    if ($desiredWidth < $width) {
        // Высчитываем высоту по пропорции
        $desiredHeight = floor($height * ($desiredWidth / $width));
        // Результирующее "виртуальное" изображение в памяти, в которое будем копировать первоначальное изображение
        $virtualImage = imagecreatetruecolor($desiredWidth, $desiredHeight);

        // Копируем изначальное изображение в результирующее
        imagecopyresampled($virtualImage, $sourceImage, 0, 0, 0, 0, $desiredWidth, $desiredHeight, $width, $height);
        // Сохраняем результирующее изображение
        imagejpeg($virtualImage, $destination, $quality);
    } else if($path !== $destination) {
        // Первоначальное изображение оказалось меньше, чем нам нужно
        // Поэтому просто копируем файл
        copy($path, $destination);
    }
}

Для вашего примера, нужно использовать так:

public function store(Request $request) {
    $image = $request->file('image');

    // Сначала сохраняем файл, который прислал клиент
    if ($image) {
        $pathImage = $image->store('uploads', 'public');
        // Точно не помню, что содержится в $pathImage.
        // Если там абсолютный путь (/var/www/...), то используем переменную "как есть"
        // Если же там относительный путь (public/...), то его нужно преобразовать в абсолютный:
        // $pathPage = storage_path('app/' . $pathImage);
        resize(200, $pathImage, $pathImage);
    }
}

P.s. Также рекомендую использовать данную функцию при каждом сохранении изображения. Так как через изображение может быть совершена атака на ваш сервер (подробнее тут https://www.securitylab.ru/analytics/456285.php). То есть идея в том, что если изменять размер не нужно, то в качестве $desiredWidth в resize() передаем реальный размер изображения. При копировании куска изображения, PHP удаляет комментарии из изображения, тем самым блокирую возможность провести атаку

→ Ссылка