Crop an Image with Croppie.js and Process it with PHP

Croppie.js is an easy to use image cropping plugin that plenty of configuration options. In this tutorial, you will learn how to crop an image using the Croppie.js library and store the cropped image in the server-side using PHP.

Croppie.js is an easy to use image cropping plugin that plenty of configuration options. In this tutorial, you will learn how to crop an image using the Croppie.js library and store the cropped image in the server-side using PHP.

Prerequisites

For this tutorial you will need:

  • A working PHP environment
  • The php-gd extension installed
  • Croppie.js

Setting up the HTML Page

We will begin with a simple HTML page that references Croppie’s javascript and stylesheet files:

<html>
<head>
    <title>My cool croppie page</title>
    <link rel="stylesheet" href="croppie.css">
</head>
<body>
    <div>
        <p>Select a file</p>
        <input type="file" id="inputFile" accept="image/png, image/jpeg">
    </div>
    <div id="actions" style="display: none;">
        <button id="cropBtn" type="button">Crop & Upload</button>
    </div>
    <div id="croppieMount"></div>
    <script src="croppie.js"></script>
    <script type="javascript/text">
        // Our javascript logic goes here
    </script>
</body>
</html>

The JavaScript Logic

We will take the file input inside inputFile and initiate Croppie with the file result. When that’s done we will unhide the action div to show the Crop & Upload button which will allow the user to submit the cropped image to the server.

Reading the Image File

let croppie = null;
let croppieMount = document.getElementById('croppie-mount');

function cleanUpCroppie() {
    croppieMount.innerHTML = '';
    croppieMount.classList.remove('croppie-container');

    croppie = null;
}

inputFile.addEventListener('change', () => {
    cleanUpCroppie();

    // Our input file
    let file = inputFile.files[0];

    let reader = new FileReader();
    reader.onloadend = function(event) {
        // Get the data url of the file
        const data = event.target.result;

        // ...
    }

    reader.readAsDataURL(file);
})

We attached a change event to inputFile, when the change event gets called by the browser our code will initialise the FileReader object which allows for our web application to asynchronously read the content of file. We will use FileReader’s readAsDataURL method to retrieve the file data as base64.

Initializing Croppie

Now we need to initialise Croppie into the croppieMount div element once the FileReader finishes loading the file.

reader.onloadend = function(event) {
    // Get the data ulr of the file
    const data = event.target.result;

    croppie = new Croppie(croppieMount, {
        url: data,
        viewport: {
            width: 500,
            height: 500,
            type: 'circle'
        },
        boundary: {
            width: 500,
            height: 500
        },
        mouseWheelZoom: false
    });

    // Binds the image to croppie
    croppie.bind();

    // Unhide the `actions` div element
    actions.style.display = '';
}

This code sets up an event listener to run a function when the FileReader’s onloadend event fires. The event.target.result property contains the data URL of the file that was loaded. The Croppie constructor is then called, passing in the croppieMount variable and the data URL. The viewport is set to 500x500px and the boundary is set to the same dimensions. The mouseWheelZoom property is set to false to prevent the image from being zoomed in when the mouse wheel is used. The bind() method is then called on the Croppie object to attach the image to the Croppie instance. Finally, the actions div element appears.

Sending the Cropped Image to the Server

Now let’s write the the onclick logic for the button. We will send the base64 data of the cropped image to the server.

cropBtn.addEventListener('click', () => {
    // Get the cropped image result from croppie
    croppie.result({
        type: 'base64',
        circle: false,
        format: 'png',
        size: 'viewport'
    }).then((imageResult) => {
        // Initialises a FormData object and appends the base64 image data to it
        let formData = new FormData();
        formData.append('base64_img', imageResult);

        // Sends a POST request to upload_cropped.php
        fetch('upload_cropped.php', {
            method: 'POST',
            body: formData
        }).then(response => response.json()).then((data) => {
            console.log(data);
        });
    });
});

In this code we use the cropBtn.addEventListener() function to listen for clicks on the crop button. When the button is clicked, the code calls the croppie.result() function to get the cropped image result from Croppie. The code then initializes a FormData object and appends the base64 image data to it. The code then sends a POST request to upload_cropped.php.

Server-Side Processing with PHP

We will a create file called upload_cropped.php. That file will process our base64 data, save it as an image and then it will output a server response in JSON.

<?php
// Return content as JSON
header('Content-Type: application/json;');

/**
 * Echos data as json and terminates the script.
 *
 * @param int $http_response The HTTP reponse to set.
 * @param mixed $data The data to output as JSON.
 * @return void
 */
function echo_data_exit($data, int $http_response = 200) {
    http_response_code($http_response);
    echo json_encode($data);
    exit;
}

// If the request method isn't POST then return a 405 HTTP error.
if($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo_data_exit(['result' => "The method {$_SERVER['REQUEST_METHOD']} is not allowed for this page."], 405);
}

if(!isset($_POST['base64_img']) {
    echo_data_exit(400, ['result' => 'Bad request']);
}

// The path where the image gets saved
$image_path = '/var/www/html/public_dir/image.png';

$data = explode(',', $_POST['base64_img']);
// Decode the base64 data
$data = base64_decode($data[1]);

// Creates a temporary file
$tmp_name = @tempnam(sys_get_temp_dir(), 'image');
// Open for writing only
$tmp_handle = fopen($tmp_name, 'w');
// Write the data to the temporary file
fwrite($tmp_handle, $data);

// Load the image from the temporary file
$image = imagecreatefrompng($tmp_name);
// Save image to the specified path
imagepng($image, $image_path);

// Closes the file handle
fclose($tmp_handle);

echo_data_exit(['result' => 'OK'], 200);

This code saves an uploaded image to a server. The first part of the code checks to see if the request method is POST, and if it’s not, then it returns a 405 HTTP error. The code then splits the base64_img variable on commas and decodes the data. A temporary file is created and the data is written to it. The image is then loaded from the temporary file and saved to the specified path. The file handle is then closed. The last part of the code returns a 200 HTTP response.

Result

The image will be saved as image.png in /var/www/html/public_dir/