1. 程式人生 > >使用Jcrop.js和jQuery.form.js,用ImageIO等進行頭像上傳縮放及裁剪

使用Jcrop.js和jQuery.form.js,用ImageIO等進行頭像上傳縮放及裁剪

首先,Java程式碼裡帶一個獲取ImageReader的Iterator

    /**
     * 從網上摘抄的。
     * 返回包含所有當前已註冊 ImageReader 的 Iterator,這些 ImageReader 聲稱能夠解碼指定格式。
     * 引數:postFix - 包含非正式格式名稱 .(例如 "jpeg" 或 "tiff")等 。
     * 
     * @param postFix
     *            檔案的字尾名
     * @author 劉各歡
     * @return
     */
    public Iterator<ImageReader> getImageReadersByFormatName(String postFix) {
        switch (postFix) {
        case "jpg":
            return ImageIO.getImageReadersByFormatName("jpg");
        case "jpeg":
            return ImageIO.getImageReadersByFormatName("jpeg");
        case "gif":
            return ImageIO.getImageReadersByFormatName("gif");
        case "bmp":
            return ImageIO.getImageReadersByFormatName("bmp");
        case "png":
            return ImageIO.getImageReadersByFormatName("png");
        default:
            return ImageIO.getImageReadersByFormatName("jpg");
        }
    }


第一步,用jQuery.form.js的ajaxSubmit()提交上傳的原始圖片,對圖片進行縮放並返回等比例大小的圖片,限制返回的圖片最大尺寸為1000px X 500px

