2017-08-07 80 views
1

在我的測試中,由BitmapFactory.decodeFile()創建的Bitmap不尊重EXIF標頭。是否有可能使BitmapFactory.decodeFile()尊重EXIF?

例如,由設備拍攝人像的圖像,根據相機方位,而是將其存儲在EXIF頭不旋轉,實際的像素數據,當我打電話Bitmap.getWidth()Bitmap.getHeight(),他們返回不正確的值(高度寬度,反之亦然)。

有沒有辦法讓BitmapFactory.decodeFile()尊重EXIF併產生正確的Bitmap

如果不是,建議的模式是什麼?

沒有經驗豐富的Android開發人員的建議,我所看到的唯一方法是預處理拍攝的圖像(加載,根據EXIF旋轉並保存)。但除了巨大的處理開銷之外,這可能會導致OutOfMemoryException s適用於大型相機分辨率(如果通過使用BitmapFactory.Options.inSampleSize加載縮小的圖像無法降低質量)。

回答

1

有沒有辦法讓BitmapFactory.decodeFile()尊重EXIF併產生正確的位圖?

不,對不起。

什麼是處理此問題的推薦模式?

使用支持庫的ExifInterface來確定所需的方向。然後,根據您對Bitmap的使用情況,旋轉視圖(例如,ImageView)或旋轉BitmapThis sample project舉例說明了這兩種方法,但我使用了一組單獨的EXIF代碼,因爲在該示例中使用的某些內容不受支持庫ExifInterface的支持。

+0

'使用支持庫的ExifInterface':在你的示例中使用'it.sephiroth.android.library.exif2'庫。與這個特定情況下的android.media.ExifInterface相比,它有什麼優勢嗎?如果這是由於'ExifInterface'股票的某些實現有缺陷,它是否仍然適用於> = 14的API?或者對於這些更新的API android.media.ExifInterface應該沒問題? –

+0

@AlexanderAbakumov:我想寫出修改過的位圖。這需要刪除縮略圖並更新EXIF方向標籤。 [支持庫的'ExifInterface'](https://developer.android.com/reference/android/support/media/ExifInterface.html)不提供'removeCompressedThumbnail()'方法。如果你沒有保存修改後的位圖,這應該不成問題。 – CommonsWare

+0

@AlexanderAbakumov:在Android 7.0之前,該平臺的'ExifInterface' [存在嚴重的安全漏洞](https://commonsware.com/blog/2016/09/08/dealing-exifinterface-security-flaw.html)。 [使用支持庫的'ExifInterface'](https://commonsware.com/blog/2016/12/15/about-support-exifinterface.html)或另一個基於Java的EXIF實現(例如我擁有的代碼那個樣本)。 – CommonsWare

1

事實證明,解決最初的問題變成了一套新的問題。以下是針對更多讀者的完整教程。

首先,作爲@CommonsWare pointed in his answer,我們必須使用EXIF方向標籤手動處理方向。爲了避免有缺陷android.media.ExifInterface車/安全性,以及第三方的依賴,最好的選擇似乎是一個新的com.android.support:exifinterface庫,並將它們加入build.gradle爲:

dependencies { 
    compile 'com.android.support:exifinterface:26.0.0' 
} 

不過,對於我來說,這導致了搖籃同步錯誤由於該庫的這個特定最新版本未在Google存儲庫中找到,儘管此版本是根據Support Library Packages頁面的最新版本。

試驗一小時後,我想通了,jcenter()倉庫是不夠的搖籃同步被加入谷歌Maven倉庫固定:

allprojects { 
    repositories { 
     jcenter() 
     maven { 
      url 'https://maven.google.com' 
      // Alternative URL is 'https://dl.google.com/dl/android/maven2/' 
     } 
    } 
} 

好了,現在我們能夠使用android.support.media.ExifInterface

下一個令人失望的是,存儲在EXIF標籤中的寬度和高度也不符合方向,即對於以縱向模式拍攝的圖像,您將獲得與使用BitmapFactory.decodeFile()創建的Bitmap相同的寬度和高度。因此,唯一的方法就是手動看EXIF ExifInterface.TAG_ORIENTATION標籤,如果說,圖像旋轉90度或270度 - 互換寬度和高度:

ExifInterface exif = new ExifInterface(fileNameFull); 
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); 

BitmapFactory.Options optsForBounds = new BitmapFactory.Options(); 
optsForBounds.inJustDecodeBounds = true; 
BitmapFactory.decodeFile(fileName, optsForBounds); 

int width = optsForBounds.outWidth, height = optsForBounds.outHeight; 
if (orientation == ExifInterface.ORIENTATION_ROTATE_90 || orientation == ExifInterface.ORIENTATION_ROTATE_270) 
{ 
    int temp = width; 
    //noinspection SuspiciousNameCombination 
    width = height; 
    height = temp; 
} 

我不知道,如果這個方法和代碼覆蓋100 %的情況下,所以如果你遇到任何問題跨各種設備/圖像來源 - 隨時發表評論。

一般來說,處理EXIF似乎並不愉快。甚至來自大公司的EXIF標準的實施似乎對細微差別的處理方式有很大不同。請參閱廣泛分析here

相關問題