1. 程式人生 > >Android中通過Exif-ExifInterface獲取圖片的相關資訊,並且在圖片上新增獲取到的資訊將圖片展示出來

Android中通過Exif-ExifInterface獲取圖片的相關資訊,並且在圖片上新增獲取到的資訊將圖片展示出來

1、Exif-ExifInterface簡介
Exif是一種影象檔案格式,它的資料儲存與JPEG格式是完全相同的。實際上Exif格式就是在JPEG格式頭部插入了數碼照片的資訊,包括拍攝時的光圈、快門、白平衡、ISO、焦距、日期時間等各種和拍攝條件以及相機品牌、型號、色彩編碼、拍攝時錄製的聲音以及GPS全球定位系統資料、縮圖等。你可以利用任何可以檢視JPEG檔案的看圖軟體瀏覽Exif格式的照片,但並不是所有的圖形程式都能處理Exif資訊。今天這篇文章就來講講Android中操作Exif。

2、ExifInterface中的功能簡單進行介紹
Android開發中,在對圖片進行展示、編輯、傳送等操作時經常會涉及Exif的操作,Android中操作Exif主要是通過ExifInterface,ExifInterface看上去是一個介面,其實是一個類,位於Android.media.ExifInterface的位置。進入ExifInterface類,發現方法很少,主要就是三個方面:讀取、寫入、縮圖。

3、ExifInterface進行讀取操作

Exif資訊在檔案頭中是以二進位制的形式儲存的,儲存的欄位名稱和欄位值格式都是固定的。我測試的Android23(6.0)版本中,總共有26個Exif欄位,其中TAG_SUBSECTIME被加上了@hide註解,也就是還剩25個,我寫了個demo,獲取這25個欄位的值,看看都是什麼樣的格式。

ExifInterface exifInterface = new ExifInterface(filePath);

String orientation = exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION);
String dateTime = exifInterface.getAttribute(ExifInterface.TAG_DATETIME); String make = exifInterface.getAttribute(ExifInterface.TAG_MAKE); String model = exifInterface.getAttribute(ExifInterface.TAG_MODEL); String flash = exifInterface.getAttribute(ExifInterface.TAG_FLASH); String imageLength = exifInterface.getAttribute
(ExifInterface.TAG_IMAGE_LENGTH); String imageWidth = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_WIDTH); String latitude = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE); String longitude = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); String latitudeRef = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF); String longitudeRef = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); String exposureTime = exifInterface.getAttribute(ExifInterface.TAG_EXPOSURE_TIME); String aperture = exifInterface.getAttribute(ExifInterface.TAG_APERTURE); String isoSpeedRatings = exifInterface.getAttribute(ExifInterface.TAG_ISO); String dateTimeDigitized = exifInterface.getAttribute(ExifInterface.TAG_DATETIME_DIGITIZED); String subSecTime = exifInterface.getAttribute(ExifInterface.TAG_SUBSEC_TIME); String subSecTimeOrig = exifInterface.getAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIG); String subSecTimeDig = exifInterface.getAttribute(ExifInterface.TAG_SUBSEC_TIME_DIG); String altitude = exifInterface.getAttribute(ExifInterface.TAG_GPS_ALTITUDE); String altitudeRef = exifInterface.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF); String gpsTimeStamp = exifInterface.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP); String gpsDateStamp = exifInterface.getAttribute(ExifInterface.TAG_GPS_DATESTAMP); String whiteBalance = exifInterface.getAttribute(ExifInterface.TAG_WHITE_BALANCE); String focalLength = exifInterface.getAttribute(ExifInterface.TAG_FOCAL_LENGTH); String processingMethod = exifInterface.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD); Log.e("TAG", "## orientation=" + orientation); Log.e("TAG", "## dateTime=" + dateTime); Log.e("TAG", "## make=" + make); Log.e("TAG", "## model=" + model); Log.e("TAG", "## flash=" + flash); Log.e("TAG", "## imageLength=" + imageLength); Log.e("TAG", "## imageWidth=" + imageWidth); Log.e("TAG", "## latitude=" + latitude); Log.e("TAG", "## longitude=" + longitude); Log.e("TAG", "## latitudeRef=" + latitudeRef); Log.e("TAG", "## longitudeRef=" + longitudeRef); Log.e("TAG", "## exposureTime=" + exposureTime); Log.e("TAG", "## aperture=" + aperture); Log.e("TAG", "## isoSpeedRatings=" + isoSpeedRatings); Log.e("TAG", "## dateTimeDigitized=" + dateTimeDigitized); Log.e("TAG", "## subSecTime=" + subSecTime); Log.e("TAG", "## subSecTimeOrig=" + subSecTimeOrig); Log.e("TAG", "## subSecTimeDig=" + subSecTimeDig); Log.e("TAG", "## altitude=" + altitude); Log.e("TAG", "## altitudeRef=" + altitudeRef); Log.e("TAG", "## gpsTimeStamp=" + gpsTimeStamp); Log.e("TAG", "## gpsDateStamp=" + gpsDateStamp); Log.e("TAG", "## whiteBalance=" + whiteBalance); Log.e("TAG", "## focalLength=" + focalLength); Log.e("TAG", "## processingMethod=" + processingMethod);

列印的結果

E/TAG: ## orientation=0
E/TAG: ## dateTime=2016:05:23 17:30:11
E/TAG: ## make=Xiaomi
E/TAG: ## model=Mi-4c
E/TAG: ## flash=16
E/TAG: ## imageLength=4160
E/TAG: ## imageWidth=3120
E/TAG: ## latitude=31/1,58/1,253560/10000
E/TAG: ## longitude=118/1,44/1,491207/10000
E/TAG: ## latitudeRef=N
E/TAG: ## longitudeRef=E
E/TAG: ## exposureTime=0.050
E/TAG: ## aperture=2.0
E/TAG: ## iso=636
E/TAG: ## dateTimeDigitized=2016:05:23 17:30:11
E/TAG: ## subSecTime=379693
E/TAG: ## subSecTimeOrig=379693
E/TAG: ## subSecTimeDig=379693
E/TAG: ## altitude=0/1000
E/TAG: ## altitudeRef=0
E/TAG: ## gpsTimeStamp=9:30:8
E/TAG: ## gpsDateStamp=2016:05:23
E/TAG: ## whiteBalance=0
E/TAG: ## focalLength=412/100
E/TAG: ## processingMethod=NETWORK

這25個欄位分別是代表什麼呢?

ExifInterface.TAG_ORIENTATION //旋轉角度,整形表示,在ExifInterface中有常量對應表示
ExifInterface.TAG_DATETIME //拍攝時間,取決於裝置設定的時間
ExifInterface.TAG_MAKE //裝置品牌
ExifInterface.TAG_MODEL //裝置型號,整形表示,在ExifInterface中有常量對應表示
ExifInterface.TAG_FLASH //閃光燈
ExifInterface.TAG_IMAGE_LENGTH //圖片高度
ExifInterface.TAG_IMAGE_WIDTH //圖片寬度
ExifInterface.TAG_GPS_LATITUDE //緯度
ExifInterface.TAG_GPS_LONGITUDE //經度
ExifInterface.TAG_GPS_LATITUDE_REF //緯度名(N or S)
ExifInterface.TAG_GPS_LONGITUDE_REF //經度名(E or W)
ExifInterface.TAG_EXPOSURE_TIME //曝光時間
ExifInterface.TAG_APERTURE //光圈值
ExifInterface.TAG_ISO //ISO感光度
ExifInterface.TAG_DATETIME_DIGITIZED //數字化時間
ExifInterface.TAG_SUBSEC_TIME //
ExifInterface.TAG_SUBSEC_TIME_ORIG //
ExifInterface.TAG_SUBSEC_TIME_DIG //
ExifInterface.TAG_GPS_ALTITUDE //海拔高度
ExifInterface.TAG_GPS_ALTITUDE_REF //海拔高度
ExifInterface.TAG_GPS_TIMESTAMP //時間戳
ExifInterface.TAG_GPS_DATESTAMP //日期戳
ExifInterface.TAG_WHITE_BALANCE //白平衡
ExifInterface.TAG_FOCAL_LENGTH //焦距
ExifInterface.TAG_GPS_PROCESSING_METHOD //用於定位查詢的全球定位系統處理方法。

其中TAG_SUBSEC_TIME 、TAG_SUBSEC_TIME_ORIG 、TAG_SUBSEC_TIME_DIG 沒有加註釋,我也沒查清楚具體是什麼意思,但是看log,三個值是一樣的。有知道的朋友可以跟我說下,謝謝!

細心的朋友會發現,上面所有的取值都是用的一個方法:exifInterface.getAttribute(String tag),其實ExifInterface還提供了其它方法。

exifInterface.getAltitude(long default); //返回海拔高度,單位米,如果exif的tag不存在,返回預設值。
exifInterface.getAttributeDouble(String tag, Double default) //返回double值,傳入預設值
exifInterface.getAttributeInt(String tag, int default) //返回int值,傳入預設值
exifInterface.getLatLong(float[] value) //返回緯度和經度,陣列第一個是緯度,第二個是經度

4、ExifInterface進行寫入操作

相對讀取,寫入就簡單很多了。

ExifInterface exifInterface = new ExifInterface(filePath);
exifInterface.setAttribute(ExifInterface.TAG_GPS_ALTITUDE,"1/1000");
exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION,"6");
exifInterface.setAttribute(ExifInterface.TAG_IMAGE_WIDTH,"2000");
exifInterface.saveAttributes();

程式碼很簡答,但有一點需要說下,setAttributes只是設定屬性值,沒有儲存,saveAttributes才真正儲存,但是這個方法比較耗時,不要每set一次都save,全部set完後,再統一save一次。
有一點很尷尬,saveAttributes()這個方法內部會遍歷儲存所有的值,哪怕你只改變了其中一個值。

5、ExifInterface獲取縮圖

getThumbnail()這個方法可以生成一個縮圖,返回一個位元組陣列,得到位元組陣列就可以輕鬆生成Bitmap。

但是在呼叫這個方法前,最好先呼叫exifInterface.hasThumbnail()判斷一下是否有縮圖。

getThumbnail()這個方法呼叫的是native方法,所以具體的實現就看不到了,我也不知道生成的縮圖的解析度是多少。到這裡,ExifInterface的使用介紹以及完畢。

6、在ExifInterface獲取的資訊中進行新增到圖片,實現步驟如下:

步驟一:我們在佈局檔案中activity_main.xml中的程式碼,建立一個控制元件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context="com.yoyoyt.exifinterfacedemo.MainActivity">

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="500dp"
        android:layout_height="300dp"
        />
</RelativeLayout>

步驟二:我們在MainActivity中找的控制,並獲取資訊,將資訊新增到圖片上面。並顯示在控制元件上,具體程式碼如下:

package com.yoyoyt.exifinterfacedemo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    //獲取載入圖片的路徑
    String path = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/IMG_20160927_135402.jpg";
    private String width;
    private String height;
    private Bitmap bitmap;
    private Bitmap imgTemp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //找到控制元件的id
        ImageView iv= (ImageView) findViewById(R.id.imageview);
        bitmap = BitmapFactory.decodeFile(path);
//        iv.setImageBitmap(bitmap);


        //android讀取圖片EXIF資訊
        try {
            ExifInterface exifInterface=new ExifInterface(path);

//         執行儲存
            exifInterface.saveAttributes();
            //獲取圖片的方向
            String orientation = exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION);
            //獲取圖片的時間
            String dateTime = exifInterface.getAttribute(ExifInterface.TAG_DATETIME);
            String make = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
            String model = exifInterface.getAttribute(ExifInterface.TAG_MODEL);
            String flash = exifInterface.getAttribute(ExifInterface.TAG_FLASH);
             height = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_LENGTH);
             width = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_WIDTH);
            String latitude = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
            String longitude = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);

            StringBuilder sb = new StringBuilder();
            sb.append(longitude)
                    .append(latitude);

            Log.e("TAG", "## orientation=" + orientation);
            Log.e("TAG", "## dateTime=" + dateTime);
            Log.e("TAG", "## make=" + make);
            Log.e("TAG", "## model=" + model);
            Log.e("TAG", "## flash=" + flash);
            Log.e("TAG", "## imageLength=" + height);
            Log.e("TAG", "## imageWidth=" + width);
            Log.e("TAG", "## latitude=" + latitude);
            Log.e("TAG", "## longitude=" + longitude);
            String driving_name="駕校名稱:東方時尚駕校";
            String coach="教練員姓名:張三";
            String lerner="學員姓名:李四";
            String time="採集時間:2016";
            String car_number="車牌號:京RF8900786";
            String longt="102.00";
            String lat="35.5";
            String car_speed="車輛行駛速度:20km/h";

            Toast.makeText(MainActivity.this,sb, Toast.LENGTH_LONG).show();
            Drawable drawable = createDrawable(driving_name,coach,lerner,time,car_number,longt,lat,car_speed);
            iv.setBackgroundDrawable(drawable);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 穿件帶字母的標記圖片
    private Drawable createDrawable(String driving_name, String coach, String lerner, String time, String car_number, String longt, String lat, String car_speed) {
        imgTemp = Bitmap.createBitmap(Integer.valueOf(width), Integer.valueOf(height), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(imgTemp);
        Paint paint = new Paint(); // 建立畫筆
        paint.setDither(true);
        paint.setFilterBitmap(true);
        Rect src = new Rect(0, 0,Integer.valueOf(width), Integer.valueOf(height));
        Rect dst = new Rect(0, 0, Integer.valueOf(width), Integer.valueOf(height));
        canvas.drawBitmap(bitmap, src, dst, paint);

        Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG
                | Paint.DEV_KERN_TEXT_FLAG);
        textPaint.setTextSize(100.0f);
        textPaint.setTypeface(Typeface.DEFAULT_BOLD); // 採用預設的寬度
        textPaint.setColor(Color.WHITE);

        canvas.drawText(driving_name,Integer.valueOf(width)/100, Integer.valueOf(height)/8,
                textPaint);
        canvas.drawText(coach,0, (Integer.valueOf(height)/8)+100,textPaint);
        canvas.drawText(lerner,0,(Integer.valueOf(height)/8)+200,textPaint);
        canvas.drawText(time,0,(Integer.valueOf(height)/8)+300,textPaint);
        canvas.drawText(car_number,0,(Integer.valueOf(height)/8)+400,textPaint);
        canvas.drawText(longt,0,(Integer.valueOf(height)/8)+500,textPaint);
        canvas.drawText(lat,0,(Integer.valueOf(height)/8)+600,textPaint);
        canvas.drawText(car_speed,0,(Integer.valueOf(height)/8)+700,textPaint);
        canvas.save(Canvas.ALL_SAVE_FLAG);
        canvas.restore();

        return (Drawable) new BitmapDrawable(getResources(), imgTemp);

    }


}

步驟三:最後,我們在配置檔案中進行新增許可權

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

這樣,我們就大功告成,可以執行看效果了。