文件上传之图片裁剪

时间:2024-03-23 18:37:30

       前面两章已经介绍了文件上传的进度条与文件切片,本章讲讲图片裁剪。

       在实际项目中,会遇到图片固定宽度和高度,作为一个开发者,我们不能总是要求用户上传的图片尺寸正好符合要求,那么只能用裁剪来解决。

 所谓裁剪,就是把一张图片放到框中,通过裁剪区域来获取最终需要的图片。

       进入正题,首先介绍下html结构:

文件上传之图片裁剪


文件上传之图片裁剪

       上传图片首先需要预览,FileReader的readAsDataURL方法能够将file对象转换为base64,将img的src设置为转换后的base64即可显示出来,那么问题来了,源图片区域的图片大小是怎么设置的呢。

       首先源图片区域宽高比例固定,如果上传的图片宽度除以裁剪区域宽度比例wp大于1或者高度除以裁剪区域高度比例hp大于1,那么就得照顾尺寸小的那条边,使比例大的边刚好显示在源图片区域内,并且保证源图片的宽高比例不变

文件上传之图片裁剪

       上面最后几行代码,使源图片和预览图片尺寸一致,没有多少注释,代码即注释。这里已经提前将预览区域设置了position:relative,预览图片设置了position: absolute,保证图片能够移动;

文件上传之图片裁剪

       这里箭头指向的两段代码记录了最终需要裁剪的图片宽高,1274、1275行分别设置了w和h的默认值,也就是裁剪出来的图片宽高就是预览区域的宽高(比如宽200px,高150px),但是用户也可能上传一个150px X 150px的图片,很明显图片应该按预览区域的比例来显示:

percentPreviewW = 150 / 200 = 0.75

percentPreviewH = 150 / 150 = 1.00

宽度比例小于1并且0.75 < 1.00,应该走if代码

percent = 200 / 150 = width / ?

       最终得出的裁剪区域宽度 = 150 * (150 / 200) = 150 * 0.75 = 112.5px,当然高度不变,还是150px。当然开发者也可以按自己的想法来,比如在percentPreviewW 或percentPreviewH 小于1时,裁剪区域宽高不按比例来,直接将比例小的那条边全部显示,另一条边直接设置为预览区域的长度即可,只要符合生产需要即可。

文件上传之图片裁剪

        设置裁剪区域:

文件上传之图片裁剪

       设置裁剪框:

文件上传之图片裁剪

       裁剪框的位置默认是left:0,top:0,border-left:0,border-top:0,但它content的区域和border的区域相加一定要刚好覆盖裁剪区域,重点来了,我们都知道裁剪图片需要把最终裁剪的宽高、源图片宽高以及裁剪区域偏移的点top和left:

文件上传之图片裁剪

       本来裁剪框的宽高和预览区域宽高是一致的,但是如果在通过裁剪框中的点来缩放图片后,percent会发生变化,所以这时候需要重新渲染预览图片,保证裁剪框中选中的部分能够完全撑满预览区域。

       在这里将博主在编写插件时遇到的几个坑分享出来,在拖动裁剪框或者拖动裁剪框中的几个点时,千万不要在mousemove的时候返回false:

文件上传之图片裁剪

文件上传之图片裁剪

       箭头处是最终鼠标的位置,因为需要用QQ截图,所以那个鼠标位置直接标注出来,因为需要考虑鼠标不在裁剪区域但是还在继续拖动裁剪框或者几个点,如果不返回false,是不会做任何操作的;但是如果返回false并且这个$fullscreenContainer是body或者document,那么恭喜你,你已经成功的禁掉了document的select事件,select事件是什么呢:

文件上传之图片裁剪


文件上传之图片裁剪

       就是上图中蓝色的这种效果。

       第二个坑就是在火狐中mousedown、mousemove的表现和IE、chrome有差异:

文件上传之图片裁剪

       这是当时记录的,至于为什么会遇到这个坑呢,在mousedown的时候如果事件源是8个点或者裁剪框,那么直接控制一个遮挡全屏的透明div显示出来,这样在mousedown的情况下继续mousemove时,触发document的select事件也不会有任何效果,因为这个div上面什么也没有,等到mousemove结束,div隐藏,我只能说不但IE调皮,FF也调皮文件上传之图片裁剪

       另外后端还是需要校验文件的真实类型,我们可爱(可恶)的用户和测试就喜欢弄一些非正常文件来捣乱,比如txt,后缀一改就成了jpg、png,不多废话,上图:

文件上传之图片裁剪


文件上传之图片裁剪


文件上传之图片裁剪

       上传的图片如果是P出来的(当时业务需要上传banner图片,裁剪后尺寸大约是1300x600,要求图片是高清晰的,所以客户那边直接P了几张图片,在上传后,发现死活裁剪不了,调试后台代码再百度百度,得出了这个结果。最终就是不裁剪,直接让用户设置P出来的图片是1300x600缩放时后端会报错,所以只对比文件头校验还是不能保证安全,必须经过层层关卡,这样才能保证系统健壮性,说的很牛叉的样子文件上传之图片裁剪

       花了这么多时间来分享这个插件,其实也是重温一下当时的思路,如果您还没有写过图片裁剪的插件,不妨试试,你会发现这个功能也就那样...还能解决一些意想不到的问题,从而提升自己,加油...