Java核心程式碼如下:

	/**
	 * 
	 * imgFileZoom:傳入一個圖片檔案輸入流,寫入縮放後的圖片到輸出流
	 * 
	 * @author 劉各歡
	 * @param postFix
	 * @param in
	 * @param out
	 * @param showHeight 網頁顯示區域的高
	 * @param showWidth 網頁顯示區域的寬
	 * @return
	 * @throws IOException
	 * @since  Ver 1.1
	 */
    public Map<String,String> imgFileZoom(String postFix,InputStream in,FileOutputStream out,int showHeight,int showWidth) throws IOException{
		//FileInputStream is = null;
        ImageInputStream iis = null;
        Map<String,String> map = new HashMap<String,String>();
        try {
            // 讀取圖片檔案
            //is = new FileInputStream(in);

            // 獲取檔案的字尾名
            
            System.out.println("圖片格式為:" + postFix);
            /*
             * 返回包含所有當前已註冊 ImageReader 的 Iterator,這些 ImageReader 聲稱能夠解碼指定格式。
             * 引數:formatName - 包含非正式格式名稱 .(例如 "jpeg" 或 "tiff")等 。
             */
            Iterator<ImageReader> it = this.getImageReadersByFormatName(postFix);

            ImageReader reader = it.next();
            // 獲取圖片流
            iis = ImageIO.createImageInputStream(in);

            /*
             * <p>iis:讀取源.true:只向前搜尋 </p>.將它標記為 ‘只向前搜尋’。
             * 此設定意味著包含在輸入源中的影象將只按順序讀取,可能允許 reader 避免快取包含與以前已經讀取的影象關聯的資料的那些輸入部分。
             */
            reader.setInput(iis, true);
            int realWidth = reader.getWidth(0);
            int realHeight = reader.getHeight(0);
            
            double ratio = 1.0;
            
            if(realWidth>showWidth){
            	BigDecimal d1 = new BigDecimal(showWidth);
            	BigDecimal d2 = new BigDecimal(realWidth);
            	ratio = d1.divide(d2, 8,BigDecimal.ROUND_HALF_UP).doubleValue();
            }else if(realHeight>showHeight){
            	BigDecimal d1 = new BigDecimal(showHeight);
            	BigDecimal d2 = new BigDecimal(showHeight);
            	ratio = d1.divide(d2, 8,BigDecimal.ROUND_HALF_UP).doubleValue();
            }else{
            	ratio = 1.0;
            }
            
            BigDecimal ratioDecimal = new BigDecimal(ratio);
            BigDecimal realWidthDecimal = new BigDecimal(realWidth);
            BigDecimal realHeightDecimal = new BigDecimal(realHeight);
            BigDecimal outputWidthDecimal = BigDecimal.ONE;
            BigDecimal outputHeightDecimal = BigDecimal.ONE;
            outputWidthDecimal = realWidthDecimal.multiply(ratioDecimal);
            outputHeightDecimal = realHeightDecimal.multiply(ratioDecimal);
            int outputWidth = outputWidthDecimal.intValue();
            int outputHeight = outputHeightDecimal.intValue();
            //裝入最終轉換過的圖片的寬高
            map.put("outputWidth", String.valueOf(outputWidth));
            map.put("outputHeight", String.valueOf(outputHeight));
            
            /*
             * 使用所提供的 ImageReadParam 讀取通過索引 imageIndex 指定的物件,並將 它作為一個完整的
             * BufferedImage 返回。
             */
            BufferedImage bi = reader.read(0);

            
            /*
             * 縮放圖片
             */
            Image imageSmall = bi.getScaledInstance(outputWidth, outputHeight, Image.SCALE_DEFAULT);  
            
            BufferedImage small = new BufferedImage(outputWidth, outputHeight, BufferedImage.TYPE_INT_RGB);
            
            Graphics g = small.getGraphics();
            g.drawImage(imageSmall, 0, 0, null); // 繪製縮小後的圖  將Image繪製到BufferedImage中
            g.dispose();
            
            
            
            //寫入新圖片到輸出流
            ImageIO.write(small, postFix, out);
        } finally {
            if (in != null)
                in.close();
            if (iis != null)
                iis.close();
            if (out != null)
                out.close();
        }
        return map;
    }
    
    /**
     * 
     * updateZoomTxService:對上傳的頭像圖片進行縮放,並返回一些引數
     * 
     * @author 劉各歡
     * @param pic
     * @param req
     * @return
     * @since  Ver 1.1
     */
    public Map<String,Object> uploadZoomTx(MultipartFile pic,String uid,HttpServletRequest req){
		//從CommonInfo中讀取上傳檔案的路徑
		String pathString = CommonInfo.touxiangPath+"/zoom/";
		String fileName = "";
		Map<String,Object> map = new HashMap<String,Object>();
		
		//判斷檔案是否已經被獲取到
		if (pic.getSize() > 0) {
			//user.setImage(pathString + pic.getOriginalFilename());
			//判斷檔案儲存路徑是否存在
			File file = new File(pathString);

			if (!file.exists() && !file.isDirectory()) {
				file.mkdirs();
			}
			try {
				String ext=pic.getOriginalFilename().substring(pic.getOriginalFilename().lastIndexOf(".")+1,pic.getOriginalFilename().length());
				fileName = System.currentTimeMillis()+uid+"."+ext;
				//建立縮放過的檔案輸出流
				FileOutputStream fout = new FileOutputStream(pathString + fileName );
				
				
				map.put("imgInfo",this.imgFileZoom(ext.toLowerCase(),pic.getInputStream(),fout,500,1000));
				map.put("imgUrl", fileName);
				
				if(fout!=null) 
					fout.close();
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return map;
	}
返回的引數中帶有縮放後的影象長寬資訊,在前臺js處獲取到,對Jcrop進行初始化。

前臺核心程式碼(ajaxSubmit()及成功後的觸發):

		$("#uploadTxBtn").click(function(){
			var option = {  
                    type: "post",  
                    success : function(data){  
                    	zoomPicName = data['imgUrl'];
                       
                       $("#p_img").attr("src", "../../touxiang/zoom/"+data['imgUrl']);
                       $("#p_img").show();
                       $("#preview_block").show();
                       $("#p_img_preview").attr("src", "../../touxiang/zoom/"+data['imgUrl']);
                       $("#p_img").width(data['imgInfo']['outputWidth']);
                       $("#p_img").height(data['imgInfo']['outputHeight']);
                       
                       $("#uploadZoomTx").height(parseInt(data['imgInfo']['outputHeight'])+150);
                       caijian();
                   }  
                  };  
                  $("#uploadZoomTx").ajaxSubmit(option);  
		});


Jcrop相關初始化的js程式碼:

function caijian(){

        
        
  // Create variables (in this scope) to hold the API and image size
  var jcrop_api, boundx, boundy;
  
  $('#p_img').Jcrop({
    onChange: updatePreview,
    onSelect: updatePreview,
    aspectRatio: 1,
    setSelect: [0,0,100,100]
  },function(){
    // Use the API to get the real image size
    var bounds = this.getBounds();
    boundx = bounds[0];
    boundy = bounds[1];
    
    console.log(1111);
    console.log(bounds);
    
    
    // Store the API in the jcrop_api variable
    jcrop_api = this;
  });

  function updatePreview(c)
  {
    if (parseInt(c.w) > 0)
    {
    	
    	
    	console.log(c);
    	img_x = c.x;
    	img_y = c.y;
    	img_w = c.w;
    	img_h = c.h;
    
		
      var rx = 100 / c.w;
      var ry = 100 / c.h;

      $('#p_img_preview').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'
      });
      

    }
  };
}


