關(guān)于uniapp部分手機(jī)拍照或圖片上傳的旋轉(zhuǎn)問題解決

uniapp雖然在某種情況下是個(gè)很好用的框架澜汤,但還是避免不了踩坑炎滞,而坑在社區(qū)或官網(wǎng)或百度里都沒法找到能立即適用的解決方案敢艰。今天遇到的一個(gè)大問題就是使用uni.chooseImage上傳圖片或者拍照在部分手機(jī)上圖片出現(xiàn)旋轉(zhuǎn),同時(shí)就算設(shè)置了壓縮結(jié)局還是沒有壓縮圖片的問題册赛。

今天我給大家一份完整的解決方案钠导,就目前運(yùn)行的項(xiàng)目來說,oppo, 小米森瘪,蘋果的手機(jī)出現(xiàn)旋轉(zhuǎn)角度有順時(shí)針牡属,逆時(shí)針90度以及旋轉(zhuǎn)180度等問題,目前測試均無問題扼睬。

因時(shí)間問題逮栅,有些地方代碼不一定是最簡潔的悴势,大家如果有更好的方式歡迎大家留言,共同學(xué)習(xí)進(jìn)步措伐。

第一步特纤,我們必須要知道圖片旋轉(zhuǎn)的方向(exifjs庫是可以拿到圖片的很多信息包括方向,但在uniapp中無法使用侥加,所以這里沒有用捧存,但大家可以嘗試),uni.getImageInfo號稱是可以拿到該值担败,但經(jīng)過實(shí)驗(yàn)沒有拿到昔穴,所以我換了種方式,該方式其實(shí)在網(wǎng)上也可搜索到提前,我們直接看源碼:

export const common = {
    // 這里的獲取exif要將圖片轉(zhuǎn)ArrayBuffer對象吗货,這里假設(shè)獲取了圖片的baes64
    // 步驟一
    // base64轉(zhuǎn)ArrayBuffer對象
    base64ToArrayBuffer: (base64) => {
        base64 = base64.replace(/^data\:([^\;]+)\;base64,/gmi, ''); 
        var binary = atob(base64); //atob() 方法用于解碼使用 base-64 編碼的字符串,windows對象里的方法
        var len = binary.length;  
        var buffer = new ArrayBuffer(len);  // 創(chuàng)建一個(gè)binary.length字節(jié)的ArrayBuffer
        var view = new Uint8Array(buffer);//創(chuàng)建一個(gè)buffer的引用狈网,類型是Uint8卿操,起始位置在0,結(jié)束位置為緩沖區(qū)尾部
        for (var i = 0; i < len; i++) {
            view[i] = binary.charCodeAt(i); //在引用指定位置里存入指定位置的字符的 Unicode 編碼
        }
        return buffer; //最終生成一個(gè)數(shù)組緩沖區(qū)孙援,里面存儲(chǔ)了該base64圖片的二進(jìn)制信息 害淤,為了后續(xù)通過底層接口拿到多種數(shù)值類型
    },
    // 步驟二,Unicode碼轉(zhuǎn)字符串
    // ArrayBuffer對象 Unicode碼轉(zhuǎn)字符串
    getStringFromCharCode: (dataView, start, length) => {
        var str = '';
        var i;
        for (i = start, length += start; i < length; i++) {
            str += String.fromCharCode(dataView.getUint8(i));
        }
        return str; //將第一步中的二進(jìn)制ArrayBuffer對象生成的unicode的碼轉(zhuǎn)成字符串
     },

    // 步驟三拓售,獲取jpg圖片的exif的角度(在ios體現(xiàn)最明顯)下面很多都是為了獲取圖片數(shù)值的底層信息窥摄,陌生的大家可以一個(gè)個(gè)查,或者去看extjs官網(wǎng)
    getOrientation: (arrayBuffer) => {
        var dataView = new DataView(arrayBuffer); //可以從 二進(jìn)制[`ArrayBuffer`]對象中讀寫多種數(shù)值類型的底層接口
        var length = dataView.byteLength;
        var orientation;
        var exifIDCode;
        var tiffOffset;
        var firstIFDOffset;
        var littleEndian;
        var endianness;
        var app1Start;
        var ifdStart;
        var offset;
        var i;
        // Only handle JPEG image (start by 0xFFD8)
        if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
            offset = 2;
            while (offset < length) {
                if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
                    app1Start = offset;
                    break;
                }
                offset++;
            }
        }
        if (app1Start) {
            exifIDCode = app1Start + 4;
            tiffOffset = app1Start + 10;
            if (common.getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
                endianness = dataView.getUint16(tiffOffset);
                littleEndian = endianness === 0x4949;

                if (littleEndian || endianness === 0x4D4D /* bigEndian */ ) {
                    if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
                        firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);

                        if (firstIFDOffset >= 0x00000008) {
                            ifdStart = tiffOffset + firstIFDOffset;
                        }
                    }
                }
            }
        }

        if (ifdStart) {
            length = dataView.getUint16(ifdStart, littleEndian);
            var standalone = window.navigator.standalone,
                userAgent = window.navigator.userAgent.toLowerCase(),
                safari = /safari/.test(userAgent),
                ios = /iphone|ipod|ipad/.test(userAgent);
        
            for (i = 0; i < length; i++) {
                offset = ifdStart + i * 12 + 2;
                if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */ ) {

                    // 8 is the offset of the current tag's value
                    offset += 8;

                    // Get the original orientation value
                    orientation = dataView.getUint16(offset, littleEndian);

                    // Override the orientation with its default value for Safari (#120)
                    // if (IS_SAFARI_OR_UIWEBVIEW) {
                    //  dataView.setUint16(offset, 1, littleEndian);
                    // }
                    if (ios) {
                        if (!standalone && safari) {
                            dataView.setUint16(offset, 1, littleEndian);
                        } else if (standalone && !safari) {
                            //standalone
                        } else if (!standalone && !safari) {
                            dataView.setUint16(offset, 1, littleEndian);
                        };
                    } 
                    break;
                }
            }
        }
        return orientation;
    }
}

