宝哥软件园

JavaScript图像处理与合成综述

编辑:宝哥软件园 来源:互联网 时间:2021-09-01

引言

图像处理现在已经成为我们生活中的必需品,我们必须一直有这种需求。在实际的前端业务中,往往有很多项目需要处理和加工。由于公司过去的业务需要,我在这方面积累了一些干货,以后会总结成一系列文章与大家分享,希望能在大家的努力中给前端童鞋带来启发和帮助

本系列分为以下四个部分:

基本类型图像处理技术的缩放和裁剪;基本型图像处理技术的图像合成:基本类型图像处理技术的文本合成;算法型图像处理技术;在文章中,我会提到很多在实际实践中遇到的坑或经验,应该算是满满的干货~ ~如果你能通读一下,应该会大大提高你对前端图像处理领域的了解。感兴趣的童鞋可以和我深入探讨。希望本文能够达到吸引有价值建议的效果,让前端在图像处理上有更多的可能性。请理解缺点。

通过这些积累,我封装了几个项目中常用的函数:

图像合成:示例Git图像剪辑:示例Git人像剪辑:示例Git

唠叨完这些老套路,我们开始起飞了!

首先,我把前端图像处理分为两类:基本型和算法型;

图像处理技术:的基本类型,如图像缩放、旋转、添加边框、图像合成、拼图等。都属于图像处理的基本类型。区别在于不需要使用像素级算法,而是通过计算改变图像的大小和位置。例如,常用的贴纸功能:

算法型图像处理:在图像处理中具有高复杂度,其特征在于通过像素级算法变换图像像素的RGBA通道值。比如我们使用photshop或者米托秀秀等工具对图像进行美颜/滤镜/黑白/抠图/模糊操作,这种类型的重点主要是算法和性能。例如,常用的化妆功能:

本系列从基本类型处理开始我们的旅程。基本类型的图像处理在实际项目中有大量的使用场景,主要是利用canvas的能力完成,没有性能和兼容性问题,能够满足在线运行标准。在这里,我把图像处理的基本类型大致分为以下几种,基本可以涵盖所有日常业务场景:

图片缩放;图片剪辑;图片的构成;图像和图像合成,如贴纸、边框、水印等。向图片添加文本;给图片添加基本几何图形;

Tips:我已经把这种类型的图片处理场景打包成了一个插件,基本可以满足这种类型图片处理的所有需求,GIT地址(欢迎讨论);在介绍具体功能之前,由于图片的绘制完全依赖于图片的加载,所以首先要了解一些前置知识。

1.图片的跨域

首先加载和绘制图片涉及跨域问题,所以如果是在线图片,需要在图片服务器上设置跨域头,在前端加载图片前将img标签的crossOrigin设置为*否则在画布上绘制时会报告跨域错误。

Tips:这里积累了一些小坑,可以分享给大家:

CrossOrigin需要严格设置,不仅是在线图片的时候,当是本地路径或者base64的时候,一定不要设置,否则会在一些系统中报错,导致图片加载失败;当项目是本地包环境时,例如在App中内置时,crossOrigin的值是无效的,无论是否设置该值,webview的安全机制都会导致报告跨域错误。解决方法是:所有图片都需要转换为base64才能正确绘制;crossOrigin的值必须在图片加载之前,也就是给img赋值src之前设置,否则无效;2.图片加载

因为画布绘制需要加载图片,需要保证绘制的素材图片已经加载,所以需要使用img的onload事件,可以使用html中已有的图片,也可以用js创建一个图片对象:

