实用技能!如何使用Canvas封装图片压缩功能

最近在学习和工作中遇到这样一个场景:如何将前端上传的图片进行压缩传递给服务端?因为此前从未了解过图片压缩的功能,所以也是带着好奇进行了一番学

整体思路

  1. 创建input框实现图片上传

  2. 将上传的文件转成base64格式

  3. 前端通过base64进行原始图片展示,并将此图片进行压缩

  4. 将压缩后的图片传给服务器

代码实现

首先我们要实现input上传文件并做一些细节处理,细节处理要对上传的文件类型和上传的文件大小做限制,类型和大小这里我们可以根据规则自定义。

习,那么我的解决思路如下展示


<div class="container">
    <input type="file" id="upload" />
</div>
const ACCEPT = ['image/jpg', 'image/png', 'image/jpeg'] // 所能接受的类型(自定义)
const MAXSIZE = 3 * 1024 * 1024 // 上传图片大小限制(自定义)
const MAXSIZE_STR = '3MB'
const upload = document.getElementById('upload')
upload.addEventListener('change', (e) => {
    const [file] = e.target.files
    if (!file) return // 上传文件为空时终止
    const { type: fileType, size: fileSize } = file
    // 类型判断
    if (!ACCEPT.includes(fileType)) {
        alert('不支持' + fileType + '文件类型')
        upload.value = ''
        return
    }
    // 图片大小判断
    if (fileSize > MAXSIZE) {
        alert(`文件超出${MAXSIZE_STR}限制`)
        upload.value = ''
        return
    }
    // 压缩图片
    covertImageToBase64(file, (base64Image) =>
        compress(base64Image, uploadServer)
    )
})

当所有限制都通过之后,就要将图片转为base64格式,也就是进入到covertImageToBase64函数,我们来看看这个函数做了什么

function covertImageToBase64(file, callback) {
    let reader = new FileReader()
    reader.readAsDataURL(file) // 读取二进制数据,并将其编码为 base64 的 data url

    // 读取完成进行下面操作
    reader.addEventListener('load', function (e) {
        const base64Image = reader.result
        callback && callback(base64Image) // 将读取到的结果传递给回调函数中
        reader = null
    })
}

这里我们要将上传获取的_file_进行编码转换,通过FileReaader[1]构造函数中的 readAsDataURL[2]方法进行转换,将编码后的格式文件传递给回调函数中准备进行压缩处理

到这里这里为了方便大家的理解,我做了一个动图方便观看效果,样式比较简陋😒

重点的压缩图片函数

上面的代码都比较好理解,这里较为复杂的逻辑就都在covertImageToBase64函数的的回调compress中,这个功能也是压缩图片中最为核心的部分。

function compress(base64Image, callback) {
    let maxW = 800 // 图片最大宽度
    let maxH = 800 // 图片最大高度
    const image = new Image()
    image.src = base64Image
    document.body.appendChild(image)
    image.addEventListener('load', function (e) {
        let ratio // 图片压缩比 
        let needCompress = false // 是否需要压缩
        // 按照比例进行图片宽高的修改
        if (image.naturalWidth > maxW ) {
            needCompress = true
            ratio = image.naturalWidth / maxW
            maxH = image.naturalHeight / ratio
         }
         if (maxH < image.naturalHeight) {
            needCompress = true
            ratio = image.naturalHeight / maxH
            maxW = image.naturalWidth / ratio
          }
         if (!needCompress) {
            maxH = image.naturalHeight
            maxW = image.naturalWidth
          }
          const canvas = document.createElement('canvas')
          canvas.setAttribute('id', '__compress__')
          canvas.width = maxW
          canvas.height = maxH
          canvas.style.visibility = 'hidden'
          document.body.appendChild(canvas)
          const ctx = canvas.getContext('2d')
          ctx.clearRect(0, 0, maxW, maxH)
          ctx.drawImage(image, 0, 0, maxW, maxH)
          const compressImage = canvas.toDataURL('image/png', 0.9)
          callback && callback(compressImage)
          // console.log(compressImage)
          canvas.remove()
        })
}
function uploadServer(compressImage) {
    console.log(`upload to server ${compressImage}`)
}

代码分析

当我们接收到传来的base64编码的图片时,可以对其进行压缩,根据自定义的宽高与图片实际宽高对比进行比例计算,通过创建canvas元素画出该图片,并通过toDataURL[3] 方法将计算宽高后也就是压缩后的base64返回,传入回调中就可以进行服务器上传了,那么通过检验也是能够看到图片确实进行了压缩

总结

要想更好的理解图片压缩,还是要把_FileReader_和_canvas_的一些api弄清楚,这样才会更加容易理解代码的逻辑,希望这篇文章能够帮助到各位大佬

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在云函数中也可以使用 `canvas` 库来进行图片的压缩处理,以下是使用 `canvas` 进行图片压缩的示例代码: ```javascript const cloud = require('wx-server-sdk') const { createCanvas, loadImage } = require('canvas') cloud.init() exports.main = async (event, context) => { // 获取文件 ID const fileID = event.fileID // 下载文件 const res = await cloud.downloadFile({ fileID: fileID }) // 读取文件内容 const buffer = res.fileContent // 使用 canvas 进行图片压缩 const image = await loadImage(buffer) const canvas = createCanvas(500, image.height * 500 / image.width) // 创建 Canvas 对象 const ctx = canvas.getContext('2d') ctx.drawImage(image, 0, 0, canvas.width, canvas.height) // 绘制图片到 Canvas 上 const compressedBuffer = canvas.toBuffer('image/jpeg') // 获取压缩后的图片 Buffer // 上传压缩后的图片到云存储 const result = await cloud.uploadFile({ cloudPath: 'compressed.jpg', fileContent: compressedBuffer }) // 返回压缩后图片的文件 ID return result.fileID } ``` 上面的示例代码中,我们首先使用 `cloud.downloadFile()` 方法下载图片文件,然后使用 `loadImage()` 方法读取图片内容,接着创建一个指定宽度的 Canvas 对象,并使用 `ctx.drawImage()` 方法将图片绘制到 Canvas 上,最后使用 `canvas.toBuffer()` 方法获取压缩后的图片 Buffer。最后,使用 `cloud.uploadFile()` 方法将压缩后的图片上传到云存储中,并返回压缩后图片的文件 ID。 需要注意的是,上面的示例代码中压缩后的图片格式为 JPEG,如果原图片为 PNG 格式,压缩后的图片格式需要修改为 `image/png`。同时,由于 Canvas 对象需要占用一定的内存,如果需要批量处理大量的图片,建议使用 `jimp` 等更轻量级的库进行处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值