Home  >  Article  >  Web Front-end  >  JS compresses uploaded images

JS compresses uploaded images

高洛峰
高洛峰Original
2016-11-22 10:36:201154browse

JS compression for uploaded images

/**
 * @Date: 2016/11/17  0017
 * @Time: 10:14
 * @Author: lxbin
 *
 * Created with JetBrains WebStorm.
 */

/**
 * http://leonshi.com/2015/10/31/html5-canvas-image-compress-crop/
 * http://jafeney.com/2016/08/11/20160811-image-upload/
 */

/**
 * 读取文件
 * @param file 文件对象
 * @return {Promise}
 */
function readFileAsync(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader()
        reader.onload = e => resolve(readFile.target.result)
        reader.onerror = e => reject(new Error('Could not read file'))
        reader.readAsDataURL(file)
    })
}

/**
 * 加载图片
 * @param url 图片地址
 * @return {Promise}
 */
function loadImageAsync(url) {
    return new Promise((resolve, reject) => {
        const image = new Image()
        image.onload = () => resolve(image)
        image.onerror = () => reject(new Error('Could not load image at ' + url))
        image.src = url
    })
}

/**
 * base64的图片dataUri转Blob
 * @param dataURI
 * @return {*}
 */
function dataURItoBlob(dataURI) {
    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
    var byteString = atob(dataURI.split(',')[1]);

    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

    // write the bytes of the string to an ArrayBuffer
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    // write the ArrayBuffer to a blob, and you&#39;re done
    var blob = new Blob([ab], {type: mimeString});
    return blob;

    // Old code
    // var bb = new BlobBuilder();
    // bb.append(ab);
    // return bb.getBlob(mimeString);
}

/**
 * 图片转Blob
 * @param image 图片对象
 * @param quality 图片质量(0到1之间)
 * @param scale 缩放比例(0到1之间)
 * @return {Promise}
 */
function imageToBlob(image, quality, scale) {
    return new Promise((resolve, reject) => {
        try {
            let canvas = document.createElement(&#39;canvas&#39;)
            canvas.width = image.naturalWidth * scale
            canvas.height = image.naturalHeight * scale
            while (canvas.width >= 3264 || canvas.height >= 2448) {//超过这个值base64无法生成,在IOS上
                canvas.width = canvas.naturalWidth * scale
                canvas.height = canvas.naturalHeight * scale
            }

            let ctx = canvas.getContext(&#39;2d&#39;).drawImage(image, 0, 0, canvas.width, canvas.height)

            //方式一:低版本兼容性差些
            //canvas.toBlob(function (blob) {
            //    console.group(&#39;[Leo]file compress to blob&#39;)
            //    console.log(&#39;文件类型 => &#39; + file.type)
            //    console.log(&#39;文件大小 => &#39; + (file.size / 1024 / 1024).toFixed(2) + &#39;M&#39;)
            //    console.log(&#39;blob质量 => &#39; + quality)
            //    console.log(&#39;blob大小 => &#39; + (blob.size / 1024 / 1024).toFixed(2) + &#39;M&#39;)
            //    console.groupEnd()
            //    resolve(blob)
            //}, &#39;image/jpeg&#39;, quality)

            //方式二:
            var base64 = canvas.toDataURL(&#39;image/jpeg&#39;, quality);
            var blob = dataURItoBlob(base64);
            console.group(&#39;[Leo]file compress to blob&#39;)
            console.log(&#39;文件类型 => &#39; + file.type)
            console.log(&#39;文件大小 => &#39; + (file.size / 1024 / 1024).toFixed(2) + &#39;M&#39;)
            console.log(&#39;blob质量 => &#39; + quality)
            console.log(&#39;blob大小 => &#39; + (blob.size / 1024 / 1024).toFixed(2) + &#39;M&#39;)
            console.groupEnd()
            resolve(blob);
        } catch (e) {
            reject(new Error("Image could not convert to blob :" + e))
        }
    })
}

/**
 * Ajax上传
 * @param uri 上传的Action地址
 * @param file 文件对象
 * @return {Promise}
 */
function uploadFile(uri, file) {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        if (xhr.upload) {
            xhr.upload.addEventListener("progress", (e) => {// 处理上传进度
                if (e.lengthComputable) {
                    let percent = (e.loaded / e.total * 100).toFixed(2) + &#39;%&#39;
                    console.log("上传中(" + percent + ")");
                    //TODO:反馈到DOM里显示
                } else {
                    console.log(&#39;unable to compute&#39;);
                }
            }, false)
        }
        xhr.onreadystatechange = (e) => {// 文件上传成功或是失败
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    resolve(xhr.responseText)// 上传成功
                } else {
                    reject(xhr.responseText)// 上传出错处理
                }
            }
        }
        xhr.open("POST", uri, true)// 开始上传
        let form = new FormData()
        form.append("filedata", file)
        xhr.send(form)
    })
}

/**
 * 上传文件
 * @param file 文件对象
 * @param quality 图片质量(0到1之间)
 * @param scale 缩放比例(0到1之间)
 */
export default async function fileUpload(file, quality, scale) {
    try {
        let fileUrl = await readFileAsync(file)
        let image = await loadImageAsync(fileUrl)
        let blob = await imageToBlob(image, quality, scale)
        let upload = await uploadFile(blob)
        return upload
    } catch (e) {
        console.log(&#39;file upload failed&#39;)
    }
}


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn