图片压缩上传的两张方式

213 阅读3分钟

图片压缩上传

前两天在项目中遇到一个需求,需要做图片压缩上传。本着没接触过且没有做过的原则,我先是在网上搜索了,了解了两种图片压缩的格式blob、Base64两种格式,当然不确定还有没有其他的方法,不过对比了一下这两种方式差不多区别不大。

看看效果图

yasuo.png

逻辑步骤

1、调用 FileReader 的 reader.readAsDataURL(img),在其onload事件中, 将用户选择的图片读入 img 对象。

2、在img对象的 onload 事件中, 通过 canvas 的 canvas.getContext('2d') 的 drawImage 方法, 将 Image 改变大小绘制到canvas上。

3、 通过 canvas.toDataURL(file.tpye, 1), 将图片变成base64字符串。

3、 通过 canvas.toBlob(file.tpye, 1), 将图片变成blob字符串。

下面我们来看代码

    <form class="form form-vertical" method="post" id="new-feedback-form" enctype="multipart/form-data">
        <input type="file" id="images-input" name="images[]" accept=".jpg,.jpeg,.png,.gif,.svg" multiple="multiple" onchange="loadFile(event)">
        <div id="uploaded-image" class="uploaded">

        </div>
        <div class="col-12 d-flex justify-content-end mt-1">
            <button class="btn btn-primary mr-1 mb-1 block-element" onclick="submitNewFeedback()">Submit</button>
            <button type="reset" class="btn btn-light-secondary mr-1 mb-1">Reset</button>
        </div>
    </form>

这里还存在一个小问题就是,直接用formdata来提交数据的话,我们得需要把原本files的数据给替换了,但是又不能直接进行赋值,会报错说是属性只读的情况。这时我们得需要点小改动了,来展示。

 var blobFFile = []
            var loadFile = async function (event) {
                var output = document.getElementById('uploaded-image');
                var imgHtml = '';
                blobFFile = [];
                for (file of event.target.files) {
                    console.log(file,'‘原始图');

                    // 调用异步函数进行压缩
                    // const compressedImage = await compressImg(file);
                    const compressedImage = await compressFileBlob(file);
                    console.log(compressedImage,'压缩后的')
                    blobFFile.push(compressedImage)
                    // 构建HTML字符串
                    imgHtml += '<div class="uploaded-image"><img src="' + compressedImage.data + '"></div>';
                }
                // console.log(blobFFile,88888)

                const imagesInput = document.getElementById('images-input')
                // 创建一个新的 DataTransfer 对象
                const dataTransfer = new DataTransfer();

                // 将 blobFFile 数组中的文件添加到 DataTransfer 对象中
                // base64
                // blobFFile.forEach(file => {
                //     dataTransfer.items.add(file);
                // });
                blobFFile.forEach(file => {
                    dataTransfer.items.add(file.file);
                });

                // 将 DataTransfer 对象中的文件列表设置到文件输入元素中
                imagesInput.files = dataTransfer.files;
                console.log(imagesInput.files)
                // 更新页面
                output.innerHTML = imgHtml;
                
                // 使用XMLHttpRequest或者Fetch API上传到服务器
                // const xhr = new XMLHttpRequest();
                // xhr.open('POST', '/upload-endpoint', true);
                // xhr.onreadystatechange = function () {
                //     if (xhr.readyState === 4 && xhr.status === 200) {
                //         // 处理服务器响应
                //         console.log(xhr.responseText);
                //     }
                // };
                // xhr.send(formData);
            };
            

这时我们通过 DataTransfer 这个对象来进行替换就替换成功,在当时写的时候也是查了好半天,后面还是leader 发给我看的呢,哈哈哈

这是转换为 Base64

            function dataURLtoFile(dataurl, filename) {
                const arr = dataurl.split(',');
                const mime = arr[0].match(/:(.*?);/)[1];
                const bstr = atob(arr[1]);
                let n = bstr.length;
                const u8arr = new Uint8Array(n);
                while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                }
                return new File([u8arr], filename, { type: mime });
            }

            // 这是压缩成Base64
            function compressImg(file) {
                return new Promise((resolve, reject) => {
                    let formData = new FormData();
                    let reader = new FileReader();

                    reader.readAsDataURL(file);

                    reader.onload = function (ev) {
                        try {
                            let img = new Image();
                            img.src = ev.target.result;

                            img.onload = function (ev) {
                                let canvas = document.createElement("canvas");
                                let context = canvas.getContext("2d");
                                let imgwidth = img.width;
                                let imgHeight = img.height;
                                let targetwidth = imgwidth;
                                let targetHeight = imgHeight;

                                if (targetwidth > targetHeight) {
                                    let scale = targetHeight / 1280;
                                    targetHeight = 1280;
                                    targetwidth = targetwidth / scale;
                                } else {
                                    let scale = targetwidth / 1280;
                                    targetwidth = 1280;
                                    targetHeight = targetHeight / scale;
                                }

                                canvas.width = targetwidth;
                                canvas.height = targetHeight;
                                context.clearRect(0, 0, canvas.width, canvas.height);
                                context.drawImage(img, 0, 0, canvas.width, canvas.height);

                                let data = "";

                                if (file.size <= 628288) {
                                    data = canvas.toDataURL(file.type);
                                    formData.append("file", file);
                                    resolve({ file, data });
                                } else {
                                    data = canvas.toDataURL(file.type,0.9);
                                    let paper = dataURLtoFile(data, file.name);
                                    formData.append("file", paper, data)
                                    resolve({ file: paper, data });
                                }
                            };
                        } catch (error) {
                            reject(error);
                        }
                    };
                });
            }


blob

            async function compressFileBlob(file) {
                return new Promise((resolve) => {
                    const img = new Image();
                    const reader = new FileReader();

                    reader.onload = function (e) {
                        img.src = e.target.result;

                        img.onload = function () {
                            const canvas = document.createElement('canvas');
                            const ctx = canvas.getContext('2d');

                            canvas.width = 300; // 设置压缩后的宽度
                            canvas.height = (img.height / img.width) * canvas.width;

                            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

                            canvas.toBlob((blob) => {
                                // 创建新的 File 对象
                                const compressedFile = new File([blob], file.name, {
                                    type: file.type,
                                    lastModified: Date.now(),
                                });

                                const compressedData = URL.createObjectURL(compressedFile);

                                // 将压缩后的文件返回
                                resolve({ data: compressedData, file: compressedFile });});
                            }, file.type, 0.9);
                        };
                    };

                    reader.readAsDataURL(file);
                });
            }

认识一下

目前正在疯狂学习前端知识,想要成为更牛批的前端工程师,因此喜欢记录并分享自己的学习笔记。我所发表的只是自己所知道的知识,算不上绝对正确,通过网上查找资料所写只知道这个方法可行,但也许代码中存在些许bug,我也不得而知,有大佬知道的可以指点指点。