Crop image with a particular aspect ratio – client side

One of our clients asked me to prepare the photo upload tool. Nothing fancy, done that dozens of times. The difference was that the photos should be displayed in a particular place on the website and should follow a particular size. To be precise – a particular aspect ratio. They should be 5:6, in other words, 250:300 or 1.25:1.5.

Since the photos will be displayed on the website only, the 200×300 px size will be just enough. This also meant that I can prepare these pictures client-side and don’t bother with uploading the full-size photos to the server.

Croppie – simple yet powerfull

The “weapon of choice” for this task for me is the Croppie library. It is lightweight, configurable, and powerful enough to handle the tasks I expect. It can work in conjunction with jQuery (if the site is old enough to use it) or just using vanilla JavaScript.

In my case, it also works with the standard HTML form upload field. The file is selected from the drive by the user and once loaded in the browser, Croppie takes its part.

The JavaScript part of the code looks as follows:

<script>
    function readFile(input) {
        if (input.files && input.files[0]) {
            var reader = new FileReader();
            reader.onload = function (e) {
                uploadCrop.croppie('bind', {
                    url: e.target.result
                }).then(function(){
                    resultToField();
                    $('#picture-frame').on('update.croppie', resultToField );
                });
            }
            reader.readAsDataURL(input.files[0]);
        }
        else {
            alert("Sorry - you're browser doesn't support the FileReader API");
        }
    }

    function resultToField() {
        uploadCrop.croppie('result','base64').then(function(baseImage) {
            $('#picturebase').val(baseImage);
        });
    }

    var uploadCrop = $('#picture-frame').croppie({
        viewport: {
            width: 250,
            height: 300
        },
        boundary: {
            width: 300,
            height: 350
        },
        enableExif: true
    });

    $('#upload').on('change', function () { readFile(this); });
</script>

In the HTML form I have to define some fields and area where the image is cropped:

<input type="file" id="upload" value="Choose a file" accept="image/*">
<div id="picture-frame"></div>
<input type="hidden" name="picturebase" id="picturebase" value="">

As you can see, I’m using the jQuery version. There is a file reader attached to the file upload field – it reads the file and binds it to the Croppy engine. The file is read by the browser, it is not sent to the server yet. On each change, the current cropped image is saved to the hidden “picturebase” field. It is encoded as a base64 string to be decoded on the server. The user can zoom the picture in and out, move it below the “cropping frame” to align it properly.

Croppie in action

If you want to use the large size photos, instead of using the small base64 version of the image, you can ask Croppy to provide the coordinates of the cropped area. This way you can upload the photo to the server and use the provided coordinates to generate the crop server-side.