1. 程式人生 > >將GPS資訊寫入到圖片裡

將GPS資訊寫入到圖片裡

一、概述

在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檔案中。