第二步:

使用者拖拽完裁剪框,點選裁剪按鈕之後,上傳四個引數,分別是起始點的橫縱座標和裁剪區域的寬度高度,

此次過程只上傳引數,並沒有上傳圖片,後臺根據引數對上一步已經縮放的圖片再次進行裁剪和縮放。

js程式碼略去,後臺Java核心程式碼如下:

	/**
	 * 
	 * imgFileCut:傳入一個圖片檔案輸入流,寫入裁減後的圖片到輸出流
	 * 
	 * @author 劉各歡
	 * @param postFix
	 * @param in
	 * @param out
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param showHeight
	 * @param showWidth
	 * @throws IOException
	 * @since  Ver 1.1
	 */
    public void imgFileCut(String postFix,InputStream in,FileOutputStream out,int x,int y,int width,int height) throws IOException{
        ImageInputStream iis = null;
        try {

            /*
             * 返回包含所有當前已註冊 ImageReader 的 Iterator,這些 ImageReader 聲稱能夠解碼指定格式。
             * 引數:formatName - 包含非正式格式名稱 .(例如 "jpeg" 或 "tiff")等 。
             */
            Iterator<ImageReader> it = getImageReadersByFormatName(postFix);

            ImageReader reader = it.next();
            // 獲取圖片流
            iis = ImageIO.createImageInputStream(in);

            /*
             * <p>iis:讀取源.true:只向前搜尋 </p>.將它標記為 ‘只向前搜尋’。
             * 此設定意味著包含在輸入源中的影象將只按順序讀取,可能允許 reader 避免快取包含與以前已經讀取的影象關聯的資料的那些輸入部分。
             */
            reader.setInput(iis, true);
            
            /*
             * <p>描述如何對流進行解碼的類<p>.用於指定如何在輸入時從 Java Image I/O
             * 框架的上下文中的流轉換一幅影象或一組影象。用於特定影象格式的外掛 將從其 ImageReader 實現的
             * getDefaultReadParam 方法中返回 ImageReadParam 的例項。
             */
            ImageReadParam param = reader.getDefaultReadParam();

            /*
             * 圖片裁剪區域。Rectangle 指定了座標空間中的一個區域,通過 Rectangle 物件
             * 的左上頂點的座標(x,y)、寬度和高度可以定義這個區域。
             */
            Rectangle rect = new Rectangle(x, y, width, height);

            // 提供一個 BufferedImage,將其用作解碼畫素資料的目標。
            param.setSourceRegion(rect);
            
            /*
             * 使用所提供的 ImageReadParam 讀取通過索引 imageIndex 指定的物件,並將 它作為一個完整的
             * BufferedImage 返回。
             */
            BufferedImage bi = reader.read(0, param);
            
            
            
            /* 
             * 縮放圖片 
             */  
            Image imageSmall = bi.getScaledInstance(100, 100, Image.SCALE_DEFAULT);    
              
            BufferedImage small = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);  
              
            Graphics g = small.getGraphics();  
            g.drawImage(imageSmall, 0, 0, null); // 繪製縮小後的圖  將Image繪製到BufferedImage中  
            g.dispose();  
            
            
            
            // 儲存新圖片
            ImageIO.write(small, postFix, out);
        } finally {
            if (in != null)
                in.close();
            if (iis != null)
                iis.close();
            if (out != null)
                out.close();
        }
    }
    
	public String saveTx(String zoomedImageName, String img_x, String img_y,
			String img_w, String img_h) {
		String zoomedImagePath = CommonInfo.touxiangPath+"/zoom/"+zoomedImageName;
		String finalImagePath = CommonInfo.touxiangPath+zoomedImageName;
		File zoomedImagefile = new File(zoomedImagePath);
		try {
			InputStream in = new FileInputStream(zoomedImagefile);
			File finalImage = new File(finalImagePath);
			FileOutputStream out = new FileOutputStream(finalImage);
			int x = new BigDecimal(img_x).intValue();
			int y = new BigDecimal(img_y).intValue();
			int w = new BigDecimal(img_w).intValue();
			int h = new BigDecimal(img_h).intValue();
			String postFix=zoomedImageName.substring(zoomedImageName.lastIndexOf(".")+1,zoomedImageName.length()).toLowerCase();
			this.imgFileCut(postFix, in, out, x, y, w, h);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("儲存頭像失敗");
			return "error";
		}
		return "success";
	}


