Wednesday, April 27, 2011

Update GPS TAG, using ExifInterface.setAttribute() and exifInterface.saveAttributes()

Update GPS TAG, using ExifInterface.setAttribute() and exifInterface.saveAttributes()

Last exercise show how to "Read EXIF of JPG file", new member method UpdateGeoTag() will be implemented to update GPS TAG of the file with dummy data.

exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE, DUMMY_GPS_LATITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, DUMMY_GPS_LATITUDE_REF);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, DUMMY_GPS_LONGITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, DUMMY_GPS_LONGITUDE_REF);

Once all attributes set, you can call exifInterface.saveAttributes() method to update the file.

with updated GPS TAG

In order to write-back data to file in SD Card, you have to modify AndroidManifest.xml grant permission of "android.permission.WRITE_EXTERNAL_STORAGE".

Related post
- "Convert Exif GPS info to Degree format".

In my exercise, the update Geo location can be recognized automatically by Picasa, Flickr and Nikon ViewNX.

MyExif.java
package com.exercise.AndroidSelectImage;

import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.database.Cursor;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;

public class MyExif {

private File exifFile; //It's the file passed from constructor
private String exifFilePath; //file in Real Path format
private Activity parentActivity; //Parent Activity

private String exifFilePath_withoutext;
private String ext;

private ExifInterface exifInterface;
private Boolean exifValid = false;;

//Exif TAG
//for API Level 8, Android 2.2
private String exif_DATETIME = "";
private String exif_FLASH = "";
private String exif_FOCAL_LENGTH = "";
private String exif_GPS_DATESTAMP = "";
private String exif_GPS_LATITUDE = "";
private String exif_GPS_LATITUDE_REF = "";
private String exif_GPS_LONGITUDE = "";
private String exif_GPS_LONGITUDE_REF = "";
private String exif_GPS_PROCESSING_METHOD = "";
private String exif_GPS_TIMESTAMP = "";
private String exif_IMAGE_LENGTH = "";
private String exif_IMAGE_WIDTH = "";
private String exif_MAKE = "";
private String exif_MODEL = "";
private String exif_ORIENTATION = "";
private String exif_WHITE_BALANCE = "";

//Constructor from path
MyExif(String fileString, Activity parent){
exifFile = new File(fileString);
parentActivity = parent;
exifFilePath = fileString;
PrepareExif();
}

//Constructor from URI
MyExif(Uri fileUri, Activity parent){
exifFile = new File(fileUri.toString());
parentActivity = parent;
exifFilePath = getRealPathFromURI(fileUri);
PrepareExif();
}

private void PrepareExif(){

int dotposition= exifFilePath.lastIndexOf(".");
exifFilePath_withoutext = exifFilePath.substring(0,dotposition);
ext = exifFilePath.substring(dotposition + 1, exifFilePath.length());

if (ext.equalsIgnoreCase("jpg")){
try {
exifInterface = new ExifInterface(exifFilePath);
ReadExifTag();
exifValid = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

private void ReadExifTag(){

exif_DATETIME = exifInterface.getAttribute(ExifInterface.TAG_DATETIME);
exif_FLASH = exifInterface.getAttribute(ExifInterface.TAG_FLASH);
exif_FOCAL_LENGTH = exifInterface.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
exif_GPS_DATESTAMP = exifInterface.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
exif_GPS_LATITUDE = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
exif_GPS_LATITUDE_REF = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
exif_GPS_LONGITUDE = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
exif_GPS_LONGITUDE_REF = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
exif_GPS_PROCESSING_METHOD = exifInterface.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
exif_GPS_TIMESTAMP = exifInterface.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
exif_IMAGE_LENGTH = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_LENGTH);
exif_IMAGE_WIDTH = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_WIDTH);
exif_MAKE = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
exif_MODEL = exifInterface.getAttribute(ExifInterface.TAG_MODEL);
exif_ORIENTATION = exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION);
exif_WHITE_BALANCE = exifInterface.getAttribute(ExifInterface.TAG_WHITE_BALANCE);

}

private String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = parentActivity.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}

