在前端开发中,当遇到图片或头像上传等功能时,有尺寸分辨率限制的话,就需要用到图片的裁剪功能。想了解图片基础知识的,可见前文图片基础知识介绍。
而canvas的使用,对于我们直接在web端实现图片裁剪功能成为可能。本文将使用前端技术实现一个图片的裁剪功能。
一、图片文件的上传和读取
使用文件上传控件,实现图片上传,获取到图片文件(File对象)后,可以通过 FileReader
或 URL.createObjectURL
两个API完成对文件数据的转换。前文有描述深入理解前端二进制API知识。
- FileReader:一般使用readAsDataURL方法将File读取为图片文件的Base64数据,可以直接作为图片数据加载。Base64知识可见前文深入理解Base64字符串编码知识。
- URL.createObjectURL:则生成一个伪协议的Blob-Url链接,用在这里是一个图片的URL链接,可以加载图片资源。
如下,即响应文件上传事件,以Base64字符串数据加载图片:
1
2
3
4
5
6
7
8
9
|
// 上传控件事件响应,加载图片文件 document.getElementById( 'input-file' ).onchange = (e) => { const file = e.target.files[0] const reader = new FileReader() reader.onload = async (event) => { initImageCut(event.target.result) } reader.readAsDataURL(file) } |
这样读取的数据就是图片Base64字符串数据,可当做图片资源被 Image
对象加载了。
二、图片展示和蒙层处理
获取到图片文件的数据以后,加载图片获取像素宽高:
1
2
3
4
5
|
const img = new Image() img.src = dataUrl img.onload = function () { resolve(img) } |
一般通过 Image
对象,生成一个img实例,加载图片数据,img实例里包含有图片宽高。
图片的宽高是比重重要的数据,如计算图片展示区的缩放比例,后续裁剪框的拖放和缩放也都需要用到。
如下代码,计算缩放比例(zoom):
1
2
|
zoom = Math.min(WIDTH / img.width, HEIGHT / img.height) zoom = zoom > 1 ? 1 : zoom |
其中,WIDTH
和 HEIGHT
是设定一个固定区域,用来展示图片和裁剪框,值的大小可以随意设置,在显示器可视区域内最好;
zoom的作用,可以方便我们后面获取图片的相对大小。
接下来就可以在页面上展示图片,并设置蒙层处理。
图片的展示,我们这里直接使用html的 <img>
标签:
1
2
|
< img class = "image" id = "bgMaskImg" /> < img class = "image" id = "cutBoxImg" /> |
这里使用了两个 <img>
标签元素,两个元素加载同样的图片资源,区别在于:
- 其中
bgMaskImg
作为底图,设置透明度(如0.5),模拟蒙层效果; cutBoxImg
作为裁剪框区域的图片展示,即非蒙层的清晰图片。
这里图片展示需要达到的效果,如下:
上图的展示中,看上去有蒙层效果的就是第一个img标签;
而中间区域清晰的图片块则是第二个img标签的效果,这里是借助CSS中的 clip-path
属性来完成的。
然后,需要给两个img标签元素加载图片,并设置各元素的样式:
1
2
3
|
bgMaskImgElm.src = cutBoxImgElm.src = imgUrl setStyle() |
CSS clip-path
clip-path
是一个CSS属性,能够只展示元素的一块部分区域,而其他区域隐藏起来。
这个特性正好可以作为裁剪功能使用,这里使用在图片上,就能模拟出来裁剪蒙层的效果。
CSS之前有个 clip
属性,但是已经废弃,虽然部分浏览器还支持,但建议使用 clip-path
。
clip-path
属性有很多取值,我们使用它的多边形值 polygon
,模拟方形的裁剪区域:
1
2
3
|
img { clip-path: polygon( 0 0 , 100px 0 , 100px 100px , 0 100px ); } |
如上代码,使用像素值,定位方形的四个顶点的坐标(左上、右上、右下、左下),展示出图片的一个方形裁剪区域,这时候其他区域不可见,就形成了上面图片展示中的清晰区域。
因为这块裁剪区域会随着裁剪框移动或者缩放而进行改变,所以需要通过JS来改变:
1
2
|
const clipPath = `polygon(...)` cutBoxImgElm.style.clipPath = clipPath |
在移动或拖动后,重新计算裁剪区域的坐标点,再进行 clip-path
属性的更新。
三、裁剪框展示
上面实现了图片的加载展示、蒙层和裁剪区域的处理后,接下来,就是对裁剪框的实现。
裁剪框使用div的方式就可以了,定义一个裁剪框:
1
2
3
|
< div id = "cutBox" class = "cut-box" style = "display: none;" > ... </ div > |
这里需要注意的是通过JS来改变这个裁剪div的位置和大小,并且也要同步更改上文提到的 clip-path
属性:
1
2
3
4
|
cutBoxElm.style.width = cutBoxWidth * zoom - 2 + 'px' cutBoxElm.style.height = cutBoxHeight * zoom - 2 + 'px' cutBoxElm.style.left = cutBoxLeft + 'px' cutBoxElm.style.top = cutBoxTop + 'px' |
裁剪框的缩放点
裁剪框的展示,一般会设计八个缩放点,如下图所示:
需要注意,图上标注了缩放点大致的名称,下文会涉及到对应的点的事件处理,可以清楚是哪个操作。
暂无评论内容