Control中的主呼叫方法:

	/**
	 * 
	 * updateZoomTx:對上傳的原始頭像進行等比例縮放,並返回檔名等一些引數
	 * 
	 * @author 劉各歡
	 * @param pic
	 * @param req
	 * @return
	 * @since  Ver 1.1
	 */
	@ResponseBody
	@RequestMapping(value = "/uploadZoomTx.do")
	public Map<String,Object> updateZoomTx(MultipartFile pic,HttpServletRequest req){
		Map<String,Object> map = null;
		if(req.getSession()!=null&&req.getSession().getAttribute("curruser")!=null){
			String uid = "";
			uid = ((User)(req.getSession().getAttribute("curruser"))).getId();
			map =userService.uploadZoomTx(pic,uid,req);
		}else{
			map=new HashMap<String,Object>();
			map.put("error","error");
		}
		return map;
	}
	
	/**
	 * 
	 * saveTx: 對上一步縮放過的影象進行裁剪並縮放,存在本地硬碟
	 * 
	 * @author 劉各歡
	 * @param zoomedImageName
	 * @param img_x
	 * @param img_y
	 * @param img_w
	 * @param img_h
	 * @param req
	 * @return
	 * @since  Ver 1.1
	 */
	@ResponseBody
	@RequestMapping(value = "/saveTx.do")
	public String saveTx(String zoomedImageName,String img_x,String img_y,String img_w,String img_h,HttpServletRequest req){
		String re =userService.saveTx( zoomedImageName,img_x, img_y, img_w, img_h);
		if(req.getSession()!=null&&req.getSession().getAttribute("curruser")!=null){
			User user = (User)(req.getSession().getAttribute("curruser"));
			user.setImage(zoomedImageName);
			userService.saveOrUpdate(user);
			return "ok";
		}else{
			return "error";
		}
	}
關於利用HTML5的canvas或者flash進行擷取的也想過,考慮到相容性,還是先這樣吧。

預覽效果:



相關推薦

使用Jcrop.jsjQuery.form.jsImageIO進行頭像裁剪

