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


Posted in Javascript onNovember 05, 2016

本文介绍了头像裁剪上传功能,用到的技术有  jQuery,springmvc,裁剪插件用的是jcrop(中间遇到很多坑,最终跨越)。

图片上传步骤:

1.用户选择图片

2.将图片传入后台:用户选择图片的时候选择的是各种各样的,但是我们的网页显示图片大小是有限的,所以我们就要在用户选择图片之后将图片添加到后台进行压缩,压缩成我们想要的大小,之后再显示到页面才好

3.利用jcrop裁剪工具对图片进行裁剪并且实时预览

4.点击确定按钮将裁剪用到的参数传入后台,后台图片进行剪切,之后缩放成我们需要的格式

5.最后将图片路径传到前台进行展示

前台页面代码为:

<script src="js-jcrop/jquery.min.js"></script> 
<script src="js-jcrop/jquery.Jcrop.js"></script> 
<script src="js/jquery-form.js"></script> 
<link rel="stylesheet" href="../css/jquery.Jcrop.css" type="text/css" /> 
<style type="text/css"> 
/* 控制预览区域大小*/ 
#preview-pane .preview-container { 
 width: 110px; 
 height: 110px; 
 overflow: hidden; 
} 
#targetDiv{ 
 width: 400px; 
 height: 400px; 
 background-color:#f7fdff; 
} 
</style> 
 
<dl class="dialogBox D_uploadLogo"> 
  <dt class="dialogHeader"> 
    <span class="title">头像上传</span> 
  </dt> 
   
  <dd class="dialogBody"> 
    <dl class="bisinessLogo"> 
      <dt class="title">预览</dt> 
      <dd class="img"> 
        <div id="preview-pane"> 
          <div class="preview-container"> 
           <img src="" id="target2" class="jcrop-preview" alt="未选择图片" /> 
          </div> 
         </div> 
      </dd> 
      <dd class="tc">尺寸:110*110px</dd> 
    </dl> 
    <dl class="bisinessInfo"> 
      <dt class="btnBox02"> 
        <form id="fileUp" action="/file/img/upload" method="post" enctype="multipart/form-data" target="ifm"> 
          <a class="btnGray" href="javascript:;"> 
            <span class="text" id="format">选择图片</span>  
            <b class="bgR"></b> 
            <input type="file" id="file_upload" class="inputFile" name="userphoto"/> 
            <input type="hidden" id="w" name="w"/> 
            <input type="hidden" id="h" name="h"/> 
            <input type="hidden" id="x" name="x"/> 
            <input type="hidden" id="y" name="y"/> 
          </a> 
        </form> 
      </dt> 
      <dd class="info"> 
       
        请从本地选择一张照片,支持jpg,png格式  <span id="msg"></span> 
        <div id="targetDiv"> 
          <img src="" id="target" width="400" height="400" alt="未选择图片"/> 
        </div> 
      </dd> 
    </dl> 
  </dd> 
  <input type="hidden" id="filePathInput" value=""/> 
 
  <dd class="dialogBottom"> 
    <a class="btnBlue btn_confirm" href="javascript:;" onclick="photoSummit();"><span class="text">确定</span><b class="bgR"></b></a> 
    <a class="btnGray btn_cancel" href="javascript:;" onclick="hideDialog();"><span class="text">取消</span><b class="bgR"></b></a> 
  </dd> 
</dl>

1.选择图片

<img src="" id="target" width="400" height="400" alt="未选择图片"/>

2.提交:首先大家知道文件上传的时候用到的标签为:<input type="file"/>   但是有时候我们需要用ajax提交文件并且异步提交,我们如果是用form表单提交的话就不是异步,这样我们回到页面就刷新页面,非常的不方便,但是现在ajax还不能支持文件提交的方式,这时候我们就用到了jquery-form.js,这个文件支持我们用ajax提交文件,代码为:

