Vaidikalaya
Crop Image in Laravel

There are many ways to crop images in Laravel. But here we will discuss a very easy and less code implementation for cropping an image before uploading it on the server.

Note:
Cropper.js: for cropping an image.
Ajax: for uploading an image.


Follow the below steps and learn how to crop images in Laravel.

Step 1: Create Laravel App
laravel new laravel-crop-image-upload

Step 2: Install laravel/ui package
composer require laravel/ui

Step 3: Install Bootstrap
php artisan ui bootstrap

Step 4: Run npm install and npm run build command
npm install
npm run build

Step 5: Setup frontend UI

Go to resources/views/welcome.blade.php and here write code for frontend UI which helps users to change their image.

Note: Add CDN links for Jquery and Cropper.js

<!--JQuery-->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<!--Cropper Js-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js"></script>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Laravel Crop Image</title>
    <meta name="csrf-token" content="{{ csrf_token() }}">

   
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

   
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.css"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js"></script>

    @vite(['resources/sass/app.scss', 'resources/js/app.js'])
   
    <style>
        .profile-user-img {
            border: 3px solid #adb5bd;
            margin: 0 auto;
            padding: 3px;
            width: 100px;
            height: 100px;
            border-radius: 50%;
        }
        .preview {
            overflow: hidden;
            width: 160px;
            height: 160px;
            margin: 10px;
            border: 1px solid red;
        }
    </style>
</head>
<body>
   
    <div class="container mt-5">
        <div class="row justify-content-center">
            <div class="col-sm-8">
                <div class="card">
                    <div class="card-body">
                       <div class="text-center">

                            <div>
                                <img src="{{asset('uploads/images/profile.png')}}" class="profile-user-img img-fluid">
                            </div>
                       
                            <div>
                                <input type="file" class="image" style="opacity: 0;height:1px;display:none">
                                <a href="javascript:void(0)" class="btn btn-primary btn-block mt-2" id="change_picture_btn"><b>Change picture</b></a>
                            </div>

                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="cropper-modal">
        <div class="modal-dialog modal-xl">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Image</h5>
                    <button type="button" class="btn btn-close" data-bs-dismiss="modal" aria-label="Close">
                    </button>
                </div>
                <div class="modal-body">
                    <div class="row">
                        <div class="col-md-8">
                            <img src="https://avatars0.githubusercontent.com/u/3456749" class="img-fluid" id="modal_image">
                        </div>
                        <div class="col-md-4">
                            <div class="preview"></div>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelbutton>
                    <button type="button" class="btn btn-primary" id="crop">Cropbutton>
                </div>
            </div>
        </div>
    </div>

<script>
    var modelImage = document.getElementById('modal_image');
    var $modal=$('#cropper-modal');
    var cropper;

    /*when user click on change picture button*/
    $(document).on('click','#change_picture_btn',function(){
        $('.image').click();
    });

    /*
       when user select image and upload
       then it will run and open modal with uploaded image
    */
    $(document).on("change",".image",function(e){
        var files = e.target.files;
        if(files && files.length > 0){
            var url=URL.createObjectURL(files[0]);
            modelImage.src = url;
            $modal.modal('show');
        }
    });

    /*
       when modal open successfully then it will run
       and add croppen in an image
    */
    $modal.on('shown.bs.modal', function () {
        cropper = new Cropper(modelImage, {
            aspectRatio: 1,
            viewMode: 3,
            preview: '.preview'
        });
    }).on('hidden.bs.modal', function () {
        cropper.destroy();
        cropper = null;
    });
   
    /*
       when user click on crop button of modal
       then it will run and send the cropped image on server
    */
    $("#crop").click(function(){
        cropper.getCroppedCanvas().toBlob((blob)=>{
            const formData = new FormData();
            formData.append('image', blob);
            formData.append('extension', blob.type.replace("image/", " "));
            $.ajax({
                url: "/crop-image-upload",
                type: "POST",
                headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
                data: formData,
                processData: false,
                contentType: false,
                success: function(res){
                    $modal.modal('hide');
                    $('.profile-user-img').attr("src","/uploads/images/"+res.image_name);
                }
            });
        })
    });
</script>
</body>
</html>

Step 6: Create a Controller

php artisan make:controller CropImageController

Step 7: Write backend logic for uploading images in the controller.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class CropImageController extends Controller
{
    public function index(Request $request){
        $image=$request->image;
        $imageName = uniqid().'.'.$request->extension;
        $image->move(public_path('uploads/images/'),$imageName);
        return response()->json(['success'=>'Image Uploaded Successfully','image_name'=>$imageName]);
    }
}

Step 8: Setup Routes
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CropImageController;

Route::get('/', function () {
    return view('welcome');
});

Route::post('/crop-image-upload',[CropImageController::class,'index']);

Step 9: Start your app and test.
php artisan serve

Test Your App

Now go to your browser and run your application on ==> localhost:8000