如何使用FormData上传压缩裁剪后的图片Blob对象

简介: 在前端页面,我们通常会遇到需要用户上传图片的操作,可能还会在前端进行图片编辑的操作(比如头像的选区裁剪),然后如果图片过大的话,我们还会对图片进行压缩。这些功能我们通常通过Canvas来进行,最后使用Canvas API函数toDataURL来得到图片...

在前端页面,我们通常会遇到需要用户上传图片的操作,可能还会在前端进行图片编辑的操作(比如头像的选区裁剪),然后如果图片过大的话,我们还会对图片进行压缩。这些功能我们通常通过Canvas来进行,最后使用Canvas API函数toDataURL来得到图片的Base64字符串,然后当我们要上传到后台的时候,会面临2种选择:

  • 直接将图片的Base64字符串Post到后端进行处理和保存
  • 在前端将Base64字符串转换成二进制的Blob对象形式,再使用常规的文件上传形式(即FormData)来将其上传到后端

第一种方式对前端来说比较简单,主要的处理逻辑在后端。而第二种的话前端的工作就稍微复杂一些。考虑到后端采用接收二进制文件的方式来处理文件上传的情况比较多,所以我们来看一下前面所说的第二种情况在前端怎么来实现,以下是主要的示例代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>使用FormData上传压缩裁剪后的图片Blob对象</title>
</head>

<body>
    <input type="file" name="myfile" id="myfile" onchange="uploadHandler(event)">

    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

    <script>
        function uploadHandler(e) {
            var files = e.target.files || e.dataTransfer.files;

            if (files && files.length > 0) {
                var file = files[0];

                resizeImage(file).then(function (result) {
                    return typeof result === 'string' ? convertToBlob(result, file.type) : result;
                }).then(function (blob) {
                    // 构建FormData
                    var formData = new FormData();
                    //注意:此处第3个参数最好传入一个带后缀名的文件名,否则很有可能被后台认为不是有效的图片文件
                    formData.append("file", blob, file.name); 
                    // 上传文件
                    $.ajax({
                        url: '/api/upload',
                        method: "POST",
                        data: formData,
                        cache: false,
                        processData: false,
                        contentType: false
                    }).then(function (res) {
                        console.log(res);
                    }).catch(function (err) {
                        console.log(err);
                    })
                });
            }
        }

        /**
         * 压缩裁剪图片
         */
        function resizeImage(file) {
            return new Promise(function (resolve, reject) {
                var reader = new FileReader();

                reader.onload = function () {
                    var img = new Image();

                    img.onload = function () {
                        var w = this.naturalWidth;
                        var h = this.naturalHeight;
                        var maxW = 500;
                        var maxH = 500;

                        // 如果图片尺寸小于最大限制,则不压缩直接上传
                        if (w <= maxW && h <= maxH) {
                            resolve(file);
                            return;
                        }

                        var level = 0.6;
                        var multiple = Math.max(w / maxW, h / maxH);
                        var resizeW = w / multiple;
                        var resizeH = h / multiple;

                        var canvas = document.createElement("canvas");

                        canvas.width = resizeW;
                        canvas.height = resizeH;

                        var ctx = canvas.getContext("2d");

                        ctx.drawImage(img, 0, 0, resizeW, resizeH);

                        var base64Img = canvas.toDataURL(file.type, level);
                        var arr = base64Img.split(",");

                        resolve(arr[1]);
                    };

                    img.src = this.result;
                };

                reader.readAsDataURL(file);
            });
        }

        /**
         * 将图片的base64字符串转换为Blob对象
         */
        function convertToBlob(base64Str, fileType) {
            var base64 = window.atob(base64Str);
            var len = base64.length;
            var buff = new ArrayBuffer(len);
            var uarr = new Uint8Array(buff);

            for (var i = 0; i < len; i++) {
                uarr[i] = base64.charCodeAt(i);
            }

            var blob = null;

            try {
                blob = new Blob([buff], { type: fileType });
            } catch (e) {
                var BlobBuilder = window.BlobBuilder = (
                    window.BlobBuilder ||
                    window.WebKitBlobBuilder ||
                    window.MozBlobBuilder ||
                    window.MSBlobBuilder
                );

                if (e.name === "TypeError" && BlobBuilder) {
                    var builder = new BlobBuilder();
                    builder.append(buff);
                    blob = builder.getBlob(fileType);
                }
            }

            return blob;
        }
    </script>
