当前位置: 首页 > Web前端 > HTML

vue下实现输入实现图片上传压缩拼接旋转

时间:2023-04-02 17:22:44 HTML

背景作为一名前端工作者,相信大家在开发系统的时候,经常会遇到这样的需求,即需要为用户保存上传的图片。很多菜鸟遇到这个问题的时候,都会被吓一跳,我认为这将是一个棘手的问题。当你读完这篇文章时,你会发现你是盲目地做的。事实就是这么简单。进入正题:图片文件上传现在很多项目都实现了在系统中保存图片,大部分只是在系统数据库中保存对应图片的url,而实际的图片资源会放在图片服务器上比如阿里.当然,有些项目会选择将图片base64格式的字符串保存在自己的数据库中,如下通过一个Vue实例来说明这两种方式的一些具体实现:首先,我们需要从用户那里获取图片资源。这时候我们需要用到HTML的标签,type值为file,指定input标签为文件类型的表单输入,其accept属性设置为“image/*”,指定仅接受图像资源的文件;接下来,我们将获取用户选择的文件,当用户选择文件时,会触发input标签的change事件。我们可以通过监听事件,获取事件对象event来获取图片文件:点击获取文件后,我们可以使用$event对象获取$event.target.files[0]获取图片资源文件对象。至于为什么要加索引值,是因为文件上传输入表单支持多文件上传。只需将multiple属性添加到input标签;我们可以看下图中文件对象的一些属性:经过观察,我们发现文件对象中有一个size属性,表示图片的大小。我们可以验证这个属性的值是否为空,检查文件是否已经被我们获取到了指定的操作;fileChange(el,index){if(!el.target.files[0].size)return;}至此我们就得到了我们想要的文件对象,接下来我们实现图片压缩功能,将压缩函数命名为:图像压缩首先,我们需要压缩我们的图像资源。第一步肯定是获取图片资源,获取之后简单的检查一下;压缩(事件){varfile=event.target.files;varreader=newFileReader(),imgFile=file[0];如果(imgFile.type.indexOf('image')==0){reader.readAsDataURL(imgFile);}else{this.$Message.infor('文件类型仅为图片')}}这里可能有些人不理解FileReader对象。FileReader对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用File或Blob对象指定要读取的文件或数据。这里我们主要用它来监控onload,判断读取是否完成。当读取完成后,我们将读取的结果赋值给我们新建的Image对象,用于后续的压缩。这个时候我们会发现,我们读到的结果其实是一个base64格式的字符串(很长..,我就是这个意思)。这时候我们会发现base64的字符串在这里出现了,可以将它作为值复制到标签的src属性中,这样也可以达到渲染图片的目的,所以有人选择保存这种格式的图片;但这不是主流方式,也会导致我们的数据库过于冗余;压缩(事件){varfile=event.target.files;varreader=newFileReader(),imgFile=file[0];如果(imgFile.type.indexOf('image')==0){reader.readAsDataURL(imgFile);}else{this.$Message.infor('文件类型仅为图片')}letimg=new图像();reader.onload=function(e){img.src=e.target.result;};}图片压缩,我们主要使用canvas来实现这个功能,通过canvas.getContext('2d')。drawImage()方法重绘图片,使用canvas.toDataURL(type,encoderOptions)方法返回一个包含图片显示的dataURI,type为图片格式,encoderOptions为图片的分辨率,从0递增到1.这个压缩过程不难理解,思路就是获取图片的高和宽,计算出它的像素大小,和自己设定的一个极限值比较,看看我们的尺寸是否需要压缩。例如,示例中的比率表示图片宽高的压缩比。我们可以在不改变宽高的情况下修改图片的文件大小,通过drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight)重绘图片,可以传入九个参数,代表绘制到上下文的元素,源图像选择矩形左上角的X坐标,源图像选择矩形左上角的Y坐标,源图像选择矩形的宽度图像,源图像的选择矩形的高度,目标画布的左上角在目标画布的X轴位置,目标画布的左上角在目标画布的X轴位置目标画布上的Y轴,目标画布上绘制的图像的宽度,目标画布上绘制的图像的高度;整个函数实现如下:compress(event){varfile=event.target.files;varreader=newFileReader(),imgFile=file[0];如果(imgFile.type.indexOf('image')==0){reader.readAsDataURL(imgFile);}else{this.$Message.infor('文件类型仅为图片')}letimg=newImage();reader.onload=函数(e){img.src=e.target.result;};varimgP=newPromise((resolve,reject)=>{img.onload=()=>{varcanvas=document.createElement("canvas");varctx=canvas.getContext('2d');//tile画布vartCanvas=document.createElement("canvas");vartctx=tCanvas.getContext("2d");varinitSize=img.src.length;varwidth=img.width;varheight=img.height;//图像像素大于400万像素,计算压缩到小于400万varratio;if((ratio=width*height/4000000)>1){ratio=Math.sqrt(ratio);width/=ratio;height/=ratio;}else{ratio=1;}canvas.width=width;canvas.height=height;ctx.fillStyle="#fff";ctx.fillRect(0,0,canvas.width,canvas.height);//如果图片太大,使用tile来绘制变量计数;if((count=width*height/1000000>1)){count=~~(Math.sqrt(count)+1);//计算瓦片数量varnw=~~(width/count);varnh=~~(高度/计数);tCanvas.width=nw;tCanvas.height=nh;for(vari=0;i{img.onload=()=>{console.log(img.width)console.log(img.naturalWidth)}})},需要注意的是每一个time我们创建了一个新的图像对象。如果我们要获取一些response属性值,必须保证onload方法中已经加载了图片。上面的控制台输出两个值,width和naturalWidth。在一定条件下,它们会是相等的。比如我们在上面的时候,就会出现不一致,因为naturalWidth返回的是图片的真实尺寸,而width返回的是img标签指定的尺寸,所以我们需要获取的是naturalWidth;旋转(imgData){varimg=newImage();img.src=imgData;varimgR=newPromise((resolve,reject)=>{img.onload=()=>{letdegree=0,drawHeight,绘制宽度;drawHeight=img.naturalHeight;drawWidth=img.naturalWidth;让maxSide=Math.max(drawWidth,drawHeight);if(maxSide===drawWidth){//判断要旋转的角度degree=90;}else{学位=360;}varcanvas=document.createElement('canvas');canvas.width=drawWidth;canvas.height=drawHeight;varcontext=canvas.getContext('2d');context.translate(drawWidth/2,drawHeight/2)//这一行和下一行的作用是修改选区中心context.rotate(degree*Math.PI/180);//旋转图片context.translate(-drawWidth/2,-drawHeight/2)//这一行和上一行的作用是修改选区中心context.drawImage(img,0,0,drawWidth,drawHeight);varndata=canvas.toDataURL('image/jpeg',1);context.width=上下文。高度=0;resolve(ndata)}})returnPromise.all([imgR])}旋转效果如下,如果宽度大于高度,即水平图片,则发送在vue下使用canvas实现以上功能后,发现canvas在图片处理方面的强大功能,对前端上传图片的性能优化会有很大的帮助;经过上面的时间,我发现需要实现用户上传图片前的裁剪功能,可以使用canvas来实现,主要是使用drawImage来控制裁剪的长度,并实现起点坐标,即真的好用!