Jcrop 整合 FileAPI 图像裁剪上传

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>


你可能感兴趣的:(jcrop,本地预览,图像裁剪上传,FileAPI)