Share this:

In this comprehensive guide, we will walk through the process of implementing image cropping functionality in a Laravel 10 application.

Image cropping is a common requirement in web applications, particularly when users are allowed to upload their own images, such as for profile pictures or product images.

By providing image cropping functionality, you can ensure that users have greater control over how their images are displayed on your website, improving the overall user experience.

The guide will cover the following key topics:

  1. Setting up a new Laravel 10 project
  2. Installing necessary packages
  3. Creating a file upload form
  4. Implementing image cropping using Cropper.js
  5. Handling image uploads and cropping on the server-side
  6. Saving cropped images to the filesystem
  7. Displaying cropped images on the front-end
  8. Testing

Let’s get started!

Setting Up a New Laravel 10 Project

To begin, create a new Laravel project using the Laravel installer or Composer. Open your terminal and run one of the following commands:

Using Laravel installer:

laravel new ImageCropper

Using Composer:

composer create-project --prefer-dist laravel/laravel ImageCropper

After the installation is complete, navigate to the project directory:

cd ImageCropper

Installing Necessary Packages

We will use the Cropper.js library for client-side image cropping and the Intervention Image library for server-side image processing. Install both packages using the following commands:

npm install cropperjs
composer require intervention/image

After installing the Intervention Image library, you need to publish its configuration file. Run the following command:

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

This will create a new configuration file at config/image.php. Open the file and set the default driver to “gd” (if not already set) to use the GD library for image processing:

'driver' => 'gd',

Creating a File Upload Form

In this step, we will create a simple file upload form to allow users to select and upload images. First, create a new Blade template file at resources/views/upload.blade.php and add the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Cropping in Laravel 10 - LaravelTuts.com</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.css">
    <style>
        /* Custom styles for the image cropping modal */
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-12 mt-5">
                <h3 class="text-center">Upload and Crop Image</h3>
                <form action="{{ route('upload') }}" method="POST" enctype="multipart/form-data">
                    @csrf
                    <div class="form-group">
                        <input type="file" name="image" id="image" accept="image/*">
                    </div>
                    <button type="submit" class="btn btn-primary">Upload</button>
                </form>
            </div>
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
    <script>
    // Custom JavaScript for image cropping functionality
    </script>

</body>
</html>

Next, create a new route and controller method to display the upload form. Open routes/web.php and add the following route:

use App\Http\Controllers\ImageController;

Route::get('/upload', [ImageController::class, 'showUploadForm'])->name('upload');

Now, create a new controller named ImageController using the following command:

php artisan make:controller ImageController

In ImageController.php, add the following method to display the upload form:

public function showUploadForm()
{
    return view('upload');
}
  1. Implementing Image Cropping Using Cropper.js

Now that we have the file upload form in place, it’s time to add image cropping functionality using Cropper.js. Update the resources/views/upload.blade.php file and add the following code inside the <style> tag:

.modal-dialog {
    max-width: 100%;
    margin: 1rem;
}

.img-container {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 500px;
    background-color: #f7f7f7;
    overflow: hidden;
}

Next, add the following HTML code just before the closing </body> tag to create a Bootstrap modal for the image cropping interface:

<div class="modal fade" id="cropImageModal" tabindex="-1" aria-labelledby="cropImageModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="cropImageModalLabel">Crop Image</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <div class="img-container">
                    <img id="imageToCrop" src="#" alt="Image to crop">
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                <button type="button" class="btn btn-primary" id="cropAndUpload">Crop and Upload</button>
            </div>
        </div>
    </div>
</div>

Now, add the following JavaScript code inside the <script> tag in resources/views/upload.blade.php to handle image selection, cropping, and form submission:

$(document).ready(function() {
    let cropper;
    let croppedImageDataURL;

    // Initialize the Cropper.js instance when the modal is shown
    $('#cropImageModal').on('shown.bs.modal', function() {
        cropper = new Cropper($('#imageToCrop')[0], {
            aspectRatio: 1 / 1,
            viewMode: 1,
            autoCropArea: 0.8,
        });
    });

    // Destroy the Cropper.js instance when the modal is hidden
    $('#cropImageModal').on('hidden.bs.modal', function() {
        cropper.destroy();
        cropper = null;
    });

    // Show the image cropping modal when an image is selected
    $('#image').on('change', function(event) {
        const file = event.target.files[0];
        const fileReader = new FileReader();

        fileReader.onload = function(e) {
            $('#imageToCrop').attr('src', e.target.result);
            $('#cropImageModal').modal('show');
        };

        fileReader.readAsDataURL(file);
    });

    // Handle the "Crop and Upload" button click
    $('#cropAndUpload').on('click', function() {
        croppedImageDataURL = cropper.getCroppedCanvas().toDataURL();
        uploadCroppedImage();
        $('#cropImageModal').modal('hide');
    });

    // Upload the cropped image to the server
    function uploadCroppedImage() {
        const formData = new FormData();
        formData.append('_token', $('input[name=_token]').val());
        formData.append('image', dataURLtoFile(croppedImageDataURL, 'cropped-image.png'));

        $.ajax({
            url: '{{ route('upload') }}',
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function(response) {
                // Handle the server response, e.g., display the cropped image
            },
            error: function(xhr, status, error) {
                // Handle errors
            },
        });
    }

    // Helper function to convert a data URL to a File object
    function dataURLtoFile(dataURL, filename) {
        const arr = dataURL.split(',');
        const mime = arr[0].match(/:(.*?);/)[1];
        const bstr = atob(arr[1]);
        let n = bstr.length;
        const u8arr = new Uint8Array(n);

        while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }

        return new File([u8arr], filename, { type: mime });
    }
});

