Jcrop是一款优秀的jQuery插件,可以非常方便地实现图像裁剪,而且功能十分的强大。
一般的情况下,图像裁剪的实现要经过两次图像上传,第一次将图片上传到后台,后台返回一个链接,通过这个链接在本地实现预览。第二次将图片本身以及裁剪参数上传到后台,后台进行裁剪,并保存在服务器。也就是说第一次的上传是不必要的,用户万一中途取消了操作,那第一次的操作就完全成了无用操作。而且增加了网络的消耗,造成了不必要的浪费。一般这种情况下,我们会考虑第二次不进行上传而使用第一次上传的图片,但这增加了技术难度,而且造成了更多的Exceptions的可能。事实
上有更好的选择,那就是FileAPI,它不进行上传,图片的预览是通过将图片加载到本地浏览器缓存实现的。我们通过FileAPI获取必要的参数,在用户“下定决心”使用该图的时候再进行上传,可以极大的降低多余消耗,增强用户体验。
要实现图像裁剪上传,首先要实现图像本地预览的功能。定义一个priviewImage.js文件,方便复用:
function previewImage(file, callback) {
/*
* file:file控件 prvid: 图片预览容器
*/
/*if (file[0].fileSize() > 3 * FileAPI.MB) {
alert("The uploading file size must less than 3MB!");
return;
}*/
var tip = "Expect jpg or png or gif!"; // 设定提示信息
var filters = {
"jpeg" : "/9j/4",
"gif" : "R0lGOD",
"png" : "iVBORw"
}
if (window.FileReader) { // html5方案
for (var i = 0, f; f = file.files[i]; i++) {
var fr = new FileReader();
fr.onload = function(e) {
var src = e.target.result;
if (!validateImg(src)) {
alert(tip);
} else {
showPrvImg(src);
}
}
fr.readAsDataURL(f);
}
} else { // 降级处理
if (!/\.jpg$|\.png$|\.gif$/i.test(file.value)) {
alert(tip);
} else {
showPrvImg(file.value);
}
}
function validateImg(data) {
var pos = data.indexOf(",") + 1;
for ( var e in filters) {
if (data.indexOf(filters[e]) === pos) {
return e;
}
}
return null;
}
function showPrvImg(src) {
callback(src);
}
}
通过callback可以拿到字节码形式的图片,将其设为img标签的src属性,浏览器即可以显示出来。以下是一个例子:
<div>
<p>预览:</p>
<div id="previewBox">
<img src="" id="previewImage" alt="预览头像">
</div>
</div>
previewImage(file, function(src) {
$("#previewImage").attr("src", src);}
现在来描述下Jcrop图像裁剪上传的基本流程:
第一步:用户点击fileinput,选择本地图片,并通过FileAPI将该文件加载到浏览器缓存,最后形成网页上的本地预览图片;
第二步:Jcrop针对预览图片进行初始化,关于初始化的具体方法,我会在后面说到。这里有一个难题,事实上解决方案是一个选择器的问题,后面详细说明,关于Jcrop的详细使用方法,可以自行百度,网上有很多的相关介绍;
第三步:通过Jcrop将用户的裁剪数据捕捉到hiddeninput中,这个便是Jcrop的核心,所以不需要我们做过多的考虑;
第四步:用户决定是应用操作还是放弃操作。若放弃,则将DOM重置,若应用,则用ajaxFileUpload上传图片。
现在来详细说明各步骤的实现:
首先是文件的加载,需要的依赖有jQuery.js,Jcrop.js,ajaxFileUpload.js以及我们先前定义的previewImage.js:
<link rel="stylesheet" href="css/jquery.Jcrop.min.css" type="text/css">
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/jquery.Jcrop.min.js"></script>
<script type="text/javascript" src="js/previewImage.js"></script>
<script type="text/javascript" src="js/ajaxfileupload.js"></script>
基本的DOM模型:
<div>
<input id="myImage" name="myImage" type="file" onchange="initImgForm(this)">
<button type="button" id="resetImgBtn">取消选择</button>
<button type="button" id="imgBtn">确认修改</button>
<input type="hidden" id="offsetX" name="offsetX" value="0">
<input type="hidden" id="offsetY" name="offsetY" value="0">
<input type="hidden" id="width" name="width" value="120">
<input type="hidden" id="height" name="height" value="120">
</div>
说到这里,我多嘴一句,button元素在使用的时候最好指定一下type="button",因为它在和form元素组合使用的时候,若不指定属性,在某些浏览器中会触发form的submit事件,造成一些不必要的错误。DOM还有一部分,预览窗格:
<div>
<p>预览:</p>
<div id="previewBox">
<img src="" id="previewImage" alt="预览头像">
</div>
</div>
当用户点击fileinput的时候,将会调用initImgForm方法,完成图片预览以及Jcrop的初始化。Jcrop出事化的关键在于$.children()方法,直接针对父元素"#previewImage"会出现错误,同时也不可对其子元素<img>调用$.Jcrop方法,也会出现错误。
<script type="text/javascript">
var JcropApi, boundx, boundy;
function initImgForm(file) {
/* 验证文件大小还未实现,服务器端最大Size 3MB,参阅 previewImage.js*/
previewImage(file, function(src) {
$("#previewImage").attr("src", src);
$("#previewBox").children().Jcrop({
onChange : showPreview,
onSelect : showPreview,
minSize : [ 120, 120 ],
maxSize : [ 400, 400 ],
aspectRatio : 1
}, function() {
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
JcropApi = this;
});
});
}
function showPreview(c) {
var w = $("#previewImage").width();
var h = $("#previewImage").height();
var rx = w / c.w;
var ry = h / c.h;
$("#previewImage").css({
width : Math.round(rx * w) + "px",
height : Math.round(ry * h) + "px",
marginLeft : "-" + Math.round(rx * c.x) + "px",
matginTop : "-" + Math.round(ry * c.y) + "py"
});
$("#offsetX").val(c.x);
$("#offsetY").val(c.y);
$("#width").val(c.w);
$("#height").val(c.h);
}
$("#resetImgBtn").on("click", function() {
resetImg();
});
$("#imgBtn").on("click", function() {
var params = {};
params.offsetX = $("#offsetX").val();
params.offsetY = $("#offsetY").val();
params.width = $("#width").val();
params.height = $("#height").val();
$.ajaxFileUpload({
url : "...",//定义你的上传路径
secureurl : false,
fileElementId : "myImage",
data : params,
dataType : "json",
success : function(json) {
if (json.status) {
$("#currentImage").attr("src", json.imgsrc);
resetImg();
alert(json.message);
} else {
alert(json.message);
}
},
error : function() {
alert("请求失败");
}
});
});
function resetImg() {
$("#previewBox").empty();
var img = "<img id=\"previewImage\" src=\"\" alt=\"预览头像\">";
$("#previewBox").append(img);
$("#myImage").val("");
JcropApi.destroy();
}
</script>
来源:oschina
链接:https://my.oschina.net/u/2541538/blog/552229