How to Upload and Crop Image in Laravel Using imgAreaSelect and Intervention Image Library

Recently one of our readers asked to write an article on how to upload and crop images in Laravel. In the past, I published an article on the same topic for PHP – Upload, Crop, and Resize Image in PHP. But when it comes to Laravel we need to write the code as per Laravel standards. The coding structure written for plain PHP applications will be changed in Laravel. In this article, we study how to upload and crop images in Laravel.

For this tutorial, I am going to use 2 libraries – imgAreaSelect and Intervention Image. Both are open-source libraries.

imgAreaSelect is a jQuery plugin that allows cropping images by selecting a rectangular area of an image. It is a lightweight plugin and easy to use.

On the other hand, Intervention Image is an image handling and manipulation library. This library helps us to create, edit and compose images on the server side.

I will use imgAreaSelect to get the coordinates of the image(for cropped version) and actually crop the image on the server side with the help of the Intervention image library.

Getting Started

For getting started, you should have installed Laravel. If you don’t have created it yet, install it through the command:

composer create-project laravel/laravel laravel-dev

The above command will set up the Laravel project called ‘laravel-dev’ for you.

Next, install the Intervention image library in your Laravel project. Run the command below from the project root directory.

composer require intervention/image

After installing the library, open the config/app.php file and include the following lines to it.

Add the service providers for this package to the $providers array.

Intervention\Image\ImageServiceProvider::class

Add the Image facade to the $aliases array.

'Image' => Intervention\Image\Facades\Image::class

Now, download the imgAreaSelect plugin. From the downloaded zip, copy images, CSS, and JS files. Paste them into the public folder of your Laravel project. Basically, your structure should be like the screenshot below.

Folder Structure

How to Use imgAreaSelect

As we are going to include CSS and JS of the imgAreaSelect plugin, let’s build a structure for it. Create a resources/views/layouts/app.blade.php file and add the code below to it.

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    
    <title>{{ config('app.name', 'Laravel') }}</title>
 
    @yield('style')
</head>
<body>
    <div id="app">
        @yield('content')
    </div>
    
    @yield('footer')
</body>
</html>

This file acts as a common file for all blades. Using the placeholders (@yield) one can inject the code from the blade file at the respective places like in the header, footer, etc.

Create the image.blade.php file inside resources/views directory. This blade file will have the following code.

@extends('layouts.app')
 
@section('style')
    <link rel="stylesheet" href="{{ asset('css/imgareaselect.css') }}" />
@endsection
 
@section('content')
 
    @if ($message = Session::get('success'))
        <strong>{{ $message }}</strong>
    @endif
     
    <form action="{{ url('image') }}" method="post" enctype="multipart/form-data">
        @csrf
        <p>Image: <input type="file" name="profile_image" class="image" required /></p>
        <input type="hidden" name="x1" value="" />
        <input type="hidden" name="y1" value="" />
        <input type="hidden" name="w" value="" />
        <input type="hidden" name="h" value="" />
        <button type="submit" name="submit">Submit</button>
    </form>
    
    <p><img id="previewimage" style="display:none;"/></p>
    @if ($path = Session::get('path'))
        <img src="{{ $path }}" />
    @endif
@endsection
 
@section('footer')
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="{{ asset('js/jquery.imgareaselect.min.js') }}"></script>
    <script>
    jQuery(function($) {
        var p = $("#previewimage");
 
        $("body").on("change", ".image", function(){
            var imageReader = new FileReader();
            imageReader.readAsDataURL(document.querySelector(".image").files[0]);
 
            imageReader.onload = function (oFREvent) {
                p.attr('src', oFREvent.target.result).fadeIn();
            };
        });
 
        $('#previewimage').imgAreaSelect({
            onSelectEnd: function (img, selection) {
                $('input[name="x1"]').val(selection.x1);
                $('input[name="y1"]').val(selection.y1);
                $('input[name="w"]').val(selection.width);
                $('input[name="h"]').val(selection.height);            
            }
        });
    });
    </script>
@endsection

You may have noticed some stuff from the above file like @extends(‘layouts.app’), @section(‘style’), @section(‘content’), etc. These sections will go to the respective places of app.blade.php. The user can get a better idea of it when you view the source of this page in the browser.

