本文介绍在Node.js Express框架下,利用Jcrop插件实现前端图片裁剪与上传的完整流程。通过HTML5 FileReader和Canvas技术,在客户端完成图片预览与实时裁切,避免服务器端重复存储。文章详细解析了Jcrop初始化、坐标转换及Base64数据提交的关键代码,并提供后端接收保存的实现方案。
需求说明
需求说明
核心目标是实现用户上传头像功能,并保存用户裁切后的指定区域作为最终头像。
第一步,选择图片:
第二步,在弹窗页面中展现并进行裁切:
第三步,点击“保存”,上传服务器。
实现过程
实现过程
开发过程经历了两轮迭代,初期存在弯路。
第一版方案是用户选择图片后立即上传至服务器,获取服务器地址后再在弹窗中展示该图片进行裁切并保存。
第2遍找到的一个方法,是在第1遍做到裁切处理时候想到的,即弹层展现的是用户机器上选择的图片,不用先上传,但是用image/base64来展现的。这样就与服务器少了一次交互啊,并且服务器不用存储2遍图片,还提高了弹层展现速度,体验更好,所以是极好的。
主要技术点
说下碰到的主要技术点:
Express框架负责后端路由,接收前端POST提交的裁切后base64数据并保存。jQuery用于控制页面展示及执行Ajax提交。
HTML5/FileReader/canvas:FileReader用于将文件读取为数据,利用其onLoad事件;Canvas用于在裁切移动时实时重绘裁切后的图片(实现实时预览,调试时可显示,最终上传的是该Canvas生成的base64数据)。
Jcrop plugin:这是必需的裁切插件,下载与说明见相关文档。服务端将base64字符串保存为图片较为简单,直接使用fs.writeFile(fileName,dataBuffer,function(err){});即可。
具体代码实现
具体代码
view页面,主要需要有一个上传控件,还有定义弹窗div以及用于重绘裁切范围图片的canvas,当然页面要引用相应的js插件和css等,主要:
<link rel="stylesheet" href="/css/jquery.Jcrop.css" rel="external nofollow" >
<script src="/js/jquery.js"></script>
<script src="/js/jquery.Jcrop.js"></script>
<!--上传控件-->
<input type="file" name="upLoadImg1" id="upLoadImg1">
<!--弹窗与裁切图-->
<div class="cover">
<img id="Img1" alt="">
<button id="btnSave">保存</button>
</div>
<!--裁切范围重绘canvas-->
<canvas id="myCanva" width="200" height="200">
js/jQuery,处理图片加载与裁切上传。
首先要监控上传控件的变化,因为我们这里没有按钮来触发,所以直接监控upLoadImg1的change来触发。
$('#upLoadImg1').on('change', function() {
if (document.getElementById("upLoadImg1").files.length === 0) {
return;
}
var oFile = document.getElementById("upLoadImg1").files[0];
if (!oFile) {
return;
}
var fileName = oFile.name;
var fileSize = oFile.size;
var fileType = fileName.substring(fileName.lastIndexOf('.'), fileName.length).toLowerCase();
if (fileType != '.jpg' && fileType != '.jpeg' && fileType != '.gif' && fileType != '.png' && fileType != '.bmp') {
alert("请选择jpg,png,gif,bmp格式的图片");
return;
}
if (fileSize > 2 * 1024 * 1024) {
alert('最大支持2MB的图片');
return;
}
var fileReader = new FileReader();
fileReader.readAsDataURL(oFile);
// 成功读取
fileReader.onload = function(e) {
// 显示弹窗
$('.cover').show();
// 将弹窗中的图片路径设置为选择的图片的base64
$('#Img1').attr('src', e.target.result);
// 裁切组件初始化
initJcrop();
};
});
裁切在弹窗一显示的时候就应该初始化:
function initJcrop() {
$('#Img1').Jcrop({
onChange: updateCoords,
onSelect: updateCoords,
aspectRatio: 1,
boxWidth: 300,
boxHeight: 300
}, function() {
//弹窗中显示的图片尺寸
var bb = this.getBounds();
var bWidth = Number(bb[0]) / 2;
var bHeight = Number(bb[1]) / 2;
//设置初始选中裁切范围
this.setSelect([0, 0, bWidth, bHeight]);
//原始图片缩小比例
try {
wdthScale = $('#Img1')["0"].width / 222;
heightScale = $('#Img1')["0"].height / 238;
} catch (e) {}
jcrop_api = this;
});
}
非常重要的一个坑是,在此之前要定义全局变量jcrop_api,widthScale和heightScale,2个scale变量用于记录选择的原始图片尺寸与在弹窗上展现尺寸的缩小/放大比例的,比如选择的是1024x768的图片,但是弹窗上展现的范围是222x238,这就需要将缩小的倍数记录下来,在裁切的重绘canvas的时候要乘以这个倍数,否则裁切的范围就是在这个222x236尺寸上裁切的,而不是原始图片的尺寸上。而前面的jcrop_api变量用于重新选择图片时要将上一次的裁切初始化组件destroy掉。
Jcrop组件中重要的事件:onChange和onSelect,用于确定裁切范围的坐标(尺寸),因此也非常重要,其实重绘canvas就是在这里面完成的。
function updateCoords(c) {
var img = document.getElementById('Img1');
var ctx = document.getElementById('myCanva').getContext('2d');
try {
wdthScale = wdthScale === 1 ? $('#Img1')["0"].width / 222 : wdthScale;
heightScale = heightScale === 1 ? $('#Img1')["0"].height / 238 : heightScale;
} catch (e) { }
//绘制canvas画布
ctx.drawImage(img, c.x, c.y, c.w * wdthScale, c.h * heightScale, 0, 0, 200, 200);
}
另外就是处理保存按钮来,一个ajax来提交canvas形成的图片的base64字符串,后台接受保存就可以了。
var data = document.getElementById('myCanva').toDataURL();
$.ajax({
url: '/xxxx',
type: 'POST',
dataType: 'JSON',
cache: false,
data: {
'imgData': data
},
success: function(res) {},
error: function(err) {}
});
这就是上传裁切(实时预览)的全部过程了。
以上所述是小编给大家介绍的node.js(express)中使用Jcrop进行图片剪切上传功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对本站网站的支持!