Laravel PHP: Crop Image with Croppie Js

Category:
PHP Laravel
Tags:
PHP
jQuery
javascript

Krunal Patel
6 months ago

Introduction

If you wish to upload a thumbnail image instead of the whole image, many websites offer the feature to crop the image before uploading it to their platform. Croppie.js is a popular JavaScript library used for image cropping, which allows users to select a specific area of the image to create a thumbnail. This process helps in optimizing image sizes and improving website performance by reducing the file size of uploaded images. With Croppie.js, users can easily crop the image to the desired dimensions and aspect ratio before uploading.


Include Croppie Script & Style:

In the code snippet below, I've added Croppie script and style, along with a Croppie div element for rendering. Once the image is uploaded, you'll see the cropped image in the preview section.

<!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>Croppie</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    {{-- Croppie Style--}}
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.css" />
    <meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
    <div class="container-fluid p-5 bg-primary text-white text-center">
        <h1>Croppie Js</h1>
    </div>
       
    <div class="container mt-5">
        <div class="row">
            <div class="col-md-4 text-center">
             {{-- Render croppie section --}}
            <div id="upload-demo"></div>
            </div>
            <div class="col-md-4" style="padding:5%;">
                <strong>Select image to crop:</strong>
                <input type="file" id="image" name="image" accept="image/*">
                <button class="btn btn-primary btn-block upload-image" style="margin-top:2%">Upload Image</button>
            </div>
            <div class="col-md-4">
             {{-- Copied image preview --}}
                <div id="preview-crop-image" style="background:#9d9d9d;width:300px;padding:50px 50px;height:300px;"></div>
            </div>
          </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
    {{-- Croppie Script--}}
    <script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.js"></script>
</body>
</html>

Create a script for Croppie JS rendering:

Initialize Croppie JS for a specific div element as per your requirements. Set viewport, boundary, show zoom control, and more as needed.

<script type="text/javascript">
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        },
    });

    var image_croppie = '';
    function init_croppie() {
        if (image_croppie) {
            image_croppie.croppie('destroy');
        }
        image_croppie = $('#upload-demo').croppie({
            enableExif: true,
            enableOrientation: true,    
            viewport: { // Default { width: 100, height: 100, type: 'square' }
                width: 200,
                height: 200,
                type: 'circle'
            },
            boundary: {
                width: 300,
                height: 300
            }
        });
    }

    init_croppie();
   
    /* !! On change event of image. !!*/
    $(document).on('change', '#image', function(){
        var file = this.files[0];
        // Check if file is an image
        if (!file.type.startsWith('image/')) {
            alert("Please select an image file.");
            return;
        }
       
        var reader = new FileReader();
        reader.onload = function (e) {
            //Bind the croppie
            image_croppie.croppie('bind',{
                url: e.target.result
            }).then(function(){
                console.log('jQuery bind complete');
            });
        }
        reader.readAsDataURL(file);
    });

    /* !! Onsubmit upload image !! */
    $('.upload-image').on('click', function (ev) {
        image_croppie.croppie('result', {
            type: 'canvas',
            size: 'viewport',
           
        }).then(function (img) {
            var formData = new FormData();
            formData.append('cropped_image', img);
            //Ajax process with submit the croppie image
            $.ajax({
                url: "{{route('croppie.upload-image')}}",
                type: "POST",
                data: formData,
                dataType:'json',
                cache: false,
                async: true,
                processData: false,
                contentType: false,
                timeout: 4000,
                success: function (data) {
                    if(data.status){
                        init_croppie();
                        $('#image').val("");
                        html = '<img src="' + data.cropped_image + '" />';
                        $("#preview-crop-image").html(html);
                    }else{
                        alert('Something went wrong, please try later.');
                    }
                }
            });
        });
    });
</script> 

Create a Controller for the Croppie Image Upload:

Below is the code to store the cropped image in a directory.

 use Illuminate\Support\Facades\File;
 use Illuminate\Support\Str;

 public function uploadCropImage(Request $request){
        try {
            $image = $request->cropped_image;

            list($type, $image) = explode(';', $image);
            list(, $image)      = explode(',', $image);

            $image = base64_decode($image);
            $image_name= time().'_'.Str::random(10).'.png';      
            $path = public_path('profile/');
            if (!File::exists($path)) {
                File::makeDirectory($path, 0755, true, true);
            }
            $image_path = $path.''.$image_name;
            file_put_contents($image_path, $image);

            return response()->json(['status'=>true, 'cropped_image' => url('profile/'.$image_name)]);
        } catch (\Exception $e) {
            return response()->json(['status'=>false]);
        }
    }

Create route:

/* !! Croppie !! */
Route::get('croppie-image', [CropImageController::class,'index']);
Route::post('upload-croppie-image', [CropImageController::class, 'uploadCropImage'])->name('croppie.upload-image');


DevZone
Made by developer, Made for developers