$("#fileUp").<span style="color:#ff0000;">ajaxSubmit</span>({ 
      type: "POST", 
      url:"/file/img/upload", 
      dataType: "json", 
      contentType:"application/json",  
        success: function(parameter){ 
        $("#target2").attr('src','/upload/'+parameter.fileName); 
        $("#filePathInput").val('/upload/'+parameter.fileName); 
        if($("#format").text()=="重新上传"){ 
          jcrop_api.destroy() 
        } 
        $("#format").text("重新上传"); 
        //启动jcrop支持 
        openJcrop('/upload/'+parameter.fileName); 
      }, 
      error : function(data) {  
        alert("ajax传输发生错误!!!"); 
      }  
     });

这样就能将文件用ajax的方式提交到后台,注意这里用的是ajaxSubmit,这个方法对应jquery-form.js,后台代码为:

package com.quanshi.ums.gate.view.rest.controllers; 
import java.io.IOException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
import org.springframework.web.bind.annotation.RequestParam; 
import org.springframework.web.bind.annotation.ResponseBody; 
import org.springframework.web.multipart.MultipartFile; 
import com.quanshi.ums.gate.persistence.entities.Parameters; 
import com.quanshi.ums.gate.view.rest.ImgEditor; 
 /** 
 * 图像上传和修改相关类 
 * @author kunpeng.zhao 
 * 
 */ 
@Controller 
@RequestMapping(value="/file") 
public class FileEditorController { 
<span style="white-space:pre">  </span>ImgEditor imgEditor = new ImgEditor(); 
<span style="white-space:pre">  </span>public String filePathFinal = ""; 
<span style="white-space:pre">  </span>private Logger logger = LoggerFactory.getLogger(FileEditorController.class); 
<span style="white-space:pre">  </span>@RequestMapping(value="/img/cutandscale",method=RequestMethod.POST) 
<span style="white-space:pre">  </span>public @ResponseBody int cutAndscaleimg( 
<span style="white-space:pre">      </span>@RequestParam("w") int w, 
<span style="white-space:pre">      </span>@RequestParam("h") int h, 
<span style="white-space:pre">      </span>@RequestParam("x") int x, 
<span style="white-space:pre">      </span>@RequestParam("y") int y 
<span style="white-space:pre">      </span>){ 
<span style="white-space:pre">    </span>imgEditor.cut(filePathFinal,filePathFinal,x,y,w,h); 
<span style="white-space:pre">    </span>imgEditor.scale(filePathFinal, filePathFinal, 110, 110, false); 
<span style="white-space:pre">    </span>return 1; 
<span style="white-space:pre">  </span>} 
<span style="white-space:pre">  </span> 
<span style="white-space:pre">  </span> 
  @RequestMapping(value="/img/upload",method=RequestMethod.POST) 
  public @ResponseBody Parameters addImage( 
  <span style="white-space:pre">   </span>@RequestParam("userphoto") MultipartFile file, 
  <span style="white-space:pre">   </span>HttpServletRequest request, 
  <span style="white-space:pre">   </span>HttpServletResponse response, 
  <span style="white-space:pre">   </span>HttpSession session 
  <span style="white-space:pre">   </span>){ 
  <span style="white-space:pre"> </span>String filePath = "";  
  <span style="white-space:pre"> </span>try { 
  <span style="white-space:pre">   </span>//上传原图 
<span style="white-space:pre">      </span>filePath = imgEditor.uploadFile(file, request,session); 
<span style="white-space:pre">      </span>filePathFinal = filePath; 
<span style="white-space:pre">      </span>//将图片压缩成指定大小 
<span style="white-space:pre">      </span>imgEditor.zoomImage(filePath,filePath,400,400); 
<span style="white-space:pre">    </span>} catch (IOException e) { 
<span style="white-space:pre">      </span>e.printStackTrace(); 
<span style="white-space:pre">    </span>}  
    logger.info("filePath:" + filePath); 
    Parameters parameter = new Parameters(); 
    parameter.setFileName(imgEditor.getFileName(file,request,session)); 
  <span style="white-space:pre"> </span>return parameter; 
  } 
   
   
   
   
}

