WebApp【公共组件库】@前端(For Git Submodule)
Tevin
2021-11-14 076face0dd29abf047d56999b6a45d8f718af86b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/**
 * 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>