首先,Java程式碼裡帶一個獲取ImageReader的Iterator /** * 從網上摘抄的。 * 返回包含所有當前已註冊 ImageReader 的 Iterator,這些 ImageReader 聲稱能夠解碼指定格式。 *

當同時使用bootstrap-datepicker.jsjquery.validate.js這兩款插件至少要選擇兩次時間才能驗證成功的問題

ont element 表單元素 進行 觸發 this hang font 改變 當用 bootstrap-datepicker.js 這個插件選擇時間,再用jquery.validate.js進行驗證,當時間不為空時則驗證通過。可能由於在時間插件彈出來時,input框的值

jquery.jsjquery.min.js的區別

jquery.js裡的程式碼是沒有進行處理的程式碼,適合人們閱讀和研究。 jquery.min.js裡的程式碼是進行過特殊處理的,所以容量比較小。 所以開發時,使用非壓縮的的,生產上使用壓縮的。 最後歡迎大家訪問我的個人網站:1024s

基於jQuerycropper點選頭像並預覽裁剪圖片

使用jquery上傳前,預覽圖片,裁剪,示例使用php接收上傳的檔案,並且儲存為裁剪後的圖片。不需要上傳後再裁剪圖片,只需要本地裁剪好即可,裁剪的時候也可以旋轉圖片。裁剪控制元件使用了,cropper。 html程式碼 <!DOCTYPE html> <html la

springMVC檔案MultipartHttpServletRequest、MultipartFile進行檔案

這裡使用apache的開源jar包完成上傳功能,使用jar包分別是:common-fileupload.jar和common-io.jar  先編寫上傳檔案幫助類,如果需要區分檔案型別,可以將檔案字尾擷取進行判斷; springmvc-mvc.xml配置,這裡主要配置spri

iOS 調取本地相簿/相機剪裁圖片進行頭像

開啟本地相簿或開啟本地相機拍照,獲取圖片裁剪圖片,上傳圖片 加入標頭檔案 #import <MobileCoreServices/MobileCoreServices.h> #import <AVFoundation/AVFoundat

通過終端命令列進行WebDav伺服器配置實現使用PUT進行檔案【圖文詳解】

HTTP的常見方法 》GET        獲取指定資源 》POST      2M 向指定資源提交資料進行處理請求,在RESTful風格中用於新增資源 》HEAD            獲取指定資源頭部資訊 》PUT        替換指定資源(不支援瀏覽器操作) 》DE

jquery-form.js提交帶文件的數據

offset 發布 文件選擇 需要 保存 con file -m 選擇 最近做一個項目需要同時向後臺傳文件和數據,經過多方考證,選擇了使用jquery-form.js插件。所以總結一下,僅大家參考; html部分: <form enctype="multipart/

25.jsjquery實現下拉列表的左右選擇

select2 hit color nts -type utf ctype block 標簽 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/x

jsjquery的使用調

name attr tar 添加 offset read query -- 文檔 4 this 關鍵字 this 表示當前函數或方法的調用者 1 全局函數由window調用,所以全局函數中的this 指的是window對象 2 事件處理函數中使用t

同時使用vue.jsjqueryjq事件無響應解決辦法

先載入vue.js,讓頁面渲染完成後載入jq,給jq繫結ready事件 $(document).ready(function(){ $(function() { //jq事件 }); }); 更新 ……ready載入太玄學了,測試3/10的

jsjQuery調搜狐IP地址查詢介面

介面返回的資料是: var returnCitySN = {"cip": "119.137.53.105", "cid": "440306", "cname": "廣東省深圳市寶安區"}; js呼叫: <script src="http://p

分別jsjQuery是實現表格的全選中全不選

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>使用jQuery和js完成複選框的全選和全不選</title> <script

Form表單提交後獲取後臺資料需要jquery-form.js指令碼

    <script type="text/javascript" src="js/jquery-form.js"></script>    <script type="text/javascript">        $(documen

jquery.form.js 利用ajaxSubmit ajaxExcel

@RequestMapping(value="importClubPersonInfoFromExcel.json", method={RequestMethod.POST}) @ResponseBody public Map<String,Object> importClubPersonIn

jsjquery實現回到頂層

left ret poi add 寬度 fadein soft 距離 jquery實現 js <!DOCTYPE html> <html> <head> <title>返回頂部</title> <styl

ECSHOP中transport.jsjquery的沖突的簡單解決辦法

order adding fun ring func 資源 代碼 spa pac ECSHOP中transport.js和jquery的沖突的簡單解決辦法 一流資源網近日在ECSHOP網站加入了幾個JS特效代碼,在谷歌、火狐下正常,在各版本IE下都不常,左思不得其解。

更好的實現js數組連接到的知識apply.

講解 ber array 方便 this var 但是 ken 兩個 最近做的萬達的一個能源管理平臺中用到了數據連接,當時想都沒想直接寫了一個a.concat(b)。今天在掘金看到了一個優化的方案。是這樣:a.push.apply(a,b);其中a,b分別為兩個數組。仔細一

跨域問題相關知識詳解(原生jsjquery兩種方法實現jsonp跨域)

syn con 加載 developer 兩種方法 ray exe 編寫 分組 1、同源策略 同源策略(Same origin policy),它是由Netscape提出的一個著名的安全策略。同源策略是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽

將原生JSjquery裏面的DOM操作進行了一下整理

ont child ace attr move 節點 沒有 設置 復制 創建元素節點 1.原生: document.createElement("div") 2.jquery: $("<div></div>") 創建文本節點並加入元素節點中