我在这规定图片在前台展示的大小为400*400,用到的图片裁剪压缩等的工具类为:

package com.quanshi.ums.gate.view.rest; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Image; 
import java.awt.Toolkit; 
import java.awt.geom.AffineTransform; 
import java.awt.image.AffineTransformOp; 
import java.awt.image.BufferedImage; 
import java.awt.image.CropImageFilter; 
import java.awt.image.FilteredImageSource; 
import java.awt.image.ImageFilter; 
import java.io.File; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
 
import javax.imageio.ImageIO; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpSession; 
 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.web.multipart.MultipartFile; 
 
public class ImgEditor { 
   /** 
   * 改变图片尺寸 
   * @param srcFileName 源图片路径 
   * @param tagFileName 目的图片路径 
   * @param width 修改后的宽度 
   * @param height 修改后的高度 
   */ 
  public void zoomImage(String srcFileName,String tagFileName,int width,int height){  
     try { 
     BufferedImage bi = ImageIO.read(new File(srcFileName)); 
     BufferedImage tag=new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB); 
     tag.getGraphics().drawImage(bi, 0, 0, width, height, null); 
     ImageIO.write(tag, "jpg", new File(tagFileName));//画图 
     } catch (IOException e) { 
     e.printStackTrace(); 
     } 
  } 
   
   
   
  /** 
   * 缩放图像(按高度和宽度缩放) 
   * @param srcImageFile 源图像文件地址 
   * @param result 缩放后的图像地址 
   * @param height 缩放后的高度 
   * @param width 缩放后的宽度 
   * @param bb 比例不对时是否需要补白:true为补白; false为不补白; 
   */ 
  public void scale(String srcImageFile, String result, int height, int width, boolean bb) { 
    try { 
      double ratio = 0.0; // 缩放比例 
      File f = new File(srcImageFile); 
      BufferedImage bi = ImageIO.read(f); 
      Image itemp = bi.getScaledInstance(width, height, bi.SCALE_SMOOTH); 
      // 计算比例 
      if ((bi.getHeight() > height) || (bi.getWidth() > width)) { 
        if (bi.getHeight() > bi.getWidth()) { 
          ratio = (new Integer(height)).doubleValue() 
              / bi.getHeight(); 
        } else { 
          ratio = (new Integer(width)).doubleValue() / bi.getWidth(); 
        } 
        AffineTransformOp op = new AffineTransformOp(AffineTransform 
            .getScaleInstance(ratio, ratio), null); 
        itemp = op.filter(bi, null); 
      } 
      if (bb) {//补白 
        BufferedImage image = new BufferedImage(width, height, 
            BufferedImage.TYPE_INT_RGB); 
        Graphics2D g = image.createGraphics(); 
        g.setColor(Color.white); 
        g.fillRect(0, 0, width, height); 
        if (width == itemp.getWidth(null)) 
          g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2, 
              itemp.getWidth(null), itemp.getHeight(null), 
              Color.white, null); 
        else 
          g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0, 
              itemp.getWidth(null), itemp.getHeight(null), 
              Color.white, null); 
        g.dispose(); 
        itemp = image; 
      } 
      ImageIO.write((BufferedImage) itemp, "JPEG", new File(result)); 
    } catch (IOException e) { 
      e.printStackTrace(); 
    } 
  } 
   
   
  /** 
   * 图像切割(按指定起点坐标和宽高切割) 
   * @param srcImageFile 源图像地址 
   * @param result 切片后的图像地址 
   * @param x 目标切片起点坐标X 
   * @param y 目标切片起点坐标Y 
   * @param width 目标切片宽度 
   * @param height 目标切片高度 
   */ 
  public void cut(String srcImageFile, String result, 
      int x, int y, int width, int height) { 
    try { 
      // 读取源图像 
      BufferedImage bi = ImageIO.read(new File(srcImageFile)); 
      int srcWidth = bi.getHeight(); // 源图宽度 
      int srcHeight = bi.getWidth(); // 源图高度 
      if (srcWidth > 0 && srcHeight > 0) { 
        Image image = bi.getScaledInstance(srcWidth, srcHeight, 
            Image.SCALE_DEFAULT); 
        // 四个参数分别为图像起点坐标和宽高 
        // 即: CropImageFilter(int x,int y,int width,int height) 
        ImageFilter cropFilter = new CropImageFilter(x, y, width, height); 
        Image img = Toolkit.getDefaultToolkit().createImage( 
            new FilteredImageSource(image.getSource(), 
                cropFilter)); 
        BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
        Graphics g = tag.getGraphics(); 
        g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图 
        g.dispose(); 
        // 输出为文件 
        ImageIO.write(tag, "JPEG", new File(result)); 
      } 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  } 
  //获得文件名字 
  public String getFileName(MultipartFile file, HttpServletRequest request,HttpSession session){ 
    String FILE_PATH = session.getServletContext().getRealPath("/") + "upload"; 
    String fileName = file.getOriginalFilename();  
    String[] suffixNameArr = fileName.split("\\."); 
    String suffixName = suffixNameArr[suffixNameArr.length-1]; 
    String userName = SecurityContextHolder.getContext().getAuthentication().getName(); 
     
    return getTime() + userName+"."+suffixName; 
  } 
  //文件上传,返回文件路径 
  public String uploadFile(MultipartFile file, HttpServletRequest request,HttpSession session) throws IOException { 
    String FILE_PATH = session.getServletContext().getRealPath("/") + "upload"; 
    String fileName = getFileName(file,request,session); 
    File tempFile = new File(FILE_PATH, fileName);  
     
    if (!tempFile.getParentFile().exists()) {  
      tempFile.getParentFile().mkdir();  
    }  
    if (!tempFile.exists()) {  
      tempFile.createNewFile();  
    }  
    file.transferTo(tempFile); //将上传文件写到服务器上指定的文件。 
     
    return FILE_PATH + "\\" + tempFile.getName();  
  }  
  
  /* public static File getFile(String fileName) {  
    return new File(FILE_PATH, fileName);  
  } */  
   
  public String getTime(){ 
    Date date = new Date(); 
    SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式 
    String nowTime = df.format(date).toString(); 
    return nowTime; 
  } 
}

这样就将图片要裁剪的图片路径返回页面展示

3.之后就是图片裁剪了,图片裁剪功能我找了好多插件,最后锁定jcrop,也是因为它的demo打动了我(太好看了),之后就是导入文件,在我这里,我在页面接收后台返回来的图片路径之后启用jcrop,也就是openJcrop()方法,这样就可以加载jcrop插件了,具体大家想进一步了解这个裁剪工具,请到官网细细的研究,我就不再做过多的谈论了。

大家注意,在这里有个大坑,真的是大坑,就是重新选择图片的时候,被jcrop加载过的img的src是不能被修改的,这个当初卡了我好长时间,被jcrop加载一次jcrop就会生成一个自己的编辑对象(我自己的理解),这时候就和原来的img没有关系了,直到最后细细研究api才找到了一个方法,唯一的方法就是将这个jcrop销毁,就是jcrop_api.destroy(),这个有很大的学问,我就提示一点,就是将jcrop_api声明为全局变量,下面贴出js代码(和上边的html是在一个文件下):

<script type="text/javascript"> 
   
   $(function(){ 
    var jcrop_api; 
   }); 
   
   $("#file_upload").change(function() { 
     $("#msg").text(''); 
     var oFile = $(this)[0].files[0]; 
     //判断上传文件大小 
     if (oFile.size > 1*1024*1024) { 
       $("#msg").text('你选择了太大的文件,请选择一个1M以下的图像文件').css('color','red'); 
       $(this).val(""); 
       return; 
     } 
       
     //判断类型 
     var filepath=$(this).val(); 
     var extStart=filepath.lastIndexOf("."); 
     var ext=filepath.substring(extStart,filepath.length).toUpperCase(); 
     if(ext!=".JPEG"&&ext!=".PNG"&&ext!=".JPG"){ 
      $("#msg").text('请选择一个有效的图像文件(jpg,png是允许的)').css('color','red'); 
        $(this).val(""); 
        return; 
     } 
       
    $("#fileUp").ajaxSubmit({ 
      type: "POST", 
      url:"/file/img/upload", 
      dataType: "json", 
      contentType:"application/json",  
      success: function(parameter){ 
        $("#target2").attr('src','/upload/'+parameter.fileName); 
        $("#filePathInput").val('/upload/'+parameter.fileName); 
        if($("#format").text()=="重新上传"){ 
          jcrop_api.destroy() 
        } 
        $("#format").text("重新上传"); 
        //启动jcrop支持 
        openJcrop('/upload/'+parameter.fileName); 
      }, 
      error : function(data) {  
        alert("ajax传输发生错误!!!"); 
      }  
     }); 
  }); 
   function photoSummit(){ 
    
     //alert($("#w").val()+","+$("#h").val()+","+$("#x").val()+","+$("#y").val()); 
     //$("#fileUp").attr("action", "/file/img/upload").submit(); 
     if($("#w").val()>0 && $("#h").val()>0){ 
      $("#fileUp").ajaxSubmit({ 
        type: "POST", 
        url:"/file/img/cutandscale", 
        dataType: "json", 
        contentType:"application/json",  
        success: function(data){ 
           $("#msg").text('上传头像成功!!!').css('color','red'); 
           //alert($("#filePathInput").val()); 
           window.parent.back($("#filePathInput").val()); 
        },  
        error : function(data) {  
          alert("ajax传输发生错误!!!"); 
        }  
      }); 
     }else{ 
      $("#msg").text('请用鼠标截取图片').css('color','red'); 
     }  
   } 
   //启动jcrop 
  function openJcrop(imgPath){ 
    //启动jcrop支持 
        var boundx,boundy, 
        xsize = $('#preview-pane .preview-container').width(), 
        ysize = $('#preview-pane .preview-container').height(); 
         
        $('#target').Jcrop({ 
         minSize: [110, 110], 
         onChange: updatePreview, 
         onSelect: updatePreview, 
         aspectRatio: xsize / ysize 
        },function(){ 
         // Use the API to get the real image size 
         var bounds = this.getBounds(); 
         boundx = bounds[0]; 
         boundy = bounds[1]; 
         jcrop_api = this; 
        }); 
        jcrop_api.setImage(imgPath); 
        function updatePreview(c) 
        { 
         if (parseInt(c.w) > 0) 
         { 
          var rx = xsize / c.w; 
          var ry = ysize / c.h; 
       
          $('#preview-pane .preview-container img').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' 
          }); 
          $("#w").val(c.w); 
          $("#h").val(c.h); 
          $("#x").val(c.x); 
          $("#y").val(c.y); 
         } 
         }; 
  } 
    
    
