文档章节

jquery.Jcrop结合JAVA后台实现图片裁剪上传

l
 luckxz999
发布于 2016/06/20 17:39
字数 2071
阅读 222
收藏 2
点赞 0
评论 0

第一步:引入相关文件

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

© 著作权归作者所有

共有 人打赏支持
l
粉丝 0
博文 5
码字总数 8084
作品 0
商丘
使用 Grapicmagick 和 Im4java 处理图片

ImageMagick是个图片处理工具可以安装在绝大多数的平台上使用,Linux、Mac、Windows都没有问题。GraphicsMagick是在ImageMagick基础上的另一个项目,大大提高了图片处理的性能,在linux平台上...

voole ⋅ 05/07 ⋅ 0

基于cropper.js的图片上传和裁剪

项目中要求图片上传并裁剪的功能,之前也有接触过很多图片裁剪插件,效果体验不是很好,今天推荐一款好用的插件-cropper,超级好用,裁剪功能丰富,满足了各种需求。 功能: 1:点击选择图片...

祈澈姑娘 ⋅ 05/17 ⋅ 0

Java学习---Java简单认识

前言 小编在学习Java方面的基础知识,发现里面有很多是结合之前的语言的特点发展过来的,不同的地方是,Java有它自己的发展和特点。下面小编先简单地做一下总结,结合看过的1-2章的J2SE视频,...

m18633778874 ⋅ 04/01 ⋅ 0

java程序员基础进阶篇,万丈高楼平地起

一.final,finally,finalize 三者区别 Final是一个修饰符: 当final修饰一个变量的时候,变量变成一个常量,它不能被二次赋值 当final修饰的变量为静态变量(即由static修饰)时,必须在声明这...

启示录是真的 ⋅ 05/26 ⋅ 0

Java 借助ImageMagic实现图片编辑服务

Java 借助ImageMagic实现图片编辑服务 java原生对于图片的编辑处理并没有特别友好,而且问题也有不少,那么作为一个java后端,如果要提供图片的编辑服务可以怎么办?也得想办法去支持业务需求...

小灰灰Blog ⋅ 04/18 ⋅ 0

通过 HttpAuthenticationMechanism 执行 Web 身份验证

通过 Java EE 8 中新的注解驱动的 HTTP 身份验证机制执行经典和自定义的 Servlet 身份验证 系列内容: 此内容是该系列 4 部分中的第 # 部分: Java EE 8 Security API 入门,第 2 部分 http...

Alex Theedom ⋅ 04/02 ⋅ 0

sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer ⋅ 05/03 ⋅ 0

基于 Java 的 CMS 解决方案 - tjpcms

官网:http://www.tjpcms.com tjpcms 是一套基于 Java 的 CMS 解决方案,开源免费。其独有的实时配置增删改查的功能,是其区别于同类 cms 的最大特点,也是最大优势,极大减少了重复劳动。懂...

金盆洗手 ⋅ 2017/01/12 ⋅ 6

JAVA使用字节流将本地图片传到前端

JAVA使用字节流将本地图片传到前端 01.基本介绍 在我们日常的开发中,会遇到对验证码的使用问题(验证码的作用这里不多多说,避免程序被恶意攻击等),如何是的前端和后端保持一致是一个问题...

meiqi0538 ⋅ 04/09 ⋅ 0

java基础thread——多线程的纷争(循序渐进)

一、多线程概述 进程: 正在运行的程序,是系统进行资源分配和调用的独立单位。 每一个进程都有它自己的内存空间和系统资源。 多进程有什么意义呢? 单进程的计算机只能做一件事情,而我们现在...

潇潇漓燃 ⋅ 05/30 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

win环境下jdk7与jdk8共存配置

1.jdk安装包 jdk安装包 安装步骤略 2.jdk等配置文件修改 在安装JDK1.8时(本机先安装jdk1.7再安装的jdk1.8),会将java.exe、javaw.exe、javaws.exe三个文件copy到了C:\Windows\System32,这...

泉天下 ⋅ 17分钟前 ⋅ 0

windows profesional 2017 build problem

.net framework .... https://stackoverflow.com/questions/43330915/could-not-load-file-or-assembly-microsoft-build-frameworkvs-2017...

机油战士 ⋅ 51分钟前 ⋅ 0

python3中报错的解决方法(长期更新)

1、ImportError: No module named ‘DjangoUeditor’ 出错原因:安装DjangoUeditor库适用于python2,需要下载适用python3的 下载地址:https://github.com/twz915/DjangoUeditor3 2、python3......

xiaoge2016 ⋅ 56分钟前 ⋅ 0

数据结构与算法之双向链表

一、双向链表 1.双向链表的结点结构 typedef struct DualNode{ ElemType data; struct DualNode *prior; // 前驱结点 struct DualNode *next; // 后继结点}DualNode, *DuL...

aibinxiao ⋅ 今天 ⋅ 0

五大最核心的大数据技术

大数据技术有5个核心部分,数据采集、数据存储、数据清洗、数据挖掘、数据可视化。关于这5个部分,有哪些核心技术?这些技术有哪些潜在价值?看完今天的文章就知道了。 大数据学习群:7165810...

董黎明 ⋅ 今天 ⋅ 0

PhpStorm 头部注释、类注释和函数注释的设置

首先,PhpStorm中文件、类、函数等注释的设置在:setting-》Editor-》FIle and Code Template-》Includes下设置即可,其中方法的默认是这样的: /**${PARAM_DOC}#if (${TYPE_HINT} != "v...

nsns ⋅ 今天 ⋅ 0

spring.net AOP

http://www.springframework.net/doc-latest/reference/html/aop-quickstart.html https://www.cnblogs.com/wujy/archive/2013/04/06/3003120.html AOP系列(一)——ProxyFactoryObject 显式创......

whoisliang ⋅ 今天 ⋅ 0

【HAVENT原创】创建 Dockerfile 生成新的镜像,并发布到 DockerHub

注意:Win7 与 Win10 的版本存在差异,Win7 版本使用 Docker Quickstart Terminal 进入控制台,Win10下面直接用管理员权限打开控制台或者 PowerShell 即可;另外 Win7 下面只能访问 C盘,/ap...

HAVENT ⋅ 今天 ⋅ 0

pom.xml出现web.xml is missing ...解决方案

提示信息应该能看懂。也就是缺少了web.xml文件,<failOnMissingWebXml>被设置成true了。 搜索了一下,Stack Overflow上的答案解决了问题,分享一下。 目前被顶次数最多的回答原文如下: This...

源哥L ⋅ 今天 ⋅ 0

js时间戳与日期格式之间相互转换

1. 将时间戳转换成日期格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 简单的一句代码 var date = new Date(时间戳); //获取一个时间对象 /** 1. 下面是获取时间日期的方法,需要什么样的格式自己...

Jack088 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部