解决多图片压缩上传和iOS端图片上传选择90度的问题

逻辑思路:
1、监听input文件值的change事件
2、获取文件列表
3、使用FileReader()函数读取图片信息,并转为base64格式
4、根据预设的阀值,判断是否压缩
5、如果不压缩,将图片转为blob格式,使用FormData()函数,上传图片
6、如果压缩图片,使用canvas重新绘制图片,根据需要,选择是否使用瓦片canvas
7、使用Exif.js,获取图片方向信息,确定是否需要使用canvas的rotate()函数进行旋转图片
8、上传图片

自定义图片上传组件:

//推荐

//不推荐使用下面这种方法,该形式在Chrome浏览器中,选择文件弹框会滞留一段时间才弹出

引入exif.js

import Exif from 'exif-js'

具体实现

upload(e) {
				let files = e.target.files || e.dataTransfer.files;
				if (!files.length) return;
				this.picValue = files[0];
				this.imgPreview(this.picValue);
			},

			//图片预览、处理、上传
			imgPreview(file) {
				let self = this;
				let Orientation;
				//去获取拍照时的信息,解决拍出来的照片旋转问题
				Exif.getData(file, function() {
					Orientation = Exif.getTag(this, 'Orientation');
				});
				// alert(Orientation,'console.log(Orientation)');
				debugger
				// 看支持不支持FileReader
				if (!file || !window.FileReader) return;

				// alert(file);
				// 创建一个reader
				let reader = new FileReader();
				// 将图片2将转成 base64 格式
				reader.readAsDataURL(file);
				// 读取成功后的回调
				reader.onloadend = function() {

					let result = this.result;
					let img = new Image();

					img.onload = function() {
						let data = self.compress(img, Orientation);
						/*self.headerImage = data;  */
						var blob = self.dataURItoBlob(data);
						var fd = new FormData();
						fd.append("file", blob, 'image.png');
						fd.fileName = blob;
						console.log(fd, 'fd')
						axios.post('/sunrise-gateway/oss/ossUpload', fd).then((res) => {
							return res
						}).then((res) => {
							console.log(res, 'res')
							if (res.data.code == '000000') {
								self.list.push(...res.data.data);
								self.objUrl = res.data.data[0];
								self.picNum++;
							} else {
								MessageBox.alert('上传失败0');
							}
							Indicator.close();
						}).catch((err) => {
							Indicator.close();
							MessageBox.alert('上传失败1');
						})
						// alert(blob)
					}
					img.src = result;
				}
			},

			//base64转blob
			dataURItoBlob(base64Data) {
				var byteString;
				if (base64Data.split(',')[0].indexOf('base64') >= 0) {
					byteString = atob(base64Data.split(',')[1]);
				} else {
					byteString = unescape(base64Data.split(',')[1]);
				}
				var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0];
				var ia = new Uint8Array(byteString.length);
				for (var i = 0; i < byteString.length; i++) {
					ia[i] = byteString.charCodeAt(i);
				}
				return new Blob([ia], {
					type: mimeString
				});
			},

			//图片旋转
			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) {
						// console.log('超过100W像素');
						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/jpeg', 0.1);
					tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
					return ndata;
				},

备注:
canvas.toDataURL() 方法返回一个包含图片展示的 data URI 。可以使用 type 参数其类型,默认为 image/png 格式。图片的分辨率为96dpi。

在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。

返回值:包含dataURI的DOMString。

DataURI格式:data:[][;base64],。其中mediatype声明了文件类型,遵循MIME规则,如“image/png”、“text/plain”;之后是编码类型,这里我们只涉及 base64;紧接着就是文件编码后的内容了。

URI(Uniform Resource Identifier):统一资源标识符,服务器资源名被称为统一资源标识符.如:img src='images/image.png'

URL(Uniform Resource Locator):统一资源定位符,描述了一台特定服务器上某资源的特定位置。如:

img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAYAAAArdgcFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABSUlEQVQ4Ee1VPUsDQRB9s3dBRCRNQvCjkDQW/hJ/gb9AOwWDoIXFgYXYXGP+hYW1/gIr7WzsE8VGxZBcwt04dznCJWw2twtWutXMmzdvlrd7t4SZVbvi1ZihZuCFqT9A/B7Qd5FI44RpPcQpE1oC1IsEq5jRBeGyc0zXaV8mvhbyOREurIRMZMZhp0VthYB9mXBi4jrUztIev1bNbKg6CMxvIWwg5GWVDOHNZ7lX6l/wrG+Fzbh/ca1bf9QWBhKtHznobgtjKF92ZBL3TUWpRbK7LhiVCY8kY3xK/iTiexNcEywSXxKBrfHvrdBN2JRsp4BoQ3dbtHLT4K+JqxWw8vr4YDaf+vR+SmXRWw99lT9N96VaypIYtwgoyWyJRtiX3T+X7TXxROcxGeAo5chlyNcBVxrb2JVpTUHsz4IQi/DL6wPucENxqvoDx69PXP8OKn4AAAAASUVORK5CYII='/

你可能感兴趣的:(JavaScript)