图片压缩上传

553 阅读2分钟

轮播图组件

轮播图滑动:github.com/surmon-chin…

演示地址:3.swiper.com.cn/demo/index.…

图片压缩和上传

参考链接:

www.zhangxinxu.com/study/20170…

前端JS压缩图片并上传segmentfault.com/a/119000001…

ios上传压缩图片发生90度旋转github.com/lin-xin/blo…

流程图:

图片压缩上传,安卓和ios,解决旋转综合代码:

<style lang="scss" scoped>
.image-upload {
    position: relative;
    display: inline-block;
    .camera {
        display: inline-block;
        width: 0.4rem;
        height: 0.4rem;
        vertical-align: middle;
    }
    .upload {
        position: absolute;
        left: 0;
        top: 0;
        height: 100%;
        width: 100%;
        opacity: 0;
    }
}
</style>
<template>
    <div class="image-upload">
        <img class="camera" src="https://img.meituan.net/codeman/343cc626b6015f355003bc3268c233c26495.png">
        <!--<input type="file" class="upload" accept="image/*" @change="upload" multiple>-->
        <input type="file" accept='.png, .jpg, .jpeg' class="upload" @change="upload">
    </div>
</template>

<script>
import {Toast, Indicator} from 'mint-ui';
import Exif from 'exif-js';
export default {
    props: {
        uploadapi: {
            type: null,
            required: true
        }
    },
    methods: {
        upload () {
            const that = this;
            let fileinput = this.$el.querySelector('.image-upload input[type=file]');
            let orientation = null;
            let file = fileinput.files[0];
            if (/image/.test(file.type)) {
                that.$emit('upload-doing');
                Exif.getData(file, function(){
                    orientation = Exif.getTag(this, 'Orientation');
                    that.compressImage(orientation, file, (file)=>{
                        const formData = new FormData();
                        formData.append('file', file);
                        that.uploadapi(formData).then(res => {
                            that.$emit('upload-success', res.data);
                            fileinput.value = '';
                        }).catch(err => {
                            that.uploadapi(formData).then(resE => {
                                that.$emit('upload-error', resE.data);
                                fileinput.value = '';
                            }).catch(errE => {
                                Toast(errE.data.message);
                            });
                        });
                    });
                });
            } else {
                Toast('请上传图片');
            }
        },
        compressImage (orientation, file, success, error) {
            // 图片小于500k不压缩
            if (file.size < Math.pow(512, 2)) {
                return success(file);
            }
            const name = file.name; //文件名
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = (e) => {
                const src = e.target.result;
                const img = new Image();
                img.src = src;
                img.onload = (e) => {
                    const maxW = 2500;
                    const maxH = 2500;
                    const w = img.width;
                    const h = img.height;
                    let targetW = w;
                    let targetH = h;

                    if (w>maxW || h>maxH) {
                        if (w/h > maxW/maxH) {
                            targetW = maxW;
                            targetH = Math.round(maxW*(h/w));
                        } else {
                            targetH = maxH;
                            targetW = Math.round(maxH*(w/h));
                        }
                    }

                    const quality = 0.5;  // 默认图片质量为0.92,这个值的区间0-1,值越小,图片越模糊,压缩力度越大
                    //生成canvas
                    const canvas = document.createElement('canvas');
                    const ctx = canvas.getContext('2d');
                    // 创建属性节点
                    const anw = document.createAttribute("width");
                    anw.nodeValue = targetW;
                    const anh = document.createAttribute("height");
                    anh.nodeValue = targetH;
                    canvas.setAttributeNode(anw);
                    canvas.setAttributeNode(anh);

                    //铺底色 PNG转JPEG时透明区域会变黑色
                    ctx.fillStyle = "#fff";
                    ctx.fillRect(0, 0, targetW, targetH);
                    // 图片压缩上传ios旋转fix
                    if (orientation && orientation!== 1) {
                        switch(orientation){
                            case 6:
                                canvas.width = targetH;
                                canvas.height = targetW;
                                ctx.rotate(Math.PI / 2);
                                ctx.drawImage(img, 0, -targetH, targetW, targetH);
                                break;
                            case 3:
                                ctx.rotate(Math.PI);
                                ctx.drawImage(img, -targetW, -targetH, targetW, targetH);
                                break;
                            case 8:
                                canvas.width = h;
                                canvas.height = w;
                                ctx.rotate(3 * Math.PI / 2);
                                ctx.drawImage(img, -targetW, 0, targetW, targetH);
                                break;
                        }
                    } else {
                        ctx.drawImage(img, 0, 0, targetW, targetH);
                    }
                    // quality值越小,所绘制出的图像越模糊
                    const base64 = canvas.toDataURL('image/jpeg', quality); //图片格式jpeg或webp可以选0-1质量区间
                    // console.log('base64', base64);

                    // 返回base64转blob的值
                    console.log(`原图${(src.length/1024).toFixed(2)}kb`, `新图${(base64.length/1024).toFixed(2)}kb`);
                    //去掉url的头,并转换为byte
                    const bytes = window.atob(base64.split(',')[1]);
                    //处理异常,将ascii码小于0的转换为大于0
                    const ab = new ArrayBuffer(bytes.length);
                    const ia = new Uint8Array(ab);
                    for (let i = 0; i < bytes.length; i++) {
                        ia[i] = bytes.charCodeAt(i);
                    }
                    file = new Blob( [ab] , {type : 'image/jpeg'});
                    file.name = name;
                    success(file);
                }
                img.onerror = (e) => {
                    error(e);
                }
            };
            reader.onerror = (e) => {
                error(e);
            };
        }
    }
};
</script>