</script>

这样我们就完成了编辑功能,之后我们点击提交就会将w,h,x,y参数传到后台。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 组件之旅(三):用 Ant 构建组件
Oct 28 Javascript
表单JS弹出填写提示效果代码
Apr 16 Javascript
jQuery源码分析-02正则表达式 RegExp 常用正则表达式
Nov 14 Javascript
解析瀑布流布局:JS+绝对定位的实现
May 08 Javascript
Javascript常用字符串判断函数代码分享
Dec 08 Javascript
推荐10 款 SVG 动画的 JavaScript 库
Mar 24 Javascript
jquery实现先淡出再折叠收起的动画效果
Aug 07 Javascript
简介AngularJS中$http服务的用法
Feb 06 Javascript
关于在Servelet中如何获取当前时间的操作方法
Jun 28 Javascript
详解Node.js如何开发命令行工具
Aug 14 Javascript
微信小程序环境下将文件上传到OSS的方法步骤
May 31 Javascript
原生JS实现留言板功能
Feb 08 Javascript
JavaScript中绑定事件的三种方式及去除绑定
Nov 05 #Javascript
Ajax与服务器(JSON)通信实例代码
Nov 05 #Javascript
Javascript 普通函数和构造函数的区别
Nov 05 #Javascript
Javascript 函数的四种调用模式
Nov 05 #Javascript
详解利用exif.js解决ios手机上传竖拍照片旋转90度问题
Nov 04 #Javascript
jQuery中 $ 符号的冲突问题及解决方案
Nov 04 #Javascript
JAVA Web实时消息后台服务器推送技术---GoEasy
Nov 04 #Javascript
You might like
从C/C++迁移到PHP——判断字符类型的函数
2006/10/09 PHP
新手配置 PHP 调试环境(IIS+PHP+MYSQL)
2007/01/10 PHP
解析在PHP中使用mysqli扩展库对mysql的操作
2013/07/03 PHP
基于PHP微信红包的算法探讨
2016/07/21 PHP
PHP中将一个字符串部分字符用星号*替代隐藏的实现代码
2019/09/08 PHP
PhpStorm 如何优雅的调试Hyperf的方法步骤
2019/11/24 PHP
BOOM vs RR BO5 第二场 2.14
2021/03/10 DOTA
JavaScript对象模型-执行模型
2008/04/28 Javascript
Jquery Ajax学习实例7 Ajax所有过程事件分析示例
2010/03/23 Javascript
httpclient模拟登陆具体实现(使用js设置cookie)
2013/12/11 Javascript
jQuery 中$(this).index与$.each的使用指南
2014/11/20 Javascript
JavaScript实现给按钮加上双重动作的方法
2015/08/14 Javascript
jQuery幻灯片特效代码分享--鼠标滑过按钮时切换(2)
2020/11/18 Javascript
DeviceOne 让你一见钟情的App快速开发平台
2016/02/17 Javascript
jQuery Layer弹出层传值到父页面的实现代码
2017/08/17 jQuery
vue中的event bus非父子组件通信解析
2017/10/27 Javascript
Angular4学习教程之HTML属性绑定的方法
2018/01/04 Javascript
解决Vue.js父组件$on无法监听子组件$emit触发事件的问题
2018/09/12 Javascript
详解关闭令人抓狂的ESlint 语法检测配置方法
2019/10/28 Javascript
JS实现简单的表格增删
2020/01/16 Javascript
jQuery表单校验插件validator使用方法详解
2020/02/18 jQuery
vue-cli4.0多环境配置变量与模式详解
2020/12/30 Vue.js
说一说Python logging
2016/04/15 Python
对numpy.append()里的axis的用法详解
2018/06/28 Python
使用python3调用wxpy模块监控linux日志并定时发送消息给群组或好友
2019/06/05 Python
Python使用线程来接收串口数据的示例
2019/07/02 Python
python Protobuf定义消息类型知识点讲解
2021/03/02 Python
使用css3背景渐变中的透明度来设置不同颜色的背景渐变
2014/03/31 HTML / CSS
Crocs波兰官方商店:女鞋、男鞋、童鞋、洞洞鞋
2019/10/08 全球购物
Solaris操作系统的线程机制
2015/07/28 面试题
甜点店创业计划书
2014/01/27 职场文书
装饰活动策划方案
2014/02/11 职场文书
2014年社区学雷锋活动总结
2014/03/09 职场文书
Java实现多文件上传功能
2021/06/30 Java/Android
MYSQL 表的全面总结
2021/11/11 MySQL
vue-cil之axios的二次封装与proxy反向代理使用说明
2022/04/07 Vue.js