Handling Image Uploads and Cropping on the Server-side

Next, we will handle the image uploads and cropping on the server-side using the Intervention Image library. First, update the `routes/web.php` file and add the following route:

Route::post('/upload', [ImageController::class, 'upload'])->name('upload');

In ImageController.php, add the following upload method to handle the image uploads and cropping:

use Illuminate\Http\Request;
use Intervention\Image\ImageManagerStatic as Image;

public function upload(Request $request)
{
    $request->validate([
        'image' => 'required|image|max:2048',
    ]);

    $image = $request->file('image');
    $filename = time() . '.' . $image->getClientOriginalExtension();
    $croppedImage = Image::make($image)->resize(300, 300, function ($constraint) {
        $constraint->aspectRatio();
    })->save(public_path('uploads/' . $filename));

    return response()->json(['status' => 'success', 'filename' => $filename]);
}

Saving Cropped Images to the Filesystem

In this step, we will save the cropped images to the filesystem. First, create a new directory named uploads inside the public folder to store the uploaded images.

Next, update the .env file to include the following line, which defines the URL path for the uploaded images:

APP_UPLOADS_URL=/uploads

Displaying Cropped Images on the Front-end

Finally, we will display the cropped images on the front-end. Update the resources/views/upload.blade.php file and add the following HTML code inside the <div class="container"> tag, below the file upload form, to create a placeholder for the cropped image:

<div class="row">
    <div class="col-md-12 mt-5">
        <h5 class="text-center">Cropped Image</h5>
        <div class="d-flex justify-content-center">
            <img id="croppedImage" src="#" alt="Cropped image" style="display: none;">
        </div>
    </div>
</div>

Now, update the JavaScript code inside the <script> tag in resources/views/upload.blade.php and modify the success function in the $.ajax() call to display the cropped image:

success: function(response) {
    if (response.status === 'success') {
        $('#croppedImage').attr('src', '{{ env('APP_UPLOADS_URL') }}/' + response.filename);
        $('#croppedImage').show();
    }
},

That’s it! You have now successfully implemented image cropping functionality in a Laravel 10 application. Users can now upload images, crop them using the Cropper.js library, and the cropped images will be saved on the server using the Intervention Image library.

Testing

Run the development server:

Open the command prompt or terminal, navigate to your Laravel project’s root directory, and start the development server using the following command:

php artisan serve

This command will start the development server at http://127.0.0.1:8000 or a similar address, depending on your system’s configuration.

Access the application in your browser:

Open your web browser and navigate to the address where the development server is running, e.g., http://127.0.0.1:8000. You should see your Laravel application’s homepage.

Test the image upload and cropping functionality:

To test the image cropping functionality, you will first need to navigate to the image upload form. If you’ve followed the previous steps in this guide, you should have a route named upload that maps to the image upload form. Access this route by navigating to http://127.0.0.1:8000/upload in your web browser.

Now, perform the following steps:
  • Click the “Choose File” button and select an image from your local filesystem.
  • The image cropping modal should appear, allowing you to crop the selected image using the Cropper.js interface.
  • Adjust the cropping area as desired, and then click the “Crop and Upload” button.
  • The cropped image should be uploaded to the server, processed using the Intervention Image library, and saved to the uploads folder inside the public directory.
  • The cropped image should be displayed on the front-end below the file upload form.

If you can successfully perform these steps without encountering any errors, the image cropping functionality in your Laravel application is working as expected.

Conclusion

In this step-by-step guide, we demonstrated how to implement image cropping functionality in a Laravel 10 application using the Cropper.js library for client-side image cropping and the Intervention Image library for server-side image processing. By providing image cropping functionality, you can improve the overall user experience and ensure that images are displayed consistently across your website.

Source Code

Share this:

Categorized in: