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):

Original avatar image showing a adult with glasses against a white background

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:

The original image resized to a height of 100px using the Intervention Image library in Laravel

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:

The original image rotated 90 degrees counter-clockwise using the Intervention Image library in Laravel

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 original image cropped to a square using the Intervention Image library in Laravel

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:

The original image that has been cropped to a square and watermarked with the Honeybadger logo in the bottom right

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:

The original image that has been cropped to a square and watermarked with the Honeybadger logo in the top left

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.

author photo
Ashley Allen

Ashley is a freelance Laravel web developer who loves contributing to open-source projects and building exciting systems to help businesses succeed.

More articles by Ashley Allen