使用Javascript对图片进行定宽或定高压缩处理
使用Javascript对图片进行定宽或定高压缩处理
本文参考了以下链接
https://www.jb51.net/article/182078.htm
https://www.cnblogs.com/xzybk/p/11593269.html
的思路和代码,在此对作者表示感谢
主要思路:
通过原生的input标签拿到要上传的图片文件
将图片文件转化成img元素标签
在canvas上压缩绘制该HTMLImageElement
将canvas绘制的图像转成blob文件
最后将该blob文件传到服务端
1、通过原生的input标签拿到要上传的图片文件
<input class="file" type="file" accept="image"> <script> // 第一步 var file=document.querySelector('.file'); file.addEventListener('change',function(){ console.log(file.files[0],'拿到上传的图片全部属性') }) </script>
2、将图片文件转化成img元素标签
拿到图片文件后,先将其转成HTMLImageElement,也就是普通的img标签,具体要使用 FileReader构造函数。
先new出来一个img和fileReader的实例,通过fileReader的 readAsDataURL这个api,来读取图片文件,其返回值是一个编码后的base64的字符串,然后将这个字符串赋值给img的src属性上,这样就完成了图片文件到 HTMLImageElement的转化。
<input class="file" type="file" accept="image"> <script> var file=document.querySelector('.file'); file.addEventListener('change',function(){ console.log(file.files[0],'拿到上传的图片全部属性') // 第二步 if(window.FileReader) { var reader=new FileReader() console.log(reader,'FileReader构造函数') // 这个地方 必须是file.files[0],否则会报错 reader.readAsDataURL(file.files[0]) reader.onloadend =function (e){ image.src=e.target.result; console.log(img,'拿到图片路径是base64的图片') } } }) </script>
3、在canvas上压缩绘制该HTMLImageElement
拿到转化后的img元素后,先取出该元素的宽高度,这个宽高度就是实际图片文件的宽高度。
然后定义一个最大限度的宽高度,如果超过这个限制宽高度,则进行等比例的缩放
计算好将要压缩的尺寸后,创建canvas实例,设置canvas的宽高度为压缩计算后的尺寸,并将img绘制到上面
<input class="file" type="file" accept="image"> <img class="image" src="" alt=""> <div class="canvas-div"></div> <script> var file=document.querySelector('.file'); var image=document.querySelector(".image") //注意别和后面的new的image混淆了。此处是我获取文档定义的image标签 file.addEventListener('change',function(){ // 第一步 console.log(file.files[0],'拿到上传的图片全部属性') // 第二步 var img=new Image() //创建一个Image对象: if(window.FileReader) { var reader=new FileReader() console.log(reader,'FileReader构造函数') // 这个地方 必须是file.files[0],否则会报错 reader.readAsDataURL(file.files[0]) reader.onloadend =function (e){ img.src=e.target.result; console.log(e.target.result,'拿到图片路径是base64的图片') // 第三步 var { width: originWidth,height:originHeight} = img console.log(originWidth,originHeight) // 最大尺寸限制 此处看个人需求设置 const maxWidth = 400,maxHeight = 400 // 需要压缩的目标尺寸 let targetWidth = originWidth, targetHeight = originHeight if(originWidth>maxWidth || originHeight>maxHeight){ console.log(originWidth /originHeight >1,'宽高比') if(originWidth / originHeight >1){ targetWidth=maxWidth targetHeight=Math.round(maxWidth /(originWidth /originHeight)) console.log(targetWidth,targetHeight,maxWidth /(originWidth /originHeight),'根据定宽') }else{ targetHeight=maxHeight targetWidth=Math.round(maxHeight *(originWidth /originHeight)) console.log(targetWidth,targetHeight,maxHeight *(originWidth /originHeight),'根据定高') } // 计算好将要压缩的尺寸后,创建canvas实例,设置canvas的宽高度为压缩计算后的尺寸,并将img绘制到上面 // 创建画布 var canvas=document.createElement('canvas'); var context=canvas.getContext('2d'); var wrap=document.querySelector('.canvas-div'); // 设置宽高度为等同于要压缩图片的尺寸 canvas.width=targetWidth; canvas.height=targetHeight; context.clearRect(0, 0, targetWidth, targetHeight) //将img绘制到画布上 此处使用离屏canvas技术(提高性能的一种技术方法) context.drawImage(img, 0, 0, targetWidth, targetHeight) // 展现在demo页面中,查看压缩过后的效果 wrap.appendChild(canvas) } } } }) </script>
4、将canvas绘制的图像转成blob文件
canvas.toBlob(function(blob) { console.log(blob)}, 'image/png')
5、最后将该blob文件传到服务端
最后对代码进行优化封装
<input class="file" type="file" accept="image"> <img class="image" src="" alt=""> <div class="canvas-div"></div> <script> var file=document.querySelector('.file'); var image=document.querySelector(".image") file.addEventListener('change',function(){ // 第一步 console.log(file.files[0],'拿到上传的图片全部属性') upload(file.files[0]).catch(e => console.log(e)) }) async function upload(file){ // 第二步 const img = await readImg(file) // 第三步 const blob = await compressImg(img,file.type,500,500) // 输出压缩图片大小 console.log(blob,byteKB(blob.size)+'KB',byteKB(file.size)+'KB','blob') } // 压缩前将file转换成img对象 function readImg(file) { return new Promise((resolve, reject) => { const img = new Image() if(window.FileReader) { const reader = new FileReader() reader.onload = function(e) { img.src = e.target.result } reader.onerror = function(e) { reject(e) } reader.readAsDataURL(file) img.onload = function() { console.log(img,'拿到图片路径是base64的图片') resolve(img) } img.onerror = function(e) { reject(e) } } }) } // 自定义封装的根据定宽或定高压缩图片 function compressImg(imgAttr,type,mxW,mxH){ return new Promise((resolve, reject) => { var { width: originWidth,height:originHeight} = imgAttr console.log(originWidth,originHeight,'宽高') // 最大尺寸限制 const maxWidth = mxW,maxHeight = mxH // 需要压缩的目标尺寸 let targetWidth = originWidth, targetHeight = originHeight if(originWidth>maxWidth || originHeight>maxHeight){ console.log(originWidth /originHeight >1,'宽高比') if(originWidth / originHeight >1){ targetWidth=maxWidth targetHeight=Math.round(maxWidth /(originWidth /originHeight)) console.log(targetWidth,targetHeight,maxWidth /(originWidth /originHeight),'根据定宽') }else{ targetHeight=maxHeight targetWidth=Math.round(maxHeight *(originWidth /originHeight)) console.log(targetWidth,targetHeight,maxHeight *(originWidth /originHeight),'根据定高') } // 计算好将要压缩的尺寸后,创建canvas实例,设置canvas的宽高度为压缩计算后的尺寸,并将img绘制到上面 // 创建画布 var canvas=document.createElement('canvas'); var context=canvas.getContext('2d'); var wrap=document.querySelector('.canvas-div'); // 设置宽高度为等同于要压缩图片的尺寸 canvas.width=targetWidth; canvas.height=targetHeight; // context.clearRect(0, 0, targetWidth, targetHeight) //将img绘制到画布上 context.drawImage(imgAttr, 0, 0, targetWidth, targetHeight) // 展现在demo页面中,查看压缩过后的效果 wrap.appendChild(canvas) // canvas转为blob并上传 canvas.toBlob(function (blob) { // 图片ajax上传 var xhr = new XMLHttpRequest(); // 开始上传 xhr.open("POST", 'action.php', true); //可以自己配置一下action.php文件,接收到该页面发送的file文件 // <?php // $action = $_GET['file']; // echo $action // ?> xhr.send(blob); }, type || 'image/png'); //canvas.toBlob(function(blob) { // resolve(blob) //}, type || 'image/jpg') } }) } //对size取kb的两位小数 function byteKB(size){ return (size/1024).toFixed(2) } </script>
最后总结:
我发现压缩大图结果确实比原来内存小了,但是压缩小的图片(50kb以下)就反而比原来文件大。
所以使用的话,建议去压缩上百kb的文件,可以加个判断验证,小的就不用压缩。
最后一点,就是目前是根据定宽或定高来进行图片压缩,最好的压缩应该是根据设定的图片大小压缩图片至最优。
目前已经有成功的插件( https://github.com/WangYuLue/image-conversion),后面我会抽时间自己研究写一个出来