I also added a form element with a few hidden fields. When we choose a portion of the image, the selected coordinates are set for these hidden elements. These values with then send to the server side to recognize which portion of the image needs to crop,

To call this view, create a controller using the command:

php artisan make:controller ImageController --resource

Add the reference of this controller in the route file.

Route::resource('image', 'ImageController');

Open the ImageController in the editor and from the index method, give a call to the view. Here, I am also including 2 facades which will be required in the next part.

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Image; //Intervention Image
use Illuminate\Support\Facades\Storage; //Laravel Filesystem
 
class ImageController extends Controller
{
    public function index()
    {
        return view('image');
    }
    .....
}

Run the Artisan serve command and you will see your form at the URL http://localhost:8000/image.

When you upload the image you should preview the image below the form. From this preview, you can select a portion of the image you want to crop.

crop

Upload and Crop Image Using Intervention Image Library

At this point, we are completed with the client-side code where the user can choose a part of the image they wish to crop. The next job is cropping the image and storing it on the server.

For storing an image on a server, I’ll use the Laravel storage facade which requires creating a symbolic link of a ‘storage’ folder. To create a symbolic link, run the command:

php artisan storage:link

This command creates a ‘storage’ directory under the ‘public’ folder.

In the ImageController, I already included a facades Image and Storage. Using these facades, we store the original and crop version of the image on the server’s disk. The controller’s store() method should have the below code.

public function store(Request $request)
{
    if ($request->hasFile('profile_image')) {

        //get filename with extension
        $filenamewithextension = $request->file('profile_image')->getClientOriginalName();

        //get filename without extension
        $filename = pathinfo($filenamewithextension, PATHINFO_FILENAME);

        //get file extension
        $extension = $request->file('profile_image')->getClientOriginalExtension();

        //filename to store
        $filenametostore = $filename.'_'.uniqid().'.'.$extension;

        Storage::put('public/profile_images/'. $filenametostore, fopen($request->file('profile_image'), 'r+'));
        Storage::put('public/profile_images/crop/'. $filenametostore, fopen($request->file('profile_image'), 'r+'));

        //Crop image here
        $cropimage = public_path('storage/profile_images/crop/'.$filenametostore);
        $img = Image::make($cropimage)->crop($request->input('w'), $request->input('h'), $request->input('x1'), $request->input('y1'))->save($cropimage);
 
        // you can save the below image path in database
        $path = asset('storage/profile_images/crop/'.$filenametostore);

        return redirect('image')->with(['success' => "Image cropped successfully.", 'path' => $path]);
    }
}

In this code, I am storing a cropped version of an image under the ‘storage/profile_images/crop’ directory. After storing it, I pass a path of the cropped image back to the view. In the view file, we already added a code that displays the cropped image to the end user.

Set Maximum Width on Image

Sometimes users may want to define the maximum width for the crop version of an image. The imgAreaSelect plugin provides several options like aspectRatio, maxWidth, maxHeight, etc. to customize the final result of an image. A user can use the maxWidth option by changing the JavaScript code as follows:

$('#previewimage').imgAreaSelect({
    maxWidth: '1000', // this value is in pixels
    onSelectEnd: function (img, selection) {
        $('input[name="x1"]').val(selection.x1);
        $('input[name="y1"]').val(selection.y1);
        $('input[name="w"]').val(selection.width);
        $('input[name="h"]').val(selection.height);            
    }
});

It’s all about how to upload and crop images in Laravel. I hope you got to know how to handle the task of cropping images. I would like to hear your thoughts and suggestions in the comment section below.

Related Articles

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

5 thoughts on “How to Upload and Crop Image in Laravel Using imgAreaSelect and Intervention Image Library

    1. In our article, we are not interacting with the database and your error is related to the database. It seems in your controller code you missed some parameters which need to pass for a query.

  1. Hello my friend. When I save the link into table of image, the name of image is another name, look this product_image -> C:\Users\arthu\AppData\Local\Temp\phpB3B0.tmp,

    This link is save in table of database;

    How I fix this?

  2. Hello friend, everything works for me but how do I indicate a maximum width to the image uploaded? that is to say previewimage a maximum width

Leave a Reply

Your email address will not be published. Required fields are marked *