我们通常在做图片上传的时候都会遇上这样的情况,一是后端接口限制上传图片的大小,或者是即使后端没有限制大小,因为图片太大在前端渲染时太慢,造成页面加载体验较差。因此我们很有必要对上传的图片进行压缩。

本文在gitthub做了收录:github.com/Michael-lzg…

本文主要包括以下流程:

用户通过input框选择图片 使用FileReader进行图片预览 将图片绘制到canvas画布上 使用canvas画布的能力进行图片压缩 将压缩后的Base64(DataURL)格式的数据转换成Blob对象进行上传

Input 标签来获取图片

通过设置input标签的type属性为file,来让用户可以选择文件,设置accept限制选择的文件类型,绑定onchange事件,来获取确认选择后的文件

<input type="file" accept="image/*" onchange="loadFile(event)"

FileReader

FileReader是什么,我们先来看看官方文档的介绍

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

FileReader常用的两个方法如下:

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

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

<div class="container">  <input type="file" accept="image/*" onchange="loadFile(event)" /></div><script>  const loadFile = function (event) {    let file =  event.target.files[0]    const reader = new FileReader()    reader.onload = function () {      console.log(reader.result)      ...    }    reader.readAsDataURL(file)  }</script>

canvas 压缩图片

这是图片上传压缩的核心所在,我们先使用CanvasRenderingContext2D.drawImage()方法将上传的图片文件在画布上绘制出来,再使用Canvas.toDataURL()将画布上的图片信息转换成base64(DataURL)格式的数据。

drawImage()

drawImage()方法在画布上绘制图像、画布或视频。drawImage()方法也能够绘制图像的某些部分,以及/或者增加或减少图像的尺寸。参数如下

img 规定要使用的图像、画布或视频。 sx 可选。开始剪切的 x 坐标位置。 sy 可选。开始剪切的 y 坐标位置。 swidth 可选。被剪切图像的宽度。 sheight 可选。被剪切图像的高度。 x 在画布上放置图像的 x 坐标位置。 y 在画布上放置图像的 y 坐标位置。 width 可选。要使用的图像的宽度。(伸展或缩小图像) height 可选。要使用的图像的高度。(伸展或缩小图像)
var cas = document.querySelector(canvas)var ctx = cas.getContext(2d)// 先创建图片对象var img = new Image()img.src = ./images/1.jpg// 图片加载完之后img.onload = function () {  ctx.drawImage(img, 206, 111, 32, 38, 100, 100, 32, 38)}

Canvas.toDataURl()

Canvas.toDataURl()方法可以将canvas画布上的信息转换为base64(DataURL)格式的图像信息,纯字符的图片表示形式。该方法接收 2 个参数:

mimeType(可选): 表示需要转换的图像的mimeType类型。默认值是image/png,还可以是image/jpegimage/webp等。 quailty(可选):quality 表示转换的图片质量。范围是 0 到 1。图片的mimeType需要是image/jpeg或者image/webp,其他mimeType值无效。默认压缩质量是 0.92。
var canvas = document.createElement(canvas)canvas.toDataURL("image/jpeg" 0.8)

到这里,我们先来上 canvas 压缩图片的代码

function compress(base64, quality, mimeType) {  let canvas = document.createElement(canvas)  let img = document.createElement(img)  img.crossOrigin = anonymous  return new Promise((resolve, reject) => {    img.src = base64    img.onload = () => {      let targetWidth, targetHeight      if (img.width > MAX_WIDTH) {        targetWidth = MAX_WIDTH        targetHeight = (img.height * MAX_WIDTH) / img.width      } else {        targetWidth = img.width        targetHeight = img.height      }      canvas.width = targetWidth      canvas.height = targetHeight      let ctx = canvas.getContext(2d)      ctx.clearRect(0, 0, targetWidth, targetHeight) // 清除画布      ctx.drawImage(img, 0, 0, canvas.width, canvas.height)      let imageData = canvas.toDataURL(mimeType, quality / 100)      resolve(imageData)    }  })}

将 base64 转化为文件

通过window.atobbase-64字符串解码为binaryString(二进制文本); 将binaryString构造为multipart/form-data格式; 用Uint8Arraymultipart格式的二进制文本转换为ArrayBuffer
function dataUrlToBlob(base64, mimeType) {  let bytes = window.atob(base64.split(,)[1])  let ab = new ArrayBuffer(bytes.length)  let ia = new Uint8Array(ab)  for (let i = 0; i < bytes.length; i++) {    ia[i] = bytes.charCodeAt(i)  }  return new Blob([ab], { type: mimeType })}

将图片上传到服务端

创建一个FormData,把blobappend 到FormData里面请求服务端接口,提交图片

function uploadFile(url, blob) {  let formData = new FormData()  let request = new XMLHttpRequest()  formData.append(image, blob)  request.open(POST, url, true)  request.send(formData)}

ps:在实际开发中,我们要不要把图片转化为FormData形式上传到服务端,这就看具体的业务需要了。我们可以上图片上传到腾讯云,直接返回一个https.xxx.jgp的图片 url 用于上传。

到此这篇关于浅析图片上传及canvas压缩的流程的文章就介绍到这了,更多相关图片上传canvas压缩内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!

浅析图片上传及canvas压缩的流程