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"/>
這樣,我們就大功告成,可以執行看效果了。