bootstrap图片剪裁预览上传

Posted ntotl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bootstrap图片剪裁预览上传相关的知识,希望对你有一定的参考价值。

效果图预览:


用到的图片剪裁插件:http://www.htmleaf.com/jQuery/Image-Effects/201504211716.html

前段ui框架:bootstrap3

java后端框架:spring + mybstis

说明:如果前端ui用的不是bootstrap的框架,则调过第一步,直接将第二步的页面地址作为弹出框的地址即可,然后在做修改

1.首先说一下bootstrap的模态框:

一般的打开模态框要在页面上隐藏一段html代码然后用$("#Id").modal('show')显示模态框或者$("#Id").modal('hide')隐藏模态框,本人觉得有点麻烦,没有easyui这样的直接用js代码打开方便 ,所以我对这个模态框进行了封装。来实现直接用js打开的效果。原理很简单就是应以自定义一个jquery的方法,传递一些设置的参数,然后js动态生成html代码然后将代码追加到页面的body后面,然后在调用$("#Id").modal('show')方法来打开模态框。模态框里面的内容是动态的 所以就需要一个url地址加载页面的内容。下面来看js代码

bootstrap-utils.js

jQuery.extend({
    //模态弹出框
    openModel:function(options){
         var defaults={//设置默认参数
                title:'',//模态框的标题
                width:'100%',//模态框的默认宽度
                height:$(window).height()-130+"px",//模态框的默认高度,默认取浏览器的可视高度
                showOkButton:true,//是否显示确定按钮
                id:"model_js",//模态框id
                frameId:"modal_iframe",//iframeId
                okButtonContent:"确定",//确定按钮显示的内容
                cancelButtonContent:"关闭"//取消按钮显示的内容
         }
         var opts = $.extend(defaults,options);
         var str = "";
         str+="<div class='modal fade' id='"+opts.id+"' tabindex='-1' role='basic' aria-hidden='true'>";
         str+="    <div class='modal-dialog'>";
         str+="        <div class='modal-content'>";
         if(opts.title != ""){
             str+="        <div class='modal-header' style='height:30px;'>";
             str+="            <button type='button' class='close' data-dismiss='modal' aria-hidden='true' style='margin-top:-10px;'>x</button>";
             str+="            <h3 class='modal-title' style='margin-top:-10px;'><b>"+opts.title+"</b></h3>";
             str+="        </div>";
         }
         str+="            <div class='modal-body' style='padding:0px;'>";
         str+="            </div>";
         str+="            <div class='modal-footer' style='height:35px;padding:0px;'>";
         if(opts.showOkButton){
             str+="                <button type='button' class='btn btn-primary  btn-sm' οnclick='"+opts.ok+"();'>"+opts.okButtonContent+"</button>";
         }
         str+="                <button type='button' class='btn btn-default  btn-sm' data-dismiss='modal'>"+opts.cancelButtonContent+"</button>";
         str+="            </div>";
         str+="        </div>";
         str+="    </div>";
         str+="</div>";

        //如果当前页面不选在当前id的模态框才追加模态框html

         if($("body").find("#"+opts.id+"").length == 0){
             $("body").append(str);
         }else{
             $("body").find("#"+opts.id+"").remove();
             $("body").append(str);
         }

         //如果参数传递的宽度或者高度不是px格式的则加上px

         var height = (opts.height+"").indexOf("px") >= 0 ? opts.height : opts.height+"px";
         var width = (opts.width+"").indexOf("px") >= 0 || (opts.width+"").indexOf("%") >= 0 ? opts.width : opts.width+"px";

         //设置页面iframe的地址

         $("#"+opts.id+"").find(".modal-body").html("<iframe name='"+opts.frameId+"' style='width:99%;height:"+height+";border:0px;' scrolling='yes' src='"+opts.url+"'></iframe>");
         $("#"+opts.id+"").find(".modal-dialog").css({"width":width,"height":height});

         //显示模态框

         $("#"+opts.id+"").modal("show");
    }
});


下面来看调用方式:

$.openModel({
    url:'editPhoto.jsp',
    frameId:'bLogoFrame',
    id:'bLogoModel',
    width:900,
    ok:'getCropData'//点击确定按钮执行的函数
});

2.下面来看editPhoto.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
    request.setAttribute("ctx", request.getContextPath());
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<!-- 引入剪裁插件的css-->

