When handling images in your Laravel applications, you may sometimes be required to edit them. This could include resizing, cropping, or converting images to meet a given criteria. For example, you may want to crop and resize all user avatar image uploads to a fixed-sized square.
In this article, we'll examine how to use the Intervention Image (intervention/image
) package in Laravel to edit images. We'll cover common tasks such as reading, storing, resizing, cropping, rotating, converting, and watermarking images.
What is Intervention Image?
Intervention Image is an open-source PHP image-processing library that allows you to create and edit images in PHP.
It serves as a wrapper around the GD and Imagick libraries using a unified, expressive, and readable API. This means you can switch between these two PHP image-processing libraries without changing your code.
If you need to work with images in your PHP and Laravel projects, the Intervention Image library is a great tool to have in your arsenal.
For a full list of its features, check out the official documentation.
When to use intervention/image
in Laravel
There are many times when you may need to edit images in your Laravel projects. Some common use cases include:
- Resizing - Resizing avatar uploads to a fixed size (e.g. - 250 x 250px)
- Cropping - For example, cropping a square image from a rectangular image when an avatar is uploaded.
- Rotating - For example, rotating an image to the correct orientation based on exchangeable image file (EXIF) data.
- Converting - Converting images to different formats (e.g. - PNG to JPEG).
- Watermarking - Adding a watermark to images (e.g. - adding a company logo to images before they're exported/downloaded).
Installing intervention/image
in Laravel
Before we get started, it's important to note that the Intervention Image library requires either the "GD" or "Imagick" PHP libraries for image processing. We won't be covering how to install either of these in this article. However, depending on your PHP setup, you may already have one of these libraries installed and available.
Although Intervention Image is a framework-agnostic package, there's a Laravel-specific package that provides a service provider, configuration file, and facade to make it easier to use in Laravel projects. In this article, we'll use this Laravel-specific package, called intervention/image-laravel
.
To get started, we need to install the package via Composer using the following command:
composer require intervention/image-laravel
The package should now be installed and ready to use for image processing.
If you wish, you can also publish the package's configuration file using the following command:
php artisan vendor:publish --provider="Intervention\Image\Laravel\ServiceProvider"
Running the above command will create a new config/image.php
config file that looks like so:
return [
/*
|--------------------------------------------------------------------------
| Image Driver
|--------------------------------------------------------------------------
|
| Intervention Image supports “GD Library” and “Imagick” to process images
| internally. Depending on your PHP setup, you can choose one of them.
|
| Included options:
| - \Intervention\Image\Drivers\Gd\Driver::class
| - \Intervention\Image\Drivers\Imagick\Driver::class
|
*/
'driver' => \Intervention\Image\Drivers\Gd\Driver::class,
/*
|--------------------------------------------------------------------------
| Configuration Options
|--------------------------------------------------------------------------
|
| These options control the behavior of Intervention Image.
|
| - "autoOrientation" controls whether an imported image should be
| automatically rotated according to any existing Exif data.
|
| - "decodeAnimation" decides whether a possibly animated image is
| decoded as such or whether the animation is discarded.
|
| - "blendingColor" Defines the default blending color.
*/
'options' => [
'autoOrientation' => true,
'decodeAnimation' => true,
'blendingColor' => 'ffffff',
]
];
You may want to review this configuration file and make any necessary changes to suit your application's needs. For example, the config is set to use the GD library driver by default (set via the driver
key), but you may wish to update it to use the Imagick driver if you have it installed and that's your desired driver (by setting the value to \Intervention\Image\Drivers\Imagick\Driver::class
).
Reading Images
Now that the package is ready to use in our Laravel project, let's walk through how to read images ready for image processing using the package.
To keep the examples simple in this article, we'll be reading and storing images in our local filesystem. So, we'll assume that our filesystems.default
configuration is set to local
as our desired driver in our config/filesystems.php
file so we can read and write images to the storage/app/private
directory.
If you wish to use a different filesystem (such as AWS S3), the approach to reading and writing files may be slightly different.
Let's say we want to open an image stored in our storage/app/private/images
directory called avatar-image.jpg
. We can do so using the following code:
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Laravel\Facades\Image;
$imageFromStorage = Storage::get('images/avatar-image.jpg');
$image = Image::read($imageFromStorage);
// Perform any image manipulation here...
In the code example above, we've started by reading the file contents of the avatar-image.jpg
file using the Storage::get
method. We then pass the contents of the image to the read
method of the Intervention\Image\Laravel\Facades\Image
facade to read the image. As a result, the $image
variable will now be an instance of the Intervention\Image\Interfaces\ImageInterface
interface. In this particular use case, it will be an example of the Intervention\Image\Image
class.
Alternatively, rather than passing the image contents to the Intervention\Image\Laravel\Facades\Image::read
method, you can pass the path to the image file directly. For example:
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Laravel\Facades\Image;
$imageFromStorage = Storage::path('images/avatar-image.jpg');
$image = Image::read($imageFromStorage);
// Perform any image manipulation here...
In the example above, we're using Storage::path
to get the full path to the avatar-image.jpg
file. We then pass this path to the Intervention\Image\Laravel\Facades\Image::read
method to read the image.
If you're working with file uploads, you can also pass the uploaded file directly to the Intervention\Image\Laravel\Facades\Image::read
method. For example, let's imagine you have a simple POST /avatar
route (we've ignored any validation or authorization here for the sake of brevity) that accepts an uploaded avatar
image. We could read the uploaded image like so:
use Illuminate\Http\Request;
use Intervention\Image\Laravel\Facades\Image;
use Illuminate\Support\Facades\Route;
Route::post('/avatar', function (Request $request) {
$image = Image::read($request->file('avatar'));
// Perform any image manipulation here...
});
Although it's possible to read the file directly from the request, you may want to consider saving the uploaded file first and then performing any edits in a queued job. By processing the image editing in queued jobs, you can avoid blocking the request and reduce the response time for the user. However, this is all dependent on things such as the size of the image, the actions you're performing, and the resources available to your application. So you'll want to decide what's best for your specific use case.
Reading Image Meta Information
Now that we know how to read images using the package, let's take a look at the common tasks we might want to perform on images. We'll start by looking at how to read the image meta information.
For the examples in this article, we'll be working with this image from Pixabay (dimensions: 5760 x 3840px):
To read the exchangeable image file (EXIF) data, we can use the exif
method on the Intervention\Image\Image
object. This will return an instance of the Intervention\Image\Collection
class which contains the EXIF data:
$image = Image::read(Storage::get('images/avatar-image.jpg'));
$exifData = $image->exif();
// Use "dd" so we can inspect the contents of the $exifData variable
dd($exifData);
In the example, we've read the EXIF data and then used dd
so that we can dump the contents of the returned Intervention\Image\Collection
object and we can see what type of information is available. If the EXIF data isn't available, the exif
method will return null
. The contents of the EXIF data (output using the dd
function in the code example above) may look something like this:
Intervention\Image\Collection {
#items: [
"FILE" => [
"FileDateTime" => 0
"FileSize" => 2140901
"FileType" => 2
"MimeType" => "image/jpeg"
"SectionsFound" => ""
]
"COMPUTED" => [
"html" => 'width="5760" height="3840"'
"Height" => 3840
"Width" => 5760
"IsColor" => 1
]
]
}
Let's say we wanted to fetch just the filesize of the image (in bytes) via the FILE.FileSize
value, we could do so like this:
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
$image = Image::read(Storage::get('images/avatar-image.jpg'));
$filesize = $image->exif('FILE.FileSize');
// $filesize will be an integer equal to: 2140901
The package also provides similar methods to get the height and width of the image. For example, to get the height and width of the image, we can use the height
and width
methods:
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
$image = Image::read(Storage::get('images/avatar-image.jpg'));
$height = $image->height(); // Integer equal to: 3840
$width = $image->width(); // Integer equal to: 5760
You may also want to read the resolution of the image. To do this, you can use the resolution
method which will return an instance of the Intervention\Image\Interfaces\ResolutionInterface
interface:
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
$image = Image::read(Storage::get('images/avatar-image.jpg'));
$resolution = $image->resolution();
// $resolution will be an instance of:
// Intervention\Image\Interfaces\ResolutionInterface
// Get the specific x and y resolution values
$xResolution = $resolution->x(); // Float equal to: 72.0
$yResolution = $resolution->y(); // Float equal to: 72.0
Resizing Images
Intervention Image provides several methods that we can use to resize images:
resize
- Resize the image to a fixed size.scale
- Scale the image to a given size while maintaining the aspect ratio.scaleDown
- Scale the image to a given size while maintaining the aspect ratio and ensure the original dimensions aren't exceeded.
Let's take a look at how to use the resize
and scale
methods and the resulting dimensions (based on the original image being 5760 x 3840px):
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
$image = Image::read(Storage::get('images/avatar-image.jpg'));
// Resize to fixed dimensions. New image dimensions: 100 x 100px
$resizedImage = $image->resize(width: 100, height: 100);
// Only change the width. The height will remain the same.
// New image dimensions: 100 x 3840px
$resizedImage = $image->resize(width: 100);
// Only change the height. The width will remain the same.
// New image dimensions: 5760 x 100px
$resizedImage = $image->resize(height: 100);
// Resize the image and keep the original aspect ratio. The height
// will be 100px and the width will be calculated automatically.
// New image dimensions: 150 x 100px
$resizedImage = $image->scale(height: 100);
// Resize the image and keep the original aspect ratio. The width
// will be 100px and the height will be calculated automatically.
// New image dimensions: 100 x 67px
$resizedImage = $image->scale(width: 100);
// Resize the image and keep the original aspect ratio. Set the maximum
// width and height. The image will be scaled down without
// exceeding these dimensions.
// New image dimensions: 120 x 80px
$resizedImage = $image->scale(width: 120, height: 100);
After you've edited your image as needed, you can save it in your local filesystem by using the save
method:
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
$image = Image::read(Storage::get('images/avatar-image.jpg'));
// Resize the image
$resizedImage = $image->scale(height: 100);
// Store it in the filesystem
$resizedImage->save(Storage::path('images/avatar-image-resized.jpg'));
In the code example above, we've read the avatar-image.jpg
file from the filesystem, then scaled it to a height of 100px. This will automatically set a width of 150px to maintain the original aspect ratio. We've then saved the resized image in storage/app/private/images/avatar-image-resized.jpg
. This will result in the resized image looking like this:
Rotating Images
There may be times when you need to rotate an image in your Laravel application. Intervention Image provides a handy rotate
method that allows you to rotate an image by a given number of degrees.
For instance, let's say we wanted to rotate an image by 90 degrees clockwise, we could do so like this:
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
$image = Image::read(Storage::get('images/avatar-image.jpg'));
// Rotate the image 90 degrees clockwise
$rotatedImage = $image->rotate(-90);
// Save the rotated image
$rotatedImage->save(Storage::path('images/avatar-image-rotated.jpg'));
In the example above, we've read the avatar-image.jpg
file from the filesystem, rotated it by 90 degrees counter-clockwise, and then saved the rotated image in storage/app/private/images/avatar-image-rotated.jpg
. This will result in the rotated image looking like so:
Cropping Images
A common image manipulation use case I've come across when building Laravel applications is needing to crop images. In particular, I usually need to do this when working with avatar images. For instance, we may want to crop a square image from a rectangular image when an avatar is uploaded.
Let's take a basic example and assume we want to crop a square image (2500 x 2500px) from the center of the original image. We can do so like this:
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage
$image = Image::read(Storage::get('images/avatar-image.jpg'));
// Cut a 2500 x 2500px square from the center of the image
$croppedImage = $image->crop(
width: 2500,
height: 2500,
position: 'center',
);
// Save the cropped image
$croppedImage->save(Storage::path('images/avatar-image-cropped.jpg'));
In the code example above, we've read the avatar-image.jpg
file from the filesystem, cropped a 2500 x 2500px square from the center of the image, and then saved the cropped image in storage/app/private/images/avatar-image-cropped.jpg
. It will result in the cropped image looking like this:
The really cool thing about the Intervention Image API is how the methods can be chained together. For example, let's say we want to read an image, crop a 2500 x 2500px square from the center of the image, scale that cropped image to 250 x 250px, and store it in the filesystem. We can do so like this:
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage
Image::read(Storage::get('images/avatar-image.jpg'))
->crop(width: 2500, height: 2500, position: 'center')
->scale(width: 250, height: 250)
->save(Storage::path('images/avatar-image-chained.jpg'));
Converting Images
Another common task you may want to perform on images is converting them to different formats. For example, you may want to convert an image to a WebP image to reduce the file size and improve page load times.
Intervention Image provides the functionality to achieve this, as well as some handy helper methods to make it easier to work with images. For example, let's say we want to convert an image from JPEG to WebP, JPEG, and PNG formats and store them in the filesystem. We can do so like this:
$imageFromStorage = Storage::get('images/avatar-image.jpg');
Image::read($imageFromStorage)
->toPng()
->save(Storage::path('images/avatar-image-converted.png'));
Image::read($imageFromStorage)
->toWebp()
->save(Storage::path('images/avatar-image-converted.webp'));
Image::read($imageFromStorage)
->toJpeg()
->save(Storage::path('images/avatar-image-converted.jpeg'));
In the example above, we read the avatar-image.jpg
file from the filesystem and converted it to PNG, WebP, and JPEG formats using the toPng
, toWebp
, and toJpeg
methods respectively.
We then saved each converted image in the filesystem, so we'll have three new images: avatar-image-converted.png
, avatar-image-converted.webp
, and avatar-image-converted.jpeg
.
Please note that the image we're working with is already a JPEG image, but we've still mentioned the toJpeg
method for this example.
Watermarking Images
A less common image manipulation use case, but still one I've encountered as a developer, is the need to watermark images. For example, let's say you're generating images in your Laravel application and want to add a watermark to the images when they're downloaded.
Intervention Image provides a handy place method that allows you to place an element (e.g. - another image) on top of the current image. You can also specify the position, offset, and opacity of the element.
Let's take a look at an example. We'll assume we're starting with our base image from previous examples. We'll then crop the image to a 2500 x 2500px square from the center, scale it to 500 x 500px, and then place a watermark (the Honeybadger logo, which we'll assume is stored in a storage/app/private/images/honeybadger-logo.png
file) in the bottom right corner with a 10px offset from the right and bottom of the image. We'll also set the opacity of the watermark to 70%. We can do so like this:
$honeybadgerLogo = Storage::get('images/honeybadger-logo.png');
Image::read(Storage::get('images/avatar-image.jpg'))
->crop(width: 2500, height: 2500, position: 'center')
->scale(width: 500, height: 500)
->place(
element: $honeybadgerLogo,
position: 'bottom-right',
offset_x: 10, // 10px from the right
offset_y: 10, // 10px from the bottom
opacity: 70 // 70%
)
->save(Storage::path('images/avatar-image-watermarked.jpg'));
As we can see in the example above, we leaned on the place
method to place the Honeybadger logo in the bottom right corner of the image with a 10px offset from the right and bottom of the image. We've also set the opacity of the watermark to 70%. The resulting watermarked image will look like this:
As another example, if we'd passed 'top-left'
as the position
argument in the place
method, the watermark would have been placed in the top left corner of the image. The resulting watermarked image would look like this:
Monitoring errors when working with images in Laravel
In this article, we've covered how to use the PHP image-processing library, Intervention Image, in Laravel to edit images. We've covered common tasks such as reading images, resizing, cropping, rotating, converting, and watermarking images. This package is a great tool for your arsenal when working with images.
Just like any other part of your application, when working with images in your Laravel applications, you may run into bugs and errors once you deploy to production. If you're looking for a tool to help you monitor and debug these issues before they impact your users, you might want to sign up for a free trial of Honeybadger.