cropper頭像上傳

花了幾天時間學習了下javaWeb中cropper頭像上傳功能,下面僅在此記錄一下.

看到有篇博客是在前臺用canvas的toDataURL處理,但貌似無法處理gif圖像(如有大俠知道如何處理,還望告知),故放棄這一做法而選擇在後端處理,

前臺提交scaleX,scaleY,rotate,x,y,width,height及原始圖片,後臺縮放、旋轉、裁剪.


一、下面先提供一個處理類:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import org.apache.commons.lang3.StringUtils;

import com.lzw.gif.AnimatedGifEncoder;
import com.lzw.gif.GifDecoder;

/**
 * @author nc-wl001 配合cropper頭像上傳插件使用的bean、(注意cropper插件縮放後圖片大小是不變的及圖片中心是不變的)
 */
public class Cropper {
	//水平方向縮放比例
	private double scaleX;
	//垂直方向縮放比例
	private double scaleY;
	// 旋轉角度15、45等
	private int rotate;
	// 注意以下數據均是相對於旋轉後的圖片
	// 裁剪框左上角x
	private int x;
	// 裁剪框左上角y
	private int y;
	// 裁剪框寬度
	private int width;
	// 裁剪框高度
	private int height;
	// 爲防止目標圖片過大而添加的一個縮放比例參數
	protected double scale = 1.0;