第二步础淤,獲取圖片的旋轉(zhuǎn)方向并壓縮:

urlTobase64(url) {
   uni.request({
      url: url,
      method: 'GET',
      responseType: 'arraybuffer',
      success: (res)=> {
        let base64 = uni.arrayBufferToBase64(res.data); //把a(bǔ)rraybuffer轉(zhuǎn)成base64
        base64 = 'data:image/jpeg;base64,' + base64; //不加上這串字符崭放,在頁面無法顯示
        const or=common.getOrientation(common.base64ToArrayBuffer(base64))
        this.or=or
        this.compressImg(base64,or)
      }
   });
},

第三步,對需要旋轉(zhuǎn)的圖片旋轉(zhuǎn)鸽凶,壓縮币砂,這里設(shè)置的canvas的width=300,height=400。里面值需要以此為參考換算:

compressImg(img,or){
    const ctx = uni.createCanvasContext('myCanvas')
    console.log(or)
      if(or==6){//逆時(shí)針旋轉(zhuǎn)了90
      ctx.translate(300,0)
      ctx.rotate(Math.PI/2)
      ctx.drawImage(img, 0, 0,400, 300)
    }else if(or==3){//逆時(shí)針旋轉(zhuǎn)了180
        ctx.translate(300,400)
        ctx.rotate(Math.PI)
        ctx.drawImage(img, 0, 0,400, 300)
    }else if(or==8){//順時(shí)針旋轉(zhuǎn)90
        ctx.translate(0,400)
        ctx.rotate(-Math.PI/2)
        ctx.drawImage(img, 0, 0,400, 300)
    }else{
        ctx.drawImage(img, 0, 0,300, 400)
    }
    ctx.draw(false,()=>{
        uni.canvasToTempFilePath({
             x: 0,
             y: 0,
              width: 300,
              height:400,
              destWidth:300,
              destHeight:400,
              fileType:'jpg',
               canvasId: 'myCanvas',
               success:(res)=> {
                this.img=res.tempFilePath
               },
                fail:(err)=>{
                    this.img=img
                }
            })
        })
    },

第四步玻侥,通過uni.chooseImage上傳圖片:

// 選擇圖片
ChooseImage() {
    uni.showLoading({
        title: '照片獲取中',
        mask: true
     });
        uni.chooseImage({
        count: 1, //默認(rèn)9
        sizeType: ['compressed'], //可以指定是原圖還是壓縮圖决摧,默認(rèn)二者都有
        sourceType: ['album', 'camera'], //從相冊選擇
    success: (res) => {
        this.urlTobase64(res.tempFilePaths[0])
        uni.hideLoading()
    },
    fail:(err)=>{
        uni.hideLoading()
    }
  });
},          

至此,一套完整的方案就已經(jīng)產(chǎn)生了凑兰。希望能幫到需要的朋友掌桩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市姑食,隨后出現(xiàn)的幾起案子波岛,更是在濱河造成了極大的恐慌,老刑警劉巖音半,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件则拷,死亡現(xiàn)場離奇詭異贡蓖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)煌茬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門斥铺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宣旱,你說我怎么就攤上這事仅父∨咽恚” “怎么了浑吟?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耗溜。 經(jīng)常有香客問我组力,道長,這世上最難降的妖魔是什么抖拴? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任燎字,我火速辦了婚禮,結(jié)果婚禮上阿宅,老公的妹妹穿的比我還像新娘候衍。我一直安慰自己,他們只是感情好洒放,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布蛉鹿。 她就那樣靜靜地躺著,像睡著了一般往湿。 火紅的嫁衣襯著肌膚如雪妖异。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天领追,我揣著相機(jī)與錄音他膳,去河邊找鬼。 笑死绒窑,一個(gè)胖子當(dāng)著我的面吹牛棕孙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播些膨,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼散罕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了傀蓉?” 一聲冷哼從身側(cè)響起欧漱,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎葬燎,沒想到半個(gè)月后误甚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缚甩,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年窑邦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了擅威。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冈钦,死狀恐怖郊丛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞧筛,我是刑警寧澤厉熟,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站较幌,受9級特大地震影響揍瑟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乍炉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一绢片、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岛琼,春花似錦底循、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至随珠,卻和暖如春灭袁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背窗看。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工茸歧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人显沈。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓软瞎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拉讯。 傳聞我的和親對象是個(gè)殘疾皇子涤浇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345