1、簡單說明css
本頭像編輯器主要實現了圖片的上傳、顯示(不溢出父窗口)、旋轉、裁剪功能!html
2、效果圖:前端
2.選擇圖片html5
3.顯示選擇的圖片jquery
4.旋轉圖片web
5.拖動鼠標選擇裁剪框ajax
6.保存頭像,而且顯示spring
3、代碼實現json
1.圖片的選擇以及上傳canvas
咱們確定都見過自帶的上傳按鈕,這個按鈕比較難看。
,這個是否是比上一張強多了!其實就是 一個buton按鈕,而後將上面的<input type="file">隱藏了,而後當點擊button按鈕的時候,調用file的事件。這樣就實現了和點擊file同樣的效果。
<input type="button" value="選擇頭像" class="bt"><font color="#999999"><span> 支持jpg、jpeg、gif、png、bmp格式的圖片</span> <input type="file" id="file" name="file"> <!--能夠在css中設置隱藏屬性或者在js中設置-->
1 $(".bt").click(function(){ 2 $("#file").click(); 3 });
這樣,就實現了彈出選擇框的功能。接下來須要實現的就是選擇圖片。這裏須要注意的是,如今因爲瀏覽器的安全機制,默認狀況下,你是不能直接訪問本地圖片地址,例如<img src="d:1.png">這種狀況下在jsp頁面中徹底不能用,除非你對瀏覽器進行設置。可是這麼是不合理的。因此,最好可以上傳圖片到服務器。
SpringMVC中,上傳圖片用到了"commons-fileupload-1.2.2.jar"這個插件,若是要使用圖片上傳,須要注意一下幾點:
1 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 2 <property name="defaultEncoding" value="utf-8" /> 3 <property name="maxUploadSize" value="10485760000" /> 4 <property name="maxInMemorySize" value="40960" /> 5</bean>
上傳完圖片後,這裏不像再去跳轉,因此,這裏我用到了異步上傳,所謂的異步上傳,其實就是異步提交表單。異步提交用獲得了JQuery的異步提交插件:"jquery-form.js";
1 $("#file").change(function(){ 2 3 var options = { 4 url : "upload/image", //這個url是異步提交的路徑,這裏對應的是上傳圖片的路徑 5 dataType : 'json', 6 contentType : "application/json; charset=utf-8", 7 success : function(data) { 8 //上傳成功後,須要進行哪些處理,比方說這裏實現的是顯示圖片 9 10 }; 11 $("#uploadImgForm").ajaxSubmit(options); 12 });
如上所示,就實現了圖片的異步上傳,那麼後臺是如何處理?這裏 是先上傳原圖,而後再用一個旋轉類,將該圖片90度,180度,270度的圖片保存成功。以供旋轉使用,這裏是一個大問題,其實咱們可使用html5的canvas實現,這樣只須要上傳一張圖片呢。
1 @Controller 2 @RequestMapping(value="upload") 3 public class FileUploadController { 4 5 @RequestMapping(value="image") 6 public void fileUpload(MultipartHttpServletRequest request, HttpServletResponse response) { 7 Map<String, Object> resultMap = new HashMap<String, Object>(); 8 String newRealFileName = null; 9 try { 10 MultipartHttpServletRequest multipartRequest = request; 11 CommonsMultipartFile file = (CommonsMultipartFile) multipartRequest.getFile("file"); 12 // 得到文件名: 13 String realFileName = file.getOriginalFilename(); 14 if(file.getSize()/1024>=5*1024){ 15 resultMap.put("status", 1); 16 resultMap.put("message", "圖片不能大於5M"); 17 }else{ 18 System.out.println("得到文件名:" + realFileName); 19 newRealFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + realFileName.substring(realFileName.indexOf(".")); 20 // 獲取路徑 21 String ctxPath = request.getSession().getServletContext().getRealPath("//") + "//temp//"; 22 System.out.println(ctxPath); 23 // 建立文件 24 File dirPath = new File(ctxPath); 25 if (!dirPath.exists()) { 26 dirPath.mkdir(); 27 } 28 File uploadFile = new File(ctxPath +"now"+ newRealFileName); 29 FileCopyUtils.copy(file.getBytes(), uploadFile); 30 // request.setAttribute("files", loadFiles(request)); 31 32 //獲取圖片的寬度和高度 33 InputStream is = new FileInputStream(ctxPath +"now"+ newRealFileName); 34 BufferedImage buff = ImageIO.read(is); 35 int realWidth=buff.getWidth(); 36 int realHeight = buff.getHeight(); 37 is.close(); 38 //接下來將圖片的四個旋轉進行保存 39 //1.向左旋轉90度 40 String onenewRealFileName = "one"+newRealFileName; 41 Thumbnails.of(uploadFile).size(realWidth, realHeight).rotate(90).toFile(new File(ctxPath+onenewRealFileName) 42 ); 43 //2.向左旋轉180度 44 String twonewRealFileName="two"+newRealFileName; 45 Thumbnails.of(uploadFile).size(realWidth, realHeight).rotate(180).toFile(new File(ctxPath+twonewRealFileName) 46 ); 47 //3.向左旋轉270度 48 String threenewRealFileName="thr"+newRealFileName; 49 Thumbnails.of(uploadFile).size(realWidth, realHeight).rotate(270).toFile(new File(ctxPath+threenewRealFileName) 50 ); 51 resultMap.put("status", 0); 52 resultMap.put("fileName", "now"+newRealFileName); 53 } 54 } catch (Exception e) { 55 resultMap.put("status", 1); 56 resultMap.put("message", "圖片上傳出錯"); 57 System.out.println(e); 58 } finally { 59 PrintWriter out = null; 60 try { 61 out = response.getWriter(); 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 //必須設置字符編碼,不然返回json會亂碼 66 response.setContentType("text/html;charset=UTF-8"); 67 out.write(JSONSerializer.toJSON(resultMap).toString()); 68 out.flush(); 69 out.close(); 70 } 71 }
80}
2.圖片的展現
圖片上傳成功後,而後講一個json字符串返回到前端,其中包括了上傳完後圖片的路徑。下面就須要展現圖片。想一下,上傳的圖片大小不一,DIV如何才能包住圖片呢?若是在<img>設置圖片的寬度=div寬度,圖片的高度=div高度,這樣的話,對圖片會進行不等比例拉伸或者縮小,這樣圖片就徹底變形,看上去確定很不美觀。咱們須要作的就是,讓圖片按照原來的比例進行縮放。這樣,圖片看上去沒有拉伸的那種效果。
這種請款下,就得分四種狀況討論:
我是經過margin-top屬性和margin-left屬性來對圖片進行設置,以使其居中。margin-top:(DIV高-圖片高)/2 margin-left:(DIV寬-圖片寬)/2
這種狀況下margin-top:0 margin-left:(DIV寬度-圖片現寬)/2讓圖片居中;
好,既然長寬都固定好了,確定圖片不會溢出DIV,那麼如今就須要在DIV中展現效果,這裏用到了"jquery.Jcrop.min.js"這個插件來實現,圖片加載成功的時候,裁剪框也跟着顯示出來。
也許你不肯意去看懂"jquery.Jcrop.min.js"的代碼,說實話,我也不肯意去看,用法:
這裏的picture_original指的是圖片外面DIV的id ,這裏的resourceImage是圖片的id
這裏的bigImage 和 smallImage指的是頭像預覽兩個DIV框
var cutter = new jQuery.UtrialAvatarCutter( { //主圖片所在容器ID content : "picture_original,resourceImage", //縮略圖配置,ID:所在容器ID;width,height:縮略圖大小 purviews : [{id:"bigImage",width:100,height:100},{id:"smallImage",width:50,height:50}], } );
1 success : function(data) { 2 3 $(".page-left-center").hide(); 4 $(".page-left-center1").show(); 5 var imagepath="temp/"+data.fileName; 6 $("#resourceImage").attr("src", imagepath).load(function(){ 7 //獲取圖片的真實大小: 8 var realWidth; 9 var realHeight; 10 realWidth = parseInt(this.width); 11 realHeight =parseInt(this.height); 12 rWidth=realWidth; 13 rHeight=realHeight; 14 realCompare=parseFloat(realWidth)/parseFloat(realHeight); 15 //讓圖片適應div大小 16 console.info("圖片的真實寬度:"+realWidth); 17 console.info("圖片的真實高度:"+realHeight); 18 if(realWidth<divWidth){ 19 if(realHeight<divHeight){ 20 console.info("進入了寬小,高小"); 21 imageWidthAfter=realWidth; 22 imageHeightAfter=realHeight; 23 shengHeight=parseInt((divHeight-imageHeightAfter)/2); 24 $("#resourceImage").css("margin-top",shengHeight); 25 shengWidth=parseInt((divWidth-imageWidthAfter)/2); 26 $("#resourceImage").css("margin-left",shengWidth); 27 suoCompare=1; 28 }else{ 29 console.info("進入了寬小,高大"); 30 imageHeightAfter=divHeight; 31 imageWidthAfter=imageHeightAfter*realCompare; 32 shengWidth=parseInt((divWidth-imageWidthAfter)/2); 33 $("#resourceImage").css("margin-left",shengWidth); 34 shengHeight=0; 35 suoCompare=parseFloat(realHeight)/parseFloat(divHeight); 36 } 37 }else{ 38 if(realHeight<divHeight){ 39 console.info("進入了寬大,高小"); 40 imageWidthAfter=divWidth; 41 imageHeightAfter=parseFloat(divWidth/parseFloat(realCompare)); 42 shengHeight=parseInt((divHeight-imageHeightAfter)/2); 43 $("#resourceImage").css("margin-top",shengHeight); 44 shengWidth=0; 45 suoCompare=parseFloat(realWidth)/parseFloat(divWidth); 46 }else{ 47 console.info("進入了高大,寬大但處理後不滿"); 48 //剛開始假如高滿寬不滿,那麼,根據高得出寬 49 imageHeightAfter=divHeight; 50 imageWidthAfter=imageHeightAfter*realCompare; 51 //處理完後,寬仍是溢出的話,說明以寬爲基準 52 console.info("處理後的寬度:"+imageWidthAfter); 53 if(imageWidthAfter>divWidth){ 54 console.info("進入到了寬大,高大但高不滿"); 55 imageWidthAfter=divWidth; 56 imageHeightAfter=parseFloat(divWidth/parseFloat(realCompare)); 57 shengHeight=parseInt((divHeight-imageHeightAfter)/2); 58 $("#resourceImage").css("margin-top",shengHeight); 59 shengWidth=0; 60 suoCompare=parseFloat(realWidth)/parseFloat(divWidth); 61 }else{ 62 shengWidth=parseInt((divWidth-imageWidthAfter)/2); 63 $("#resourceImage").css("margin-left",shengWidth); 64 shengHeight=0; 65 suoCompare=parseFloat(realHeight)/parseFloat(divHeight); 66 } 67 } 68 } 69 70 $("#resourceImage").show(); 71 $(".jcrop-holder").remove(); 72 console.info("shengHeight:"+shengHeight); 73 $("#resourceImage").width(imageWidthAfter); 74 $("#resourceImage").height(imageHeightAfter); 75 cutter.init(); 76 $(".jcrop-holder").css("margin-top",shengHeight); 77 $(".jcrop-holder").css("margin-left",shengWidth); 78 $(".jcrop-holder img").css("margin-top","0px"); 79 $(".jcrop-holder img").css("margin-left","0px"); 80 }); 81 $("#rechose").show(); 82 $(".btsave").attr("disabled",false); 83 $(".btsave").addClass("btsaveclick"); 84 } 85 };
3.圖片的旋轉
這塊實現的不是特別理想,前面也說過了,就是剛開始上傳的時候,上傳四張,0度,90度,180度,270度。最近查看了HTML5的canvas,以爲這個挺好的。之後會試着經過HTML5來實現。旋轉的實現很簡單,每點擊的時候,設置一個表示step 而後,經過switch進行判斷,若是switch=0,則設置image的src=0度的圖片,一次日後推。設置完成後,而後經過 cutter.init();從新顯示裁剪框以及圖片!
4.圖片的裁剪
圖片的裁剪原理,其實就是在原有圖片的基礎上,從(x,y)點開始,截取長度爲寬度爲w,高度爲h的區域。
注意:因爲顯示的時候,不讓圖片超出DIV,因此,對圖片進行了縮放,因此一這裏你的x,y,w,h是還原後的。
1 $(".btsave").click(function(){ 2 var data = cutter.submit(); 3 var trueX=parseInt(parseFloat(data.x)*suoCompare); 4 var trueY=parseInt(parseFloat(data.y)*suoCompare); 5 var trueW=parseInt(parseFloat(data.w)*suoCompare); 6 var trueH=parseInt(parseFloat(data.h)*suoCompare); 7 var message=trueX+","+trueY+","+trueW+","+trueH+","+data.s; 8 console.info(message); 9 $("#cutHeader").val(message); 10 $("#formSubmit").submit(); 11});
如上所示,提交到後臺,在後臺進行處理,後臺邏輯以下:
1 @RequestMapping(value="cutImage") 2 public ModelAndView cutImage(HttpServletRequest request, HttpServletResponse response) throws IOException { 3 String message=request.getParameter("header"); 4 int x=Integer.parseInt(message.split(",")[0]); 5 int y=Integer.parseInt(message.split(",")[1]); 6 int w=Integer.parseInt(message.split(",")[2]); 7 int h=Integer.parseInt(message.split(",")[3]); 8 String src=message.split(",")[4].split("\\?")[0]; 9 // 10 // 獲取路徑 11 String ctxPath = request.getSession().getServletContext().getRealPath("//") ; 12 System.out.println(ctxPath); 13 // 建立文件 14 src =ctxPath+"\\"+src; 15 String last=src.substring(src.lastIndexOf (".")); 16 File dirPath = new File(ctxPath+"\\header"); 17 if (!dirPath.exists()) { 18 dirPath.mkdir(); 19 } 20 String dest = ctxPath+"\\header\\"+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+last; 21 String headerurl="header/"+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+last; 22 boolean isSuccess=cutImageHeader(src,dest,x,y,w,h); 23 if(isSuccess){ 24 return new ModelAndView("showHeader","image",headerurl); 25 }else{ 26 return new ModelAndView("changeHeader"); 27 } 28 29 } 30 31 public static boolean cutImageHeader(String src,String dest,int x,int y,int w,int h) throws IOException{ 32 String last=src.substring(src.lastIndexOf (".")+1); 33 System.out.println("*****"+last); 34 Iterator iterator = ImageIO.getImageReadersByFormatName(last); 35 ImageReader reader = (ImageReader)iterator.next(); 36 InputStream in=new FileInputStream(src); 37 ImageInputStream iis = ImageIO.createImageInputStream(in); 38 reader.setInput(iis, true); 39 ImageReadParam param = reader.getDefaultReadParam(); 40 Rectangle rect = new Rectangle(x, y, w,h); 41 System.out.println("x:"+x+";y:"+y+";w:"+w+";h:"+h); 42 param.setSourceRegion(rect); 43 BufferedImage bi = reader.read(0,param); 44 boolean isSuccess=ImageIO.write(bi, last, new File(dest)); 45 return isSuccess; 46 }