JS实现图片压缩,兼容ios,

代码参考的七牛官方compress.js(https://github.com/qiniu/js-sdk/blob/master/src/compress.js)

但是七牛官方的压缩,在ios下我试着是有问题的,压缩完后,图片只显示一小截,然后大片空白,

于是参考他们的代码,重新写了一下,也精简了一下,测试ios下也正常了。

其中七牛的下面这段代码我没看懂,所以就跳过了,在我的代码里没有处理,但我也怀疑就是下面这段代码让该插件在ios下出现问题。

下面是我的代码:

HTML:

<body>
	<input type="file" name="" onchange="upload(this.files[0])" id="" />
	
	<img src="" alt="" id="img" style="width:400px; "/>
</body>

 

JS: 依赖 exis.js 需要自己下载

<script src="wechat/assets/js/exif.js"></script>
<script>
/**
 * 压缩类
 * 构造函数,需要传两个参数
 * 一个是file,要压缩的图片文件
 * 另一个是压缩参数{maxWidth:压缩后最大宽度,maxHeight:压缩后最大高度,quality:压缩质量,取值0-1}
 */
class Compress{
		
	constructor(file, option){
		this.file = file;
		this.config = Object.assign({
			quality : 0.9
		},option);
		
		return this.process();
	}
	
	//支持压缩的格式
	get mimeTypes()  {
		return {
			PNG : "image/png",
			JPEG : "image/jpeg",
			WEBP : "image/webp",
			BMP : "image/bmp"	
		}
	};
	
	get supportTypes(){
		return Object.keys(this.mimeTypes).map(type => this.mimeTypes[type]);
	}
	//判断格式是否支持
	isSupportedType (type){
		return this.supportTypes.includes(type);
	}
	
	process(){
		this.outputType = this.file.type;
		if(this.isSupportedType(this.file.type) == false){
			return Promise.reject(new Error("不支持该文件类型"));
		}
		
		return this.getOriginImage().then(img => {
			return this.getCanvas(img);
		}).then(canvas => {
			let scale = 1;
			
			if(this.config.maxWidth){
				scale = Math.min(1, this.config.maxWidth / canvas.width);
			}
			if(this.config.maxHeight){
				scale = Math.min(1, scale, this.config.maxHeight / canvas.height);
			}
			
			
			return this.doScale(canvas, scale);
		}).then(result => {
			return new Promise((resolve, reject) => {
				resolve(this.toBlob(result));
			})
		})
	}
	
	//通过file 初始化 image
	getOriginImage() {
		return new Promise((resolve, reject) => {
			let img = new Image();
			img.onload = () => {
				resolve(img);
			};
			img.onerror = () => {
				reject("图片加载失败");
			};
			
			img.src = URL.createObjectURL(this.file);
		})
	}
	
	getCanvas(img) {
		return new Promise((resolve, reject) => {
			// 通过得到图片的信息来调整显示方向以正确显示图片,主要解决 ios 系统上的图片会有旋转的问题
			EXIF.getData(img, () => {
				let orientation = EXIF.getTag(img, "Orientation") || 1;
				
				let canvas = document.createElement("canvas");
				
				
				let ctx = canvas.getContext("2d");
				
				if(orientation == 6){
					canvas.width = img.height;
					canvas.height = img.width;
					ctx.rotate(90 * Math.PI / 180);
					ctx.drawImage(img, 0 , 0 , img.width, img.height, 0, -img.height ,canvas.height,canvas.width);
					
				}else{
					canvas.width = img.width;
					canvas.height = img.height;
					ctx.drawImage(img, 0, 0);
				}
				
				resolve(canvas);
			});
		})
	}
	
	doScale(source, scale){
		if(scale == 1){
			return Promise.resolve(source);
		}
		
		let mirror = document.createElement("canvas");
		mirror.width = Math.ceil(source.width * scale);
		mirror.height = Math.ceil(source.height * scale);
		
		let mctx = mirror.getContext("2d");
		
		mctx.drawImage(source, 0, 0, source.width, source.height, 0, 0, mirror.width, mirror.height);
		
		
		return Promise.resolve(mirror);
	}
	
	// 这里把 base64 字符串转为 blob 对象
	toBlob(result) {
		let dataURL = result.toDataURL(this.outputType, this.config.quality);
		let buffer = atob(dataURL.split(",")[1]).split("").map(char => char.charCodeAt(0));
		let blob = new Blob([ new Uint8Array(buffer) ], {
			type : this.outputType
		});
		return {
			blob: blob,
			url: dataURL
		};
	}
	
}



/**
 * 示例代码
 */
function upload(file){
	new Compress(file,{maxWidth:1000, maxHeight:1000, quality: 0.7}).then(function(data){
		//这里写回调函数,data会传入两个属性,url:压缩后图片url,blob:压缩后图片blob值
		document.getElementById("img").src = data.url;
	},function(err){
		//这里写异常处理
		console.log(err);
	})
	
}
</script>

 

实测 1.5M 的3000*4000分辨率 图片 按照上面代码压缩后 50K,

另外七牛源代码还提供了特殊情况处理,如果压缩后图片体积比原来还大,就返回原图片,这些我都没处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catastrophe_zy

如果真的帮到你了,我很荣幸

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值