一、概述
在Android2.2中,Camera的應用程序並不支持將GPS信息寫入到JPEG文件中,但如果要實現這個功能,有如下兩種方式:
1、修改底層camera驅動。在拍照時,一般都是使用硬件去進行JPEG編碼,這樣就需要修改JPEG編碼器,使其可以將GPS信息寫入JPEG文件的頭部,即EXIF部分。這種方式使用與手機驅動開發者。
2、修改camera應用程序。Camera應用程序本身不支持該功能,但是android系統中提供了支持該功能的類——ExifInterface。本文介紹如何使用該類進行GPS信息的寫入。這種方法的不足在於,每次寫入GPS功能,都會把原有的JPEG文件讀出,修改了Exif header部分後再寫入文件。
二、實現GPS寫入功能
首先來看看文件ImageManager.java,該文件位於:
/package/apps/Camera/src/com/android/camera/
該文件中,有個addImage()函數,其定義爲:
public static Uri addImage(ContentResolver cr, String title, long dateTaken,
Location location, String directory, String filename,
Bitmap source, byte[] jpegData, int[] degree) {
。。。。。。
String filePath = directory + "/" + filename;
。。。。。。
if (location != null) {
values.put(Images.Media.LATITUDE, location.getLatitude());
values.put(Images.Media.LONGITUDE, location.getLongitude());
}
}
return cr.insert(STORAGE_URI, values);
}
此處,當location不等於null時,表示已經開啓存儲位置的功能,並且該手機的GPS功能已開啓並且正常。在這裏,我們就可以把GPS的信息寫入JPEG文件中。其具體code如下:
public static Uri addImage(ContentResolver cr, String title, long dateTaken,
Location location, String directory, String filename,
Bitmap source, byte[] jpegData, int[] degree) {
。。。。。。
String filePath = directory + "/" + filename;
。。。。。。
if (location != null) {
values.put(Images.Media.LATITUDE, location.getLatitude());
values.put(Images.Media.LONGITUDE, location.getLongitude());
ExifInterface exif = null;
try {
exif = new ExifInterface(filePath);
} catch (IOException ex) {
Log.e(TAG, "cannot read exif", ex);
}
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, Double.toString(location.getLatitude()));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, Double.toString(location.getLongitude()));
try{
if(exif != null)
exif.saveAttributes();
} catch (IOException ex) {
Log.e(TAG, "Fail to exif.saveAttributes().");
}
}
return cr.insert(STORAGE_URI, values);
}
三、分析GPS寫入功能的實現
首先看看類ExifInterface的構造函數,其位於:
/framework/base/media/java/android/media/ ExifInterface.java
其具體實現爲:
public ExifInterface(String filename) throws IOException {
mFilename = filename;
loadAttributes();
}
其功能是從指定的文件中獲取其Exif信息。函數loadAttributes()的定義爲:
private void loadAttributes() throws IOException {
// format of string passed from native C code:
// "attrCnt attr1=valueLen value1attr2=value2Len value2..."
// example:
// "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
mAttributes = new HashMap<String, String>();
String attrStr;
synchronized (sLock) {
attrStr = getAttributesNative(mFilename);
}
……
}
該函數從文件中讀取Exif信息,並將其寫入mAttributes中。函數
getAttributesNative(mFilename),調用了JNI接口,其定義位於:
/external/jhead/main.c
static JNINativeMethod methods[] = {
{"saveAttributesNative", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)saveAttributes },
{"getAttributesNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAttributes },
{"appendThumbnailNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)appendThumbnail },
{"commitChangesNative", "(Ljava/lang/String;)V", (void*)commitChanges },
{"getThumbnailNative", "(Ljava/lang/String;)[B", (void*)getThumbnail },
};
函數setAttribute()的實現如下:
public void setAttribute(String tag, String value) {
mAttributes.put(tag, value);
}
向mAttributes寫入對應的項,比如經度和緯度信息。
最重要的函數saveAttributes(),它也是調用JNI接口。它負責將所有的Exif項寫入到JPEG文件中。由於時間關係,就不做介紹了,具體代碼請大家自己看,有問題的話,一起討論。