<link rel="stylesheet" type="text/css" href="${ctx}/business/js/crop/css/normalize.css" />
<link rel="stylesheet" type="text/css" href="${ctx}/business/js/crop/css/default.css">

<link href="${ctx }/business/js/crop/assets/css/bootstrap.min.css" rel="stylesheet">
<link href="${ctx }/business/js/crop/dist/cropper.css" rel="stylesheet">
<link href="${ctx }/business/js/crop/css/main.css" rel="stylesheet">
<!--[if IE]>
    <script src="http://libs.useso.com/js/html5shiv/3.7/html5shiv.min.js"></script>
<![endif]-->
<style type="text/css">
td{vertical-align:top;padding-left:10px;}
.div_photo{
    position:absolute;
    width:150px;
    height:150px;
    border-radius:100px;
}
</style>

<!-- 引入剪裁插件的js-->

<script src="${ctx }/business/js/crop/assets/js/jquery.min.js"></script>
<script src="${ctx }/business/js/crop/assets/css/bootstrap.min.css"></script>
<script src="${ctx }/business/js/crop/dist/cropper.js"></script>
<script src="${ctx }/business/js/crop/js/main.js"></script>
<script type="text/javascript">
var data;

function getData(){
    var result= $('#cropper-img').cropper("getCroppedCanvas");
    data=result.toDataURL('image/jpeg',1);//获取剪裁的图片并且转为base64格式
    $("#data").val(data);//将剪裁后的base64代码保存的隐藏域中

    $("#isValidate").val(1);//设置是否校验通过

}


</script>
</head>
<body οnlοad="javascript:$('#cropper-img').cropper('setAspectRatio',1);"><!-- 初始化剪裁你插件的剪裁比例为1:1,如需要其他的查看文档修改-->
  <input style="display:none;" id="getData" οnclick="getData();" type="button" value="确定"/>
  <input id="isValidate" type="hidden" value="0"/>
  <input id="picName" type="hidden" value=""/>
  <input id="data" type="hidden" value=""/>
  <table style="margin-top:20px;">
      <tr style="height:200px;">
          <td rowspan="3">
              <div class="img-container" style="width:630px;height:400px;margin-left:0px;">

                  <!-- 传递到这个页面的url不为空则显示要编辑的图片,否则显示默认的图片-->

                  <c:choose>
                      <c:when test="${url != null and url !='' }">
                      <img id="cropper-img" src="${url }">
                      </c:when>
                      <c:otherwise>
                      <img id="cropper-img" src="${ctx }/res/img/upimg.jpg">
                      </c:otherwise>
                  </c:choose>
              </div>
          </td>
          <td>
              <div class="docs-preview clearfix">
              <div class="img-preview preview-lg"></div>
            </div>
              <div class="docs-preview clearfix">
              <div class="img-preview preview-lg div_photo"></div>
            </div>
          </td>
      </tr>
      <tr style="height:20px;">
          <td>
              <div class="btn-group">
              <label class="btn btn-primary btn-upload" style="border:0px;background-color:red;" for="inputImage" title="Upload image file">
                <input class="sr-only" id="inputImage" name="file" type="file" accept="image/*">
                <span class="docs-tooltip pull-left" data-toggle="tooltip" title="选择文件">
                  <span class="icon icon-upload"></span>
                </span>
                <span class="pull-right">&nbsp;选择图片</span>
              </label>
            </div>
          </td>
      </tr>
      <tr style="height:20px;">
          <td>
              <div class="btn-group">
              <button class="btn btn-primary" data-method="setDragMode" data-option="move" type="button" title="移动">
                <span class="docs-tooltip" data-toggle="tooltip" title="$().cropper(&quot;setDragMode&quot;, &quot;move&quot;)">
                  <span class="icon icon-move"></span>
                </span>
              </button>
              <button class="btn btn-primary" data-method="setDragMode" data-option="crop" type="button" title="裁剪">
                <span class="docs-tooltip" data-toggle="tooltip" title="$().cropper(&quot;setDragMode&quot;, &quot;crop&quot;)">
                  <span class="icon icon-crop"></span>
                </span>
              </button>
              <button class="btn btn-primary" data-method="zoom" data-option="0.1" type="button" title="放大">
                <span class="docs-tooltip" data-toggle="tooltip" title="$().cropper(&quot;zoom&quot;, 0.1)">
                  <span class="icon icon-zoom-in"></span>
                </span>
              </button>
              <button class="btn btn-primary" data-method="zoom" data-option="-0.1" type="button" title="缩小">
                <span class="docs-tooltip" data-toggle="tooltip" title="$().cropper(&quot;zoom&quot;, -0.1)">
                  <span class="icon icon-zoom-out"></span>
                </span>
              </button>
              <button class="btn btn-primary" data-method="rotate" data-option="-45" type="button" title="向左旋转">
                <span class="docs-tooltip" data-toggle="tooltip" title="$().cropper(&quot;rotate&quot;, -45)">
                  <span class="icon icon-rotate-left"></span>
                </span>
              </button>
              <button class="btn btn-primary" data-method="rotate" data-option="45" type="button" title="向右旋转">
                <span class="docs-tooltip" data-toggle="tooltip" title="$().cropper(&quot;rotate&quot;, 45)">
                  <span class="icon icon-rotate-right"></span>
                </span>
              </button>
            </div>
          </td>
      </tr>
  </table>
