websanova/vue-upload

Can I do a client-side resize before upload?

shinsenter opened this issue · 2 comments

Thank you (again) for making this awesome component.

I would like to resize the photos before they got upload. It may help a lot because I only want to store small-size photos on my server (let say 1600 x 1200 px each).

Can I do a client-side resize before upload?

@websanova
Thank you for your advice.

I have tried implementing my own http method in component options. Photo resizing works well.

const options = {
    http: function(data) {
        const reader_flag = (window.File && window.FileReader && window.FileList && window.Blob);
        const form_flag = (data.body && ('get' in data.body) && ('set' in data.body));
        let resize_flag = false;

        if (reader_flag && form_flag) {
            resize_flag = true;

            let file = data.body.get('files');
            const maxWidth = MOTORCYCLE_PHOTO_MAX_WIDTH
            const maxHeight = MOTORCYCLE_PHOTO_MAX_HEIGHT

            // Resize before upload
            var reader = new FileReader();
            reader.onload = function(e) {
                let img = document.createElement('img');
                img.onload = function() {
                    if (maxWidth >= img.width && maxHeight >= img.height) {
                        axios.post(data.url, data.body, { onUploadProgress: data.progress })
                            .then(data.success)
                            .catch(data.error)
                        return;
                    }

                    let canvas = document.createElement('canvas')
                    let ctx = canvas.getContext('2d')

                    // calculate new size
                    const ratio = Math.min(maxWidth / img.width, maxHeight / img.height)
                    const width = img.width * ratio + .5 | 0
                    const height = img.height * ratio + .5 | 0

                    // resize the canvas to the new dimensions
                    canvas.width = width
                    canvas.height = height

                    // scale & draw the image onto the canvas
                    ctx.drawImage(img, 0, 0, width, height)

                    // Get the binary (aka blob)
                    canvas.toBlob(blob => {
                        const name = file.name.replace(/\.[a-z0-9]+$/i, '.jpg')
                        const resized = new File([blob], name, file)
                        data.body.set('files', resized)

                        axios.post(data.url, data.body, { onUploadProgress: data.progress })
                            .then(data.success)
                            .catch(data.error)
                    }, 'image/jpeg', 0.95);
                }
                img.src = e.target.result
            }
            reader.readAsDataURL(file)
        }

        if (!resize_flag) {
            axios.post(data.url, data.body, { onUploadProgress: data.progress })
                .then(data.success)
                .catch(data.error)
        }
    },
}

I hope this feature will be added soon in next release.