public String getSummary(){
if(!exifValid){
return ("Invalide EXIF!");
}else{
return( exifFilePath + " : \n" +

"Name without extension: " + exifFilePath_withoutext + "\n" +
"with extension: " + ext + "\n" +

//"Date Time: " + exif_DATETIME + "\n" +
//"Flash: " + exif_FLASH + "\n" +
//"Focal Length: " + exif_FOCAL_LENGTH + "\n" +
//"GPS Date Stamp: " + exif_GPS_DATESTAMP + "\n" +
"GPS Latitude: " + exif_GPS_LATITUDE + "\n" +
"GPS Latitute Ref: " + exif_GPS_LATITUDE_REF + "\n" +
"GPS Longitude: " + exif_GPS_LONGITUDE + "\n" +
"GPS Longitude Ref: " + exif_GPS_LONGITUDE_REF);
//"Processing Method: " + exif_GPS_PROCESSING_METHOD + "\n" +
//"GPS Time Stamp: " + exif_GPS_TIMESTAMP + "\n" +
//"Image Length: " + exif_IMAGE_LENGTH + "\n" +
//"Image Width: " + exif_IMAGE_WIDTH + "\n" +
//"Make: " + exif_MAKE + "\n" +
//"Model: " + exif_MODEL + "\n" +
//"Orientation: " + exif_ORIENTATION + "\n" +
//"White Balance: " + exif_WHITE_BALANCE + "\n");
}
}

public void UpdateGeoTag(){
//with dummy data
final String DUMMY_GPS_LATITUDE = "22/1,21/1,299295/32768";
final String DUMMY_GPS_LATITUDE_REF = "N";
final String DUMMY_GPS_LONGITUDE = "114/1,3/1,207045/4096";
final String DUMMY_GPS_LONGITUDE_REF = "E";

exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE, DUMMY_GPS_LATITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, DUMMY_GPS_LATITUDE_REF);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, DUMMY_GPS_LONGITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, DUMMY_GPS_LONGITUDE_REF);
try {
exifInterface.saveAttributes();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
}


AndroidSelectImage.java
package com.exercise.AndroidSelectImage;

import java.io.File;
import java.io.FileNotFoundException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class AndroidSelectImage extends Activity {

TextView textTargetUri;
ImageView targetImage;
Button buttonSaveImage;

File targetFile;
String exifAttribute;

MyExif myExif;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonLoadImage = (Button)findViewById(R.id.loadimage);
buttonSaveImage = (Button)findViewById(R.id.saveimage);
textTargetUri = (TextView)findViewById(R.id.targeturi);
targetImage = (ImageView)findViewById(R.id.targetimage);

buttonLoadImage.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
buttonSaveImage.setEnabled(false);
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 0);
}});

buttonSaveImage.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
myExif.UpdateGeoTag(); //with dummy data
}});
}

@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_OK){
Uri targetUri = data.getData();

Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(targetUri));
targetImage.setImageBitmap(bitmap);
buttonSaveImage.setEnabled(true);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

myExif = new MyExif(targetUri, this);
textTargetUri.setText(myExif.getSummary());
}
}

}


main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/loadimage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Load Image"
/>
<Button
android:id="@+id/saveimage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Update Geo Tag (with DUMMY data)"
android:enabled="false"
/>
<TextView
android:id="@+id/targeturi"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/targetimage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>


Download the files.

7 comments:

Anonymous said...

Hi,This is great example of exif it help me alot but geotag is not updating.Please reply me what i doing wrong?

Erik said...

Make sure you have modify AndroidManifest.xml to add permission of "android.permission.WRITE_EXTERNAL_STORAGE". If you miss it, it will not save, WITHOUT error message!

And, the Android buildin Gallery will not re-scan the Exif, may be you have to re-boot your device, such that Gallery will re-scan it. And Gallery is not show the Exif GPS location, it show the nearby location.

Unknown said...

Great code ,i got an exif image data, but one problem,i test my own mobile android(2.3) the camera image,from there GPS Latitude: 33619970/65540, 22937600/3368550N at the same time GPS Longitude will be 114/1,3/1, 207045/4096, what wrong my code please help me..

Unknown said...

Hi Prasanth Gs.
Please look at the http://stackoverflow.com/questions/10531544/write-geotag-jpegs-exif-data-in-android

it should solve your problem.

NIHAR said...

@ Admin.
Really a good tutorial,implemented part of it.

However can u tell me how to add custom data to the exif .I have tried the suggestion in stackoverflow but it does not work

"http://stackoverflow.com/questions/15506862/android-create-custom-exif-attributes-for-an-image-file"

if u have solution then post or at least let me know whether it is possible or not .I am scratching my head for a few good no of days.

Thanks.

Hitesh Patel said...

E/JHEAD: can't open '/storage/ and i don't have external storage.how to solve it

Divya said...

can't load the attributes.what to do..plz say any suggestion