代码参考的七牛官方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,
另外七牛源代码还提供了特殊情况处理,如果压缩后图片体积比原来还大,就返回原图片,这些我都没处理