F2e踩坑之路Js让前端飞

前端实现本地图片读取与简单压缩功能

2017-12-17  本文已影响81人  ac68882199a1

在上一篇文章 Javascript 基础夯实 —— 通过代码构建一个包含文件的 FormData 对象 中提到了前端压缩图片的功能,所以本篇文章就来实现一下这个功能

前端获取本地图片文件

<input id="input" type="file" accept="image/*" >

通过一个类型为fileinput标签,我们可以获取到设备本地的文件,input还可以声明一个accept的属性,这个属性用来过滤input可以选择的文件,如果不声明则可以选择所有文件

在这里,accept的值是image/*,这表示input可以选择所有类型的图片文件,包括 png/jpg/jpeg/gif/bmp 等等,如果需要限制可以选择的文件类型,则可以改写成这样:

// input 仅可以选择 png/jpg/jpeg 格式的图片文件
<input id="input" type="file" accept="image/png, image/jpg, image/jpeg" >

如果需要多选,还可以再声明一个multiple属性

onchange 事件与获取选择的文件

我们可以通过onchange事件监听到input状态的改变,这样就能在选择完文件后,对文件进行操作

input元素有一个files属性,这个属性的值是一个文件对象数组,用来保存当前选择过的文件

const $input = document.getElementById('input')
$input.onchange = e => {
    // 文件对象数组
    console.log($input.files)
}

读取文件对象内容

虽然获取到了选择的图片文件,但是我们并不能对 File 对象直接进行压缩的操作,而是需要先读取 File 对象的内容,再对读取到的内容进行操作

读取 File 对象的内容,我们可以通过 FileReader 对象来实现,此处以选择的第一张图片为例:

$input.onchange = e => {
    // 获取到第一个文件
    const file = $input.files[0]
    // 声明一个 FileReader 实例
    const fileReader = new FileReader()
    // fileReader 读取完成触发的事件
    fileReader.onload = () => {
      // 打印 file 的读取结果
      console.log(fileReader.result)
    }
    // 读取 file 的内容
    fileReader.readAsDataURL(file)
}

FileReader 对象上有以下属性及方法:

需要注意的是, readAsDataURLreadAsText 都是异步的,必须监听 readyState 或者在 onload 事件中才能获取到读取到的结果,所以出现多个文件需要遍历读取的情况时,需要特别注意

在上面的代码中,将图片文件读取为了一个 base64 编码的 URL 字符串,下面就可以通过这个字符串来创建一个 Image 对象了:

fileReader.onload = () => {
    const image = new Image()
    image.onload = () => {
      // 对 image 进行的操作
    }
    image.src = fileReader.result
}

拿到图片文件生成的 image 对象,下面就可以正式进行图片的压缩了!

前端压缩图片的实现

压缩的实现又要借助到 canvas 画布元素。先来说一下原理,再来实现功能

原理简述

首先需要先有一个 canvas 来绘制图片,这个 canvas 的宽高需要设置为我们最终图片压缩后的宽高,比如将一张 19201920 的图片压缩到 300300 的尺寸,那就要将 canvas 的尺寸设置为 300*300

然后再将图片按比例缩放绘制到 canvas 上,再将 canvas 的上下文导出为一个 base64 的 url,导出的过程中我们可以设定导出的压缩比率和导出的图片格式

最终我们拿到了一个压缩后的图片的 base64 编码的 url,我们可以将这个 url 转为 Blob 对象,再通过表单的方式传输到后台。关于这一步,在开头的链接中,也就是上一篇文章已经说过了,在本文中不再赘述:

代码实现

image.onload = () => {
    const imageUrl = compressImage (image)
    console.log(imageUrl)
    // 拿到 base64 URL 后,就可以将其转为 Blob 对象
}

function compressImage (image) {
  // 创建一个 canvas 元素并获取其上下文
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  // 将 canvas 宽高设为原图的 1/10,即将原图宽高压缩 10 倍
  canvas.width = image.width / 10
  canvas.height = image.height / 10
  // 绘制图片
  ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height)
  // 将 canvas 导出为 base64 URL 并返回
  return canvas.toDataURL('image/jpeg', 0.1)
} 

需要注意的几点:

  1. drawImage() 方法是 canvas 上下文环境的方法,而不是 canvas 元素的方法,这个方法可以接收多个参数,并且参数长度不同,作用也不同,在这里的作用是:将 image 从 (0, 0) 的位置开始截取一个宽高为 image.width, image.height 的图像(即将图像完整截取),放置在 canvas 上从 (0, 0) 开始,到 canvas.height, canvas.width 的区域中(也就是完整缩放在 canvas 中)。当传入其他数量参数时,小伙伴们可以参考这个页面:HTML DOM drawImage() 方法
  2. 导出图像方法toDataURL 是 canvas 的方法,第一个参数hi导出的格式,不传或者传入错误格式的话,会默认使用 png 格式;第二个参数是导出的品质系数,范围为 0-1,默认 0.92,但是这个系数只对导出类型为 jpeg 和 webp 的图片生效
扫码关注前端周记公众号
上一篇 下一篇

猜你喜欢

热点阅读