前端实现截图并预览的效果

关于截图,已有不少插件,比如Jcrop、imageAreaSelect等等,但功能都不是很全,本文在 imageAreaSelect 的基础上做了一些改进,具体实现如下功能(纯前端):

  • 在标签中自定义裁切后的长宽,方便代码复用
  • 在裁切框中,图片自适应
  • 可连续选择同一张图片
  • 前端进行裁图并显示出来
  • 限制图片大小

效果图:

演示地址 戳这里

点击上传图片:
点击上传图片

裁图:
裁图

预览裁后结果:
预览裁后结果

用法

例:

配置html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<input style="display:none" type="file"
id="imgInput"
onchange="imgCrop.change(this)"
data-width="380"
data-height="380"
data-previd="imgPrev"
data-maxsize="2">
<a href="javascript:void(0);"
class="image-show J-upload-img-btn"
data-target="imgInput">
<div class="upload-img-box">
<span>上传图片</span>
</div>
</a>
<p class="img-desc">支持小于2M,格式为jpg、png的图片,分辨率为380*380px</p>
<div class="img-prev" id="imgPrev"></div>

裁切框:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="modal fade crop-modal J-crop-modal" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="image-box">
<p><img></p>
</div>
<div class="preview-box" style="width:150px;">
<img>
</div>
<canvas class="J-canvas" style="overflow:hidden; display:none"></canvas>
</div>
<div class="crop-btns">
<a href="javascript:void(0);" class="btn confirm-btn J-confirm-btn" onclick="imgCrop.confirm()">确定</a>
<a href="javascript:void(0);" class="btn cancel-btn" onclick="imgCrop.cancel()">取消</a>
</div>
</div>
</div>
</div>

在dom底部加载js:

1
2
3
4
5
6
7
8
9
<script type="text/javascript" src="../js/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="../js/bootstrap.min.js"></script> <!--用到了模态框-->
<script type="text/javascript" src="js/jquery.imgareaselect.pack.js"></script> <!--imgAreaSelect文件-->
<script type="text/javascript" src="js/img-crop.js"></script> <!--实现crop的功能文件-->
<script>
$(function(){
imgCrop.init('.J-upload-img-btn'); //初始化crop事件
})
</script>

说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#html设置
<input style="display:none" type="file"
id="文件输入ID"
onchange="imgCrop.change(this)"
data-width="要裁切的宽度,/px"
data-height="要裁切的高度,/px"
data-previd="裁切后要显示在哪儿的ID"
data-maxsize="图片大小设置,/M">
<a href="javascript:void(0);"
class="image-show J-upload-img-btn"
data-target="文件输入ID">
<div class="upload-img-box">
<span>上传图片</span>
</div>
</a>
<p class="img-desc">支持小于2M,格式为jpg、png的图片,分辨率为380*380px</p>
<div class="img-prev" id="裁切后要显示在哪儿的ID"></div>

原理:

  • 裁切原理:
    其实是用canvas根据尺寸重绘一张图

  • 预览原理:
    将图片转成base64,直接载到img的src中

  • 连续选择同一张图片进行裁切的原理:
    裁切时用到的的重要的事件是change,而两次连续相同的选择是不会触发这个事件的,而直接重新绑定change事件,本银试过了,不行,应为value值不能真正的被清空,还涉及到兼容性问题,妈呀,头好大,怎么办呢?其实~~~很简单,用replace重新替换下,然后再重绑change就可以了。

分解

获取文件大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
getFileSize : function(o){
var self = this;
var fileSize = 0;
if (self.isIE && !o.files) { // IE浏览器
var filePath = o.value; // 获得上传文件的绝对路径
var fileSystem = new ActiveXObject("Scripting.FileSystemObject");
// GetFile(path) 方法从磁盘获取一个文件并返回。
var file = fileSystem.GetFile(filePath);
fileSize = file.Size; // 文件大小,单位:b
}else { // 非IE浏览器
fileSize = o.files[0].size;
}
return fileSize / 1024 / 1024;
}

使用canvas模拟裁图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var size = cropImgSize;
var cropModalObj = $(".J-crop-modal");
var primary_width = cropModalObj.find(".image-box img").width();
var sourseImg = new Image();
sourseImg.src = cropModalObj.find(".image-box img").attr('src');

var R = sourseImg.width / primary_width;
var canvas = cropModalObj.find(".J-canvas")[0];
var context = canvas.getContext("2d");
context.drawImage(sourseImg, size.x1 * R, size.y1 * R, size.w * R, size.h * R, 0, 0, canvas.width, canvas.height);

$('#'+prevID)
.html('')
.append("<img src='" + canvas.toDataURL('image/jpeg',0.8) + "'/>");

图片转base64渲染

1
2
3
4
5
6
7
8
9
10
11
12
if (!self.isIE) {
var file = o.files[0];
var reader = new FileReader();
reader.onload = function () {
var img = new Image();
img.src = reader.result;
self.setCropImgSize(img.width, img.height);
imgModalObj.find('.image-box img').attr('src', reader.result);
imgModalObj.find('.preview-box img').attr('src', reader.result);
};
reader.readAsDataURL(file);
}

阅读更多

总结

代码地址,戳这里

修改

1
2
3
4
5
6
7
<input style="display:none" type="file"
id="imgInput"
onchange="imgCrop.change(this)"
data-width="380"
data-height="380"
data-previd="imgPrev"
data-maxsize="2">


1
2
3
4
5
6
7
<input style="display:none" type="file"
id="imgInput"
onchange="imgCrop.change(this)"
data-width="540"
data-height="300"
data-previd="imgPrev"
data-maxsize="2">

后,裁切效果如下:

裁图:
修改尺寸后裁图

预览裁后结果:
修改尺寸后预览裁后结果

O(∩_∩)O哈哈~~~~是不是很好玩。。。
还在路上,欢迎指正