SpringMVC+JQuery實現頭像編輯器

1、簡單說明css

  本頭像編輯器主要實現了圖片的上傳、顯示(不溢出父窗口)、旋轉、裁剪功能!html

  1. 圖片的上傳用到的是異步上傳,頁面不進行刷新,原理是經過JQuery的異步提交+SpringMVC的上傳
  2. 上傳完畢後,在顯示的時候,若是圖片的長寬都比父窗口小,則垂直 水平 居中顯示在父窗口中,不然,對圖片按照寬高比進行縮放,直到長寬都不溢出!
  3. 旋轉功能,這塊有待改進!我在上傳一張圖片的時候,直接在後臺將90度,180度,270度的也上傳了,而後,裁剪完成後,保存頭像以後,將不用的都刪除!這兒確實不太現實!這裏推薦用HTML5的canvas實現!
  4. 裁剪功能。用到了JQuery的一個插件。參見區域選擇完成後,會自動返回 x,y,w,h。這裏的x,y,w,h還須要通過處理,由於你前面可能進行了縮小顯示,這裏須要讓x,y,w,h還原到未縮放前的座標。而後,在後臺中,經過這些座標,截取圖片中 (x,y) 寬:w 高:h的圖片!

2、效果圖:前端

  1. 初始化界面

 

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>&nbsp;&nbsp;支持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"這個插件,若是要使用圖片上傳,須要注意一下幾點:

  • 在SpringMVC的配置文件中,添加一下內容
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>
  • 在HTML中,表單的提交中,須要設置'enctype="multipart/form-data" '

上傳完圖片後,這裏不像再去跳轉,因此,這裏我用到了異步上傳,所謂的異步上傳,其實就是異步提交表單。異步提交用獲得了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高度,這樣的話,對圖片會進行不等比例拉伸或者縮小,這樣圖片就徹底變形,看上去確定很不美觀。咱們須要作的就是,讓圖片按照原來的比例進行縮放。這樣,圖片看上去沒有拉伸的那種效果。

這種請款下,就得分四種狀況討論:

  • 圖片的原始寬和高都比DIV的寬和高小,那麼這種狀況下,圖片須要在水平和垂直上居中顯示

我是經過margin-top屬性和margin-left屬性來對圖片進行設置,以使其居中。margin-top:(DIV高-圖片高)/2    margin-left:(DIV寬-圖片寬)/2

  • 圖片的原始寬<DIV的寬,圖片的原始高>DIV的高,這種狀況下,計算圖片的原始寬高比compareImage,而後,讓圖片的高=DIV高度,再根據圖片的原始寬高比,算出如今圖片的寬,也就是圖片縮放的效果;

這種狀況下margin-top:0 margin-left:(DIV寬度-圖片現寬)/2讓圖片居中;

  • 圖片的原始寬>DIV的寬,圖片的原始高<DIV的高,這種狀況下,計算圖片的原始寬高比compareImage,而後,讓圖片的寬=DIV寬,再根據圖片的原始寬高比,算出如今圖片的高,也就是圖片縮放的效果;後面兩種效果圖就不展現了
  • 圖片的原始寬>DIV的寬,圖片的原始高>DIV的高,這種狀況比較複雜,由於你要比較誰最後溢出,例如,由於圖片的寬和高都溢出,因此,若是圖片你的寬==DIV的寬度,那麼按照比例縮放後,你必須保證圖片現高<=DIV的高度。也就是必須保證圖片的寬和高都不溢出。

 好,既然長寬都固定好了,確定圖片不會溢出DIV,那麼如今就須要在DIV中展現效果,這裏用到了"jquery.Jcrop.min.js"這個插件來實現,圖片加載成功的時候,裁剪框也跟着顯示出來。

也許你不肯意去看懂"jquery.Jcrop.min.js"的代碼,說實話,我也不肯意去看,用法:

  • 初始化一個對象,這個對象在個人"jQuery.UtrialAvatarCutter.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}],
  }
);

    

  • 在圖片加載完成的時候,這裏,也就是異步提交完成的時候,進行的處理,在上面異步提交圖片的時候有說明,success()裏面的邏輯代碼沒有寫,下面就是要處理的業務邏輯,也就是設置圖片的寬和高,顯示裁剪框
 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     }
相關文章
相關標籤/搜索