</body>
</html>


说明:如果前端ui用的不是bootstrap,那么为了避免样式的冲突 可以用iframe的方式

例如:<a href="editPhotoInit.jsp">编辑头像</a>

editPhotoInit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
String serviceId = request.getParameter("serviceId");
%>
<iframe src="<%=path %>/editPhoto.jsp?serviceId=<%=serviceId %>" style="width:99%;height:100%;border:0px;overflow:hidden;"></iframe>

然后在用第三步的方法取iframe对象里的属性

3.点击确定按钮的时候在页面上显示剪裁后的图片

第一步中我们讲到打开模态框的方式为:

$.openModel({
    url:'editPhoto.jsp',
    frameId:'bLogoFrame',
    id:'bLogoModel',
    width:900,
    ok:'getCropData'//点击确定按钮执行的函数
});

点击ok按钮后执行的函数

function getCropData(){
            var obj = $(window.frames["bLogoFrame"].document);//获取当前模态框内容的iframe对象,id即为上面设置的iframeId.
            obj.find("#getData").click();//因为不能直接获取子页面的方法和属性,所以就用间接的点击按钮或者链接的方法,然后再获取隐藏域的内容,方法有点笨 ,有好的方法可以修改
            var isValidate = obj.find("#isValidate").val();//校验图片大小及尺寸,1.为校验通过,0.为不通过
            if(isValidate == 1){
                var data = obj.find("#data").val();//获取剪裁后的base64图片
                $("#logo").attr("src",data);//直接将剪裁后的base64图片显示在img控件中
                var pos = data.indexOf("4")+2;
                data = data.substring(pos, data.length - pos);//去掉Base64:开头的标识字符
                $("#pic").val(data);//设置项后台提交的隐藏域的值,去掉base64开头的标示字符后的值

                //设置表单中图片为校验通过

                if(data != null && data != ""){
                    $("#addBusinessForm").bootstrapValidator('updateStatus', 'pic', 'VALID');
                }
                $("#bLogoModel").modal('hide');//关闭模态框
            }
 }


如果用封装的方法打开模态框,获取模态框的值都需要这样取(获取iframe对象,然后在获取 iframe对象中的元素,属性或者方法只能用间接的方法取),但是我觉得还是比在页面中直接写模态框的代码还是简单可许多呢。

4.上传图片

在第三不我们已经把剪裁后的base64的并且去掉了头部的标示信息的数据已经放到隐藏域中了,需要注意的是,base64的图片格式的数据一般来说都比较大,一般的post传递按理说是不受长度限制的,但是有时候后还是会出现问题,后台取不到值为null的情况,所以我们采用

formData+ajax的方式进行表单提交,下面来看代码

为提交表单的按钮绑定事件

