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:
- Setting up a new Laravel 10 project
- Installing necessary packages
- Creating a file upload form
- Implementing image cropping using Cropper.js
- Handling image uploads and cropping on the server-side
- Saving cropped images to the filesystem
- Displaying cropped images on the front-end
- 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'); }
- 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 thepublic
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.