Resize ảnh trong Laravel

84

Chào các bạn,

Hình ảnh là một trong những nội dung phổ biến nhất trên bất kỳ website nào, vì vậy mà thao tác xử lý ảnh cũng thường xuyên xảy ra. Một trong những thao tác xử lý ảnh phổ biến nhất mà các developer thường phải làm xử lý đó chính là “Resize”, vậy làm sao để resize hình ảnh trong dự án Laravel thì các bạn hãy theo dõi bài hướng dẫn này của mình nhé.

I. Resize ảnh là gì, tại sao cần resize ảnh?

Resize ảnh là thao tác làm thay đổi kích thước (size) của hình ảnh để phù hợp hơn với các chúng hiển thị trên website.

Ví dụ một ảnh có kích thước thực tế (kích thước gốc) là 1000×1000, tuy nhiên nó chỉ được hiển thị với kích thước 100×100 trên website của bạn. Điều này rõ ràng không cần thiết và gây lãng phí tài nguyên máy chủ, chưa kể hình ảnh nặng sẽ khiến trình duyệt tải lâu hơn, khiến người dùng phải đợi lâu hơn.

Để hình ảnh có kích thước phù hợp với cách chúng hiển thị, khi tải lên một bức ảnh các developer sẽ sinh ra thêm một số phiên bản khác với các kích thước khác nhau, ví dụ như:

  • Thumbnail: Có kích thước 150×150
  • Medium: Có kích thước 400×400
  • Large: Có kích thước 600×600
  • Original: Kích thước ảnh gốc

Với các mốc kích thước trên, tùy trường hợp chúng ta sẽ lựa chọn một phiên bản khác nhau để phù hợp với các hiển thị.

II. Resize ảnh trong Laravel

Để resize ảnh trong Laravel, mình sẽ sử dụng một package có tên là Intervention Image. Package này cũng có tài liệu chính thức về việc sử dụng kết hợp với Laravel – Bạn có thể tham khảo thêm.

2.1 Tích hợp Intervention Image

Ở đây mình sử dụng Laravel 5.5, các phiên bản Laravel khác cũng tượng tự.

Bước 1: Tích hợp vào dự án thông qua Composer

composer require intervention/image

Bước 2: Thêm provider và alias cần thiết

Trong dự án Laravel, bạn mở config/app.php, thêm các thông tin sau.

<?php

// config/app.php

'prodivers' => [
    //...
    Intervention\Image\ImageServiceProvider::class
],

'alias' => [
    //...
    'Image' => Intervention\Image\Facades\Image::class
]

Bước 3: Publish các file cần thiết

php artisan vendor:publish --provider="Intervention\Image\ImageServiceProviderLaravelRecent"

Sau khi chạy xong command trên, một file mới config/image.php sẽ được thêm mới vào dự án của bạn, đó là nơi chưa các thông tin cấu hình của thư viện Intervention Image này.

2.2 Resize ảnh với Intervention Image

Trước khi thực hiện ở phần này, bạn hãy chọn trước cho mình một bức ảnh có kích thước lớn chút, tầm 1000×1000 chẳng hạn. Chúng ta sẽ dùng tấm hình này để làm demo cho việc resize ảnh.

Mình sẽ thực hiện resize bức ảnh gốc thành 3 kích thước khác nữa đó là 150×150 (Thumbnail), 400×400 (Medium) 600×600 (Large).

Bắt đầu nào.

Bước 1: Tạo 1 Controller và 1 route tương tứng để test.

php artisan make:controller ImageController
<?php

// routes/web.php

Route::get('test', '[email protected]');

Bước 2: Resize ảnh thành 3 kích thước

Trong App\Http\Controllers\ImageController, mình tạo một action resize với nội dung như sau

<?php

// app\Http\Controllers\ImageController.php

// use Image;

public function resize()
{
    $image = Image::make('/path/to/image.jpg');
    $image->fit(600, 600)->save('path/to/save/large.jpg');
    $image->fit(400, 400)->save('path/to/save/medium.jpg');
    $image->fit(150, 150)->save('path/to/save/thumbnail.jpg');
    
    return 'Done';
}

Mình sử dụng fit() thay vì resize() hay crop() là vì muốn giữ nguyên tỷ lệ ảnh, và việc resize ảnh nhỏ dần (từ 600 – 400 – 150) là một điều quan trọng.

Bạn nhớ thay path/to/image.jpg thành đường dẫn tới file ảnh gốc, path/to/save/thumbnail.jpg, path/to/save/medium.jpg, path/to/save/large.jpg thành đường dẫn tới các phiên bản ảnh có kích thước tương ứng nhé.

Bước 3: Thử nghiệm

Khởi động Laravel serve

php artisan serve

Truy cập vào http://localhost:8080/test để kích hoạt tính năng resize. Sau đó kiểm tra xem các file ảnh với các kích thước kể trên có được tạo ra trong dự án của bạn không nhé.

Bạn có thể kết hợp resize ảnh như trên với việc upload ảnh, sẽ rất tuyệt vời đấy.

2.3 Resize fly image

Với cách reszie như trên, chúng ta tạo sẵn ra những hình ảnh với kích thước khác nhau để khi nào cần đến sẽ lấy ra sử dụng. Tuy nhiên có nhiều bạn sẽ không thích làm cách này bởi nó tốn dung lượng để lưu trữ trong trường hợp bạn tạo ra 3 kích thước khác nhau nhưng không mấy khi sử dụng cả 3 kích thước này cả. Vậy thì mình sẽ gợi ý thêm tới bạn cách số 2 này – Resize fly image.

Ý tưởng của cách này là chúng ta sẽ không tạo ra hình ảnh với các kích thước khác nhau trước, mà khi nào cần tới thì mới tạo – sẽ tiết kiệm được dung lượng lưu trữ trong trường hợp mình kể trên.

Chi tiết ý tưởng như sau

Giả sử mình có hình ảnh gốc nằm ở http://domain/images/demo.jpg – tại thời điểm này chưa hề có bất kỳ một phiên bản resize nào khác. Khi dùng thước thumbnail, mình sẽ gọi tới http://domain/resizes/thumbnail/images/demo.jpg. Khi dùng kích thước medium, mình sẽ gọi tới http://domain/resizes/medium/images/demo.jpg, tương tự với kích thước large.

Ban đầu mình có nói chưa hề có bất kỳ phiên bản resize nào, vậy thì khi truy cập vào các link thumbnail, medium, larage thì lấy đâu ra ảnh? Bạn cứ giữ câu hỏi này nhé, cuối mục này sẽ rõ.

Triển khai ý tưởng

Bạn mở routes/web.php thêm routes mới sau:

<?php

// routes/web.php

Route::get('resizes/{size}/{imagePath}', '[email protected]')->where('imagePath', '(.*)');

Mở config/image.php bổ sung thêm thông tin cấu hình sau:

<?php

// config/image.php

//...

'sizes' => [
    'thumbnail' => [150, 150],
    'medium' => [400, 400],
    'larage' => [600, 600],
],

Trong App\Http\Controllers\ImageController, tạo action flyResize như sau:

<?php

// app\Http\Controllers\ImageController.php

// use Image;

public function flyResize($size, $imagePath)
{
    $imageFullPath = public_path($imagePath);
    $sizes = config('image.sizes');

    if (!file_exists($imageFullPath) || !isset($sizes[$size])) {
        abort(404);
    }

    $savedPath = public_path('resizes/' . $size . '/' . $imagePath);
    $savedDir = dirname($savedPath);
    if (!is_dir($savedDir)) {
        mkdir($savedDir, 777, true);
    }

    list($width, $height) = $sizes[$size];

    $image = Image::make($imageFullPath)->fit($width, $height)->save($savedPath);

    return $image->response();
}

Khởi tạo Laravel serve

php artisan serve

Thưởng thức kết quả.

Bạn lần lượt truy cập vào http://localhost:8000/resizes/thumbnail/images/demo.jpg, http://localhost:8000/resizes/medium/images/demo.jpg, http://localhost:8000/resizes/larage/images/demo.jpg sẽ thấy hình ảnh được resize theo kích thước phù hợp.

Mình có chụp lại kết quả resize ở bên dưới để các bạn tiện theo dõi.

Bạn đã biết tại sao ban đầu mặc dù chưa có phiên bản resize nào, nhưng khi chúng ta truy cập vào link ảnh thumbnail, link ảnh medium, link ảnh large thì vẫn thấy xuất hiện ảnh chưa? Nếu chưa biết thì hãy xem lại phần route và action flyResize trong ImageController nhé.

Nhớ chmod quyền ghi cho thư mục public nhé. Bạn có thể chmod thành 777 hoặc 755 chẳng hạn.

III. Tổng kết

Đây là một trick nhỏ mà mình hay sử dụng trong các dự án, hy vọng sẽ bổ ích với bạn.