前端js实现canvas压缩图片并上传(代码片段)

铁锤妹妹@ 铁锤妹妹@     2023-03-26     536

关键词:

一. 上传前压缩图片的好处

  1. 可以减少用户的等待时间,提升使用体验,目前手机拍摄的图片文件大小一般在几 M 左右,文件直接上传时会有卡顿现象。
  2. 可以减少服务端存储空间
  3. 再次回去图片资源是也可以快速的加载。虽然目前阿里云的 oss 有相对应的 api 可以通过降低图片质量等方法减少体积,不过使用 canvas 可以直接减少源文件的体积。

因此我们很有必要对上传的图片进行压缩。

二. 处理流程

主要包括以下流程:

  1. 用户通过van-uploader选择图片。
  2. 使用FileReader进行图片预览。
  3. 将图片绘制到canvas画布上,使用canvas画布的能力进行图片压缩todataurl()方式会把图片自动转成base64。
  4. 将压缩后的Base64(DataURL)格式的数据转换成Blob对象进行上传,或者直接上传base64格式,这个根据自己需求。
  5. 将图片上传服务端,上传时候创建Formdata对象实例 new FromData(),把base64或Blob,append()到Formdata里面请求服务端接口,提交图片。
  6. 上传成功,后台接口返回图片的URL。

三. 了解概念

在写代码之前,先来了解几个概念。当然也可以跳过这部分,直接看代码。

1)new FileReader()
我们先来看看官方文档的介绍 FileReader

FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

FileReader常用的两个方法如下:

FileReader.onload: 处理load事件。即该钩子在读取操作完成时触发,通过该钩子函数可以完成例如读取完图片后进行预览的操作,或读取完图片后对图片内容进行二次处理等操作。
FileReader.readAsDataURL():读取方法,并且读取完成后,result属性中将包含一个data: URL 格式的 Base64 字符串以表示所读取文件的内容(比如图片)。

在图片上传中,我们可以通过readAsDataURL()方法进行了文件的读取,并且通过result属性拿到了图片的Base64(DataURL)格式的数据,然后通过该数据实现了图片预览的功能。

2)new FormData()
我们先来看看官方文档的介绍 FormData 对象的使用

FormData 对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据。其主要用于发送表单数据,但亦可用于发送带键数据 (keyed data),而独立于表单使用。如果表单enctype属性设为 multipart/form-data,则会使用表单的submit()方法来发送数据,从而,发送数据具有同样形式。

let formdata = new FormData()
console.log(formdata)

操作方法:new FormData()对象的作用以及使用方法

3)new Image()

我们先来看看官方文档的介绍 Image()

Image()函数将会创建一个新的HTMLImageElement实例。它的功能等价于 document.createElement('img')
Image对象是JS中的宿主(或内置)对象,他代表嵌入的图像。当我们创建一个Image对象时,就相当于给浏览器缓存了一张图片,Image对象也常用来做预加载图片(也就是将图片预先加载到浏览器中,当浏览图片的时候就能享受到极快的加载速度)。在HTML页面中,标签每出现一次,也就创建了一个Image对象。

建立图像对象:`let 图像对象名称=new Image([宽度],[高度])`
图像对象的属性: `border complete height hspace lowsrc name src vspace width`
图像对象的事件:`onabort onerror onkeydown onkeypress onkeyup onload`

var img = new Image(); //创建一个Image对象 ,会渲染为img标签
img.src = "17.png";  //相当于给浏览器缓存了一张图片
img.onload = function()alert("img is loaded");  //onload 事件在图片加载完成后立即执行。
img.onerror = function()alert("error!");  // 当图片加载出现错误,会触发,经常在该事件中将图片导向报错图片,以免页面上出现红色的叉叉
img.border="3px solid #ccc"; 

4)canvas的toDataURL()方法
我们先来看看官方文档的介绍HTMLCanvasElement.toDataURL()

HTMLCanvasElement.toDataURL() 方法返回一个包含图片展示的 data URI 。可以使用 type 参数其类型,默认为 PNG 格式。图片的分辨率为 96dpi。

语法:

canvas.toDataURL(type, encoderOptions);

参数:

type:图片格式,默认为 image/png,可以是其他image/jpeg等
encoderOptions:01之间的取值,主要用来选定图片的质量,只要导出为jpg和webp格式的时候此参数才有效果。默认值是0.92,超出范围也会选择默认值。

返回值:

返回值是一个数据url,是base64组成的图片的源数据、可以直接赋值给图片的src属性。

5)图片的展示方式有三种:分别为file(文件流)、blob(本地流)、base64(二进制流)

四. 代码实现

1)通过van-uploader来获取图片

<van-field name="business_license" :rules="[ required: true, message: '请上传图片' ]">
     <template #input>
         <van-uploader
           :max-size="3000 * 1024"
           @oversize="onOversize"
           :after-read="afterReadLicense"
           :before-delete="deleteLicense"
           v-model="form.licenseArray"
           :max-count="1"
          />
     </template>