$("#submitForm").click(function(){
     var $form = $("#myForm");//获取当前form对象
     var bv = $form.data('bootstrapValidator');//获取bootstrap表单校验对象
     var formData = new FormData($form[0]);//转换成formData对象

     //可以为formData添加数据,例如 :formData.append("file", $("#file_upload")[0].files[0]);

     bv.validate();//校验表单

    if(bv.isValid()){
                  $(obj).addClass('disabled');//置提交按钮为不可用,防止多次点击
                  $.ajax({  
                      url : $form.attr('action'),  //获取form表单的提交地址
                      type : 'POST',  
                      async: false,
                      data : formData,
                      /**   
                       * 必须false才会避开jQuery对 formdata 的默认处理   
                       * XMLHttpRequest会对 formdata 进行正确的处理
                       */  
                      processData : false,  
                      /**   
                       *必须false才会自动加上正确的Content-Type   
                       */  
                      contentType : false,  
                      success : function(data) {
                          var id = data.id;
                          var opType = data.opType;//操作类型,1.编辑,0.添加
                          if(data.result == "1"){
                                 alert("提交成功");
                          }else{
                                alert(data.message);//显示错误信息
                                $(obj).removeClass('disabled');
                          }
                      },error:function(){
                            alert("网络异常,请重试!");
                                $(obj).removeClass('disabled');
                      }
                  });
     }else{
                  alert("表单数据不完整!");
     }

});

后端代码,上传到七牛(与阿里云类似),如果上传到本地请查看第五步:

//获取上传到七牛的图片地址

String fileBusLogoPath = new QiniuUpload().base64Upload(‘前段传过来的base64格式’, ‘upload/photo/logo’);

说明:upload/photo/logo为logo上传地址,可以配置到属性配置文件中

比如:

systemConfig.properties

#七牛访问地址
qiniuUrl:http://7xsrph.com2.z0.glb.qiniucdn.com
#文件上传根目录
base_path:D:/image/
#商家logo上传地址
logo_path:upload/logo/
#商家二维码大小
qrcode_size:1000

怎么获取属性配置文件的值呢,这个需要在框架启动的时候把属性配置文件的值读取到java对象中,在spring配置文件的配置加如下代码:

spring.xml

    <!--     加载系统配置文件 -->

    <bean id="configBean"  class="com.util.CustomizedPropertyConfigurer">
        <property name="locations">
            <list>
                <value>classpath:systemConfig.properties</value>
            </list>
        </property>

    </bean>


CustomizedPropertyConfigurer.java

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

public class CustomizedPropertyConfigurer extends PropertyPlaceholderConfigurer {  
      
    private static Map<String, Object> ctxPropertiesMap;  
 
    @Override  
    protected void processProperties(ConfigurableListableBeanFactory beanFactory,  
            Properties props)throws BeansException {  
 
        super.processProperties(beanFactory, props);  
        //load properties to ctxPropertiesMap  
        ctxPropertiesMap = new HashMap<String, Object>();  
        for (Object key : props.keySet()) {  
            String keyStr = key.toString();  
            String value = props.getProperty(keyStr);  
            ctxPropertiesMap.put(keyStr, value);  
        }  
    }  
 
    //static method for accessing context properties  
    public static Object getContextProperty(String name) {  
        return ctxPropertiesMap.get(name);  
    }  
    
}


这样就可以通过CustomizedPropertyConfigurer类来获取属性配置文件的值

上传代码可以改为:

//获取logo上传路径

String logoPath = (String)CustomizedPropertyConfigurer.getContextProperty("logo_path");

String fileBusLogoPath = new QiniuUpload().base64Upload(‘前段传过来的base64格式’,logoPath);

然后将 fileBusLogoPath这个地址更新到数据库字段中,数据库保存的字段格式为:upload/logo/201605231403202561.jpg

显示给页面要拼接上七牛的访问地址:

图片完整的路径为:

String qiniuUrl = (String)CustomizedPropertyConfigurer.getContextProperty("qiniuUrl");

String logUrl = qiniuUrl+"/"+fileBusLogoPath;//图片完整路径

七牛上传工具类:QiniuUpload.java

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import javax.imageio.ImageIO;

import sun.misc.BASE64Decoder;

import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;

public class QiniuUpload {
    private final String accessKey = "";
    private final String secretKey = "";
    private final String bucketname = "test";
    private final String qiniuUrl = "http://7xsrph.com2.z0.glb.qiniucdn.com";//七牛地址
    //密钥配置
    Auth auth = Auth.create(accessKey, secretKey);
    //创建上传对象
    UploadManager uploadManager = new UploadManager();

    //简单上传,使用默认策略,只需要设置上传的空间名就可以了
    public String getUpToken(){
        return auth.uploadToken(bucketname);
    }
    /**
     * 字节流上传
     * @param bytes
     * @param filePath
     * @return
     * @throws IOException
     */
    public String upload(byte[] bytes,String filePath) throws IOException{
        try {
            
            String fileName = filePath+getFileName();
            //调用put方法上传
            Response res = uploadManager.put(bytes, fileName, getUpToken());
            return fileName;
          } catch (QiniuException e) {
              Response r = e.response;
              // 请求失败时打印的异常的信息
              System.out.println(r.toString());
              try {
                  //响应的文本信息
                  System.out.println(r.bodyString());
              } catch (QiniuException e1) {
                  //ignore
              }
          }
        return null;       
    }
    /**
     * base64格式图片上传
     * @param base64
     * @param filePath
     * @return
     * @throws IOException
     */
    public String base64Upload(String base64,String filePath) throws IOException{
        try {
            BASE64Decoder decoder = new BASE64Decoder();
            // Base64解码
            byte[] bytes = decoder.decodeBuffer(base64);
            for (int i = 0; i < bytes.length; ++i) {
                if (bytes[i] < 0) {// 调整异常数据
                    bytes[i] += 256;
                }
            }
            String fileName = filePath+getFileName();
            //调用put方法上传
            Response res = uploadManager.put(bytes, fileName, getUpToken());
            return fileName;
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            System.out.println(r.toString());
            try {
                //响应的文本信息
                System.out.println(r.bodyString());
            } catch (QiniuException e1) {
                //ignore
            }
        }
        return null;       
    }
    /**
     * 创建待logo的二维码
     * @param filePath
     * @param text
     * @return
     * @throws IOException
     */
    public String createQrcode(String filePath,String text) throws IOException{
        try {
//            fileBusLogoPath.replace(".", "_qrCode.")
            URL url = new URL(qiniuUrl+"/"+filePath);
//            URLConnection conn = url.openConnection();
//            urlcon.connect();         //获取连接
            
            BufferedImage bufferedImg = ImageIO.read(url);
            int width = bufferedImg.getWidth();
            
            String fileName = filePath.replace(".", "_qrCode.");
            BufferedImage bi = null;
            BufferedImage logo = null;
            
            logo = ImageUtils.resizeImage1(bufferedImg,100, 0.9f, true);
            bi = QrCodeUtil.createQrCode(logo,text,width,width);
            
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(bi, "jpg", os);
            //调用put方法上传
            Response res = uploadManager.put(os.toByteArray(),fileName, getUpToken());
            System.out.println(res.toString());
            return fileName;
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            System.out.println(r.toString());
            try {
                //响应的文本信息
                System.out.println(r.bodyString());
            } catch (QiniuException e1) {
                //ignore
            }
        }
        return null;       
    }
    /**
     * 获取时间格式的文件名称
     * @return
     */
    private String getFileName(){
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        String now = df.format(new Date());
        //生成五位随机数字
        Random random = new Random();  
        int rannum = (int) (random.nextDouble() * (99999 - 10000 + 1)) + 10000;// 获取5位随机数  
        String fileName = now+rannum+".jpg";
        return fileName;
    }
    /**
     * 文件转byte[]
     * @param filePath
     * @return
     */
    public static byte[] File2byte(String filePath)  
    {  
        byte[] buffer = null;  
        try  
        {  
            File file = new File(filePath);  
            FileInputStream fis = new FileInputStream(file);  
            ByteArrayOutputStream bos = new ByteArrayOutputStream();  
            byte[] b = new byte[1024];  
            int n;  
            while ((n = fis.read(b)) != -1)  
            {  
                bos.write(b, 0, n);  
            }  
            fis.close();  
            bos.close();  
            buffer = bos.toByteArray();  
        }  
        catch (FileNotFoundException e)  
        {  
            e.printStackTrace();  
        }  
        catch (IOException e)  
        {  
            e.printStackTrace();  
        }  
        return buffer;  
    }  
     public static void main(String args[]) throws IOException{
        URL url = new URL("http://imgz.we-going.com/service/1453884689193.jpg");
        BufferedImage bufferedImg = ImageIO.read(url);
        int width = bufferedImg.getWidth();
//        new QiniuUpload().upload(File2byte("D:/image/upload/photo/business/2016/4/2016040923532026335.jpg"),"");
//        new QiniuUpload().createQrcode("D:/image/upload/photo/business/2016/4/2016040923532026335.jpg","http://www.baidu.com");
     }

}

二维码工具类:QrCodeUtil.java

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * 二维生成工具类,返回图片流或生成文件
 * @author ZYL
 *
 */
