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 在线压缩和格式化收藏
Jan 16 Javascript
jquery插件之easing 动态菜单
Aug 21 Javascript
javascript中的this详解
Dec 08 Javascript
JS上传图片前实现图片预览效果的方法
Mar 02 Javascript
Spring mvc 接收json对象
Dec 10 Javascript
js学习阶段总结(必看篇)
Jun 16 Javascript
纯JS前端实现分页代码
Jun 21 Javascript
javascript 定时器工作原理分析
Dec 03 Javascript
浅谈jQuery操作类数组的工具方法
Dec 23 Javascript
React实现全局组件的Toast轻提示效果
Sep 21 Javascript
详解用vue2.x版本+adminLTE开源框架搭建后台应用模版
Mar 15 Javascript
vue自动化路由的实现代码
Sep 30 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
PHP自动更新新闻DIY
2006/10/09 PHP
BBS(php &amp; mysql)完整版(五)
2006/10/09 PHP
判“新”函数:得到今天与明天的秒数
2006/10/09 PHP
PHP 和 MySQL 开发的 8 个技巧
2007/01/02 PHP
php将mysql数据库整库导出生成sql文件的具体实现
2014/01/08 PHP
php实现的三个常用加密解密功能函数示例
2017/11/06 PHP
javascript 全选与全取消功能的实现代码
2012/12/23 Javascript
js函数中onmousedown和onclick的区别和联系探讨
2013/05/19 Javascript
JavaScript的作用域和块级作用域概念理解
2014/09/21 Javascript
js实现点击向下展开的下拉菜单效果代码
2015/09/01 Javascript
用JavaScript来美化HTML的select标签的下拉列表效果
2015/11/17 Javascript
jQuery EasyUI 菜单与按钮之创建简单的菜单和链接按钮
2015/11/18 Javascript
jQuery获取多种input值的简单实现方法
2016/06/20 Javascript
JS闭包与延迟求值用法示例
2016/12/22 Javascript
微信小程序 参数传递实例代码
2017/03/20 Javascript
js移动端图片压缩上传功能
2020/08/18 Javascript
Vue中使用webpack别名的方法实例详解
2018/06/19 Javascript
详解easyui 切换主题皮肤
2019/04/04 Javascript
[25:59]Newbee vs TNC 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python轻松查到删除自己的微信好友
2016/01/10 Python
zookeeper python接口实例详解
2018/01/18 Python
python 遍历列表提取下标和值的实例
2018/12/25 Python
使用Django简单编写一个XSS平台的方法步骤
2019/03/25 Python
windows环境中利用celery实现简单任务队列过程解析
2019/11/29 Python
Python 使用 prettytable 库打印表格美化输出功能
2019/12/26 Python
Python argparse模块使用方法解析
2020/02/20 Python
Python-jenkins 获取job构建信息方式
2020/05/12 Python
python 负数取模运算实例
2020/06/03 Python
Giglio德国网上精品店:奢侈品服装和配件
2016/09/23 全球购物
5.1手机促销活动
2014/01/17 职场文书
《小猫刮胡子》教学反思
2014/02/21 职场文书
技术负责人岗位职责
2015/02/10 职场文书
催款函范本大全
2015/06/24 职场文书
2015年计算机教学工作总结
2015/07/22 职场文书
MySQL约束(创建表时的各种条件说明)
2022/06/21 MySQL
Python通用验证码识别OCR库ddddocr的安装使用教程
2022/07/07 Python