Image cropping in UploadWidget

Hello,

I know this is a recurring topic, my apologies for that.

Since the Implementation from the core team seems to be in void therefore i want to know if someone can help in implementing this. I would be very grateful for any meaningful guidance.

Hey @ibrarartisan

This is indeed a planned feature, but it doesn’t gain much traction: https://portal.octobercms.com/c/30-crop-images-selected-via-the-file-upload-widget

Can you share more about your story and why you need this? The resizer included with media manager serves most cases pretty well.

Regarding the guidance, there is some decent services that are prebuilt that might be able to use for this. It would involve creating your own custom form widget:

Hey daft, thanks alot.

We have a customer who is using some weird images. He want to have a functionality that whenever he want to upload a picture he can be able to crop it to a predefined ratio.

The reaize service is good however that is not desirable at the moment.

Hi @ibrarartisan ,
I can help you implement this image cropping feature for your widget.
Have search some JavaScript libraries that can be help achieving your expectation.

Please let me know If you are still looking for professional.

Regards
Deep

I recently used cropperjs for this and it was a great experience:

@ferro thanks alot.

Can you show the steps how you implemented this? It would be of great help. Thabks alot

Its was not a OctoberCMS project tho, here is the js part :

const _URL = window.URL;
const cropper_image = document.getElementById("cropper_image");
const info_text =  document.getElementById("info_text");
const upload_section =  document.getElementById("upload_section");
//const upload_cropped_image =- document.getElementById("upload_cropped_image")
//const image_chooser_button =- document.getElementById("image_chooser_button")

document.addEventListener("DOMContentLoaded", () =>
{
    console.log("script loaded")
    let cropper;


    /**
     *
     * @param blob
     * @returns {Promise<unknown>}
     */
    async function uploadCroppedImage(blob)
    {
        return new Promise((resolve) =>
        {
            const firstname = document.getElementById("firstname")
            const lastname  = document.getElementById("lastname")
            const upload_progress = document.getElementById("upload_progress")

            const formData = new FormData();

            formData.append('croppedImage', blob);
            formData.append('firstname', firstname.value);
            formData.append('lastname', lastname.value);

            const xhr = new XMLHttpRequest();
            xhr.open("POST", '/upload.php');

            xhr.onprogress = (e)=>{
                console.log("ProgressEvent",e)
            }

            xhr.upload.onprogress = (event) =>{

                console.log(`Uploaded ${event.loaded} of ${event.total} bytes`);
                let percent = (event.loaded / event.total) * 100;
                upload_progress.setAttribute("value",percent)
            };

            xhr.upload.onload = () =>{
                console.log(`Upload finished successfully.`);
            };

            xhr.onloadend = (e) => {
                if (xhr.status == 200) {
                    console.log("success");
                    resolve('resolved');
                } else {
                    console.log("error " + this.status);
                }
            }

            xhr.upload.onerror = () =>{
                console.log(`Error during the upload: ${xhr.status}`);
            };

            xhr.send(formData);


        });
    }


    /**
     * SET Cropper Image and add eventListener for upload after crop
     */
    function setCropperImage() {
        console.log("cropper_image", cropper_image)
        if(cropper){
            cropper.destroy();
        }
        cropper = new Cropper(cropper_image, {
            aspectRatio: 16 / 9,
            crop(event) {
                console.log(event.detail.x);
                console.log(event.detail.y);
                console.log(event.detail.width);
                console.log(event.detail.height);
                console.log(event.detail.rotate);
                console.log(event.detail.scaleX);
                console.log(event.detail.scaleY);
            },
        });
        document.getElementById("upload_cropped_image").addEventListener("click", (e) => {
            _URL.revokeObjectURL(cropper_image.src);
            cropper.getCroppedCanvas().toBlob((blob) => {
                uploadCroppedImage(blob).then((data) => {
                    //console.log("CHECK", data)
                    cropper.destroy();
                });
            })
        })
    }


    /**
     * FILE INPUT CHANGE
     * set cropper image on file input
     */
    document.getElementById("file_input").addEventListener('change', (e) =>
    {
        info_text.style.display                 = "none"
        upload_section.style.display            = "block"
        //upload_cropped_image.style.display      = "block"
        //image_chooser_button.style.display      = "none"

        const file = e.target.files[0];

        if (file)
        {
            const img = new Image();

            console.log("file:", file)
            console.log("_URL:", _URL)

            const objectUrl = _URL.createObjectURL(file);
            img.src = objectUrl

            img.onload = () => {
                //alert(this.width + " " + this.height);
                //image_info_display.innerHTML = this.width + " " + this.height
                cropper_image.src = objectUrl;

                cropper_image.addEventListener('load', () => {
                    setCropperImage()
                    // _URL.revokeObjectURL(objectUrl);
                }, { once: true });

            };

        }
    })

})

Another example I found:

@ferro thanks alot. that is so nice of you.

well i implemeted already in non-ocotbercms projects. however problem is to implement within the widget in octobercms.

@daft can you help somehow?

1 Like