public class QrCodeUtil {
    public static void main(String[] args) throws WriterException
    {
        String content = "766EBCD59621E305170616BA3D3DAC32";
        String filePath = "D:/qrCode.jpg";
        BufferedImage logo = null;
        try
        {
            File file=new File("D://logo.png");
            InputStream is=new FileInputStream(file);
            logo = ImageIO.read(is);
            
//            String path= "http://112.126.83.175/laiqu/head/20150612/SERVICE_HEAD_PHOTO_576_20150612123514641.png";
//            URL url = new URL(path);           
//            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//          logo = ImageIO.read(conn.getInputStream());
            logo = ImageUtils.resizeImage1(logo,80, 0.9f, true);
            createQrCode(logo,content,500,500,filePath);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    public static void createQrCode(BufferedImage logo,String content,int width,int height,String filePath){
        try {
            if(width == 0){width = 500;}
            if(height == 0){height = 500;}
            QrCodeUtil zp = new QrCodeUtil();
            BufferedImage bi = null;
            BufferedImage bim = zp.Encode_QR_CODE(content, BarcodeFormat.QR_CODE, width, height, zp.getDecodeHintType());
            if(logo != null){
                bi =  zp.LogoMatrix(bim, logo);
            }else{
                bi = bim;
            }
           ImageIO.write(bi, "jpeg", new File(filePath));
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
    public static BufferedImage createQrCode(BufferedImage logo,String content,int width,int height){
        try {
            if(width == 0){width = 500;}
            if(height == 0){height = 500;}
            QrCodeUtil zp = new QrCodeUtil();
            BufferedImage bi = null;
            BufferedImage bim = zp.Encode_QR_CODE(content, BarcodeFormat.QR_CODE, width, height, zp.getDecodeHintType());
            if(logo != null){
                bi =  zp.LogoMatrix(bim, logo);
                
            }else{
                return bim;
            }
//            parseQR_CODEImage(bi);
            return bi;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 设置 logo
     * @param matrixImage 源二维码图片
     * @return 返回带有logo的二维码图片
     * @throws IOException
     */
     public BufferedImage LogoMatrix(BufferedImage matrixImage,BufferedImage logo_) throws IOException{
         /**
          * 读取二维码图片,并构建绘图对象
          */
         Graphics2D g2 = matrixImage.createGraphics();
        
         int matrixWidth = matrixImage.getWidth();
         int matrixHeigh = matrixImage.getHeight();
        
         /**
          * 读取Logo图片
          */
         BufferedImage logo = logo_;

         //开始绘制图片
         g2.drawImage(logo,matrixWidth/5*2,matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5, null);//绘制     
         BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
         g2.setStroke(stroke);// 设置笔画对象
         //指定弧度的圆角矩形
         RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth/5*2, matrixHeigh/5*2, matrixWidth/5, matrixHeigh/5,20,20);
         g2.setColor(Color.white);
         g2.draw(round);// 绘制圆弧矩形
         
         g2.dispose();
         matrixImage.flush() ;
         return matrixImage ;
     }
     
    /**
     * 生成二维码bufferedImage图片
     *
     * @param content
     *            编码内容
     * @param barcodeFormat
     *            编码类型
     * @param width
     *            图片宽度
     * @param height
     *            图片高度
     * @param hints
     *            设置参数
     * @return
     */
    public BufferedImage Encode_QR_CODE(String content, BarcodeFormat barcodeFormat, int width, int height, Map<EncodeHintType, ?> hints)
    {
        MultiFormatWriter multiFormatWriter = null;
        BitMatrix bm = null;
        BufferedImage image = null;
        try
        {
            multiFormatWriter = new MultiFormatWriter();
 
            // 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
            bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints);
 
            int w = bm.getWidth();
            int h = bm.getHeight();
            image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
 
            // 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色
            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    image.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }
        }
        catch (WriterException e)
        {
            e.printStackTrace();
        }
        return image;
    }
 
    /**
     * 设置二维码的格式参数
     *
     * @return
     */
    public Map<EncodeHintType, Object> getDecodeHintType()
    {
        // 用于设置QR二维码参数
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        // 设置QR二维码的纠错级别(H为最高级别)具体级别信息
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 设置编码方式
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//        hints.put(EncodeHintType.MAX_SIZE, 350);
//        hints.put(EncodeHintType.MIN_SIZE, 100);
        hints.put(EncodeHintType.MARGIN, 0);//设置二维码边的空度,非负数
 
        return hints;
    }
}


图片处理工具类:ImageUtils.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * @作者 王建明
 * @创建日期 2012-6-16
 * @创建时间 下午02:35:31
 * @版本号 V 1.0
 */  
public class ImageUtils {  
    public String path = "";
 
    public ImageUtils(String path) {
        this.path = path;  
    }  
 
    public void change(int size) {  
        compressImg(new File(path), size, null);
    }  
 
    /**
     * @param oldfile
     * @param size
     * @param newfile
     * @return
     * @描述 —— 将oldfile的图片文件等比例压缩为size的newfile文件
     */  
    public static File compressImg(File oldfile, int size, File newfile) {
        if(!newfile.exists())  
            try {  
                newfile.createNewFile();  
            } catch (IOException e1) {
                // TODO Auto-generated catch block  
                //e1.printStackTrace();  
                System.out.println("无法创建文件!!!");
                return null;  
            }  
        BufferedImage bi;
        try {  
            System.out.println("正在压缩:" + oldfile.getName());
            bi = ImageIO.read(new FileInputStream(oldfile));
            int width = bi.getWidth();  
            int height = bi.getHeight();  
            if (width > size || height > size) {  
                Image image;
                if (width > height) {  
                    height = (int) (bi.getHeight() / (bi.getWidth() * 1d) * size);  
                    image = bi.getScaledInstance(size, height,  
                            Image.SCALE_DEFAULT);
                } else {  
                    width = (int) (bi.getWidth() / (bi.getHeight() * 1d) * size);  
                    image = bi.getScaledInstance(width, size,  
                            Image.SCALE_DEFAULT);
                }  
                ImageIO.write(toBufferedImage(image), "jpg",
                        new FileOutputStream(newfile));
                System.out.println("压缩完成:" + newfile.getName());
                return newfile;  
            } else {  
                System.out.println("无须压缩:" + oldfile.getName());
                return oldfile;  
            }  
        } catch (Exception e) {
            e.printStackTrace();  
        }  
        return null;  
    }  
 
    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }  
        image = new ImageIcon(image).getImage();
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();  
        try {  
            int transparency = Transparency.TRANSLUCENT;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null), image  
                    .getHeight(null), transparency);  
        } catch (HeadlessException e) {
        }  
        if (bimage == null) {  
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image
                    .getHeight(null), type);  
        }  
        Graphics g = bimage.createGraphics();
        g.drawImage(image, 0, 0, null);  
        g.dispose();  
        return bimage;  
    }  
 
    /**
     * @return
     * @描述 —— 生成随机名字,不可能重复(用于文件的命名)
     */  
    public static String getRandomName() {
        Random r = new Random();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmssSSS");
        StringBuffer sb = new StringBuffer();
        sb.append(r.nextInt(100));  
        sb.append(r.nextInt(100));  
        sb.append("_");  
        sb.append(sdf.format(new Date()));
        sb.append("_");  
        sb.append(r.nextInt(100));  
        sb.append(r.nextInt(100));  
        return sb.toString();  
    }  
 
    /**
     * @param inputFile源文件
     * @param outFile生成文件
     * @param width指定宽度
     * @param height指定高度
     * @param proportion是否等比例操作
     * @return
     * @描述 —— 是否等比例缩放图片
     */  
    public static boolean compressPic(String inputFile, String outFile,
                                      int width, int height, boolean proportion) {
        try {  
            // 获得源文件  
            File file = new File(inputFile);
            if (!file.exists()) {  
                return false;  
            }  
            Image img = ImageIO.read(file);
            // 判断图片格式是否正确  
            if (img.getWidth(null) == -1) {  
                return false;  
            } else {  
                int newWidth;  
                int newHeight;  
                // 判断是否是等比缩放  
                if (proportion == true) {  
                    // 为等比缩放计算输出的图片宽度及高度  
                    double rate1 = ((double) img.getWidth(null))  
                            / (double) width + 0.1;  
                    double rate2 = ((double) img.getHeight(null))  
                            / (double) height + 0.1;  
                    // 根据缩放比率大的进行缩放控制  
                    double rate = rate1 > rate2 ? rate1 : rate2;  
                    newWidth = (int) (((double) img.getWidth(null)) / rate);  
                    newHeight = (int) (((double) img.getHeight(null)) / rate);  
                } else {  
                    newWidth = width; // 输出的图片宽度  
                    newHeight = height; // 输出的图片高度  
                }  
 
                // 如果图片小于目标图片的宽和高则不进行转换  
                /*
                 * if (img.getWidth(null) < width && img.getHeight(null) <
                 * height) { newWidth = img.getWidth(null); newHeight =
                 * img.getHeight(null); }
                 */  
                BufferedImage tag = new BufferedImage((int) newWidth,
                        (int) newHeight, BufferedImage.TYPE_INT_RGB);
 
                // Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的,优先级比速度高 生成的图片质量比较好 但速度慢  
                tag.getGraphics().drawImage(  
                        img.getScaledInstance(newWidth, newHeight,  
                                Image.SCALE_SMOOTH), 0, 0, null);
                FileOutputStream out = new FileOutputStream(outFile);
                // JPEGImageEncoder可适用于其他图片类型的转换  
                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
                encoder.encode(tag);  
                out.close();  
            }  
        } catch (IOException ex) {
            ex.printStackTrace();  
        }  
        return true;  
    }  
 
    /**
     * @param srcFile源文件
     * @param outFile输出文件
     * @param x坐标
     * @param y坐标
     * @param width宽度
     * @param height高度
     * @return
     * @描述 —— 裁剪图片
     */  
    public static boolean cutPic(String srcFile, String outFile, int x, int y,
                                 int width, int height) {
        FileInputStream is = null;
        ImageInputStream iis = null;
        try {  
            // 如果源图片不存在  
            if (!new File(srcFile).exists()) {
                return false;  
            }  
 
            // 读取图片文件  
            is = new FileInputStream(srcFile);
 
            // 获取文件格式  
            String ext = srcFile.substring(srcFile.lastIndexOf(".") + 1);
 
            // ImageReader声称能够解码指定格式  
            Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(ext);
            ImageReader reader = it.next();
 
            // 获取图片流  
            iis = ImageIO.createImageInputStream(is);
 
            // 输入源中的图像将只按顺序读取  
            reader.setInput(iis, true);  
 
            // 描述如何对流进行解码  
            ImageReadParam param = reader.getDefaultReadParam();
 
            // 图片裁剪区域  
            Rectangle rect = new Rectangle(x, y, width, height);
 
            // 提供一个 BufferedImage,将其用作解码像素数据的目标  
            param.setSourceRegion(rect);  
 
            // 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象  
            BufferedImage bi = reader.read(0, param);
 
            // 保存新图片  
            File tempOutFile = new File(outFile);
            if (!tempOutFile.exists()) {  
                tempOutFile.mkdirs();  
            }  
            ImageIO.write(bi, ext, new File(outFile));
            return true;  
        } catch (Exception e) {
            e.printStackTrace();  
            return false;  
        } finally {  
            try {  
                if (is != null) {  
                    is.close();  
                }  
                if (iis != null) {  
                    iis.close();  
                }  
            } catch (IOException e) {
                e.printStackTrace();  
                return false;  
            }  
        }  
    }  
 
    /**
     * @param doubleValue
     * @return
     * @描述 —— 将浮点型数据保留整数位转换成int型
     */  
    public static Integer getRoundIntFromDouble(Double doubleValue) {
        return Integer.parseInt(String.valueOf(Math.round(doubleValue)));
    }  
    
    public static String GetImageStr(String imgFilePath) {// 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
        byte[] data = null;
        
        // 读取图片字节数组
        try {
            InputStream in = new FileInputStream(imgFilePath);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data);// 返回Base64编码过的字节数组字符串
    }

    public static byte[] GenerateImage(String imgStr) {// 对字节数组字符串进行Base64解码并生成图片
        if (imgStr == null) // 图像数据为空
            return null;
        BASE64Decoder deco

以上是关于bootstrap图片剪裁预览上传的主要内容,如果未能解决你的问题,请参考以下文章

利用插件剪裁图片,并上传

图片上传组件开发

cropper+pillow处理上传图片剪裁

JavaScript中上传文件为图片如何读取(UI组件之图片剪裁器)

ThinkPHP整合cropper剪裁图片上传功能

Android选择/拍照 剪裁 base64/16进制/byte上传图片+PHP接收图片