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 相关文章推荐
商城常用滚动的焦点图效果代码简单实用
Mar 28 Javascript
javascript计算用户打开网页的停留时间
Jan 09 Javascript
javascript内置对象操作详解
Feb 04 Javascript
JavaScript使表单中的内容显示在屏幕上的方法
Jun 29 Javascript
Bootstrap编写一个兼容主流浏览器的受众巨幕式风格页面
Jul 01 Javascript
js中遍历对象的属性和值的方法
Jul 27 Javascript
详解AngularJS如何实现跨域请求
Aug 22 Javascript
解决URL地址中的中文乱码问题的办法
Feb 10 Javascript
JavaScript实现的数字与字符串转换功能示例
Aug 23 Javascript
web前端开发中常见的多列布局解决方案整理(一定要看)
Oct 15 Javascript
jQuery中可见性过滤器简单用法示例
Mar 31 jQuery
JavaScript实现与使用发布/订阅模式详解
Jan 19 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 date函数参数详解
2006/11/27 PHP
用PHP提取中英文词语以及数字的首字母的方法介绍
2013/04/23 PHP
php导出CSV抽象类实例
2014/09/24 PHP
php关闭warning问题的解决方法
2016/05/17 PHP
锋利的jQuery 要点归纳(二) jQuery中的DOM操作(下)
2010/03/23 Javascript
关于COOKIE个数与大小的问题
2011/01/17 Javascript
JSF中confirm弹出框的用法示例介绍
2014/01/07 Javascript
jQuery 如何给Carousel插件添加新的功能
2016/04/18 Javascript
javascript如何定义对象数组
2016/06/07 Javascript
基于JS实现发送短信验证码后的倒计时功能(无视页面刷新,页面关闭不进行倒计时功能)
2016/09/02 Javascript
jquery 正整数数字校验正则表达式
2017/01/10 Javascript
基于nodejs+express4.X实现文件下载的实例代码
2017/07/13 NodeJs
基于vue-cli vue-router搭建底部导航栏移动前端项目
2018/02/28 Javascript
vue实现前台列表数据过滤搜索、分页效果
2019/05/28 Javascript
一文读懂vue动态属性数据绑定(v-bind指令)
2020/07/20 Javascript
[06:44]2018DOTA2亚洲邀请赛4.5 SOLO赛 MidOne vs Sumail
2018/04/06 DOTA
Flask SQLAlchemy一对一,一对多的使用方法实践
2013/02/10 Python
Django集成百度富文本编辑器uEditor攻略
2014/07/04 Python
Pycharm 设置自定义背景颜色的图文教程
2018/05/23 Python
Python给定一个句子倒序输出单词以及字母的方法
2018/12/20 Python
python通过tcp发送xml报文的方法
2018/12/28 Python
详解Python读取yaml文件多层菜单
2019/03/23 Python
Python实现二叉树的最小深度的两种方法
2019/09/30 Python
Python统计时间内的并发数代码实例
2019/12/28 Python
Python3 全自动更新已安装的模块实现
2020/01/06 Python
Python中BeautifulSoup通过查找Id获取元素信息
2020/12/07 Python
哄娃神器4moms商店:美国婴童用品品牌
2019/03/07 全球购物
瑞士男士时尚网上商店:Babista
2020/05/14 全球购物
优秀医生事迹材料
2014/02/12 职场文书
家长会标语
2014/06/24 职场文书
2014年部门工作总结
2014/11/12 职场文书
2014年幼儿园保育工作总结
2014/12/02 职场文书
党风廉政建设个人总结
2015/03/06 职场文书
2016年幼儿园教师政治学习心得体会
2016/01/23 职场文书
2016优秀毕业生个人事迹材料
2016/02/29 职场文书
2019入党申请书格式
2019/06/25 职场文书