圖片裁剪工具——JCorp

需求:用戶上傳或者修改頭像的時候先將圖片裁剪,固定寬度和高度,這樣在不一樣的情景下顯示的時候不會出現壓縮失真。javascript

中間折騰過的方法:css

1.smartCorp.jshtml

國外一個大神寫的,根據圖像的飽和度裁剪最好看的照片,剛開始覺得很好用的,在官網上下載了源碼,demo跑起來還能夠,可是裁剪成小圖片的時候裁剪不了,項目是Java的,可是demo用的是PHP,我也不會PHP,也沒有運行環境,最後放棄了。前端

2.JS素材網上下載的插件。也是同樣的問題,裁剪成小圖片的後臺代碼運行不了,並且樣式也很差看,仍是選擇放棄。java

3.JCorp.js 這也是國外的開源軟件,第一眼看上去清新大方,有點意思。還有詳盡的使用方法,不錯不錯。可是最核心的裁剪問題依然存在。有博客上用的是後臺的Java代碼裁剪,demo支持直接本地讀取,和寫入,沒有問題,可是放在網頁上,圖片走服務器上傳是很麻煩的一個問題,除了上傳原圖,還要返回裁剪後的圖片base64碼,這樣子顯示是沒問題了 ,可是怎麼上傳到阿里雲服務器又是問題了。找啊找,終於找到一個博客寫的是用前端H5的<canvas>畫布裁剪,不走服務器,很nice。因而乎直接放在項目裏用了,集成好也沒問題,很開心。開心了一分鐘,而後,流文件怎麼上傳到阿里雲服務器呢,翻遍了阿里雲的社區和手冊也沒找到答案。而後簡書上的一篇文章講清楚了要怎麼處理上傳,搬過來,解決好了。最後還有一個問題,如何上傳到網易雲呢?翻了網易雲的開發文檔,用斷點走了幾遍js文件,找到了上傳的文件格式,一遍一遍的試,最後也搞好了。超級超級開心的。如下是實現代碼:jquery

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!doctype html>  
<html>  
<head>  
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>  
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/>  
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>  
  <meta name="description" id="description1" content="1">  
  <meta name="renderer" content="webkit">  
  <meta name="format-detection" content="telephone=no">  
  <title>圖片上傳</title>  
  
  
    <style type="text/css">  
    
    .jcrop-holder {  
        direction: ltr;  
        text-align: center;  
        margin: 0 auto;  
        /* IE10 touch compatibility */  
        -ms-touch-action: none;  
    }  
        /* Selection Border */  
    .jcrop-vline,  
    .jcrop-hline {  
        background: #ffffff url("Jcrop.gif");  
        font-size: 0;  
        position: absolute;  
    }  
    .jcrop-vline {  
        height: 100%;  
        width: 1px !important;  
    }  
    .jcrop-vline.right {  
        right: 0;  
    }  
    .jcrop-hline {  
        height: 1px !important;  
        width: 100%;  
    }  
    .jcrop-hline.bottom {  
        bottom: 0;  
    }  
        /* Invisible click targets */  
    .jcrop-tracker {  
        height: 100%;  
        width: 100%;  
        /* "turn off" link highlight */  
        -webkit-tap-highlight-color: transparent;  
        /* disable callout, image save panel */  
        -webkit-touch-callout: none;  
        /* disable cut copy paste */  
        -webkit-user-select: none;  
    }  
        /* Selection Handles */  
    .jcrop-handle {  
        background-color: #333333;  
        border: 1px #eeeeee solid;  
        width: 7px;  
        height: 7px;  
        font-size: 1px;  
    }  
    .jcrop-handle.ord-n {  
        left: 50%;  
        margin-left: -4px;  
        margin-top: -4px;  
        top: 0;  
    }  
    .jcrop-handle.ord-s {  
        bottom: 0;  
        left: 50%;  
        margin-bottom: -4px;  
        margin-left: -4px;  
    }  
    .jcrop-handle.ord-e {  
        margin-right: -4px;  
        margin-top: -4px;  
        right: 0;  
        top: 50%;  
    }  
    .jcrop-handle.ord-w {  
        left: 0;  
        margin-left: -4px;  
        margin-top: -4px;  
        top: 50%;  
    }  
    .jcrop-handle.ord-nw {  
        left: 0;  
        margin-left: -4px;  
        margin-top: -4px;  
        top: 0;  
    }  
    .jcrop-handle.ord-ne {  
        margin-right: -4px;  
        margin-top: -4px;  
        right: 0;  
        top: 0;  
    }  
    .jcrop-handle.ord-se {  
        bottom: 0;  
        margin-bottom: -4px;  
        margin-right: -4px;  
        right: 0;  
    }  
    .jcrop-handle.ord-sw {  
        bottom: 0;  
        left: 0;  
        margin-bottom: -4px;  
        margin-left: -4px;  
    }  
        /* Dragbars */  
    .jcrop-dragbar.ord-n,  
    .jcrop-dragbar.ord-s {  
        height: 7px;  
        width: 100%;  
    }  
    .jcrop-dragbar.ord-e,  
    .jcrop-dragbar.ord-w {  
        height: 100%;  
        width: 7px;  
    }  
    .jcrop-dragbar.ord-n {  
        margin-top: -4px;  
    }  
    .jcrop-dragbar.ord-s {  
        bottom: 0;  
        margin-bottom: -4px;  
    }  
    .jcrop-dragbar.ord-e {  
        margin-right: -4px;  
        right: 0;  
    }  
    .jcrop-dragbar.ord-w {  
        margin-left: -4px;  
    }  
        /* The "jcrop-light" class/extension */  
    .jcrop-light .jcrop-vline,  
    .jcrop-light .jcrop-hline {  
        background: #ffffff;  
        filter: alpha(opacity=70) !important;  
        opacity: .70!important;  
    }  
    .jcrop-light .jcrop-handle {  
        -moz-border-radius: 3px;  
        -webkit-border-radius: 3px;  
        background-color: #000000;  
        border-color: #ffffff;  
        border-radius: 3px;  
    }  
        /* The "jcrop-dark" class/extension */  
    .jcrop-dark .jcrop-vline,  
    .jcrop-dark .jcrop-hline {  
        background: #000000;  
        filter: alpha(opacity=70) !important;  
        opacity: 0.7 !important;  
    }  
    .jcrop-dark .jcrop-handle {  
        -moz-border-radius: 3px;  
        -webkit-border-radius: 3px;  
        background-color: #ffffff;  
        border-color: #000000;  
        border-radius: 3px;  
    }  
        /* Simple macro to turn off the antlines */  
    .solid-line .jcrop-vline,  
    .solid-line .jcrop-hline {  
        background: #ffffff;  
    }  
        /* Fix for twitter bootstrap et al. */  
    .jcrop-holder img,  
    img.jcrop-preview {  
        max-width: none;  
    }  
        .uploadPics {  
            position: relative;  
            width: 380px;  
            background-color: #fff;  
            height: 460px;  
            overflow: hidden;  
        }  
  
        .uploadPics > img {  
            position: absolute;  
            top: 20px;  
            right: 10px;  
            cursor: pointer;  
        }  
  
        .uploadPics .picTil {  
            padding: 20px;  
            font-size: 16px;  
            color: #323232;  
            border-bottom: 1px solid #f3f3f3;  
        }  
  
        .uploadPics .picCont {  
            margin: 20px;  
            padding: 15px;  
            width: 300px;  
            height: 337px;  
            background-color: #f2f2f5;  
        }  
  
        .uploadPics .picCont > p {  
            margin-top: 20px;  
            text-align: center;  
        }  
  
  
        .uploadPics .picFooter {  
            text-align: center;  
        }  
  
        .uploadPics .picFooter{  
            display: inline-block;  
            margin: 20px;  
            width: 130px;  
            height: 35px;  
            font-size: 18px;  
            line-height: 35px;  
            color: #fff;  
            border-radius: 5px;  
            cursor: pointer;  
        }  
  
        .uploadPics .picFooter .upload {  
            background-color: #aaa;  
        }  
  
        .uploadPics .picFooter .confirm {  
            background-color: #ed2828;  
        }  
        #myCan{  
            position: absolute;  
            top: 86px;  
            right: 110px;  
        } 
        .info{
        	 position: absolute;  
            top: 16px;  
            right: 196px;  
        }
    </style>  
    <link rel="stylesheet" href="<%=request.getContextPath()%>/Jcrop/css/jquery.Jcrop.css" type="text/css" />
    <script type="text/javascript" src="<%=request.getContextPath()%>/Jcrop/js/jquery.Jcrop.js"></script>
