將GPS資訊寫入到圖片裡
阿新 • • 發佈:2019-01-28
一、概述
在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檔案中。