最近公司編輯在發佈新聞的時候遇到一個問題,編輯後臺提供的原有的圖片裁剪功能在移動端和一些特定類型的顯示時達不到具體的要求。最後去深究發現咱們的服務器對上傳上來的圖片進行了一次裁剪,爲了減少圖片大小對它進行了不一樣比例,不一樣尺寸的裁剪。但這種裁剪會丟失一些圖片上的信息,對於咱們這種信息傳遞的公司確定是不但願的。如何解決,有以下方案:javascript
因此基於上面所說的這些,這個功能放在後端顯然不現實。爲了一個小的功能改變現有的業務邏輯,因此就想放在前端先把圖片裁剪好,而後上傳服務器。服務器的裁剪後最後選擇最全的那一張,顯然服務器如今也是這麼作的。html
首先想到的是有沒有這樣的插件可使用,幸運的是有這樣的一個優秀插件可使用cropper.js.翻看了它的文檔,發現也是很好使用的。前端
<!-- Wrap the image or canvas element with a block element (container) --> <div> <img id="image" src="picture.jpg"> </div>
$('#image').cropper({ aspectRatio: 16 / 9, crop: function(e) { // Output the result data for cropping image. console.log(e.x); console.log(e.y); console.log(e.width); console.log(e.height); console.log(e.rotate); console.log(e.scaleX); console.log(e.scaleY); } });
可是細細研究了下發現它是使用了canvas進行的圖片裁剪,因此只有在現代瀏覽器才能支持。諮詢了下需求,慶幸的是咱們的系統不考慮兼容性。那就好辦了,既然已有了好的輪子爲何不用。
以前咱們的圖片上傳是這樣的,很是簡陋。就根本是個按鈕上傳圖片,沒有什麼交互體驗。
圖片按鈕以下,
選擇圖片後以下,
這樣的確定是不行的,必須首先將圖片呈現出來。可是javascript操做在瀏覽器環境中讀取文件確定是很困難的。window.URL.createObjectURL() 靜態方法會建立一個 DOMString,其中包含一個表示參數中給出的對象的URL。這個 URL 的生命週期和建立它的窗口中的 document 綁定。這個新的URL 對象表示指定的 File 對象或 Blob 對象。這樣就能夠對本地上傳圖片進行操做了。java
//local image change function setImagePreview(avalue) { var docObj=document.getElementById("doc"), imgObjPreview=document.getElementById("image"), img_src; if(docObj.files[0].size/1024/1024 > 1.2) { alert('請選擇小於1.2M圖片'); return false; } if(docObj.files &&docObj.files[0]) { //火狐7以上版本不能用上面的getAsDataURL()方式獲取,須要一下方式 img_src = window.URL.createObjectURL(docObj.files[0]); imgObjPreview.src = img_src; } else { //IE下,使用濾鏡 docObj.select(); var imgSrc = document.selection.createRange().text; var localImagId = document.getElementById("localImag"); //必須設置初始大小 localImagId.style.width = "150px"; localImagId.style.height = "180px"; //圖片異常的捕捉,防止用戶修改後綴來僞造圖片 try { localImagId.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)"; localImagId.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = imgSrc; img_src = imgSrc; } catch(e) { alert("您上傳的圖片格式不正確,請從新選擇!"); return false; } imgObjPreview.style.display = 'none'; document.selection.empty(); } return img_src; }
選擇圖片後引入cropper.js,效果以下
ajax
代碼以下:canvas
/*init cropper*/ function cropperContainer() { var cropperContainer = $('#image').cropper({ aspectRatio: 4/3, viewMode: 1, autoCropArea: 1, cropBoxResizable:true }); } //init cropper cropperContainer(); $('#cropper').on('click', function() { var croppedCanvas, roundedCanvas; /*if (!croppable) { return false; }*/ $('.cropper-text').show(); // true croppedCanvas = $('#image').cropper('getCroppedCanvas'); // Round roundedCanvas = getRoundedCanvas(croppedCanvas); //true var base64 = roundedCanvas.toDataURL(); // var imgData = base64.split(',')[1]; // imgData = window.atob(imgData); // var resultData = new Uint8Array(imgData.length); // for(var i = 0; i < imgData.length; i++) { // resultData[i] = imgData.charCodeAt(i); // } // var blob = new Blob([resultData], {type:'image/png'}); // Show $('#results').html('<img src="' + base64 + '">'); $('#save-btn').click(function() { window.opener._getImageObj(base64); window.close(); }); });
最終獲得的是一個base64圖片,經過ajax提交給服務器彷佛會由於base64太大提交不成功。而後我作了個很傻的事情,將base64轉化爲blob轉化爲文件後端
//base64 to blob then to file function to_blob(base64) { var imgData = base64.split(',')[1]; imgData = window.atob(imgData); var resultData = new Uint8Array(imgData.length); for(var i = 0; i < imgData.length; i++) { resultData[i] = imgData.charCodeAt(i); } //convert var blob = new Blob([resultData], {type:'image/png'}); var file = new File([blob], 'upload_'+Date.now()+'.png', {type: 'image/png', lastModified: Date.now()}); return file; }
最後又將整個表單經過FormData對象轉化爲javascript對象提交到後臺。
裁剪後如圖,
跨域
其實在我說來彷佛沒什麼技術含量,可是在具體的生產環境中將插件集成上去也是遇到了不少麻煩。好比當處理跨域的用document.domain來處理,而且要在已成型的系統中迎合原有的後臺架構。後端的支持極其的少,因此幾乎是去了解後端的業務邏輯,而後完成的功能。瀏覽器