本文介紹了頭像裁剪上傳功能,用到的技術有 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參數傳到後台。
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。