</head>  
<body>  
<div id="showbg" style="display: none;"> 
<div class="uploadPics">  
    <div class="picCont" style="width:300px;height:300px;margin:20px auto 0;padding:0;" >  
        <div id=imgfield  style=overflow:hidden;width:100%;height:100% ></div>  
    </div>  
    <div class="picFooter">  
        <input type="file" accept=".jpg,.jpeg,.png,.gif" id="fileimg" name="fileimg" style="display:none" onchange="imgchange()" />  
        <span class="layui-btn layui-btn-sm"  onclick="getimg()">上傳原圖</span>  
        <!-- <span class="btn confirm" onclick="subform()">確認</span>   -->
    </div>  
  
</div> 
<div class="info">裁剪後圖片:<br>圖片大小:200 × 200</div>
<canvas id="myCan" width="200" height="200"></canvas>   
</div>  
  
</body>  

  
<script type="text/javascript">  
	//上傳的文件名
	var fileName ="";
//	var nim = '';
    function subform() {  
  
        if($("#imgfield").html()){  
        	var ossurl = "";
            //獲取裁剪完後的base64圖片url,轉換爲blob  
        	var urlData=document.getElementById("myCan").toDataURL();  
        	var blob = dataURLtoBlob(urlData);  
            // blob轉arrayBuffer
            var reader = new FileReader();
            reader.readAsArrayBuffer(blob);
            reader.onload = function (event) {
           	var opts = {
             		url : "web?module=stwmgr&action=Advertisement&method=getOSSSecurityToken&tokenId=<%=request.getParameter("tokenId")%>",
             		type : "POST",
             		processData : false,
             		contentType : false,
             		dataType : "json",
             		async:false,
             		success : function(token) {
             			var client = new OSS.Wrapper({
             						accessKeyId : token.accessKeyId,//key
             						accessKeySecret : token.accessKeySecret,//密碼、
             						stsToken : token.securityToken,
             						region : token.ossRegion,//阿里雲服務器地址
             						bucket : token.ossBucket,//上傳的到的文件夾
             						secure:true
             					});
             			var key = "stw_mgr/images/portrait_images/" + getCurrentDate() + getExtension(fileName);
             			//arrayBuffer轉buffer
             			var buffer = new OSS.Buffer(event.target.result);
             			//上傳接口改成put
             			client.put(key, buffer).then(function(result) {
             				console.log(result);
          					var url = client.signatureUrl(key);
          					$("input[name='portraitUri']").val(key);
          					$("#portraitImage").attr("src", url);
             				console.log(url);
             				ossurl = url;
    					}).catch(function(err) {
    						console.log(err.message);
    					});
             		}
            };
            $.ajax(opts);
        }
       // uploadTitleImage(blob);          //網易雲信上傳
        nim.sendFile({
       	    scene: 'p2p',
       	    to: 'account',
       	    type: 'image',
       	 	blob: blob,
       	 //	wxFilePath: neteaseFile,
       	    beginupload: function(upload) {
       	        // - 若是開發者傳入 fileInput, 在此回調以前不能修改 fileInput
       	        // - 在此回調以後能夠取消圖片上傳, 此回調會接收一個參數 `upload`, 調用 `upload.abort();` 來取消文件上傳
       	    },
       	    uploadprogress: function(obj) {
       	        console.log('文件總大小: ' + obj.total + 'bytes');
       	        console.log('已經上傳的大小: ' + obj.loaded + 'bytes');
       	        console.log('上傳進度: ' + obj.percentage);
       	        console.log('上傳進度文本: ' + obj.percentageText);
       	    },
       	    uploaddone: function(error, file) {
       	        console.log(file);
       	        $('#neteaseUri').val(file.url);
       	        console.log('上傳' + (!error?'成功':'失敗'));
       	    }
       	});
        }  
    }  
  
  
    function getimg() {  
  
        $("#fileimg").click();  
  
    }  
    function imgchange() {  
  
        var localimg = $("#fileimg").get(0).files[0];  
  
        if(!localimg){  
            return;  
        }  
  
        fileName = localimg.name;  
        var fileSize = localimg.size;  
        var fileType=fileName.substring(fileName.lastIndexOf('.'),fileName.length).toLowerCase();  
        if(fileType!='.gif' && fileType!='.jpeg' && fileType!='.png' && fileType!='.jpg')  
        {  
            alert("上傳失敗,請上傳jpg,jpeg,png格式的圖片");  
            return;  
        }  
  
        var size=10*1024*1024;  
        if(fileSize>size){  
            alert("上傳失敗,請上傳10MB之內的圖片。");  
            return;  
        }  
  
        var reader=new FileReader();  
        //將文件讀取爲DataURL  
        reader.readAsDataURL(localimg);  
        reader.onload= function (e) {  
            var localimghtml = '<img id="cropbox" src="' +  e.target.result + '" >';  
            $("#imgfield").html(localimghtml);  
            initJcrop();  
        };  
  
    }  
  
  
    function initJcrop(){  
        $('#cropbox').Jcrop({  
            onSelect: updateCoords,  
            aspectRatio: 1,  
            boxWidth: 300,  
            boxHeight: 300  
        }, function () {  
  
            //圖片實際尺寸  
            var bb = this.getBounds();  
            var bWidth= Number(bb[0]) / 2;  
            var bHeight= Number(bb[1]) / 2;  
  
            this.setSelect([0, 0, bWidth,bHeight]);  
  
  
            var ss = this.getWidgetSize();  
            var aheight = (300 - Number(ss[1])) / 2 + "px";  
            $(".jcrop-holder").css("margin-top", aheight);  
  
  
        });  
    }  
    function updateCoords(c){  
//      console.log(c);  
        var img=document.getElementById("cropbox");  
        var ctx=document.getElementById("myCan").getContext("2d");  
  
        //img,開始剪切的x,Y座標寬高,放置圖像的x,y座標寬高。  
        ctx.drawImage(img,c.x,c.y, c.w, c.h,0,0,200,200);  
    }  
  
  
  
    //**dataURL to blob**  
    function dataURLtoBlob(dataurl) {  
        var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],  
                bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);  
        while (n--) {  
            u8arr[n] = bstr.charCodeAt(n);  
        }  
        return new Blob([u8arr], { type: mime });  
    }  
  