函数loadimage (image,loader,错误){//创建一个image对象加载图片;让img=new Image();//当是在线图片时,需要设置crossOrigin属性;if(image . indexof(' http '==0)img . cross origin=' * ';img . onload=()={ loaded(img);//清空对象,使用后释放内存;setTimeout(()={ img=null;},1000);};img.onerror=()={ error('img加载错误');};img.src=image}介绍完图像加载的前置知识,我们先来看看最简单的图像处理——缩放和裁剪!

Tips:认为,如果阅读本文时对canvas了解不多,可以查询相应的API文档。本文不会详细解释canvas的基本API。首先,图片的缩放

图像缩放最常见的场景是图像压缩。在保证画面清晰度的前提下,通过合理缩小画面尺寸,可以大幅缩小画面尺寸。在实际应用场景中,它有着广泛的用途。例如,在上传图片时,用户上传的图片可能非常大。比如手机拍摄的照片大小往往可以达到1920*2560,大小可能超过5M。在项目中,我们可能不需要使用这么大的尺寸。此时图片的压缩可以大大优化加载速度,节省带宽;

1.新建画布,将宽度和高度设置为需要压缩的大小;

画布是图片的缩放尺寸。这里有一点需要保持图片的比例不变,所以需要计算画布的宽度和高度:

让imgRatio=img . natural width/img . natural height;//创建画布容器;let CVS=document . create element(' canvas ');//获取容器中的画板;let CTX=CVS . GetContext(' 2d ');cvs.width=1000CVS . height=CVS . width/imgRatio;2.绘制图片并导出到base64

这里使用了两种最常用的方法:

事实上,CTX。drawimage (image,dx,dy,dw,DH) :最多可以接收9个参数实现压缩,只需要使用其中的5个,其他参数在使用其他部分时会详细说明;

Image :需要绘制图片的来源需要接收加载的HTMLImageElement、HTMLCanvasElement或HTMLVideoElement。Dx/dy :绘图起点相对于画布左上角的坐标;dw/dh :绘制的宽高和宽高比没有锁定,会使图片变形;

CVS。todataurl(类型,质量):此方法用于将画布上的内容导出为base64格式的图片,可以配置两个参数。

Type:图片格式一般可以使用image/png或image/jpeg。当图片不包含透明度时,建议使用jpeg,这样可以将导出图片的大小缩小很多Quality:图片质量,0到1之间的任何值都可以使用;经过测试,将该值设置为0.9比较合适,可以有效减小图片文件的大小,基本不影响图片清晰度。导出的base64是压缩图片;

Tips:这里有个坑。如果要导出jpg格式的图片,必须使用image/jpeg,但不能使用image/jpg;//在缩放后的画布上等比例绘制原始图形;ctx.drawImage(image,0,0,cvs.width,CVS . height);//将绘制的图形导出为base64格式;让b64=CVS . todaytaul(' image/JPEG ',0.9);3.将各种格式的图片转换为base64

对于图像上传功能,我们经常使用本机输入类型='File '标记。这时候我们得到的是文件格式的图像,格式不同,大小也比较大,所以要先压缩再使用。

使用文件阅读器:

let file=e . files[0];if(窗口。file reader){ let fr=new file reader();fr . onloadend=e={ let b64=e . target . result;//b64是base64格式的用户上传地图;};fr.readAsDataURL(文件);}刚才用画布压缩base64图片;

Tips:这里有一个小坑。图片EXIF信息中的方向值会影响图片的显示。在IOS中,会出现图片的宽度和高度与图片的方向不匹配的问题,因此需要特殊处理来纠正图片的方向。方案:

1.exif.js可以用来获取图片信息中的Orientation属性,画布的旋转图可以用来修正。

2.有一个canvasResize.js插件,可以解决从File到base64的所有问题。

第二,图片的切割

在实际项目中,由于图片的宽高比是多种多样的,显示和使用一般需要一个相对固定的比例,所以需要将图片裁剪成我们此时需要的宽高比。其实使用的方法与图片的缩放基本一致,主要是通过调整drawImage的dx、DX、dy参数来实现的。其实原理是把drawImage的绘图起点(dx,dy)上移。此时,由于裁剪后画布已经设置好了想要的尺寸,超出画布的部分就不会被画出来,从而达到裁剪的目的;通过灵活设置数值,基本可以完成各种图片裁剪要求。简单示例图(黑框代表创建的画布的大小):

这里需要把一个600*800的矩形图垂直切割成一个600*600的正方形图作为例子,简单的打包成一个函数:

//用法:letb64=裁剪图像(img,{width : 600,height : 600,});//居中裁剪功能cropImage(img,ops){ //图片原始大小;让imgOriginWidth=img . natural width,imgOriginHeight=img . natural height;//图片的长宽比保证了图片不变形;让imgRatio=imgOriginWidth/imgOriginHeight;//裁剪后图片的宽度和高度,默认值为原图片的宽度和高度;让imgcropedwith=ops . width | | imgOriginWidth,imgCropedHeight=ops . height | | imgOriginHeight;//计算起始坐标点的偏移量,等于前后/2的差值,因为是中间切的;设dx=(imgCropedWidth-imgOriginWidth)/2,dy=(imgCropedHeight-imgOriginHeight)/2;//创建画布,设置裁剪后的宽度和高度;let CVS=document . create element(' canvas ');let CTX=CVS . GetContext(' 2d ');cvs.width=imgCropedWidthcvs.height=imgCropedHeight//绘制和导出图片;ctx.drawImage(img,dx,dy,imgcropedwindth,imgcropedwindth/imgRatio);返回CVS . todaytaul(' image/JPEG ',0.9);} 3.图片旋转

图片旋转的原理也是在画布上画出图片进行旋转,然后导出。实际上,使用的是画布的旋转方法;

let CVS=document . create element(' canvas ');let CTX=CVS . GetContext(' 2d ');//将参考点移动到画板的中心点;ctx.translate(ctx.width/2,CTX . height/2);//旋转画板;ctx.rotate=90//画图;CTX . draw image(img);//导出旋转后的图片;CVS . todaytaurl();这里有一个特殊的部分,就是画布的画板部分在这里是旋转的,不是整个画布容器,画布容器的外部不会被画出来,所以会出现一个图像的四个角都被切掉的问题。

解决方案是:

将画布容器放大到:

在上面的例子中,因为图片是正方形的,所以通过将容器的宽度和高度放大1.5倍可以保证图片不会被切割,而在现实中,由于宽度和高度的比例不确定,放大系数是:的动态值

Tips:由于我们将画板的基点移动到了画布的中心,所以在绘图时应该相对于基点调整dx和dy;//创建画布,获取画板;放大倍数设iw=img.width,ih=img.height让ir=iw ih?iw/ih : ih/iw;cvs.width=iw * ir * 1.5cvs.height=ih * ir * 1.5//将参考点移动到画板的中心点;ctx.translate(cvs.width/2,CVS . height/2);//旋转画板;ctx.rotate=90//画图;ctx.drawImage(img,-cvs.width/2,-CVS . height/2);//导出图片;摘要

本文主要介绍:前端图像处理的一些前期知识

图像处理技术分类;

基本型图像处理技术;算法型图像处理技术;图片的跨域;图片加载;

还有两种最简单的:属于图像处理的基本类型

图片缩放;图片剪辑;图片的旋转;

相信大家对图像处理都有一个大概的了解。在下一篇文章中,我们将继续研究基本类型的图像合成,它充满了干货和美丽。

最后,非常感谢大家阅读童鞋。如果你有任何建议或疑问,可以随时和我讨论

更多资讯
游戏推荐
更多+