最近公司编辑在发布新闻的时候遇到一个问题,编辑后台提供的原有的图片裁剪功能在移动端和一些特定类型的显示时达不到具体的要求。最后去深究发现咱们的服务器对上传上来的图片进行了一次裁剪,为了减少图片大小对它进行了不一样比例,不一样尺寸的裁剪。但这种裁剪会丢失一些图片上的信息,对于咱们这种信息传递的公司确定是不但愿的。如何解决,有以下方案: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来处理,而且要在已成型的系统中迎合原有的后台架构。后端的支持极其的少,因此几乎是去了解后端的业务逻辑,而后完成的功能。浏览器