一、图片的选择
二、图片从手机相机选择、拍照
三、图片选择后的裁剪
四、图片在页面的显示效果
五、图片的删除
六、base64图片转化为file类型的文件
七、图片的上传vue
首先安装cropperjs 和exif-js 裁剪依赖这两个包
cnpm install --save cropperjs exif-jsios
图片选择后的裁剪web
initilize(opt) { let self = this; this.options = opt; //建立dom this.createElement(); this.resultObj = opt.resultObj; //初始化裁剪对象 this.cropper = new Cropper(this.preview, { aspectRatio: opt.aspectWithRatio / opt.aspectHeightRatio, autoCropArea: opt.autoCropArea || 0.8, viewMode: 2, guides: true, cropBoxResizable: true, //是否经过拖动来调整剪裁框的大小 cropBoxMovable: true, //是否经过拖拽来移动剪裁框。 dragCrop: false, dragMode: "move", //‘crop’: 能够产生一个新的裁剪框3 ‘move’: 只能够移动3 ‘none’: 什么也不处理 center: true, zoomable: true, //是否容许放大图像。 zoomOnTouch: true, //是否能够经过拖动触摸来放大图像。 scalable: true, // minCropBoxHeight: 750, // minCropBoxWidth: 750, background: false, checkOrientation: true, checkCrossOrigin: true, zoomable: false, zoomOnWheel: false, center: false, toggleDragModeOnDblclick: false, ready: function() { if (opt.aspectRatio == "Free") { let cropBox = self.cropper.cropBox; cropBox.querySelector("span.cropper-view-box").style.outline = "none"; self.cropper.disable(); } } }); }, //建立一些必要的DOM,用于图片裁剪 createElement() { //初始化图片为空对象 this.preview = null; let str = '<div><img id="clip_image" src="originUrl"></div><button type="button" id="cancel_clip">取消</button><button type="button" id="clip_button">肯定</button>'; str += '<div class="crop_loading"><div class="crop_content"><div class="crop_text">图片修剪中...</div></div></div>'; str += '<div class="crop_success"><div class="crop_success_text">上传成功</div></div></div>'; let body = document.getElementsByTagName("body")[0]; this.reagion = document.createElement("div"); this.reagion.id = "clip_container"; this.reagion.className = "container"; this.reagion.innerHTML = str; body.appendChild(this.reagion); this.preview = document.getElementById("clip_image"); //绑定一些方法 this.initFunction(); }, //初始化一些函数绑定 initFunction() { let self = this; this.clickBtn = document.getElementById("clip_button"); this.cancelBtn = document.getElementById("cancel_clip"); //肯定事件 this.addEvent(this.clickBtn, "click", function() { self.crop(); }); //取消事件 this.addEvent(this.cancelBtn, "click", function() { self.destoried(); }); //清空input的值 this.addEvent(this.fileObj, "click", function() { this.value = ""; }); }, //外部接口,用于input['file']对象change时的调用 clip(e, opt) { let self = this; this.fileObj = e.srcElement; let files = e.target.files || e.dataTransfer.files; if (!files.length) return false; //不是图片直接返回 //调用初始化方法 this.initilize(opt); //获取图片文件资源 this.picValue = files[0]; //调用方法转成url格式 this.originUrl = this.getObjectURL(this.picValue); //每次替换图片要从新获得新的url if (this.cropper) { this.cropper.replace(this.originUrl); } }, //图片转码方法 getObjectURL(file) { let url = null; if (window.createObjectURL != undefined) { // basic url = window.createObjectURL(file); } else if (window.URL != undefined) { // mozilla(firefox) url = window.URL.createObjectURL(file); } else if (window.webkitURL != undefined) { // webkit or chrome url = window.webkitURL.createObjectURL(file); } return url; }, //点击肯定进行裁剪 crop() { let self = this; let image = new Image(); let croppedCanvas; let roundedCanvas; // Crop document.querySelector(".crop_loading").style.display = "block"; setTimeout(function() { croppedCanvas = self.cropper.getCroppedCanvas(); // Round roundedCanvas = self.getRoundedCanvas(croppedCanvas); let imgData = roundedCanvas.toDataURL(); image.src = imgData; //判断图片是否大于100k,不大于直接上传,反之压缩 if (imgData.length < 100 * 1024) { // self.resultObj.src = imgData; //图片上传 self.postImg(imgData); } else { image.onload = function() { //压缩处理 let data = self.compress(image, self.Orientation); // self.resultObj.src = data; //图片上传 self.postImg(data); }; } }, 20); }, //获取裁剪图片资源 getRoundedCanvas(sourceCanvas) { let canvas = document.createElement("canvas"); let context = canvas.getContext("2d"); let width = sourceCanvas.width; let height = sourceCanvas.height; canvas.width = width; canvas.height = height; context.imageSmoothingEnabled = true; context.drawImage(sourceCanvas, 0, 0, width, height); context.globalCompositeOperation = "destination-in"; context.beginPath(); context.rect(0, 0, width, height); context.fill(); return canvas; }, //销毁原来的对象 destoried() { let self = this; //移除事件 this.removeEvent(this.clickBtn, "click", null); this.removeEvent(this.cancelBtn, "click", null); this.removeEvent(this.fileObj, "click", null); //移除裁剪框 this.reagion.parentNode.removeChild(this.reagion); //销毁裁剪对象 this.cropper.destroy(); this.cropper = null; }, //图片上传 postImg(imageData) { console.log(imageData); this.$emit("callback", imageData); //这边写图片的上传 let self = this; self.destoried(); this.imgList.push(imageData); }, //图片旋转 rotateImg(img, direction, canvas) { //最小与最大旋转方向,图片旋转4次后回到原方向 const min_step = 0; const max_step = 3; if (img == null) return; //img的高度和宽度不能在img元素隐藏后获取,不然会出错 let height = img.height; let width = img.width; let step = 2; if (step == null) { step = min_step; } if (direction == "right") { step++; //旋转到原位置,即超过最大值 step > max_step && (step = min_step); } else { step--; step < min_step && (step = max_step); } //旋转角度以弧度值为参数 let degree = (step * 90 * Math.PI) / 180; let ctx = canvas.getContext("2d"); switch (step) { case 0: canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0); break; case 1: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, 0, -height); break; case 2: canvas.width = width; canvas.height = height; ctx.rotate(degree); ctx.drawImage(img, -width, -height); break; case 3: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, -width, 0); break; } }, //图片压缩 compress(img, Orientation) { let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); //瓦片canvas let tCanvas = document.createElement("canvas"); let tctx = tCanvas.getContext("2d"); let initSize = img.src.length; let width = img.width; let height = img.height; //若是图片大于四百万像素,计算压缩比并将大小压至400万如下 let ratio; if ((ratio = (width * height) / 4000000) > 1) { console.log("大于400万像素"); ratio = Math.sqrt(ratio); width /= ratio; height /= ratio; } else { ratio = 1; } canvas.width = width; canvas.height = height; // 铺底色 ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, canvas.width, canvas.height); //若是图片像素大于100万则使用瓦片绘制 let count; if ((count = (width * height) / 1000000) > 1) { count = ~~(Math.sqrt(count) + 1); //计算要分红多少块瓦片 // 计算每块瓦片的宽和高 let nw = ~~(width / count); let nh = ~~(height / count); tCanvas.width = nw; tCanvas.height = nh; for (let i = 0; i < count; i++) { for (let j = 0; j < count; j++) { tctx.drawImage( img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh ); ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, width, height); } //修复ios上传图片的时候 被旋转的问题 if (Orientation != "" && Orientation != 1) { switch (Orientation) { case 6: //须要顺时针(向左)90度旋转 this.rotateImg(img, "left", canvas); break; case 8: //须要逆时针(向右)90度旋转 this.rotateImg(img, "right", canvas); break; case 3: //须要180度旋转 this.rotateImg(img, "right", canvas); //转两次 this.rotateImg(img, "right", canvas); break; } } //进行最小压缩 let ndata = canvas.toDataURL("image/png", 0.1); console.log("压缩前:" + initSize); console.log("压缩后:" + ndata.length); console.log( "压缩率:" + ~~((100 * (initSize - ndata.length)) / initSize) + "%" ); tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; return ndata; }, //添加事件 addEvent(obj, type, fn) { if (obj.addEventListener) { obj.addEventListener(type, fn, false); } else { obj.attachEvent("on" + type, fn); } }, //移除事件 removeEvent(obj, type, fn) { if (obj.removeEventListener) { obj.removeEventListener(type, fn, false); } else { obj.detachEvent("on" + type, fn); } }
图片在页面的显示效果
暂无
图片的删除
base64图片转化为file类型的文件
bytes = window.atob(this.imgList[i].split(',')[1]);chrome
var array = []; array.push(bytes.charCodeAt(j)); var blob = new Blob([new Uint8Array(array)], {type: 'image/jpeg'}); form.append("file", blob, Date.now() + '.jpg');
图片的上传
暂无npm
最终效果:
图片裁剪参考:https://blog.csdn.net/ch83430...canvas
ps: 须要源码的请联系我(请尊重一下别人的劳动成果,源码须要付费10 哦。):微信