</body>

</html>

代码中值得注意的一点是下面这行代码:

formData.append("file", blob, file.name); 

如果不传第三个参数的话,生成的表单数据中,上传文件对应的filename会被设置为blob

通常情况下这也是没问题的。但是可能由于后端使用的不同框架或自己的逻辑代码的原因,对上传的文件名做了强制的后缀名检查,会发生报错导致上传失败,遇到这种情况,请记得使用上面的方式加上第三个参数,这样问题应该就能迎刃而解了。

目录
相关文章
|
JavaScript
vue3-在自定义hooks使用useRouter 报错问题
vue3-在自定义hooks使用useRouter 报错问题
2650 0
|
移动开发 前端开发 JavaScript
js实现图片压缩上传
最近在研究H5前端图片处理相关技术,方向有图片压缩、裁切、旋转、模糊等。
647 0
|
Web App开发 前端开发 JavaScript
React 之 requestIdleCallback 来了解一下
React 之 requestIdleCallback 来了解一下
1924 0
|
Rust 前端开发 JavaScript
Tauri 开发实践 — Tauri 日志记录功能开发
本文介绍了如何为 Tauri 应用配置日志记录。Tauri 是一个利用 Web 技术构建桌面应用的框架。文章详细说明了如何在 Rust 和 JavaScript 代码中设置和集成日志记录,并控制日志输出。通过添加 `log` crate 和 Tauri 日志插件,可以轻松实现多平台日志记录,包括控制台输出、Webview 控制台和日志文件。文章还展示了如何调整日志级别以优化输出内容。配置完成后,日志记录功能将显著提升开发体验和程序稳定性。
1359 1
Tauri 开发实践 — Tauri 日志记录功能开发
|
索引
鸿蒙开发:自定义切换动画实现Swiper层叠滑动效果
customContentTransition不仅仅可以实现平移上的改变,很多的效果,我们都可以实现,比如放大缩小,旋转等等。
571 2
鸿蒙开发:自定义切换动画实现Swiper层叠滑动效果
|
开发者
HarmonyOS NEXT实战:网络图片加载和失败占位图
本教程介绍如何在HarmonyOS应用中实现网络图片加载时显示加载图、加载完成后显示图片、加载失败时显示占位图的功能。内容涵盖Image组件的alt、onComplete、onError等接口使用,适用于教育和实战开发场景。
571 0
|
数据库连接 网络安全 数据库
Could not create connection to database server.Attempted reconnect 3 times. Giving up.
这篇文章提供了解决数据库连接问题的方法,建议在连接字符串后添加`?serverTimezone=UTC`来指定时区,并检查网络设置、连接属性、驱动版本以及是否需要SSH或SSL连接。
Could not create connection to database server.Attempted reconnect 3 times. Giving up.
|
Web App开发 Java iOS开发
webp详解
WebP是一种由谷歌开发的图像文件格式,旨在提供更高效的图像压缩方法,以加快网页加载速度。它支持有损和无损压缩模式,并且在相同的视觉质量下,相比JPEG和PNG等格式,文件大小更小,从而优化了网络传输效率。此外,WebP还支持透明度和动画图像。
|
存储 SQL 关系型数据库
MySQl中的乐观锁是怎么实现的
MySQl中的乐观锁是怎么实现的
833 0
MySQl中的乐观锁是怎么实现的
uniapp前置摄像头拍照功能怎么实现?
uniapp前置摄像头拍照功能怎么实现?
1021 0