js提交图片到七牛云,解决压缩和iphone拍照旋转问题

思路:拿到图片之后,转为 base64格式,然后用EXIF解决旋转的问题,再将base64格式的文件传给七牛云,返回url。

七牛云base64文件上传参考文档: https://developer.qiniu.com/kodo/kb/1326/how-to-upload-photos-to-seven-niuyun-base64-code

<template>
    <div>
        <div class="weui-gallery" v-bind:class="{showgallery: showgallery}">
            <span
                class="weui-gallery__img"
                @click="closeGallery"
                :style="{backgroundImage:'url('+galleryimgUrl+')'}"
            ></span>
            <div class="weui-gallery__opr">
                <a href="javascript:" class="weui-gallery__del" @click="delGallery">
                    <i class="weui-icon-delete weui-icon_gallery-delete"></i>
                </a>
            </div>
        </div>

        <div class="weui-cell">
            <div class="weui-uploader">
                <div class="weui-uploader__hd">
                    <p class="weui-uploader__title">图片上传</p>
                    <div class="weui-uploader__info">{{uploadNum}}/{{allUploadNum}}</div>
                </div>
                <div class="weui-uploader__bd">
                    <ul class="weui-uploader__files" id="uploaderFiles">
                        <li
                            v-for="(item,index) in imgArr"
                            :key="index"
                            :style="{backgroundImage:'url('+item.src+')'}"
                            @click="openGallery(index)"
                            class="weui-uploader__file weui-uploader__file_status"
                        >
                            <div class="weui-uploader__file-content">
                                <i
                                    :class="[item.uploadimg == 0 ? 'weui-loading' : (item.flag == 1 ? 'weui-icon-success' : 'weui-icon-warn')]"
                                ></i>
                            </div>
                        </li>

                        <!--<li class="weui-uploader__file weui-uploader__file_status">
                            <div class="weui-uploader__file-content">
                                <div class="weui-loading"></div>
                            </div>
                        </li>-->
                    </ul>

                    <div class="weui-uploader__input-box" v-show="showUploadBtn">
                        <input
                            id="uploaderInput"
                            class="weui-uploader__input"
                            v-on:change="uploadImg"
                            type="file"
                            accept="image/*"
                            multiple
                        />
                    </div>
                </div>
            </div>
        </div>

    </div>
</template>

<script>
import axios from "axios"
import EXIF from "exif-js"
export default {
    name: "TestContent",
    props: {
        maxImgUploadNum: {
            type: Number
        }
    },
    data() {
        return {
            //所有图片列表
            imgArr: [],
            //是否显示 gallery
            showgallery: false,
            //gallery当前的图片地址
            galleryimgUrl: "",
            //当前点击的图片地址索引
            currentImgIndex: -1,
            //一共可以上传多少张图片
            allUploadNum: this.maxImgUploadNum,
            //已经上传的图片数量
            uploadNum: 0,
            //是否显示上传按钮,当大于最大上传数量的时候,隐藏,否则显示
            showUploadBtn: true,
            //每次添加图片给一个特定的id值,默认为1
            uploadid: 1

        }
    },
    watch: {
        imgArr: function() {
            this.uploadNum = this.imgArr.length
            if (this.imgArr.length > this.allUploadNum) {
                this.imgArr = this.imgArr.slice(0, this.allUploadNum)
                this.$weui.toast("只能添加" + this.allUploadNum + "张图片")
            }
            // 触发事件,把imgArr的值返回给调用父级
            this.$emit('getImgArrList', this.imgArr)

            //当图片达到允许最大上传值 等于大于的时候,则隐藏
            if (this.imgArr.length >= this.allUploadNum) {
                this.showUploadBtn = false
            } else {
                this.showUploadBtn = true
            }
        }
    },
    mounted () {
        console.log(this.maxImgUploadNum)
    },
    methods: {
        //测试最新的方法
        uploadImg(e) {
            let tag = e.target
            let fileList = tag.files
            let imgNum = fileList.length

            // 这里要注意,如果选择的图片加上已经存在的图片数量大于最大上传的数量,只能上传最大数量,然后提示打到达最大的数量
            let nowUploadNum = fileList.length + this.imgArr.length

            if (nowUploadNum > this.allUploadNum) {
                // 如果已经存在的数量加上上传的数量大于 最大上传数量, 则上传 最大上传数量 - 实际存在的数量
                let trueUplaodNum = this.allUploadNum - this.imgArr.length
                if (trueUplaodNum > 0) {
                    // 如果实际上传数量大于0, 说明还需上传
                    this.uploadImgEvent(trueUplaodNum, fileList)
                } else {
                    // 如果实际上传数量 不大于 0, 说明已经是最大上传数量,不上传,直接提示 已经是最大数量
                    this.$weui.alert("最大只能上传" + this.allUploadNum + "张")
                }
            } else {
                //如果现在要上传的数量加上一句存在的图片数量 小于 最大上传数量,则直接上传
                this.uploadImgEvent(fileList.length, fileList)
            }
        },

        //处理函数
        uploadImgEvent(imgNum, fileList) {
            let loading = this.$weui.loading('上传中...')

            let Orientation
            const _this = this
            for (let i = 0; i < imgNum; i++) {
                let fileSize = fileList[i].size
                
                EXIF.getData(fileList[i], function() {
                    Orientation = EXIF.getTag(fileList[i], "Orientation")
                });
                
                let reader = new FileReader()
                reader.readAsDataURL(fileList[i])
                reader.onload = function() {
                    var oReader = new FileReader()
                    oReader.onload = function(e) {
                        var image = new Image()
                        image.src = e.target.result
                        image.onload = function() {
                            var expectWidth = this.naturalWidth
                            var expectHeight = this.naturalHeight
                            if (
                                this.naturalWidth > this.naturalHeight &&
                                this.naturalWidth > 600
                            ) {
                                expectWidth = 600
                                expectHeight =
                                    (expectWidth * this.naturalHeight) /
                                    this.naturalWidth
                            } else if (
                                this.naturalHeight > this.naturalWidth &&
                                this.naturalHeight > 1000
                            ) {
                                expectHeight = 1000
                                expectWidth =
                                    (expectHeight * this.naturalWidth) /
                                    this.naturalHeight
                            }
                            var canvas = document.createElement("canvas")
                            var ctx = canvas.getContext("2d")
                            canvas.width = expectWidth
                            canvas.height = expectHeight
                            ctx.drawImage(
                                this,
                                0,
                                0,
                                expectWidth,
                                expectHeight
                            )
                            var base64 = null
                            //修复ios上传图片的时候 被旋转的问题
                            if (Orientation != "" && Orientation != 1) {
                                switch (Orientation) {
                                    case 6: //需要顺时针(向左)90度旋转
                                        _this.rotateImg(this, "left", canvas)
                                        break
                                    case 8: //需要逆时针(向右)90度旋转
                                        _this.rotateImg(this, "right", canvas)
                                        break
                                    case 3: //需要180度旋转
                                        _this.rotateImg(this, "right", canvas) //转两次
                                        _this.rotateImg(this, "right", canvas)
                                        break
                                }
                            }
                            base64 = canvas.toDataURL("image/jpeg", 0.95)
                            let uploadid = _this.uploadid + 1
                            _this.uploadid = _this.uploadid + 1
                            
                            //清除加载层
                            loading.hide()

                            if (fileList[i].size / 1024000 > 1) {
                                
                                //大于1的情况下,把处理放在下面的函数中处理
                                _this.imgScale(base64, 3, uploadid, fileSize)
                            } else {
                                //小于1的情况下,用下面的办法处理
                                _this.imgArr.push({ src: base64, flag : 0, uploadimg: 0,  uploadid: uploadid })

                                //上传到七牛云,上传成功修改 imgArr 状态
                                _this.putb64(_this.getBase64Str(base64), uploadid, fileSize)
                            }
                            
                        }
                    }
                    oReader.readAsDataURL(fileList[i])
                }
            }
        },

        getBase64Str (str_base64){
            let arr_str = str_base64.split(',')
            if(arr_str.length == 2 && arr_str[1]){
                return arr_str[1]
            }else{
                return 0
            }
        },

        imgScale(imgUrl, quality, uploadid, fileSize) {
            let img = new Image()
            let _this = this
            let canvas = document.createElement("canvas")
            let cxt = canvas.getContext("2d")
            img.src = imgUrl
            img.onload = function() {
                //缩放后图片的宽高
                let width = img.naturalWidth / quality
                let height = img.naturalHeight / quality
                canvas.width = width
                canvas.height = height
                cxt.drawImage(this, 0, 0, width, height)

                let base64 = canvas.toDataURL("image/jpeg")

                _this.imgArr.push({ src: base64, flag: 0, uploadimg: 0,  uploadid: uploadid })
                //上传到七牛云,上传成功修改 imgArr 状态
                _this.putb64(_this.getBase64Str(base64), uploadid, fileSize)
                
            }
        },

        //图片旋转
        rotateImg(img, direction, canvas) {
            var min_step = 0
            var max_step = 3
            if (img == null) return
            var height = img.height
            var width = img.width
            var step = 2
            if (step == null) {
                step = min_step
            }
            if (direction == "right") {
                step++
                step > max_step && (step = min_step)
            } else {
                step--
                step < min_step && (step = max_step)
            }
            var degree = (step * 90 * Math.PI) / 180
            var ctx = canvas.getContext("2d")
            switch (step) {
                case 0:
                    canvas.width = width
                    canvas.height = height
                    ctx.drawImage(img, 0, 0)
                    break
                case 1:
                    canvas.width = height
                    canvas.height = width
                    ctx.rotate(degree)
                    ctx.drawImage(img, 0, -height)
                    break
                case 2:
                    canvas.width = width
                    canvas.height = height
                    ctx.rotate(degree)
                    ctx.drawImage(img, -width, -height)
                    break
                case 3:
                    canvas.width = height
                    canvas.height = width
                    ctx.rotate(degree)
                    ctx.drawImage(img, -width, 0)
                    break
            }
        },

        //base64 提交到 七牛云
        putb64(str_base64, uploadid, fileSize) {
            //获取七牛云token
            let postData = {
                'uploadid' : uploadid
            }
            const qs = require('qs')
            const that = this
            axios.post(this.common.HTTPHOST+"/api/qiniu/getToken", qs.stringify(postData), {
                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
            }).then(function(res){
                let retData = res.data
                
                if(retData.ret == 1){
                    //获取成功
                    let token = retData.data.token
                    
                    let pic = str_base64
                    // let url = "http://upload-z1.qiniup.com/putb64/" + fileSize
                    let url = "http://up-z1.qiniup.com/putb64/-1"
                    
                    let xhr = new XMLHttpRequest()
                    xhr.onreadystatechange = function() {
                        let uploadid = res.data.data.uploadid
                        that.imgArr.forEach((item, index, array) => {
                            if(item.uploadid == uploadid){
                                
                                if (xhr.readyState == 4) {
                                    that.imgArr[index]['flag'] = 1  //上传成功
                                    that.imgArr[index]['uploadimg'] = 1 //完成上传
                                }
                                
                            }
                        })

                    }
                    xhr.open("POST", url, true)
                    xhr.setRequestHeader("Content-Type", "application/octet-stream")
                    xhr.setRequestHeader("Authorization", 'UpToken ' + token)
                    xhr.send(pic)
                    
                }else{
                    //获取失败
                    that.imgArr.forEach((item, index, array) => {
                        if(item.uploadid == uploadid){
                            that.imgArr[index]['flag'] = 0  //上传失败
                            that.imgArr[index]['uploadimg'] = 1 //完成上传
                            
                        }
                    })
                    // that.$weui.alert('网络错误')
                }

            }).catch(function(err){
                //获取失败
                that.imgArr.forEach((item, index, array) => {
                    if(item.uploadid == uploadid){
                        that.imgArr[index]['flag'] = 0  //上传失败
                        that.imgArr[index]['uploadimg'] = 1 //完成上传
                        
                    }
                })
                // that.$weui.alert('网络错误')

                console.log(err)
            })
            
        },

        //打开 gallery
        openGallery(index) {
            this.currentImgIndex = index
            this.galleryimgUrl = this.imgArr[index]["src"]
            this.showgallery = true
        },

        //删除gallery
        delGallery() {
            const that = this
            if (this.currentImgIndex > -1) {
                //如果当前索引大于0,说明存在
                this.imgArr.splice(this.currentImgIndex, 1)
                this.currentImgIndex = -1
            }
            that.$weui.toast("删除成功", {
                duration: 1000,
                callback: function() {
                    that.showgallery = false
                }
            });
        },

        //关闭gllery
        closeGallery() {
            this.showgallery = false
        }
    }
};
</script>

<style lang="stylus" scoped>
.showgallery {
    display: block;
}
</style>
发布了88 篇原创文章 · 获赞 6 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/codipy/article/details/103325636