第一步:引入相关文件 jQuery主文件:<script src="jquery-1.9.1.min.js" type="text/javascript"></script> Jcrop主文件<scr
第一步:引入相关文件
jQuery主文件:<script src="jquery-1.9.1.min.js" type="text/javascript"></script>
Jcrop主文件<script src="jquery.Jcrop.js" type="text/javascript"></script><link rel="stylesheet" href="jquery.Jcrop.css" type="text/css" />文件异步上传JS,用于不刷新页面上传图片<script src="ajaxfileupload.js" type="text/javascript"></script>第二步:图片处理流程及HTML页面组织处理流程如下:先把原图异步上传(ajaxFileUpload)至服务器某临时目录(我是放在tomcat的webapps某目录下,方便删除),保证该原图可以通过http访问到;将该原图展示在页面上,通过jcrop进行裁剪,点击“裁剪上传”按钮,把裁剪的尺寸信息提交给后台,后台程序根据裁剪的尺寸及原图(webapps某目录下)进行图片的裁剪(ImageReader和Rectangle等);裁剪后的图片上传至图片服务器,原图(webapps某目录下)删除。
图片上传输入框:<input type="file" name="img_poster" id="img_poster" onchange="ajaxFileUpload()"/>
裁剪框:<div class="cutDiv"> <p id="cutInfo"></p> <img id="img1" alt="" src="" /> <input type="hidden" id="x1" name="x1" value="0" /> <input type="hidden" id="y1" name="y1" value="0" /> <input type="hidden" id="x2" name="x2" value="0" /> <input type="hidden" id="y2" name="y2" value="0" /> <input type="hidden" id="cw" name="cw" value="0" /> <input type="hidden" id="ch" name="ch" value="0" /> <input type="hidden" id="imgName" name="imgName" value="" /> <input type="hidden" id="imgType" name="imgType" value="" /> <input id="cutimg" type="button" value="裁剪上传" /> <input id="cancelimg" type="button" value="取消" /></div>第三步:js代码初始化
<script type="text/javascript"> var _jcropApi, _boundx, _boundy, _ratio=1;//定义比例、长宽等 $(document).ready(function() { //取消按钮事件 $("#cancelimg").click(function() { $("#img_hotLine").attr('value',''); $(".img-group").show(); $("#cutDiv").hide(); if (_jcropApi) { _jcropApi.destroy(); } $("#img1").hide(); }); //裁剪上传按钮事件 $("#cutimg").click(function() { ajaxFileCut(); });
_ratio = 1; //当裁剪框变动时,将左上角相对图片的X坐标与Y坐标,宽度以及高度放到<input type="hidden">中 (上传到服务器上裁剪会用到) function showCoords(c) { $('#x1').val(c.x * _ratio); $('#y1').val(c.y * _ratio); $('#x2').val(c.x2 * _ratio); $('#y2').val(c.y2 * _ratio); $('#cw').val(c.w * _ratio); $('#ch').val(c.h * _ratio); $("#cutInfo").text("已选择宽*高:" + (parseInt($('#x2').val()) - parseInt($('#x1').val())) + "*" + (parseInt($('#y2').val()) - parseInt($('#y1').val()))); }
});
第四步:异步图片上传代码
//当AJAX上传图片操作function ajaxFileUpload() { $.ajaxFileUpload ( { url: '/ajaxImageUpload', //用于文件上传的服务器端请求地址 secureuri: false, //一般设置为false,是否安全上传 fileElementId: 'img_poster', //文件上传控件的id属性 <input type="file" id="file" name="file" /> dataType: 'json', //返回值类型 一般设置为json 期望服务器传回的数据类型 success: function (data, status) //服务器成功响应处理函数 { var result = data.result; if (result && result == "success") { $("#cutDiv").show();//显示裁剪框 var _imgTemp = new Image(); _imgTemp.src = "http://localhost/images/" + data.img_urls; _imgTemp.onload = function() { //上传成功后在将服务器上刚刚上传的图片显示在img1上 $("#img1").attr("src", "http://localhost/images/" + data.img_urls).show(); $("#imgName").val(data.img_urls); //同时启动裁剪操作,触发裁剪框显示,让用户选择图片区域 $("#img1").Jcrop({ aspectRatio: 2 / 1, bgOpacity: .4, fadeTime: 10, boxWidth: 500, boxHeight: 500, onChange: showCoords, //当裁剪框变动时执行的函数 onSelect: showCoords //当选择完成时执行的函数 }, function() { _jcropApi = this; _jcropApi.focus(); var bounds = this.getBounds(); _boundx = bounds[0]; _boundy = bounds[1]; _jcropApi.setImage("${ctximages}" + data.img_urls); _jcropApi.animateTo([0, 0, 320, 160]); _jcropApi.setOptions({allowSelect: false}); _jcropApi.setOptions({ minSize: [320, 160] }); }); } } else { if (typeof (data.error) != 'undefined') { if (data.error != '') { alert(data.error); } else { alert(data.msg); } } } }, error: function (data, status, e)//服务器响应失败处理函数 { alert("系统错误:请检查图片尺寸及大小是否符合要求"); } } ) return false;}
第五步:原图异步上传后台处理
/** * 异步上传源图片 * @param request 请求 * @param response 响应 */@ResponseBody@RequestMapping(value = "/ajaxImageUpload")public void ajaxImageUpload(HttpServletRequest request, HttpServletResponse response) { response.setContentType("application/json; charset=UTF-8"); Map<String, String> result = new HashMap<>(); try { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; Map<String, MultipartFile> fileMap = multipartRequest.getFileMap(); if (fileMap != null && fileMap.size() > 0) { String img_urls = ""; Map.Entry<String, MultipartFile> entity = fileMap.entrySet().iterator().next(); // 上传文件名key对应from表单中的name值, value即为上传的文件 MultipartFile img_cover = entity.getValue(); String fileName = img_cover.getOriginalFilename(); // 获取文件扩展名 String ext = fileName.substring(fileName.lastIndexOf(".") + 1); //如果文件不是图片,则不上传 if (!"jpg".equalsIgnoreCase(ext) && !"jpeg".equalsIgnoreCase(ext) && !"png".equalsIgnoreCase(ext) && !"gif".equalsIgnoreCase(ext) && !"bmp".equalsIgnoreCase(ext)) { throw new Exception("文件格式错误"); } if (img_cover.getSize() > 0) { String pc_img_url = uploadImageToWebServer(request, img_cover);//上传图片至本机tomcat的webapps目录下,返回图片名称 if (StringUtils.isNotBlank(pc_img_url)) { img_urls += pc_img_url + ConstUtils.SPLIT_CHAR; } } if (img_urls.length() > 0) { img_urls = img_urls.substring(0, img_urls.length() - 1); } result.put("result", "success"); result.put("img_urls", img_urls); } else { throw new Exception("请选择要上传的文件"); } } catch (Exception e) { e.printStackTrace(); result.put("result", "fail"); result.put("error", "文件上传失败:" + e.getMessage()); } try { response.setContentType("text/html;charset=UTF-8"); response.getWriter().write(JsonMapper.getInstance().toJson(result)); }catch (IOException e) { logger.error(e.getMessage(), e); }}
第六步:裁剪上传JS
//AJAX上传图片裁剪function ajaxFileCut() { $.ajax({ type: "get", url: "/ajaxImageCut", data: 'imgName=' + $("#imgName").val() + '&x1='+$("#x1").val() + "&y1="+$("#y1").val() + "&cw="+$("#cw").val() + "&ch="+$("#ch").val(), datatype: "json", success: function (data) { if (data && data.result) { if (data.result == "success") { $(".img-group").show(); $("#cutDiv").hide(); $("#img1").hide(); if (_jcropApi) { _jcropApi.destroy(); } //TODO 此处客户端自行控制显示后台返回的裁剪后的图片地址
data.img_url } else { if (typeof (data.error) != 'undefined') { if (data.error != '') { alert(data.error); } else { alert(data.msg); } } } } }, error: function (data, status, e)//服务器响应失败处理函数 { alert(e); } }); return false;}
第七步:裁剪后台处理
/** * 裁剪图片,原图片已上传至工程部署目录的images文件夹下 * @param request 请求 * @param response 响应 * @param imgName 要裁剪的图片名称,即临时保存在webapps下的图片名称 * @param x1 起始点x坐标 * @param y1 起始点y坐标 * @param cw 裁剪后的宽度 * @param ch 裁剪后的高度 */@ResponseBody@RequestMapping(value = "/ajaxImageCut")public void ajaxImageCut(HttpServletRequest request, HttpServletResponse response, String imgName, Double x1, Double y1, Double cw, Double ch) { Map<String, String> result = new HashMap<>(); try { if (StringUtils.isNotBlank(imgName)) { String img_url = cutImage(request, imgType, imgName, x1 == null ? 0 : x1.intValue(), y1 == null ? 0 : y1.intValue(), cw == null ? 0 : cw.intValue(), ch == null ? 0 : ch.intValue(), 0, 0); if (StringUtils.isBlank(img_url)) { throw new Exception("请确认图片格式及尺寸是否正确"); } result.put("result", "success"); result.put("img_url", img_url); } else { throw new Exception("请选择要裁剪的文件"); } } catch (Exception e) { e.printStackTrace(); result.put("result", "fail"); result.put("error", "文件裁剪失败:" + e.getMessage()); } try { response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(JsonMapper.getInstance().toJson(result)); }catch (IOException e) { logger.error(e.getMessage(), e); }}
附录:图片裁剪代码参考
private File file = null; // 文件对象private String inputDir; // 输入图路径private String outputDir; // 输出图路径private String inputFileName; // 输入图文件名private String outputFileName; // 输出图文件名private int outputWidth = 100; // 默认输出图片宽private int outputHeight = 100; // 默认输出图片高private boolean proportion = true; // 是否等比缩放标记(默认为等比缩放)private boolean enlarge = false;//是否放大图片(默认否)
// ===剪切点x y坐标private int x;private int y;
/** 对图片裁剪,并把裁剪完的新图片保存 */ private boolean cut(){ FileInputStream is = null; ImageInputStream iis = null; try { File file = new File(inputDir + inputFileName); Image image = ImageIO.read(file); int width = image.getWidth(null); int height = image.getHeight(null); //如果裁剪尺寸大于原图尺寸,则不裁剪 if (width <= outputWidth && height <= outputHeight) { FileUtils.copyFileCover(inputDir + inputFileName, outputDir + outputFileName, true); return true; } // 读取图片文件 is = new FileInputStream(inputDir + inputFileName); String ext = inputFileName.substring(inputFileName.lastIndexOf(".") + 1); /* * 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。 * 参数:formatName - 包含非正式格式名称 . (例如 "jpeg" 或 "tiff")等 。 */ Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(ext.toLowerCase());// if (it.next() == null) {// return false;// } ImageReader reader = it.next(); // 获取图片流 iis = ImageIO.createImageInputStream(is); /* * <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。 * 此设置意味着包含在输入源中的图像将只按顺序读取,可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。 */ reader.setInput(iis, true); /* * <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O * 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 将从其 ImageReader 实现的 * getDefaultReadParam 方法中返回 ImageReadParam 的实例。 */ ImageReadParam param = reader.getDefaultReadParam(); /* * 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域,通过 Rectangle 对象 * 的左上顶点的坐标(x,y)、宽度和高度可以定义这个区域。 */ Rectangle rect = new Rectangle(x, y, outputWidth, outputHeight); // 提供一个 BufferedImage,将其用作解码像素数据的目标。 param.setSourceRegion(rect); /* * 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象,并将 它作为一个完整的 * BufferedImage 返回。 */ BufferedImage bi = reader.read(0, param); // 保存新图片 ImageIO.write(bi, ext.toLowerCase(), new File(outputDir + outputFileName)); return true; } catch (Exception e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (Exception e) { e.printStackTrace(); } } if (iis != null) { try { iis.close(); } catch (Exception e) { e.printStackTrace(); } } } return false; }