Exif圖片方向的一些發現

背景

首先,先要了解Exif是個什麼東東,搬出百度百科html

可交換圖像文件格式(英語:Exchangeable image file format,官方簡稱Exif),是專門爲數碼相機的照片設定的,能夠記錄數碼照片的屬性信息和拍攝數據。

說到底Exif就是一種格式,用來存儲圖片的一些信息,這些信息和咱們平常比較相關的有拍攝設備,拍攝地點,圖片尺寸等,不過今天的主角是另一個——那就是圖片方向(orientation)。這個圖片方向不是指咱們平時使用圖片編輯器旋轉的方向,而是拍照時手機的方向。總共有八個方向:
在這裏插入圖片描述git

下圖是JPEG ORIENTATION對應圖片方向的糾正算法,這裏它經過三位二進制數表明八種方向,而後再經過每一位二進制數對應不一樣的操做來對圖片進行糾正,以下:
在這裏插入圖片描述github

最高位二進制數表明對角線翻轉的操做,第二位二進制數表明旋轉180度的操做,最低位表明水平翻轉的操做。
例如001,就是水平翻轉,因此能夠看到001的圖形和原圖形關於水平軸對稱。經過把八個方向的圖形用3個二進制數即三種操做組合,就能夠很方便的對圖形作轉換,編碼僞代碼以下:算法

if (value & 100b != 0)  image.flip-diagonally
if (value & 010b != 0)  image.rotate-180
if (value & 001b != 0)  image.flip-horizontally

那有人就會困惑了,本身怎麼平時沒有看到這種圖片呢,這是由於咱們使用的圖片查看器或者是瀏覽器對orientation作了兼容,會對展現的圖片作轉換。windows

以下是windows文件夾的展現:
瀏覽器

下面則是Android Studio的圖片展現
性能優化

因此能夠看到,windows是默認對圖片orientation作了處理,而Android的ImageView則沒有處理因此看到的是圖片原本的方向。
這是八個F的圖片連接編輯器

應用

在Android裏面,三星手機的拍照是個奇葩的存在,三星手機的exif是旋轉90度,別家手機則是0度,因此三星手機的照片須要作處理,這裏是一張三星手機照片的exif信息:
在這裏插入圖片描述post

三星手機的方向是Rotate 90CW,意思就是須要順時針方向(ClockWise)旋轉90度。
腦袋轉的快的同窗能夠對照上面的F圖,相信很快看出是101這張圖。
那咱們取出圖片的orientation值進行驗證:性能

try {
            val exifInterface = ExifInterface(resources.openRawResource(id))
            val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
            Log.e("orientation", orientation.toString())
        } catch (e: IOException) {
            e.printStackTrace()
        }

打印結果是6,和上面的101對不上,其實在Android的orientation是須要作減1處理的,也就是說6其實對應的是101這種狀態。另外,須要注意的是,若是打印結果是0,那麼說明圖片沒有orientation這個信息。

那接下來咱們進行編碼,這是第一張方式:

val options = BitmapFactory.Options()
  var bitmap = BitmapFactory.decodeResource(resources, R.mipmap.error_orientation, options)
  val matrix = Matrix()
  matrix.postRotate(getOrientation(R.mipmap.error_orientation).toFloat())
  bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
  imageview.setImageBitmap(bitmap)

  private fun getOrientation(id:Int): Int {
        var degree = 0
        try {
            val exifInterface = ExifInterface(resources.openRawResource(id))
            val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> degree = 90
                ExifInterface.ORIENTATION_ROTATE_180 -> degree = 180
                ExifInterface.ORIENTATION_ROTATE_270 -> degree = 270
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return degree
    }

通常來講,咱們只須要處理這三種角度,上面三個角度對應的orientation是6 3 8,也就是101,010,111這三種狀態。爲何通常只須要處理這三種狀態呢,本身腦補一下拿相機的角度,不外乎就四種狀況,除了正常的狀況下,不就只須要處理三種狀況嗎?嘿嘿,我真是個小機靈鬼。
固然,若是要嚴謹一點,仍是須要按照JPEG那種操做方式來,以下:

val options = BitmapFactory.Options()
 var bitmap = BitmapFactory.decodeResource(resources, R.mipmap.f7t, options)
 val matrix = genOrientationMatrix(R.mipmap.f7t)
 bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
 imageview.setImageBitmap(bitmap)

 private fun genOrientationMatrix(id:Int): Matrix {
        val matrix = Matrix()
        try {
            val exifInterface = ExifInterface(resources.openRawResource(id))
            var orientation =  exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
            if (orientation > 0) {
                orientation--
                if (orientation and 0b100 != 0) { //對角線翻轉
                    matrix.postScale(-1.0f, 1.0f)
                    matrix.postRotate(-90f)
                }
                if (orientation and 0b010 != 0) { //旋轉180度
                    matrix.postRotate(180f)
                }
                if (orientation and 0b001 != 0) { //水平翻轉
                    matrix.postScale(-1.0f, 1.0f)
                }
            }
            return matrix
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return matrix
    }

其實就是將JPEG對於orientation的轉換利用代碼進行實現,對矩陣進行相應的變換。

總結

Exif是一種存儲了相片一些信息的格式,日常咱們在進行Android開發的時候,通常須要考慮方向的問題,可是在平常生活,這個也是暴露咱們隱私的入口,因此手機在拍照的時候,最好將保存位置這些選項關閉,避免泄漏本身的隱私。

參考

Android性能優化:圖片保存,還能更快

JPEG Orientation

相關文章
相關標籤/搜索