/**
|
* CImageCompressor
|
* @author Tevin
|
*/
|
|
<template>
|
<view class="c-image-compressor">
|
<canvas
|
:canvas-id="cavId"
|
:style="{width:cavWidth+'px', height:cavHeight+'px'}"
|
ref="canvas"
|
/>
|
</view>
|
</template>
|
|
<script>
|
import Taro from '@tarojs/taro';
|
import { $ } from '@tarojs/extend';
|
import './cImageCompressor.scss';
|
|
export default {
|
name: 'CImageCompressor',
|
props: {
|
maxSize: {
|
type: Number,
|
default: 1600,
|
},
|
},
|
data() {
|
return {
|
// canvas id
|
cavId: 'compressor' + parseInt(Math.random() * 10000 + 1000),
|
// canvas 大小
|
cavWidth: 0,
|
cavHeight: 0,
|
// 图片
|
imgBlobs: [],
|
};
|
},
|
methods: {
|
$compress(tempPaths, callback) {
|
this.imgBlobs = []; // 重置已转图片
|
if (typeof this.canvasContext === 'undefined') {
|
this.canvasContext = Taro.createCanvasContext(this.cavId, this);
|
}
|
let curIndex = 0;
|
const processImg = () => {
|
this._compressImg(tempPaths[curIndex], () => {
|
curIndex++;
|
// 递归依次完成所有图片压缩
|
if (curIndex < tempPaths.length) {
|
processImg();
|
}
|
// 完成图片压缩
|
else {
|
callback(this.imgBlobs);
|
}
|
});
|
};
|
processImg();
|
},
|
_compressImg(tempPath, callback) {
|
Taro.getImageInfo({
|
src: tempPath,
|
success: res => {
|
const size = this._limitSize(res);
|
const drawSet = this._creatDrawSet(res, size);
|
this._drawImage(tempPath, drawSet, compress => {
|
this.imgBlobs.push({
|
source: tempPath,
|
compress,
|
});
|
callback();
|
});
|
},
|
});
|
},
|
_limitSize(res) {
|
const rate = res.width / res.height;
|
let width, height;
|
// 宽大于高,按宽算
|
if (res.width >= res.height) {
|
width = Math.min(res.width, this.maxSize);
|
height = Math.round(width / rate);
|
}
|
// 按高算
|
else {
|
height = Math.min(res.height, this.maxSize);
|
width = Math.round(height * rate);
|
}
|
return [width, height];
|
},
|
_setCanvasSize(width, height) {
|
this.cavWidth = width;
|
this.cavHeight = height;
|
if (process.env.TARO_ENV === 'h5') {
|
$(this.$refs.canvas.$el)
|
.find('canvas')
|
.attr('width', width)
|
.attr('height', height);
|
}
|
// TODO: 小程序中的 canvas 重设
|
},
|
_creatDrawSet(res, [width, height]) {
|
const orientation = res.orientation || 'up';
|
// 根据orientation值处理图片
|
switch (orientation) {
|
// 不需要旋转
|
case 'up':
|
this._setCanvasSize(width, height);
|
return [['drawImage', [0, 0, width, height]]];
|
// 需要需要旋转180度
|
case 'down':
|
this._setCanvasSize(width, height);
|
return [
|
['translate', [width / 2, height / 2]],
|
['rotate', [(180 * Math.PI) / 180]],
|
['drawImage', [-width / 2, -height / 2, width, height]],
|
];
|
// 需要顺时针旋转270度
|
case 'left':
|
this._setCanvasSize(height, width);
|
return [
|
['translate', [height / 2, width / 2]],
|
['rotate', [(270 * Math.PI) / 180]],
|
['drawImage', [-width / 2, -height / 2, width, height]],
|
];
|
// 需要顺时针旋转90度
|
case 'right':
|
this._setCanvasSize(height, width);
|
return [
|
['translate', [height / 2, width / 2]],
|
['rotate', [(90 * Math.PI) / 180]],
|
['drawImage', [-width / 2, -height / 2, width, height]],
|
];
|
}
|
},
|
_drawImage(tempPath, drawSet, callback) {
|
drawSet.forEach(step => {
|
const [key, params] = step;
|
if (key === 'drawImage') {
|
// 使用图片
|
const img = new Image();
|
img.src = tempPath;
|
this.canvasContext.drawImage(img, ...params);
|
} else {
|
this.canvasContext[key](...params);
|
}
|
});
|
// 清空再绘制
|
this.canvasContext.draw(false, () => {
|
Taro.canvasToTempFilePath({
|
canvasId: this.cavId,
|
width: this.cavWidth,
|
height: this.cavHeight,
|
quality: 0.6,
|
fileType: 'jpeg',
|
success: res => {
|
callback(this._transBase64ToBlob(res.tempFilePath));
|
},
|
});
|
});
|
},
|
_transBase64ToBlob(base64) {
|
const arr = base64.split(',');
|
const mime = arr[0].match(/:(.*?);/)[1];
|
const bstr = atob(arr[1]);
|
let n = bstr.length;
|
const u8arr = new Uint8Array(n);
|
while (n--) {
|
u8arr[n] = bstr.charCodeAt(n);
|
}
|
const blob = new Blob([u8arr], { type: mime });
|
return URL.createObjectURL(blob);
|
},
|
},
|
beforeDestroy() {
|
this.canvasContext = null;
|
},
|
};
|
</script>
|