jquery.Jcrop结合JAVA后台实现图片裁剪上传
jquery.Jcrop结合JAVA后台实现图片裁剪上传
luckxz999 发表于1年前
jquery.Jcrop结合JAVA后台实现图片裁剪上传
  • 发表于 1年前
  • 阅读 182
  • 收藏 2
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

摘要: 后台管理系统中常会遇到需要按比例裁剪上传图片的功能,如活动海报、相册、头像等。Jcrop是一个强大的jQuery插件,结合后台java程序,能轻松实现图片裁剪后上传的功能。

第一步:引入相关文件

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;
    }

 
标签: Jcrop 图片裁剪
共有 人打赏支持
粉丝 0
博文 5
码字总数 8084
×
luckxz999
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: