iOS手機豎著拍的照片經(jīng)過前端處理之后被旋轉(zhuǎn)了90°的原因以及解決方案

在網(wǎng)頁應(yīng)用中上傳圖片的操作是非常廣泛的粱年,比如近期我公司上線的一個小游戲“專業(yè)審核夫妻相”:

專業(yè)審核夫妻相

它的主要功能就是上傳兩張人像综苔,通過算法進行分析對比酣倾,最后得出一個相似度的分?jǐn)?shù)煎饼,以驗證你們是天造地設(shè)還是顏值互補讹挎。

但是校赤,當(dāng)我們把上傳的圖片轉(zhuǎn)換成base64格式吆玖,發(fā)送給后臺時,會發(fā)現(xiàn)偶爾會出現(xiàn)問題马篮,有一些圖片本來是這樣的:

柴犬

處理之后卻變成了這樣:

柴犬2

經(jīng)過測試發(fā)現(xiàn)沾乘,只有iOS手機豎著拍的照片才會出現(xiàn)這樣的問題,而iOS手機橫著拍的照片浑测、Android手機拍的照片以及通過屏幕截圖翅阵、網(wǎng)絡(luò)下載等途徑獲得的圖片都不會產(chǎn)生這個問題。

那么迁央,這到底是為什么呢掷匠?

在開發(fā)過程中,由于時間緊迫岖圈,未求甚解讹语,使用了github上的一個開源項目 lrz.js 來解決此問題,這個工具的主要用途是在盡量保證圖片質(zhì)量的前提下壓縮圖片的大小蜂科,但同時也附帶了圖片旋轉(zhuǎn)角度糾正的功能顽决。

通過閱讀 lrz.js 的源代碼短条,我發(fā)現(xiàn)它引入了一個叫做 exif.js 的庫來實現(xiàn)旋轉(zhuǎn)角度的糾正,它提供了js讀取圖像的原始數(shù)據(jù)的功能擴展才菠,例如:拍照方向茸时、相機設(shè)備型號、拍攝時間赋访、ISO 感光度可都、GPS 地理位置等數(shù)據(jù)。而拍照方向就是關(guān)鍵所在蚓耽!

exif.js 獲取圖像的拍照方向的代碼如下:

EXIF.getData(IMG_FILE, function () { // IMG_FILE為圖像數(shù)據(jù)
  var orientation = EXIF.getTag(this, "Orientation");
  console.log("Orientation:" + orientation); // 拍照方向
});

獲取拍照方向的結(jié)果為1-8的數(shù)字:

拍照方向信息

注意:對于上面的八種方向中汹粤,加了*的并不常見,因為它們代表的是鏡像方向田晚,如果不做任何的處理嘱兼,不管相機以任何角度拍攝,都無法出現(xiàn)鏡像的情況贤徒。

這個表格代表什么意義芹壕?我們來看第一行,值為1時接奈,右邊兩列的值分別為:Row #0 is Top踢涌,Column #0 is Left side,其實很好理解序宦,它表示照片的第一行位于頂端睁壁,而第一列位于左側(cè),那么這張照片自然就是以正常角度拍攝的互捌。

而這8種結(jié)果潘明,就是第一行與第一列所在的位置的8種組合。

那么秕噪,我們來測試一下iOS手機橫著拍的照片钳降,來看看它的拍照方向是什么呢?

測試1

結(jié)果是1腌巾,即以正常角度拍攝的遂填,其實也就是原圖啦~

那么,我們再測試一下iOS手機豎著拍的照片澈蝙,來看看它的拍照方向是什么呢吓坚?

測試2

原來是6!即第一行位于右側(cè)灯荧,第一列位于頂端礁击,其實相當(dāng)于將照片順時針旋轉(zhuǎn)了90度!

所以,實際上iOS手機豎著拍出的照片與橫著拍出的照片其本質(zhì)上是一樣的客税,只不過豎著拍出的照片被添加了一個順時針旋轉(zhuǎn)90°拍照方向况褪,所以顯示的時候,就變成了上下邊窄左右邊寬的狀態(tài)更耻,其實也就是橫著拍的照片順時針旋轉(zhuǎn)90°而成的~

那么明白了這些测垛,文章開頭所說的照片旋轉(zhuǎn)bug的原因,也就很簡單啦~

其實就是當(dāng)我們在前端對圖片進行像素處理或者drawInRect等操作之后秧均,照片的Orientaion信息食侮,即為拍照方向信息被刪除了,所以iOS手機豎著拍的照片又回到了橫著的狀態(tài)目胡,看起來也就是逆時針旋轉(zhuǎn)了90°锯七!

那么如何糾正這個旋轉(zhuǎn)角度呢?

其實思路也很簡單:在處理圖片之前誉己,先讀取并保存圖片的拍照方向信息眉尸,然后在處理圖片之后,再根據(jù)拍照方向巨双,對圖片進行相應(yīng)的調(diào)整噪猾,lrz.js 中的代碼如下:

switch (orientation) {
    case 3:
        ctx.rotate(180 * Math.PI / 180);
        ctx.drawImage(img, -resize.width, -resize.height, resize.width, resize.height);
        break;
    case 6:
        ctx.rotate(90 * Math.PI / 180);
        ctx.drawImage(img, 0, -resize.width, resize.height, resize.width);
        break;
    case 8:
        ctx.rotate(270 * Math.PI / 180);
        ctx.drawImage(img, -resize.height, 0, resize.height, resize.width);
        break;
    case 2:
        ctx.translate(resize.width, 0);
        ctx.scale(-1, 1);
        ctx.drawImage(img, 0, 0, resize.width, resize.height);
        break;
    case 4:
        ctx.translate(resize.width, 0);
        ctx.scale(-1, 1);
        ctx.rotate(180 * Math.PI / 180);
        ctx.drawImage(img, -resize.width, -resize.height, resize.width, resize.height);
        break;
    case 5:
        ctx.translate(resize.width, 0);
        ctx.scale(-1, 1);
        ctx.rotate(90 * Math.PI / 180);
        ctx.drawImage(img, 0, -resize.width, resize.height, resize.width);
        break;
    case 7:
        ctx.translate(resize.width, 0);
        ctx.scale(-1, 1);
        ctx.rotate(270 * Math.PI / 180);
        ctx.drawImage(img, -resize.height, 0, resize.height, resize.width);
        break;
    default:
        ctx.drawImage(img, 0, 0, resize.width,resize.height);
}

其中,translate是平移變換筑累,scale(-1,1)是向左翻轉(zhuǎn)袱蜡,rotate是順時針旋轉(zhuǎn)。

舉例說明 case 2慢宗,當(dāng)圖片的拍照方向為2時坪蚁,即第一行位于頂端,而第一列位于右側(cè)镜沽,其實相當(dāng)于把照片進行了左右的翻轉(zhuǎn)敏晤。所以,這里對圖片的操作是淘邻,先向右平移等于圖片寬度的距離茵典,再向左翻轉(zhuǎn)湘换,這相當(dāng)于以圖片水平方向的對稱軸為軸進行了左右翻轉(zhuǎn)宾舅,然后再以(0,0)為起始點繪制原寬高的圖片彩倚,即完成了對拍照方向的糾正筹我。

最后

經(jīng)過一系列的測試,發(fā)現(xiàn)確實只有iOS手機的豎拍照片與橫拍照片是通過拍照方向來區(qū)別的帆离,Android手機無論豎拍還是橫拍的照片蔬蕊,拍照方向都為1,也就是說即使丟失了拍照方向這一信息哥谷,也不會影響到圖片的旋轉(zhuǎn)角度岸夯。而手機或電腦的屏幕截圖麻献、網(wǎng)絡(luò)上的圖片、通過PS制作的圖片等也是如此猜扮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勉吻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子旅赢,更是在濱河造成了極大的恐慌齿桃,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煮盼,死亡現(xiàn)場離奇詭異短纵,居然都是意外死亡,警方通過查閱死者的電腦和手機僵控,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門香到,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人报破,你說我怎么就攤上這事养渴。” “怎么了泛烙?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵理卑,是天一觀的道長。 經(jīng)常有香客問我蔽氨,道長藐唠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任鹉究,我火速辦了婚禮宇立,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘自赔。我一直安慰自己妈嘹,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布绍妨。 她就那樣靜靜地躺著润脸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪他去。 梳的紋絲不亂的頭發(fā)上毙驯,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音灾测,去河邊找鬼爆价。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铭段。 我是一名探鬼主播骤宣,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼序愚!你這毒婦竟也來了涯雅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤展运,失蹤者是張志新(化名)和其女友劉穎活逆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拗胜,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蔗候,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了埂软。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锈遥。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖勘畔,靈堂內(nèi)的尸體忽然破棺而出所灸,到底是詐尸還是另有隱情,我是刑警寧澤炫七,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布爬立,位于F島的核電站,受9級特大地震影響万哪,放射性物質(zhì)發(fā)生泄漏侠驯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一奕巍、第九天 我趴在偏房一處隱蔽的房頂上張望吟策。 院中可真熱鬧,春花似錦的止、人聲如沸檩坚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匾委。三九已至,卻和暖如春权谁,著一層夾襖步出監(jiān)牢的瞬間剩檀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工旺芽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓采章,卻偏偏與公主長得像运嗜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子悯舟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容