</script>  
  
  
</html>
//點擊頭像框觸發事件
$("#portraitImage").click(function(){
	 var c=document.getElementById("myCan");  
	 var cxt=c.getContext("2d");  
	 cxt.clearRect(0,0,c.width,c.height); 
	var porsrc = this.src;
	var orginimg = '<img id="cropbox" src="" crossorigin="Anonymous" >';  		//" crossorigin="Anonymous"
	//var image = new Image();
	//image.setAttribute("crossOrigin",'Anonymous')
	//image.crossOrigin = "Anonymous";
	//image.src = porsrc;
	$("#imgfield").html(orginimg);         //把原有的頭像圖片添加到可編輯框裏
	$("#cropbox").attr("src",porsrc);
  //初始化插件方法
    initJcrop(); 
	layer.open({
		  type: 1,
		  scrollbar: false,
		  title: ['頭像裁剪框', 'font-size:16px;'],
		  area: ['800px', '500px'],
		  btn: ['保存'],
		  tipsMore: true,
		  content: $("#showbg"),
		  yes: function(index, layero){
			  subform();
			  $('#showbg').css('display','none');
			  layer.closeAll();
		  },
		  cancel: function(){ 
			 $('#showbg').css('display','none');
		   }
		});
	});

最後想了一個改進的地方,就是以前已經有頭像的用戶,可能會複用之前的頭像,因此點擊修改的時候要把原來的圖片帶到圖片處理框裏。這裏遇到了圖片的跨越請求問題。解決辦法是在img標籤添加一個屬性:crossorigin="Anonymous"。web

先後大概5天的時間作了這麼一個小小的功能,收穫了圖像處理的知識,雖然理解上並無很深,可是能運用起來,也蠻有成就感的了。記錄下探索的歷程。望更進一步。ajax

JCrop官網地址:http://deepliquid.com/content/Jcrop_Download.htmlchrome

相關文章
相關標籤/搜索