vue之图片上传解决图片压缩和拍摄的角度旋转的问题

参考Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。(地址:http://code.ciaoca.com/javascript/exif-js/),结合vue的使用,兼容pc端和移动端,实现单张或者多张图片上传,图片压缩,解决拍摄角度旋转的问题。

效果图:


vue文件:

<template>
    <div class="add_tuzhi add_tuzhi_textarea">
        <div class="add_tuzhi_com mb bg-fff">
            <input id="plus_sent_pic" type="file"  @change="handleFileChange" ref="inputer"  class="trans_file" accept="image/png, image/jpeg, image/gif, image/jpg" multiple>
            <div class="add_img clearfix">
                <div class="add_img_list" v-for="(data,index) in imgData" @click="delImg(index)">
                    <img :src="data" >
                    <span class="tuzhi_sel"></span>
                </div>
                <template v-if="img_loading">
                    <div class="add_img_list">
                        <p class="map_loading">图片上传中</p>
                    </div>
                </template>
                <template v-else>
                     <label for="plus_sent_pic" class="add_img_list" v-if="num<9">
                        <div class="tuzhi_add">
                            <p><span>{{num}}</span>/9</p>
                        </div>
                    </label> 
                </template>   
                    
            </div>
        </div>
    </div>
</template>
<script>
import EXIF from '../../common/js/small-exif.js';
export default {
    data () {
        return {
            num:0,  //上传图片数量      
            base64:'' ,  //压缩后的图片       
            imgData:[],   //图片
            data:{base64:''},
            imgType:2,     //图片上传的状态  0:图片已经成功上传  1表示图片在上传中 2表示图片还没上传,
            img_loading:false,
            Orientation:''  ,    //图片的拍摄角度
        }
    },
    mounted:function(){
    },
    methods:{
        delImg(id,index){   //删除图片
            this.imgData.splice(index, 1);
            if(this.num>=1){
                this.num-=1;
            } 
        },
        handleFileChange () {  //获取图像
            let that=this;
            let inputDOM = this.$refs.inputer;
            // 通过DOM取文件数据
            for(let i in inputDOM.files){
                this.file= inputDOM.files[i];
                this.imgPreview(this.file);
                EXIF.getData(this.file, function() {  
                    that.Orientation = EXIF.getTag(this, 'Orientation');
                });
            }
        },
        imgPreview (file) {   //base64 格式
            this.imgType=1;
            this.img_loading=true;
            let self = this;
            let imgContent={};
            imgContent.name=file.name;
            // 看支持不支持FileReader
            if (!file || !window.FileReader) return;

            if (/^image/.test(file.type)) {
                // 创建一个reader
                var reader = new FileReader();
                // 将图片将转成 base64 格式
                reader.readAsDataURL(file);
                // 读取成功后的回调
                reader.onloadend = function () {
                    let IMG = new Image();
                    IMG.src = this.result;
                    IMG.onload = function(){
                        let w = this.naturalWidth,
                            h = this.naturalHeight,
                            resizeW = 0,
                            resizeH = 0;
                        //压缩设置
                        let maxSize = {
                            width:1280,      //图片最大宽度
                            height:1280,     //图片最大高度
                            level:0.6       //图片保存质量
                        };
                        //计算缩放比例
                        if(w > maxSize.width || h > maxSize.height){
                            let multiple = Math.max(w / maxSize.width , h / maxSize.height);
                            resizeW = w / multiple;
                            resizeH = h / multiple;
                        }else{
                            resizeW = w;
                            resizeH = h;
                        }
                        let canvas = document.createElement("canvas"),
                            cxt = canvas.getContext('2d');
                        //根据拍摄的角度进行图片旋转调整
                        if (self.Orientation == 3) {
                            canvas.width = resizeW;
                            canvas.height = resizeH;
                            cxt.rotate(Math.PI);
                            cxt.drawImage(IMG, 0, 0, -resizeW, -resizeH)
                        } else if (self.Orientation == 8) {
                            canvas.width = resizeH;
                            canvas.height = resizeW;
                            cxt.rotate(Math.PI * 3 / 2);
                            cxt.drawImage(IMG, 0, 0, -resizeW, resizeH)
                        } else if (self.Orientation == 6) {
                            canvas.width = resizeH;
                            canvas.height = resizeW;
                            cxt.rotate(Math.PI / 2);
                            cxt.drawImage(IMG, 0, 0, resizeW, -resizeH)
                        } else {
                            canvas.width = resizeW;
                            canvas.height = resizeH;
                            cxt.drawImage(IMG, 0, 0, resizeW, resizeH)
                        }
                        //base64,最终输出的压缩文件
                        self.base64 = canvas.toDataURL('image/jpeg',maxSize.level);
                        self.num+=1;
                        self.imgType=0;
                        self.img_loading=false;
                        self.imgData.push(self.base64 )
                    }
                };
            }
        }
    }
}
</script>
<style scoped src="./approach_add.css">
</style>

css文件:

@charset "utf-8";
.add_tuzhi{
    height: 100%;
    overflow-y: scroll;
    padding-bottom: 2rem;
}
.trans_file{
    display: none;
}
.add_img{
    padding: 0.213333rem;
}
.add_img_list{
    float: left;
    width: 3.893333333333333rem;
    height: 3.893333333333333rem;
    position: relative;
    padding: 0.213333rem;
    box-sizing: border-box;
}
.add_img_list img{
    width: 100%;
    height: 100%;
}
.add_img_list .tuzhi_sel{
    position: absolute;
    width: 0.64rem;
    height: 0.64rem;
    right:0;
    top:0;
    background: url(./colse.png);
    background-size: 100% 100%;
}
.add_img_list .tuzhi_add{
    display: block;
    width:100%;
    height: 100%;
    position: relative;
    background:url(./add.png);
    background-size: 100% 100%;
}
.add_img_list .tuzhi_add p{
    color: #ccc;
    font-size: 0.554667rem;
    position: absolute;
    left: 1.28rem;
    bottom:0.32rem;
}
.add_img_list .map_loading{
    width:100%;
    text-align:center;
    height: 3.466666666666333rem;
    line-height: 3.466666666666333rem;
    color:#333;
    font-size: 0.554667rem;
    border:1px  #dedede dashed;
}

封装好的exif-js文件:

var EXIF = {};
var TiffTags = EXIF.TiffTags = {
    0x0112: "Orientation"
};

function imageHasData(img) {
    return !!(img.exifdata);
}

function getImageData(img, callback) {
    function handleBinaryFile(binFile) {
        var data = findEXIFinJPEG(binFile);
        img.exifdata = data || {};
        if (callback) {
            callback.call(img);
        }
    }

    if (window.FileReader && (img instanceof window.Blob || img instanceof window.File)) {
        var fileReader = new FileReader();
        fileReader.onload = function (e) {
            handleBinaryFile(e.target.result);
        };
        fileReader.readAsArrayBuffer(img);
    }
}

function findEXIFinJPEG(file) {
    var dataView = new DataView(file);

    if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) {
        return false; // not a valid jpeg
    }

    var offset = 2,
        length = file.byteLength,
        marker;

    while (offset < length) {
        if (dataView.getUint8(offset) != 0xFF) {
            return false; // not a valid marker, something is wrong
        }

        marker = dataView.getUint8(offset + 1);

        if (marker == 225) {
            return readEXIFData(dataView, offset + 4, dataView.getUint16(offset + 2) - 2);
        } else {
            offset += 2 + dataView.getUint16(offset + 2);
        }
    }
}

function readTags(file, tiffStart, dirStart, strings, bigEnd) {
    var entries = file.getUint16(dirStart, !bigEnd),
        tags = {},
        entryOffset, tag,
        i;

    for (i = 0; i < entries; i++) {
        entryOffset = dirStart + i * 12 + 2;
        tag = strings[file.getUint16(entryOffset, !bigEnd)];
        tags[tag] = readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd);
    }
    return tags;
}

function readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd) {
    var type = file.getUint16(entryOffset + 2, !bigEnd),
        numValues = file.getUint32(entryOffset + 4, !bigEnd),
        valueOffset = file.getUint32(entryOffset + 8, !bigEnd) + tiffStart,
        offset,
        vals, val, n,
        numerator, denominator;
    switch (type) {
        case 1: // byte, 8-bit unsigned int
        case 7: // undefined, 8-bit byte, value depending on field
            if (numValues == 1) {
                return file.getUint8(entryOffset + 8, !bigEnd);
            } else {
                offset = numValues > 4 ? valueOffset : (entryOffset + 8);
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getUint8(offset + n);
                }
                return vals;
            }

        case 2: // ascii, 8-bit byte
            offset = numValues > 4 ? valueOffset : (entryOffset + 8);
            return getStringFromDB(file, offset, numValues - 1);

        case 3: // short, 16 bit int
            if (numValues == 1) {
                return file.getUint16(entryOffset + 8, !bigEnd);
            } else {
                offset = numValues > 2 ? valueOffset : (entryOffset + 8);
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getUint16(offset + 2 * n, !bigEnd);
                }
                return vals;
            }

        case 4: // long, 32 bit int
            if (numValues == 1) {
                return file.getUint32(entryOffset + 8, !bigEnd);
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getUint32(valueOffset + 4 * n, !bigEnd);
                }
                return vals;
            }

        case 5: // rational = two long values, first is numerator, second is denominator
            if (numValues == 1) {
                numerator = file.getUint32(valueOffset, !bigEnd);
                denominator = file.getUint32(valueOffset + 4, !bigEnd);
                val = new Number(numerator / denominator);
                val.numerator = numerator;
                val.denominator = denominator;
                return val;
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    numerator = file.getUint32(valueOffset + 8 * n, !bigEnd);
                    denominator = file.getUint32(valueOffset + 4 + 8 * n, !bigEnd);
                    vals[n] = new Number(numerator / denominator);
                    vals[n].numerator = numerator;
                    vals[n].denominator = denominator;
                }
                return vals;
            }

        case 9: // slong, 32 bit signed int
            if (numValues == 1) {
                return file.getInt32(entryOffset + 8, !bigEnd);
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getInt32(valueOffset + 4 * n, !bigEnd);
                }
                return vals;
            }

        case 10: // signed rational, two slongs, first is numerator, second is denominator
            if (numValues == 1) {
                return file.getInt32(valueOffset, !bigEnd) / file.getInt32(valueOffset + 4, !bigEnd);
            } else {
                vals = [];
                for (n = 0; n < numValues; n++) {
                    vals[n] = file.getInt32(valueOffset + 8 * n, !bigEnd) / file.getInt32(valueOffset + 4 + 8 * n, !bigEnd);
                }
                return vals;
            }
    }
}

function getStringFromDB(buffer, start, length) {
    var outstr = "";
    for (var n = start; n < start + length; n++) {
        outstr += String.fromCharCode(buffer.getUint8(n));
    }
    return outstr;
}

function readEXIFData(file, start) {
    if (getStringFromDB(file, start, 4) != "Exif") {
        return false;
    }

    var bigEnd,
        tags, tag,
        exifData, gpsData,
        tiffOffset = start + 6;

    // test for TIFF validity and endianness
    if (file.getUint16(tiffOffset) == 0x4949) {
        bigEnd = false;
    } else if (file.getUint16(tiffOffset) == 0x4D4D) {
        bigEnd = true;
    } else {
        return false;
    }

    if (file.getUint16(tiffOffset + 2, !bigEnd) != 0x002A) {
        return false;
    }

    var firstIFDOffset = file.getUint32(tiffOffset + 4, !bigEnd);
    if (firstIFDOffset < 0x00000008) {
        return false;
    }

    tags = readTags(file, tiffOffset, tiffOffset + firstIFDOffset, TiffTags, bigEnd);

    return tags;
}

EXIF.getData = function (img, callback) {
    if ((img instanceof Image || img instanceof HTMLImageElement) && !img.complete) return false;

    if (!imageHasData(img)) {
        getImageData(img, callback);
    } else {
        if (callback) {
            callback.call(img);
        }
    }
    return true;
}

EXIF.getTag = function (img, tag) {
    if (!imageHasData(img)) return;
    return img.exifdata[tag];
}
export default EXIF


Logo

前往低代码交流专区

更多推荐