	public Cropper(double scaleX,double scaleY,int rotate, int x, int y, int width, int height) {
		super();
		this.scaleX=scaleX;
		this.scaleY=scaleY;
		this.rotate = rotate;
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	public int getRotate() {
		return rotate;
	}

	public void setRotate(int rotate) {
		this.rotate = rotate;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public double getScaleX() {
		return scaleX;
	}

	public void setScaleX(double scaleX) {
		this.scaleX = scaleX;
	}

	public double getScaleY() {
		return scaleY;
	}

	public void setScaleY(double scaleY) {
		this.scaleY = scaleY;
	}

	/**
	 * 設置縮放比例
	 * 
	 * @param scale
	 */
	protected void setScale(double scale) {
		this.x = (int) Math.ceil(this.x * scale / this.scale);
		this.y = (int) Math.ceil(this.y * scale / this.scale);
		this.width = (int) Math.ceil(this.width * scale / this.scale);
		this.height = (int) Math.ceil(this.height * scale / this.scale);
		this.scale = scale;
	}

	/**
	 * 設置目標圖片寬度
	 * 
	 * @param width
	 */
	public void setFactWidth(int width) {
		double scale = width * this.scale / this.width;
		this.setScale(scale);
	}

	/**
	 * 設置目標圖片高度
	 * 
	 * @param height
	 */
	public void setFactHeight(int height) {
		double scale = height * this.scale / this.height;
		this.setScale(scale);
	}

	/**
	 * 獲取源圖片旋轉後的目標容器大小
	 * 
	 * @param source
	 *            源圖片大小
	 * @return
	 */
	protected final Dimension getTargetDimension(Dimension source) {
		source.setSize(source.getWidth() * this.scale, source.getHeight()
				* this.scale);
		// 獲取旋轉後圖片大小
		double theta = Math.toRadians(this.rotate);
		double target_width, target_height;
		if ((int) Math.floor(this.rotate / 90.0) % 2 == 0) {// 也即Math.sin(2*theta)>0(Math.sin(2*theta)=0時兩個分支結果一樣)
			target_width = Math.abs(source.width * Math.cos(theta)
					+ source.height * Math.sin(theta));
			target_height = Math.abs(source.height * Math.cos(theta)
					+ source.width * Math.sin(theta));
		} else {
			target_width = Math.abs(source.width * Math.cos(theta)
					- source.height * Math.sin(theta));
			target_height = Math.abs(source.height * Math.cos(theta)
					- source.width * Math.sin(theta));
		}
		Dimension target = new Dimension();
		target.setSize(target_width, target_height);
		return target;
	}

	/**
	 * 獲取旋轉並裁剪後的圖片
	 * 
	 * @param src
	 *            源圖片
	 * @return 旋轉並裁剪後的圖片
	 */
	protected final BufferedImage rotate_CropImage(BufferedImage src) {
		// 原圖大小
		Dimension source = new Dimension(src.getWidth(), src.getHeight());
		// 旋轉後大小
		Dimension target = this.getTargetDimension(source);
		// 旋轉並裁剪後的目標圖片
		BufferedImage rotate_crop_Image = new BufferedImage(this.width,
				this.height, BufferedImage.TYPE_INT_RGB);
		Graphics2D rotate_crop_g2d = rotate_crop_Image.createGraphics();
		// 設置填充色爲白色
		rotate_crop_g2d.setColor(Color.WHITE);
		rotate_crop_g2d.fillRect(0, 0, this.width, this.height);
		// transform;translate(x,y)是將座標系往右平移x,往下平移y,(x,y的正負對應正反方向)
		rotate_crop_g2d.translate((target.width - source.width) / 2 - this.x,
				(target.height - source.height) / 2 - this.y);// 平移座標系(以便後面將原圖畫上去)
		// rotate 旋轉座標系
		rotate_crop_g2d.rotate(Math.toRadians(this.rotate), source.width / 2,
				source.height / 2);// 旋轉座標系、注意旋轉中心
		rotate_crop_g2d.translate((1-this.scaleX)*source.width/2, (1-this.scaleY)*source.height/2);
		// 將圖畫上去
		rotate_crop_g2d.drawImage(src,AffineTransform.getScaleInstance(this.scale*this.scaleX, this.scale*this.scaleY), null);// 畫圖
		rotate_crop_g2d.dispose();
		return rotate_crop_Image;
		
	}

	/**
	 * 獲取旋轉並裁剪後的圖片二進制流
	 * 
	 * @param inputStream
	 *            圖片文件輸入流
	 * @param imageType
	 *            圖片文件類型(jpeg,png,jpg,gif等)
	 * @return 旋轉並裁剪後的圖片二進制流
	 */
	public byte[] rotate_CropImage(InputStream inputStream, String imageType) {
		byte[] result = new byte[] {};
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		try {
			if (StringUtils.equalsIgnoreCase(imageType, "gif")) {

				/*----------------AnimatedGifEncoder.java處理----------------------*/
				GifDecoder decoder = new GifDecoder();
				decoder.read(inputStream);
				AnimatedGifEncoder encoder = new AnimatedGifEncoder();
				encoder.start(outputStream);// 若要生成gif圖片則使用encoder.start("xxx.gif");
				encoder.setRepeat(decoder.getLoopCount());
				for (int i = 0, n = decoder.getFrameCount(); i < n; i++) {
					encoder.setDelay(decoder.getDelay(i));
					encoder.addFrame(this.rotate_CropImage(decoder.getFrame(i)));
				}
				encoder.finish();

			} else {// 其他格式圖片文件處理
				ImageIO.write(this.rotate_CropImage(ImageIO.read(inputStream)),
						imageType, outputStream);
			}
			result = outputStream.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}

}


說明:此類是基於Cropper插件的幾個裁剪數據而建的,可處理動態圖,動態圖處理部分是在網上找的幾個處理gif的類.

這裏打成了jar包方便使用:http://download.csdn.net/download/xinshijimanon/9796051

此類的重點是後三個方法,由於本人表達能力先天欠缺難過,就不詳細熬敘此方法了(主要是獲取旋轉後的圖片大小,以及在scaleX,scaleY不爲1時如何將座標系平移、旋轉到正確位置)。

二、前臺部分代碼:

我這裏是以彈窗的形式彈出修改頭像框的,用的是layer插件,請酌情替換.

1、html/jsp

<!-- 修改頭像2 -->
		<div id="editPhotoDialog" class="dialog">
		
			<label class="btn btn-primary btn-upload" for="inputImage" style="margin: 15px;">
				<input type="file" class="sr-only" id="inputImage" accept=".jpg,.jpeg,.png,.gif,.bmp">
				<span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="上傳圖片文件(.jpg、.jpeg、.png、.gif、.bmp)">
					<span class="icon icon-upload"> 選擇圖片</span>
				</span>
			</label>
			
			<div>
				<div class="col-md-8">
			        <!-- <h3>Demo:</h3> -->
			        <div class="img-container" style="width:390px;height:390px;">
			        	<img id="image" src="">
			        </div>
			    </div>
			    <div class="col-md-3">
			        <!-- <h3>Preview:</h3> -->
			        <div class="docs-preview clearfix">
			          <div class="img-preview preview-lg"></div>
			          <div class="img-preview preview-md"></div>
			          <div class="img-preview preview-sm"></div>
			          <div class="img-preview preview-xs"></div>
			        </div>
			    </div>
		    </div>
		    
		    
		    <div>
			    <div class="col-md-9 docs-buttons">
			    	<div class="btn-group">
			          	<button class="btn btn-primary" data-method="zoom" data-option="0.1" type="button" title="Zoom In">
			           		<span class="docs-tooltip" data-toggle="tooltip" title="放大">
			              		<span class="icon icon-zoom-in"></span>
			            	</span>
			          	</button>
			          	<button class="btn btn-primary" data-method="zoom" data-option="-0.1" type="button" title="Zoom Out">
			            	<span class="docs-tooltip" data-toggle="tooltip" title="縮小">
			              		<span class="icon icon-zoom-out"></span>
			            	</span>
			          	</button>
			          	<button class="btn btn-primary" data-method="rotate" data-option="-45" type="button" title="Rotate Left">
			            	<span class="docs-tooltip" data-toggle="tooltip" title="左旋轉45度">
			              		<span class="icon icon-rotate-left"></span>
			            	</span>
			          	</button>
			          	<button class="btn btn-primary" data-method="rotate" data-option="45" type="button" title="Rotate Right">
			            	<span class="docs-tooltip" data-toggle="tooltip" title="右旋轉45度">
			              		<span class="icon icon-rotate-right"></span>
			            	</span>
			          	</button>
			        </div>
			        
			        <div class="btn-group">
				          <button type="button" class="btn btn-primary" data-method="move" data-option="-2" data-second-option="0" title="Move Left">
				            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="左移">
				              <span class="icon icon-arrow-left"></span>
				            </span>
				          </button>
				          <button type="button" class="btn btn-primary" data-method="move" data-option="2" data-second-option="0" title="Move Right">
				            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="右移">
				              <span class="icon icon-arrow-right"></span>
				            </span>
				          </button>
				          <button type="button" class="btn btn-primary" data-method="move" data-option="0" data-second-option="-2" title="Move Up">
				            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="上移">
				              <span class="icon icon-arrow-up"></span>
				            </span>
				          </button>
				          <button type="button" class="btn btn-primary" data-method="move" data-option="0" data-second-option="2" title="Move Down">
				            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="下移">
				              <span class="icon icon-arrow-down"></span>
				            </span>
				          </button>
			       </div>
			       
			       <div class="btn-group">
			          <button type="button" class="btn btn-primary" data-method="addScaleX" data-option="0.08" data-second-option="2" data-three-option="3" title="Flip Horizontal">
			            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="水平放大">
			              <span class="icon  icon-chevron-left"></span>
			            </span>
			          </button>
			          <button type="button" class="btn btn-primary" data-method="addScaleX" data-option="-0.08" data-second-option="2" data-three-option="3" title="Flip Horizontal">
			            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="水平縮小">
			              <span class="icon icon-chevron-right"></span>
			            </span>
			          </button>
			          <button type="button" class="btn btn-primary" data-method="addScaleY" data-option="0.08" data-second-option="2" data-three-option="3" title="Flip Vertical">
			            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="豎直放大">
			              <span class="icon  icon-chevron-up"></span>
			            </span>
			          </button>
			          <button type="button" class="btn btn-primary" data-method="addScaleY" data-option="-0.08" data-second-option="2" data-three-option="3" title="Flip Vertical">
			            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="豎直縮小">
			              <span class="icon icon-chevron-down"></span>
			            </span>
			          </button>
			       </div>
			    </div>
		    </div>

		    
		</div>

說明:可以看到最後一組按鈕中有data-Method="addScaleX"或data-Method="addScaleY",這需要修改cropper.js的源碼,添加addScaleX,addScaleY方法.

在cropper.js中找到scaleX,scaleY方法,在其後面分別添加這兩個方法(分別用於在水平、垂直方向拉伸原圖):

 /**
   * add scaleX of the image
   *
   * @param {Number} addNumber
   * 
   * @param {Number} decimalCount
   * 
   * @param {Number} maxABS
   * 
   */
  addScaleX:function addScaleX(addNumber,decimalCount,maxABS){
	  var self = this;
	  var scaleX = self.image.scaleX;
	  scaleX+=addNumber;
	  if(decimalCount&&!isNaN(decimalCount)){
		  scaleX=scaleX.toFixed(parseInt(decimalCount));
	  }
	  if(scaleX>Math.abs(maxABS)||scaleX<-Math.abs(maxABS)){
		  return;
	  }
	  this.scaleX(scaleX);
  },


  /**
   * add scaleY of the image
   *
   * @param {Number} addNumber
   * 
   * @param {Number} decimalCount
   * 
   * @param {Number} maxABS
   * 
   */
  addScaleY:function addScaleY(addNumber,decimalCount,maxABS){
	  var self = this;
	  var scaleY = self.image.scaleY;
	  scaleY+=addNumber;
	  if(decimalCount&&!isNaN(decimalCount)){
		  scaleY=scaleY.toFixed(parseInt(decimalCount));
	  }
	  if(scaleY>Math.abs(maxABS)||scaleY<-Math.abs(maxABS)){
		  return;
	  }
	  this.scaleY(scaleY);
  },

2、js

	$("a.editPhoto").on("click",function(){
		layer.closeAll();
		layer.open({
			type : 1,
			title : false,
			closeBtn : 1,
			shift : 2,
			shade : 0.01,
			shadeClose : false,
			area : ['600px','600px'],
			content : $("#editPhotoDialog"),
			btn : [ '確認', '取消' ],
			yes : function(index) { // 確認按鈕
				if($("#image").attr("src")==""){
					layer.msg("未選擇圖片文件", {
						time : 1000
					});
					return;
				}

				var cropperData=$("#image").cropper("getData");
				var fd=new FormData();
				fd.append("file",$("#image").data("file"));				
				fd.append("scaleX",cropperData.scaleX);
				fd.append("scaleY",cropperData.scaleY);
				fd.append("rotate",parseInt(cropperData.rotate));
				fd.append("x",parseInt(cropperData.x));
				fd.append("y",parseInt(cropperData.y));
				fd.append("width",parseInt(cropperData.width));
				fd.append("height",parseInt(cropperData.height));
				var loadIndex=0;
				$.ajax({
					url : "../../user/webSetPersonalPhoto",//設置個人頭像接口
					type: 'post',
					data: fd,
					dataType: 'json',
					cache: false,
					processData: false,
					contentType: false,
					beforeSend: function(){
						layer.close(index);
						loadIndex = layer.load(1);
					},
					success:function(data, status, xhr, $form) {
						layer.msg(data.msg, {
							time : 1000
						});
						$("#header .userinfo div").css({//刷新個人頭像
							"background-image" : "url(../../user/getPersonalPhoto?_="+ new Date().getTime()+ ")"
						});
					},
					complete : function(xhr, status, $form) {
						layer.close(loadIndex);
						if (status == "parsererror") {
							location.reload(true);// 刷新瀏覽器,類似於按F5
						}
					}
				});

			},
			end : function(index) {
				$("#image").cropper("destroy").attr("src","").data("file",null);
			}
		});
	});
	
	$(".btn-group").on('click', '[data-method]', function () {
		
		var $this = $(this);
	    var data = $this.data();
	    var $target;
	    var result;
 
	    if ($this.prop('disabled') || $this.hasClass('disabled')) {
	      return;
	    }

	    if ($("#image").data('cropper') && data.method) {
	      data = $.extend({}, data); // Clone a new one
	      if (typeof data.target !== 'undefined') {
	        $target = $(data.target);
	        if (typeof data.option === 'undefined') {
	          try {
	            data.option = JSON.parse($target.val());
	          } catch (e) {
	            console.log(e.message);
	          }
	        }
	      }
	      if (data.method === 'rotate') {
	    	  $("#image").cropper('clear');
	      }
	      if(data.method === 'addScaleX'||data.method === 'addScaleY'){
	    	  result = $("#image").cropper(data.method, data.option, data.secondOption,data.threeOption);
	      }else{
	    	  result = $("#image").cropper(data.method, data.option, data.secondOption);
	      }
	      
	      if (data.method === 'rotate') {
	    	  $("#image").cropper('crop');
	      }
	      if ($.isPlainObject(result) && $target) {
	        try {
	          $target.val(JSON.stringify(result));
	        } catch (e) {
	          console.log(e.message);
	        }
	      }

	    }
		
	});
	
	var URL = window.URL || window.webkitURL;
	var uploadedImageURL;
	if (URL) {
		$('#inputImage').change(function (e) {
			var files = this.files;
		    var file;
		    if (files && files.length) {
		    	file = files[0];
		    	var errorMsg="";
		    	if (!/^image\/\w+$/.test(file.type)) {
		    		errorMsg="請選擇圖片文件";
		        }else if(file.size==0){
		        	errorMsg="圖片爲空,請重新選擇";
	    		}else if(file.size>2048000){
	    			errorMsg="圖片大小超過最大限制(2MB)";
	    		}
		    	if(errorMsg!=""){
		    		$("#inputImage").val("");
		    		layer.msg(errorMsg,{time:1000});
		    		return;
		    	}
	    		if (uploadedImageURL) {
	    			URL.revokeObjectURL(uploadedImageURL);
	    		}
	    		uploadedImageURL = URL.createObjectURL(file);
	    		$("#image").cropper("destroy").attr('src', uploadedImageURL).data('file',file).cropper({
					aspectRatio: 1 / 1,
					dragMode:"move",
					toggleDragModeOnDblclick:false,
					strict:true,
					minCanvasWidth: 50,//畫布
					minCanvasHeight: 0,
					minCropBoxWidth: 50,//裁剪框
					minCropBoxHeight: 0,
					minContainerWidth: 50,//容器
					minContainerHeight: 50,
					/*viewMode:2,*/
				    preview: '.img-preview',
				    crop: function (e) {
				    	
				    }
				});
	    		$("#inputImage").val("");
		    }
		});
	} else {
		$('#inputImage').prop('disabled', true).parent().addClass('disabled');
	}

說明:以上代碼中使用的cropper版本是Cropper v3.0.0-beta,下載地址:https://github.com/fengyuanchen/cropper

js部分使用的是FormData提交文件即裁剪旋轉數據(因input file選擇文件時再單擊'取消'(而不是'打開')後file就沒有了,造成不好的體驗).

3、css

/* Basic */


/* Main
 * ========================================================================== */


/* Icons
 * -------------------------------------------------------------------------- */

.icon {
  display: inline-block;
  width: 20px;
  height: 20px;
  background-image: url("../assets/img/icons.png");
  vertical-align: middle;
}

.icon-move {
  background-position: 0 0;
}

.icon-crop {
  background-position: -30px 0;
}

.icon-zoom-in {
  background-position: -60px 0;
}

.icon-zoom-out {
  background-position: -90px 0;
}

.icon-rotate-left {
  background-position: -120px 0;
}

.icon-rotate-right {
  background-position: -150px 0;
}

.icon-lock {
  background-position: -180px 0;
}

.icon-unlock {
  background-position: -210px 0;
}

.icon-remove {
  background-position: -240px 0;
}

.icon-refresh {
  background-position: -270px 0;
}

.icon-upload {
  background-position: -300px 0;
}

.icon-off {
  background-position: -330px 0;
}

.icon-info {
  background-position: -360px 0;
}


/* Alerts
 * -------------------------------------------------------------------------- */

.docs-alert {
  display: none;
  position: fixed;
  top: 20px;
  left: 0;
  right: 0;
  height: 0;
  text-align: center;
  opacity: 0.9;
}

.docs-alert .message {
  display: inline-block;
  padding: 5px 10px;
  border-radius: 2px;
  background-color: #aaa;
  color: #fff;
}

.docs-alert .primary {
  background-color: #0074d9;
}

.docs-alert .success {
  background-color: #2ecc40;
}

.docs-alert .info {
  background-color: #39cccc;
}

.docs-alert .warning {
  background-color: #ff851b;
}

.docs-alert .danger {
  background-color: #ff4136;
}

/* Button
 * -------------------------------------------------------------------------- */

.btn-primary {
  border-color: #003973; /* hsb(210, 100%, 45%) */
  background-color: #00468c; /* hsb(210, 100%, 55%) */
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary.active,
.btn-primary.active:focus,
.btn-primary.active:hover {
  border-color: #00264d; /* hsb(208, 100%, 10%) */
  background-color: #003366; /* hsb(208, 100%, 40%) */
}


/* Basic style
 * -------------------------------------------------------------------------- */

body {
  overflow-x: hidden;
}


/* Header */

.docs-header {
  border-color: #003973;
  background-color: #00468c;
  color: #fff;
}

.docs-header .navbar-brand {
  color: #eee;
}

.docs-header .navbar-toggle {
  border-color: #003973;
  background-color: #00468c;
}

.docs-header .navbar-toggle:hover,
.docs-header .navbar-toggle:focus {
  border-color: #003366;
  background-color: #003973;
}

.docs-header .navbar-collapse {
  border-color: #003973;
}

.docs-header .navbar-text {
  color: #ddd;
}

.docs-header .navbar-nav > li > a {
  color: #eee;
}


/* Content */

.img-container,
.img-preview {
  background-color: #f7f7f7;
  overflow: hidden;
  width: 100%;
  text-align: center;
}

.img-container {
  min-height: 200px;
  max-height: 390px;
  margin-bottom: 20px;
}

@media (min-width: 768px) {
  .img-container {
    min-height: 390px;
  }
}

.img-container > img {
  max-width: 100%;
}

.docs-preview {
  margin-left: 15px;
  margin-bottom: 10px;
}

.img-preview {
  float: left;
  margin-right: 10px;
  margin-bottom: 10px;
  border: 1px solid grey;
}

.img-preview > img {
  max-width: 100%;
}

.preview-lg {
  width: 148px !important;
  height: 148px !important;
}

.preview-md {
  width: 78px !important;
  height: 78px !important;
}

.preview-sm {
  width: 39px !important;
  height: 39px !important;
}

.preview-xs {
  width: 25px !important;
  height: 25px !important;
  margin-right: 0;
}

.docs-data > .input-group {
  margin-bottom: 10px;
}

.docs-data > .input-group > label {
  min-width: 80px;
}

.docs-data > .input-group > span {
  min-width: 50px;
}

.docs-buttons > .btn,
.docs-buttons > .btn-group,
.docs-buttons > .form-control {
  margin-right: 5px;
  margin-bottom: 10px;
}

.docs-toggles > .btn,
.docs-toggles > .btn-group,
.docs-toggles > .dropdown {
  margin-bottom: 10px;
}

.docs-tooltip {
  display: block;
  margin: -6px -12px;
  padding: 6px 12px;
}

.docs-tooltip > .icon {
  margin: 0 -3px;
  vertical-align: middle;
}

.tooltip-inner {
  white-space: normal;
}

.btn-upload .tooltip-inner {
  white-space: nowrap;
}

@media (max-width: 400px) {
  .btn-group-crop {
    margin-right: -15px!important;
  }

  .btn-group-crop > .btn {
    padding-left: 5px;
    padding-right: 5px;
  }

  .btn-group-crop .docs-tooltip {
    margin-left: -5px;
    margin-right: -5px;
    padding-left: 5px;
    padding-right: 5px;
  }
}

.docs-options .dropdown-menu {
  width: 100%;
}

.docs-options .dropdown-menu > li {
  padding: 3px 20px;
}

.docs-options .dropdown-menu > li:hover {
  background-color: #f7f7f7;
}

.docs-options .dropdown-menu > li > label {
  display: block;
}

.docs-cropped .modal-body {
  text-align: center;
}

.docs-cropped .modal-body > img,
.docs-cropped .modal-body > canvas {
  max-width: 100%;
}


三、後臺部分代碼:

1、後臺用的是spring的MultipartFile、Spring這部分的配置大致如下:

<!-- file uploader support -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="defaultEncoding" value="UTF-8" />
		<property name="maxUploadSize" value="255541538" />
	</bean>
2、後臺接口:(這裏圖片是以二進制流的形式存在數據庫中的、請酌情修改)

/** 設置個人頭像
	 * @param scaleX 裁剪參數scaleX
	 * @param scaleY 裁剪參數scaleY
	 * @param rotate 裁剪參數rotate
	 * @param x 裁剪參數x
	 * @param y 裁剪參數y
	 * @param width 裁剪參數width
	 * @param height 裁剪參數height
	 * @param file 圖片文件
	 * @return
	 */
	@RequestMapping(value = "/webSetPersonalPhoto", method = RequestMethod.POST)
	@ResponseBody
	public Tidings<User> webSetPersonalPhoto(
			@RequestParam("scaleX") Double scaleX,
			@RequestParam("scaleY") Double scaleY,
			@RequestParam("rotate") Integer rotate,
			@RequestParam("x") Integer x,
			@RequestParam("y") Integer y,
			@RequestParam("width") Integer width,
			@RequestParam("height") Integer height,
			@RequestParam("file") MultipartFile file) {
		String fileName=file.getOriginalFilename().toLowerCase();
		String imageType=fileName.substring(fileName.lastIndexOf(".")+1);
		if (!fileName.matches(".*\\.(jpg|jpeg|png|gif|bmp)")) {
			return new Tidings<User>("failure", "請選擇圖片文件");
		}
		//初始化裁剪信息
		Cropper cropper=new Cropper(scaleX,scaleY,rotate, x, y, width, height);
		//設置目標圖片寬度
		cropper.setFactWidth(512);
		
		Subject subject = SecurityUtils.getSubject();
		String username = (String) subject.getPrincipal();
		InputStream input;
		byte[] photo = null;
		try {
			input = file.getInputStream();
			photo=cropper.rotate_CropImage(input, imageType);
			input.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		User user=userServiceImpl.findByUsername(username);
		if (photo != null && this.userServiceImpl.updatePropByUsername(username, "personalPhoto", photo)) {
			return new Tidings<User>("success", "設置個人頭像成功",user);
		} else {
			return new Tidings<User>("failure", "設置個人頭像失敗",user);
		}
	}


上面的SecurityUtils、Subject是Shiro權限框架中的東西,Tidings是封裝返回結果的類.請酌情修改部分代碼.

附:

1、Tiddings.java:

public class Tidings<T> {
	private String status;
	private String msg;
	private T t;
	
	public Tidings(){
		super();
	}

	public Tidings(String status,String msg){
		super();
		this.status=status;
		this.msg=msg;
	}
	
	public Tidings(String status,String msg,T t){
		super();
		this.status=status;
		this.msg=msg;
		this.t=t;
	}


	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}

}
2、獲取個人頭像:

/**
	 * 獲取個人頭像
	 * 
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "/getPersonalPhoto", method = RequestMethod.GET)
	public void getPersonalPhoto(HttpServletRequest request, HttpServletResponse response) {
		Subject subject = SecurityUtils.getSubject();
		String username = (String) subject.getPrincipal();
		User user = this.userServiceImpl.findByUsername(username);
		byte[] b = user.getPersonalPhoto();
		if (b == null) {//未設置圖片則用一張默認圖片
			FileInputStream fis = null;
			try {
				fis = new FileInputStream(
						request.getSession().getServletContext().getRealPath("/") + "img/default_personalPhoto.png");
				b = new byte[fis.available()];
				fis.read(b);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (fis != null) {
					try {
						fis.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		response.setContentType("image/png");
		OutputStream out = null;
		try {
			out = response.getOutputStream();
			out.write(b);
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章