</van-field>
    //获取上传图片大小,进行压缩处理
  compressImg (file) 
      let quality = 1
      if (file.file.size / (1024 * 1024) > 1) 
        quality = 1 / Math.ceil(file.file.size / (1024 * 1024)) // 默认到1m以下
      
      quality = quality / 2 // 默认质量减半(超过1m的图片,默认质量为500k)
      var that = this
      return new Promise(function (resolve, reject) 
        if (file == []) 
          reject(error)
         else 
          if (that.isImageAutomaticRotation) 
            that.imgHandle(file.file, quality).then(res => 
              resolve(res)
            )
           else 
            lrz(file.file,  quality: quality ).then(res => 
              resolve(res.base64)
            )
          
        
      )
    ,
    // 这是图片上传压缩的核心所在,我们先使用CanvasRenderingContext2D.drawImage()方法将上传的图片文件在画布上绘制出来;
   // 再使用Canvas.toDataURL()将画布上的图片信息转换成base64(DataURL)格式的数据。
   imgHandle (file, quality) 
      return new Promise(function (resolve, reject) 
        let fileType = file.type
        let imgResult = ''
        let reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onload = function () 
          let img = new Image() //先创建图片对象
          img.src = this.result
          let canvas = document.createElement('canvas')
          let ctx = canvas.getContext('2d')
          img.onload = function ()  //图片加载完后
            // 做适配
            let width = 500
            if (img.width < 500) 
              width = img.width
            
            canvas.width = width
            canvas.height = (img.height / img.width) * width
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height)  //绘制图像;把大图片画在一张小画布上,压缩就这么实现了
            // 返回base64
            //quality表示导出的图片质量,只要导出为jpg和webp格式的时候此参数才有效果,默认值是0.92
            imgResult = canvas.toDataURL(fileType, quality)
            resolve(imgResult)
            
            // 这时可能后端要求我们传文件格式图片 base64转Blob
            // const blobImg = that.converrVase64UrlToBlob(imgResult , fileType)
            // resolve(blobImg)
          
        
        reader.onerror = function (error) 
          reject(error)
        
      )
    ,
  // base64转Blob
  converrVase64UrlToBlob (base64, mimeType) 
      // mimeType 图片类型,例如 mimeType='image/png'
      const bytes = window.atob(base64.split(',')[1]) // atob方法用于解码base64
      // 创建一个长度为 bytes.length 的 buffer(一个二进制文件), 它会分配一个 16 字节(byte)的连续内存空间,并用 0 进行预填充。
      const ab = new ArrayBuffer(bytes.length)

      // Uint8Array —— 将 ArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位)。这称为 “8 位无符号整数”。
      const ia = new Uint8Array(ab)
      for (let i = 0; i < bytes.length; i++) 
        // 更改里面的初始化内容
        ia[i] = bytes.charCodeAt(i)
      
      // 创建blob格式数据,并传入二进制文件和文件原本类型
      return new Blob([ia],  type: mimeType )
    ,
    
  // 上传前置处理
  // 将图片上传到服务端
  afterReadLicense (file) 
      this.compressImg(file).then(res => 
        let formData = new FormData()
        formData.append('m_pic', res)  //append方法往formData里添加数据
        formData.append('token', sessionStorage.getItem('token'))
        console.log(formData.get('m_pic'), 'm_pic') //只能通过get方法查看添加的m_pic
        //请求接口,上传图片
        indexApi
          .uploadImg(formData)
          .then(response => 
            if (response.data.code === 200) 
              this.form.business_license = response.data.data.url //赋值
             else 
              this.$toast.fail(response.data.message)
            
          )
          .catch(error => 
            console.log(error)
          )
      )
    ,
// 封装的上传图片接口
 uploadImg (val) 
    return formRequest(
      url: 'merchant/upload_img',
      method: 'post',
      data: val,
      headers: 
        'Content-Type': 'multipart/form-data'
      
    )
  ,

注意:
在实际开发中,我们要不要把图片转化为FormData形式上传到服务端,这就看具体的业务需要了。
我们还可以把canvas压缩过的图片,通过axios请求 URL,并通过FormData附带额外的参数,上传到阿里云oss,会返回一个url,就是我们上传到阿里云的图片地址;然后前端拼成一个图片 url 用于from表单提交上传。

学习过程中参考了其他文章:
浅析图片上传及canvas压缩的流程(canvas图片压缩)
Canvas怎么实现上传并压缩图片
vue + elementUi + upLoadIamge组件 上传文件到阿里云oss

html5fileapi加canvas实现图片前端js压缩并上传(转载)

一、图片上传前端压缩的现实意义对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验。这种体验包括两方面:由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅,同时... 查看详情

前端通过canvas实现图片压缩

...体验,所以要求对用户上传图片进行压缩后再上传;那么前端怎么实现这个功能呢?亲测可将4M图片压缩至100kb左右,代码如下:<inputid="file"type="file"><scripttype="text/javascript">vareleFile=docum 查看详情

前端js利用canvas的drawimage()对图片进行压缩

  对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验。  这种体验包括两方面:  1、由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅,同时大大降低了网络... 查看详情

前端预览图片和h5canvas压缩图片上传

思路是将图片抽样显示在canvas上,然后用通过canvas.toDataURL方法得到base64字符串来实现压缩。1.base64转二进制文件/***dataURLtoblob,reftohttps://gist.github.com/fupslot/5015897*@paramdataURI*@returns{Blob}*/functiondataURItoBlob(dataURI){var 查看详情

前端图片压缩方案及代码实现(代码片段)

...页进行预加载,抖音的滑屏滚动就是这种方式;2.前端图片压缩方案前端实现图片压缩的基本思路为:在上传图片时,将file转换成image对象,然后再利用canvas及其 api 将图片压缩成指定体积。 3. 前端图片压缩方案... 查看详情

前端图片压缩方案及代码实现(代码片段)

...页进行预加载,抖音的滑屏滚动就是这种方式;2.前端图片压缩方案前端实现图片压缩的基本思路为:在上传图片时,将file转换成image对象,然后再利用canvas及其 api 将图片压缩成指定体积。 3. 前端图片压缩方案... 查看详情

前端图片压缩方案及代码实现(代码片段)

1.为什么要进行图片压缩?随着互联网的发展,图片在各种网站和应用中铺天盖地,运营人员在后台管理系统中上传图片时常常忽略的图片的体积大小,随之产生的带宽和服务器容量也大大增加,图片压缩的需求随... 查看详情

前端获取图片压缩后上传给后台(代码片段)

 此前有同事跟我聊过关于移动端用canvas压缩图片后再上传的功能,最近有了点空闲时间,所以就实践了一下。demo效果链接在文章底部贴出。  在做移动端图片上传的时候,用户传的都是手机本地图片,而本地图片一般都... 查看详情

canvas剪裁图片并上传,前端一步到位,无需用到后端

...作剪裁。   目前看来这个剪裁主要还是先通过前端上传图片到服务器,然后前端操作后把一些坐标和大小数据传到后台,然后后台来执行剪裁。我一直觉得这样有很多问题:   1.必须要先把图 查看详情

vue中前端实现生成pdf并下载(代码片段)

思路:通过html2canvas将HTML页面转换成图片,然后再通过jspdf将图片的base64生成为pdf文件。1.安装及引入//将页面html转换成图片npminstallhtml2canvas--save//将图片生成pdfnpminstalljspdf--save在项目主文件main.js中引入定义好的实现方法... 查看详情

canvas保存图片到七牛云(代码片段)

最近在做一个项目,需要在前端对图片切片并上传到七牛云技术要点canvas.toBlob(blob=>);//可将canvas保存成二进制文件formData.append(‘file‘,blob,‘filename‘);//将二进制文件添加到FormData中ajax.send(formData);//上传数据到后端处理代码实... 查看详情

h5+jqweui实现手机端图片压缩上传

...,使用H5的formData上传base64格式的图片,canvas压缩图片,前端样式使用weui,为方便起见,使用了jquery封装过的weui,jqweui。话不多少,开始上代码。前端代码,直接在jqweui官网下的demo里改的(是dist下的demo)<!DOCTYPEhtml><html&g... 查看详情

前端压缩并上传图片

参考技术A移动端工单报修的场景中,上传图片的功能已经屡见不鲜,但现在手机像素普遍较高,随手拍一张图片都6、7M,十几兆的图片也并不罕见。如果这些未处理的图片直接随数据上传向服务器,不但会占用更多的存储空间... 查看详情

图片压缩canvas

实现流程:获取<inputtype="file">上传的文件;使用FileReader读取图片,并新建一个Image对象将FileReader读取的图片数据放进去;使用canvas将Image对象等比缩放并写入到画布中,保存为base64格式的数据(这里使用的是FormData对象上传... 查看详情

图片压缩上传(代码片段)

图片压缩的方法//图片压缩compressImage(file,success,error)//图片小于1M不压缩//if(file.size<Math.pow(1024,2))//returnsuccess(file);//constname=file.name;//文件名constreader=newFileReader();reader.readAsDataURL(file);reader.onload=e=>constsrc=e.target.result;constimg=newImage... 查看详情

h5图片预览压缩上传(代码片段)

目标实现:  1、选择图片,前端预览效果  2、图片大于1.2M的时候,对图片进行压缩  3、以表单的形式上传图片  4、图片删除   预览效果图: 代码说明:1、input:file选择图片<!--html部分--><ulid="preview"cla... 查看详情

微信小程序用canvastotempfilepath压缩图片,开发工具压缩正常而真机上比例失调(代码片段)

...机上比例失调。主要是用wx.canvasToTempFilePath方法。我是要实现一个上传4张图片的功能:二.实现:用于处理压缩图片的canvas<!--用于处理压缩图片的canva 查看详情

微信小程序用canvastotempfilepath压缩图片,开发工具压缩正常而真机上比例失调(代码片段)

...机上比例失调。主要是用wx.canvasToTempFilePath方法。我是要实现一个上传4张图片的功能:二.实现:用于处理压缩图片的canvas<!--用于处理压缩图片的canva 查看详情