`

springMVC + ajaxfileupload异步上传图片预览,裁剪并保存图片

 
阅读更多

1、整体效果图:

2、实现原理:

(1)利用input的onchange事件异步上传图片到服务器

(2)获取上传图片的相对地址,回显到img标签中

(3)利用jcrop裁剪图片,提交给后台裁剪的起始坐标,宽度、高度

(4)后台裁剪图片并保存


3、用到的插件:

(1)JCrop图片裁剪插件

(2)异步上传图片插件:Ajaxfileupload.js

4、实现:

(1)jsp关键代码:

<fieldset>
	<legend>头像上传</legend>
	<!-- 显示图片的img -->
	<img src="" id="realPic" width="400px" height="400px" />
	<!-- 缩略图预览 -->
	<div id="preview-pane">
		<div class="preview-container">
			<img src="" width="150px" height="150px" />
		</div>
	</div>
	<div class="container">
		<!-- 打开图片控制 -->
    <span class="btn btn-success fileinput-button"> 
        <i class="icon-plus icon-white"></i> 
        <span>选择图片</span> 
        <input type="file" onchange="ajaxFileUpload()" name="realPicFile" id="realPicFile" multiple />
    </span>
    <!--  
    这种做法IE不支持,拒绝访问.              
    <input id="realPicFile" value="选择图片" onchange="ajaxFileUpload()" type="file" style="display: none;" name="realPicFile" />
    <a class="btn btn-success" href="javascript:selectPic();" > <i class="icon-plus icon-white"></i>
      选择图片 
    </a>
                -->
		<!-- 上传并裁剪图片 -->
		<img src="${ctx}/images/ajax-loader.gif" id="loading" style="display: none;">  
		<a class="btn btn-success" href="javascript:cutPic();"><i class="icon-picture icon-white"></i>保存头像</a>
		<!-- 获取裁剪的起始坐标和宽度、高度给后台 -->
		<form id="coords" class="coords">
		    <div class="inline-labels">
			    <input type="hidden" size="4" id="x1" name="x1" />
			    <input type="hidden" size="4" id="y1" name="y1" />
			    <input type="hidden" size="4" id="x2" name="x2" />
			    <input type="hidden" size="4" id="y2" name="y2" />
			    <input type="hidden" size="4" id="w" name="w" />
			    <input type="hidden" size="4" id="h" name="h" />
		    </div>
		 </form>
	</div>
</fieldset>

控制样式的CSS :

.jcrop-holder #preview-pane {
  width:156px;
  height:156px;	
  display: block;
  position: absolute;
  /*z-index: 2000;*/
  top: 0px;
  right: -200px;
  padding: 6px;
  border: 1px rgba(0,0,0,.4) solid;
  background-color: white;

  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  border-radius: 6px;

  -webkit-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
  -moz-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
  box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
}

/* The Javascript code will set the aspect ratio of the crop
   area based on the size of the thumbnail preview,
   specified here */
#preview-pane .preview-container {
  width: 156px;
  height: 156px;
  overflow: hidden;
}
#target-pane {
	width: 400px;
	height: 400px;
}


.fileinput-button {
  position: relative;
  overflow: hidden;
}
.fileinput-button input {
  position: absolute;
  top: 0;
  right: 0;
  margin: 0;
  opacity: 0;
  filter: alpha(opacity=0);
  transform: translate(-300px, 0) scale(4);
  font-size: 23px;
  direction: ltr;
  cursor: pointer;
}

注意fileinput-button这个样式,本人对css不熟悉,所以这个代码是从jquery-file-upload插件中拷贝过来的,大概的意思是将file的input放到按钮上,置为透明,这样就能够兼容IE,否则如果隐藏input,而触发它的click事件,IE认为这样做不安全,报拒绝访问的错误
(2)、javascript关键代码:

//Create variables (in this scope) to hold the API and image size
var jcrop_api, boundx, boundy, path;
/**
 * 更新缩略图,实现原理:根据原图框选的内容,显示到缩略图上,而缩略图也是原图是进行了放大,只是超过img范围的部分被隐藏
 */
function updatePreview(c) {
	if (parseInt(c.w) > 0) {
	    $('#x1').val(c.x);
	    $('#y1').val(c.y);
	    $('#x2').val(c.x2);
	    $('#y2').val(c.y2);
	    $('#w').val(c.w);
	    $('#h').val(c.h);
	  
		var rx = xsize / c.w;
		var ry = ysize / c.h;

		// 精确计算图片的位置
		$pimg.css({
			width : Math.round(rx * boundx) + 'px',
			height : Math.round(ry * boundy) + 'px',
			marginLeft : '-' + Math.round(rx * c.x) + 'px',
			marginTop : '-' + Math.round(ry * c.y) + 'px'
		});
	}
}

/**
 * 异步上传图片
 * @returns {Boolean}
 */
function ajaxFileUpload() {
	$("#loading").ajaxStart(function() {
		$(this).show();
	})//开始上传文件时显示一个图片  
	.ajaxComplete(function() {
		$(this).hide();
	});//文件上传完成将图片隐藏起来  

	var file = $("#realPicFile").val();
	if(!/\.(gif|jpg|jpeg|png|JPG|PNG)$/.test(file))
    {
        Error("不支持的图片格式.图片类型必须是.jpeg,jpg,png,gif格式.");
        return false;
    }
	
	$.ajaxFileUpload({
		url : Util.getContentPath() + '/user/uploadHeaderPicTmp.do?inputId=realPicFile',//用于文件上传的服务器端请求地址  
		secureuri : false,//一般设置为false  
		fileElementId : 'realPicFile',//文件上传空间的id属性  <input type="file" id="file" name="file" />  
		dataType : 'json',//返回值类型 一般设置为json  
		success : function(data, status) //服务器成功响应处理函数  
		{	
			// 图片在服务器上的相对地址,加随机数防止不刷新
			path = Util.getContentPath() + data.path + "?" + Math.random();
			$("#realPic").attr("src", path);
			var imgs = $(".jcrop-holder").find("img");
			// 原本有图片,重新上传后,所有的img都需要刷新
			imgs.each(function (i, v) {
				$(this).attr("src", path);
			});
			$('#preview-pane .preview-container img').attr("src", path);
			
			// 切图样式
			// Grab some information about the preview pane
			$preview = $('#preview-pane'), $pcnt = $('#preview-pane .preview-container'), $pimg = $('#preview-pane .preview-container img'),
			xsize = $pcnt.width(), ysize = $pcnt.height();
			//console.log('init', [ xsize, ysize ]);
			
			$('#realPic').Jcrop({
				onChange : updatePreview, //切图框改变事件
				onSelect : updatePreview, // 切图框选择事件
				onRelease: clearCoords, // 切图框释放的事件
				bgFade   : true,
		        bgOpacity: .8, // 截图框以外部分的透明度
		        setSelect: [10, 10, 100, 100], // 默认选择的区域
			aspectRatio : 1 //xsize / ysize 截图比例,这里我采用1 : 1 的比例,即切出来的为正方形
			}, function() {
				// Use the API to get the real image size
				var bounds = this.getBounds();
				boundx = bounds[0];
				boundy = bounds[1];
				// Store the API in the jcrop_api variable
				jcrop_api = this;
				// Move the preview into the jcrop container for css positioning
				$preview.appendTo(jcrop_api.ui.holder);
			});
		},
		error : function(data, status, e)//服务器响应失败处理函数  
		{
			Error(e);
		}
	});
	return false;
}

function _getShowWidth(str) {
	return _getValue(str, "width");
}

function _getShowHeight(str) {
	return _getValue(str, "height");
}

function _getValue (str, key) {
	var str = str.replace(/\:|\;|\s/g, '').toLowerCase();
	var pos = str.indexOf(key);
	if (pos >= 0) {
		// 截取
		var tmp = str.substring(pos, str.length);
		var px = tmp.indexOf("px");
		if (px > 0){
			var width = tmp.substring(key.length, px);
			return width;
		}
		return 0;
	}
	return 0;
}

/**
 * 裁剪图片
 */
function cutPic() {
	// 初始化数据
	var x1 = $('#x1').val() == "" ? 0 : $('#x1').val();
    var y1 = $('#y1').val() == "" ? 0 : $('#y1').val();
    var x2 = $('#x2').val();
    var y2 = $('#y2').val();
    var w = $('#w').val() == "" ? 150 : $('#w').val();
    var h= $('#h').val() == "" ? 150 : $('#h').val();
    
    var srcFile = $("#realPic").attr("src");
    if (srcFile == "" || !srcFile) {
    	Error("没有选择任何图片.");
    	return;
    }
     
    var showDiv = $(".jcrop-holder > .jcrop-tracker");
    // 从压缩存放图片的div中获取压缩后显示的宽度和高度,用来交给后台同比例进行裁剪
    // width: 404px; height: 304px; position: absolute; top: -2px; left: -2px; z-index: 290; cursor: crosshair;
    var style = showDiv.attr("style");
    // 原图片页面显示的宽度
    var showWidth = _getShowWidth(style);
    // 原图片页面显示的高度
    var showHeight = _getShowHeight(style);
    // console.log(showWidth + " " + showHeight);
    // 原地图的src地址,去掉后边防止不刷新的随机数
    srcFile = srcFile.substring(0, srcFile.indexOf("?"));
    $.ajax({
    	type : "post",
    	dataType : "json",
    	url : Util.getContentPath() + "/user/uploadHeaderPic.do",
    	data : {
    		srcImageFile : srcFile,
    		x : x1,
    		y : y1,
    		destWidth : w,
    		destHeight : h,
    		srcShowWidth : showWidth,
    		srcShowHeight : showHeight,
    	},
    	success : function(data) {
    		var okCallBack = function () {
    			this.top.window.location = Util.getContentPath() + "/user/pcModiInfoInit.do";
    		};
    		var msg = eval(data);
			if(msg && msg.msg)
				if (msg.code == 1)
					Alert(msg.msg, okCallBack);
				else Error(msg.msg, okCallBack);
			else {
				Error("上传失败,请稍后重试.", okCallBack);
				return;
			}
    	},
    	error : function () {
    		Error ("上传失败,请稍后重试.") ;
    	}
    });
}

function clearCoords()
{
  $('#coords input').val('');
};

(3)springMVC代码:

@RequestMapping("uploadHeaderPicTmp")
	@ResponseBody
	public String uploadHeaderPic(String inputId, MultipartHttpServletRequest request) {
		try {
			MultipartFile realPicFile = request.getFile(inputId);
			InputStream in = realPicFile.getInputStream();
			String path = request.getSession().getServletContext().getRealPath("/");
			path += TMP;
			User loginUser = SystemUtil.getLoginUser(request.getSession());
			String fileName = loginUser.getName() + "." + FilenameUtils.getExtension(realPicFile.getOriginalFilename());
			File f = new File(path + "/" + fileName);
			FileUtils.copyInputStreamToFile(in, f);
			return "{\"path\" : \"" + TMP + "/" + fileName + "\"}";
		} catch (Exception e) {
			LOG.error("upload header picture error : ", e);
		}
		return null;
	}

	@RequestMapping("uploadHeaderPic")
	@ResponseBody
	public GeneralMessage cutImage(String srcImageFile, int x, int y, int destWidth, int destHeight, int srcShowWidth, int srcShowHeight,
			HttpServletRequest request) {
		try {
			String path = request.getSession().getServletContext().getRealPath("/");
			Image img;
			ImageFilter cropFilter;
			String srcFileName = FilenameUtils.getName(srcImageFile);
			// 读取源图像  
			File srcFile = new File(path + TMP + "/" + srcFileName);

			BufferedImage bi = ImageIO.read(srcFile);
			//前端页面显示的并非原图大小,而是经过了一定的压缩,所以不能使用原图的宽高来进行裁剪,需要使用前端显示的图片宽高
			int srcWidth = bi.getWidth(); // 源图宽度  
			int srcHeight = bi.getHeight(); // 源图高度
			if (srcShowWidth == 0)
				srcShowWidth = srcWidth;
			if (srcShowHeight == 0)
				srcShowHeight = srcHeight;

			if (srcShowWidth >= destWidth && srcShowHeight >= destHeight) {
				Image image = bi.getScaledInstance(srcShowWidth, srcShowHeight, Image.SCALE_DEFAULT);//获取缩放后的图片大小  
				cropFilter = new CropImageFilter(x, y, destWidth, destHeight);
				img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), cropFilter));
				BufferedImage tag = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_RGB);
				Graphics g = tag.getGraphics();
				g.drawImage(img, 0, 0, null); // 绘制截取后的图  
				g.dispose();

				String ext = FilenameUtils.getExtension(srcImageFile);

				path += HEADER_PIC;
				User loginUser = SystemUtil.getLoginUser(request.getSession());
				String fileName = loginUser.getName() + "." + ext;
				File destImageFile = new File(path + "/" + fileName);
				// 输出为文件  
				ImageIO.write(tag, ext, destImageFile);

				loginUser.setPicPath(SystemConst.SYSTEM_CONTEXT_PATH_VALUE + HEADER_PIC + "/" + fileName);
				userService.update(loginUser);
				// 删除原临时文件
				srcFile.delete();

				GeneralMessage msg = new GeneralMessage();
				msg.setCode(GeneralMessage.SUCCESS);
				msg.setMsg("上传成功!");
				return msg;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics