canvas应用-----图片压缩

150 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情


随着在前端的不断学习,越来越觉得canvas的功能是真的很强大!首先不仅可以当画布,而且还可以进行图片相关的处理。这篇文章是介绍canvas的其中一个用处---图片压缩。该文章所述的图片压缩包括压缩尺寸和压缩分辨率。相关代码都是使用原生js进行实现,框架用多了,感觉自己的原生js编码能力有了不同程度的退步。

所以写这篇文章的目的有三,总结知识,锻炼原生js能力,锻炼文字表达能力。

回归正题,开始代码!

第一步

在html中创建一个input标签,用做上传图片。

<input type="file" id="upload">

第二步

创建一个script标签进行编写代码,并获取input的dom元素,对input进行"change"监听,如果用户使用input上传文件就会触发监听器。并在事件监听的回调函数中,设置上传图片的类型和大小标准。

<script>
const acceptType = ['image/png','image/jpeg']//可接受的图片类型
const MAX_SIZE = 1024*1024*3//图片最大的储存大小
const MAX_STR = '3MB'//图片大小的提示语
const input = document.getElementById('upload')
input.addEventListener("change",(e)=>{
    const [file] = e.target.files//等同于 const file = e.target.files[0]
    let flag = true//图片是否符合标准的flag
    const {type:fileType,size:fileSize} = file //对上传的图片文件进行结构,获取类型和大小(准备设置标准)
    if(!acceptType.includes(fileType)){//对图片的类型进行判断
        input.value = ''//如果不符合标准,就将input的文件清空
        flag = false//表明图片不符合标准
        alert(`不接受类型${fileType}的文件`)
      }
      if(fileSize>MAX_SIZE){//对图片的大小进行判断
        input.value = ''
        flag = false
        alert(`图片大小超过了最大限制${MAX_STR}`)
      }
      if(flag){//如果图片符合标准,进行下一步
        coverImageToBase64(file,(baseImg)=>compress(baseImg))
      }
})
</script>

第三步

构建coverImageToBase64函数,将图片文件转为base64格式,在进行其他处理。

function coverImageToBase64(file,callback){
    let reader = new FileReader()//FileReader读取input上传的file对象的文件
    reader.addEventListener("load",(e)=>{//当FileReader回调load的时候,就证明图片已经加载好了
        const base64Image = e.target.result
        callback&&callback(base64Image)//对图片的base64进行处理
        reader=null//用完reader置为空,利于垃圾回收(写出高质量代码,从我做起,哈哈哈哈)
    })
    reader.readAsDataURL(file)//先设置监听器,再读取文件,这样读取文件完成后,就可以触发监听器啦
    
}

第四步

由第二步代码段的最后一步,我们可知,回调函数就是compress函数,也就是真正的压缩函数。全文的关键部分都在这里。首先创建image对象,获取其原生宽高,与所设置的最大值进行比较,然后矫正。然后创建canvas绘制图片,再转换格式等操作实现压缩,具体操作都在代码中。注释很详细

function compress(base64){
    let maxW = 1024//图片的最大宽度
    let maxH = 1024//图片的最大高度
    const image = new Image()//图片对象
    image.addEventListener("load",(e)=>{//对图片对象设下事件监听,不多说了,同reader
        let radio;//大小的比率
        let needcompress;//是否需要压缩的flag
        if(maxW<image.natrualWidth){//如果图片的原生大小大于规定的最大宽度
            radio = image.natrualWidth/maxW;//算出要缩小的比率
            maxH = image.natrualHeight/radio//将高度也等比率缩小
            needcompress = true//表明图片需要压缩
        }
        if(maxH<image.natrualHeight){//如果图片的原生大小大于规定的最大宽度
            radio = image.natrualWidth/maxH;//算出要缩小的比率
            maxW = image.natrualWidth/radio//将高度也等比率缩小
            needcompress = true//表明图片需要压缩
        }
        let canvas = document.getElementById("canvas")
        if(!canvas){//页面中是否存在canvas的dom元素,存在直接获取,不存在就创建一个加进去
            canvas = document.createElement("canvas")
            canvas.setAttribute("id","canvas");
            document.body.appendChild(canvas)
        }
        canvas.width = maxW
        canvas.height = maxH//设置canvas的宽度
        const ctx = canvas.getContext("2d")
        ctx.drawImage(image,0,0,maxW,maxH)//绘制图片到canvas中
        const compressImage = canvas.toDataURL("image/jpeg",0.1)//转为base64降低质量为0.1
        const image1 = new Image()
        image1.src = compressImage
        document.body.appendChild(image1)//将压缩后的图片加入页面
    })
    image.src = base64
}

效果对比图: 我们可以看到压缩后的图片,锯齿很明显,实际上更明显,我为了形成对比,将页面缩小的很多(可以注意到左下角的上传按钮已经变得很小了) image.png 压缩前

image.png 压缩后

image.png

我们在观察下图片的大小

压缩前

image.png 压缩后

image.png

可以看到图片缩小的很多了,这就可以证明我们此次压缩是成功的。 补充:在调用toDataURL方法的时候,我们是第二个参数传递的是0.1,这个参数的作用是用于设置转换为base64编码后图片的质量,取值范围为0-1,超出取值范围用默认值0.92代替;,所以说0.1是个很小的数字,通常我们会使用0.8,0.7等数字保证图片的质量,也进行了压缩。

总结:

首先要获取到input中上传的图片,可以对上传规则进行限制,如图片的大小(所占储存的大小,不是尺寸)和类型等。上传的图片通过规则校验后,会将图片转为base64格式进行处理,将base64赋值到image对象的src上,判断图片的原生宽高,如果超过我们所设置的阈值就进行强行矫正,这就达到了压缩尺寸大小的目的,将图片添加到页面中,同时向页面中添加canvas,利用canvas的drawImage的方法进行绘制图片,然后调用toDataURL方法,对canvas上的图片格式转换为base64,并且可以调节图片的质量,从而达到压缩存储大小的目的。

再补充

如果要将图片传回服务端的话,可以将改写compress函数,设置compress函数的第二个参数为回调函数,这个回调函数就是上传服务端的函数,使用方法大致与下文代码相同

coverImageToBase64(file,(baseImg)=>compress(baseImg))

全文结束!