Writing location coordinates to exif changes location - android

I have an app published on Google Play, which at some point fetches the users geographical location and saves it with a picture. I have however now gotten reports from a few Brazilian users complaining about the pictures are getting GeoTagged in Saudi Arabia. Have only gotten this complaint from users in Brazil and I am by no means what so ever able to reproduce the issue myself.
What could be causing this?
// I save and read the location in an ExifInterface with this "book"..
// Write Geotag and time to Image's Exif
public Boolean writeExifData(Location location, Date date, String filepath){
// Determine if we got a location
boolean isLocationOn = false;
if(location != null){ isLocationOn = true; }
try {
// Set up exif
ExifInterface exif = new ExifInterface(filepath);
if(isLocationOn){
// Get location values
double latitude = location.getLatitude();
double longitude = location.getLongitude();
float accuracy = location.getAccuracy();
// Convert Latitude and Longitude
int num1Lat = (int)Math.floor(latitude);
int num2Lat = (int)Math.floor((latitude - num1Lat) * 60);
double num3Lat = (latitude - ((double)num1Lat+((double)num2Lat/60))) * 3600000;
int num1Lon = (int)Math.floor(longitude);
int num2Lon = (int)Math.floor((longitude - num1Lon) * 60);
double num3Lon = (longitude - ((double)num1Lon+((double)num2Lon/60))) * 3600000;
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, num1Lat+"/1,"+num2Lat+"/1,"+num3Lat+"/1000");
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, num1Lon+"/1,"+num2Lon+"/1,"+num3Lon+"/1000");
if (latitude > 0) {
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "N");
}else {
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "S");
}
if (longitude > 0) {
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "E");
}else {
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "W");
}
// Add accuracy to exif
String accuracy_value = String.valueOf(Math.round(accuracy));
exif.setAttribute("UserComment", "accuracy=" + accuracy_value);
}
// Add capture time to exif
exif.setAttribute(ExifInterface.TAG_DATETIME, date.toString());
// Save exif
exif.saveAttributes();
Log.v(Constants.TAG_ALERT_PROCESS, "Wrote data to Exif successfully");
return true;
} catch (IOException e) {
Log.v(Constants.TAG_ALERT_PROCESS, "Failed writing data to Exif with error: " + e.getMessage());
return false;
}
}
public Object_ImageExifData readExifData(String filePath){
Helper_ExifGeoConverter geoConverter;
Location location = null;
ExifInterface exif;
// Format filePath String (remove "file://" )
if(filePath.startsWith("file://")){
filePath = filePath.replace("file://", "");
}
try {
exif = new ExifInterface(filePath);
if(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE) != null){
geoConverter = new Helper_ExifGeoConverter(exif);
location = new Location("");
float float_lat = geoConverter.getLatitude();
location.setLatitude(float_lat);
float float_lon = geoConverter.getLongitude();
location.setLongitude(float_lon);
/** Get accuracy. Accuracy is stored
* under the tag UserComment as "accuracy=xx"*/
if(exif.getAttribute("UserComment") != null){
String value = exif.getAttribute("UserComment");
value = value.replace("accuracy=", "");
float accuracy = Integer.parseInt(value);
location.setAccuracy(accuracy);
}
// Get capture time
String time = "";
if(exif.getAttribute(ExifInterface.TAG_DATETIME) != null){
time = exif.getAttribute(ExifInterface.TAG_DATETIME);
}
return new Object_ImageExifData(location, time);
}else{
// Get capture time
String time = "xx.xx.xxxx";
if(exif.getAttribute(ExifInterface.TAG_DATETIME) != null){
time = exif.getAttribute(ExifInterface.TAG_DATETIME);
}
return new Object_ImageExifData(location, time);
}
} catch (IOException e) {
e.printStackTrace();
Log.v("myTag", "Failed to read exif data");
return null;
}
}
public class Helper_ExifGeoConverter{
private boolean valid = false;
Float Latitude, Longitude;
Helper_ExifGeoConverter(ExifInterface exif) {
String attrLATITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
String attrLATITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
String attrLONGITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
String attrLONGITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
if ((attrLATITUDE != null) && (attrLATITUDE_REF != null)
&& (attrLONGITUDE != null) && (attrLONGITUDE_REF != null)) {
valid = true;
if (attrLATITUDE_REF.equals("N")) {
Latitude = convertToDegree(attrLATITUDE);
} else {
Latitude = 0 - convertToDegree(attrLATITUDE);
}
if (attrLONGITUDE_REF.equals("E")) {
Longitude = convertToDegree(attrLONGITUDE);
} else {
Longitude = 0 - convertToDegree(attrLONGITUDE);
}
}
}
private Float convertToDegree(String stringDMS){
Float result;
String[] DMS = stringDMS.split(",", 3);
String[] stringD = DMS[0].split("/", 2);
Double D0 = Double.valueOf(stringD[0]);
Double D1 = Double.valueOf(stringD[1]);
Double FloatD = D0/D1;
String[] stringM = DMS[1].split("/", 2);
Double M0 = Double.valueOf(stringM[0]);
Double M1 = Double.valueOf(stringM[1]);
Double FloatM = M0/M1;
String[] stringS = DMS[2].split("/", 2);
Double S0 = Double.valueOf(stringS[0]);
Double S1 = Double.valueOf(stringS[1]);
Double FloatS = S0/S1;
result = new Float(FloatD + (FloatM/60) + (FloatS/3600));
return result;
}
SOLUTION
With the help of #greenapps I came to realize that I was, when writing to Exif, converting location from decimal format to degrees, minutes, seconds format falsely. Used this code instead.

If you put geo lat/lon tags in the exif info of a jpg then all lat/lons are positive. You also have to set a E/O and N/S tag. Are you doing that?

Related

Save and Retrieve location inside JPEG image

Am going to share a solution which include save and retrieve location inside a JPEG image file.The latitude and longitude is save and retrive inside the image metadata using ExifInterface
More about ExifInterface can be found here
http://developer.android.com/reference/android/media/ExifInterface.html
public void saveLocation() {
ExifInterface exif = null;
try {
exif = new ExifInterface(imagePath);
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latitude);
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, longitude);
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
}
}
public void retriveLocation() {
ExifInterface exif = null;
try {
exif = new ExifInterface(imagePath);
String[] latitudeValue = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE).split(",");
String[] longitudeValue = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE).split(",");
String[] tmp = new String[2];
tmp = latitudeValue[0].split("/");
setLatitude(String.valueOf(Float.valueOf(tmp[0]) / Float.valueOf(tmp[1])));
tmp = longitudeValue[0].split("/");
setLongitude(String.valueOf(Float.valueOf(tmp[0]) / Float.valueOf(tmp[1])));
} catch (IOException e) {
e.printStackTrace();
}
}
Using ExifInterface you can get following information from media.
Variable Declaration.
String mediaDateTime,attrLATITUDE,attrLATITUDE_REF,attrLONGITUDE,attrLONGITUDE_REF,zip, city,state, country;;
Double Latitude, Longitude;
List<Address> addresses;
Geocoder geocoder;
User ExifInterface using following way.
ExifInterface exifInterfaceMedia = new ExifInterface(<Your Image Path>);
// This will give you data and time
mediaDateTime = exifInterfaceMedia.getAttribute(ExifInterface.TAG_DATETIME);
attrLATITUDE = exifInterfaceMedia.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
attrLATITUDE_REF = exifInterfaceMedia.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
attrLONGITUDE = exifInterfaceMedia.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
attrLONGITUDE_REF = exifInterfaceMedia.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
if ((attrLATITUDE != null) && (attrLATITUDE_REF != null) && (attrLONGITUDE != null) && (attrLONGITUDE_REF != null)) {
valid = true;
if (attrLATITUDE_REF.equals("N")) {
Latitude = convertToDegree(attrLATITUDE);
} else {
Latitude = 0 - convertToDegree(attrLATITUDE);
}
if (attrLONGITUDE_REF.equals("E")) {
Longitude = convertToDegree(attrLONGITUDE);
} else {
Longitude = 0 - convertToDegree(attrLONGITUDE);
}
try {
addresses = geocoder.getFromLocation(Latitude, Longitude, 1);
} catch (IOException e) {
e.printStackTrace();
}
if (addresses != null && addresses.size() > 0) {
zip = addresses.get(0).getPostalCode();
city = addresses.get(0).getLocality();
state = addresses.get(0).getAdminArea();
country = addresses.get(0).getCountryName();
if (zip != null) {
title += zip + ",";
}
if (city != null) {
title += city + ",";
}
if (state != null) {
title += state + ",";
}
if (country != null) {
title += country;
}
} else {
title = "Unknown Location";
}
}
private Double convertToDegree(String stringDMS) {
Double result = null;
String[] DMS = stringDMS.split(",", 3);
String[] stringD = DMS[0].split("/", 2);
Double D0 = new Double(stringD[0]);
Double D1 = new Double(stringD[1]);
Double FloatD = D0 / D1;
String[] stringM = DMS[1].split("/", 2);
Double M0 = new Double(stringM[0]);
Double M1 = new Double(stringM[1]);
Double FloatM = M0 / M1;
String[] stringS = DMS[2].split("/", 2);
Double S0 = new Double(stringS[0]);
Double S1 = new Double(stringS[1]);
Double FloatS = S0 / S1;
result = new Double(FloatD + (FloatM / 60) + (FloatS / 3600));
return result;
}

How to get the latitude and longitude of an image in sdcard to my application?

From my application I can open gallery. Is there any way to get latitude and longitude of any selected image in gallery to my application?
You can actually use a "buildin" function:
ExifInterface exif = new ExifInterface(path);
float[] latLong = new float[2];
boolean hasLatLong = exif.getLatLong(latLong)
if (hasLatLong) {
System.out.println("Latitude: " + latLong[0]);
System.out.println("Longitude: " + latLong[1]);
}
Maybe is something new, but I think is much more convenient than the accepted answer.
You Should Go with ExifInterface class to read various EXIF metadata from Images:
Example :
ExifInterface exif = new ExifInterface(filepath);
exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
Edited :
Now Here you will get lat-long as Below format.
lat = 30/1,12/1,34/1,
long=81/1,22/1,41/1
To Convert this into Real Values this Blog Helped Me.
we need to do conversion from degree, minute, second form to GeoPoint form.
By Below Way you can Do it.
String LATITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
String LATITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
String LONGITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
String LONGITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
// your Final lat Long Values
Float Latitude, Longitude;
if((LATITUDE !=null)
&& (LATITUDE_REF !=null)
&& (LONGITUDE != null)
&& (LONGITUDE_REF !=null))
{
if(LATITUDE_REF.equals("N")){
Latitude = convertToDegree(LATITUDE);
}
else{
Latitude = 0 - convertToDegree(LATITUDE);
}
if(LONGITUDE_REF.equals("E")){
Longitude = convertToDegree(LONGITUDE);
}
else{
Longitude = 0 - convertToDegree(LONGITUDE);
}
}
private Float convertToDegree(String stringDMS){
Float result = null;
String[] DMS = stringDMS.split(",", 3);
String[] stringD = DMS[0].split("/", 2);
Double D0 = new Double(stringD[0]);
Double D1 = new Double(stringD[1]);
Double FloatD = D0/D1;
String[] stringM = DMS[1].split("/", 2);
Double M0 = new Double(stringM[0]);
Double M1 = new Double(stringM[1]);
Double FloatM = M0/M1;
String[] stringS = DMS[2].split("/", 2);
Double S0 = new Double(stringS[0]);
Double S1 = new Double(stringS[1]);
Double FloatS = S0/S1;
result = new Float(FloatD + (FloatM/60) + (FloatS/3600));
return result;
};
#Override
public String toString() {
// TODO Auto-generated method stub
return (String.valueOf(Latitude)
+ ", "
+ String.valueOf(Longitude));
}
public int getLatitudeE6(){
return (int)(Latitude*1000000);
}
public int getLongitudeE6(){
return (int)(Longitude*1000000);
}
the exif.getLatLong(float[]) is now deprecated, you can use a better method which returns a double[] :
ExifInterface exifInterface = new ExifInterface(file);
double[] latlng = exifInterface.getLatLong();
if (latlng != null) {
Double currentLatitude = latlng[0];
Double currentLongitude = latlng[1];
Log.d("Debug", "Exif : latitude: " + currentLatitude + ", longitude: " + currentLongitude)
}
Happy coding.

Android write EXIF GPS Latitude and Longitude onto JPEG failed

I would like to add GPS data such as longitude and latitude into the jpeg photo.
The photo is captured by tabbing the card (NFC)
In the logcat correct values can be displayed but these values cannot be written into the jpg photo file !
Below is my code:
It is used to take saved jpg files and call the method below
The method is used to add EXIF GPS parameters into the jpg
The GPS parameters such as longitude and latitude are already taken in another activity.
I use EXIF Viewer in Firefox to see the result.
Does the position for the IO Exception matters?
The following is the important log cat log which may render the failure:
07-26 11:48:30.386: D/NativeNfcTag(195): Tag lost, restarting polling loop
public static void writeFile (File photo, double latitude, double longitude) throws IOException{
ExifInterface exif = null;
try{
Log.v("latiDouble", ""+latitude);
Log.v("longiDouble", ""+longitude);
exif = new ExifInterface(photo.getCanonicalPath());
if (exif != null) {
double latitu = latitude;
double longitu = longitude;
double alat = Math.abs(latitu);
double along = Math.abs(longitu);
String stringLati = convertDoubleIntoDegree(alat);
String stringLongi = convertDoubleIntoDegree(along);
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, stringLati);
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, stringLongi);
Log.v("latiString", ""+ stringLati);
Log.v("longiString", ""+ stringLongi);
exif.saveAttributes();
String lati = exif.getAttribute (ExifInterface.TAG_GPS_LATITUDE);
String longi = exif.getAttribute (ExifInterface.TAG_GPS_LONGITUDE);
Log.v("latiResult", ""+ lati);
Log.v("longiResult", ""+ longi);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The below is the position to call the method
...
Cursor locationCursor = dbHandler.fetchGpsLocationTypeByAttendInfoID(attendInfoId);
if (locationCursor.getCount()>0) {
double latitude = dbHandler.fetchDoubleItem(locationCursor,"LATITUDE");
double longitude = dbHandler.fetchDoubleItem(locationCursor,"LONGITUDE");
Log.v("latitude",""+latitude);
Log.v("latitude",""+longitude);
try {
GpsUtils.writeFile(photoFile, latitude, longitude);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
dbHandler.close();
cameraHandler.startPreview();
Ok, I struggled with this for a long time but finally got it. Last time I used it this code worked:
ExifInterface exif = new ExifInterface(imgFile.getCanonicalPath());
//String latitudeStr = "90/1,12/1,30/1";
double lat = location.getLatitude();
double alat = Math.abs(lat);
String dms = Location.convert(alat, Location.FORMAT_SECONDS);
String[] splits = dms.split(":");
String[] secnds = (splits[2]).split("\\.");
String seconds;
if(secnds.length==0)
{
seconds = splits[2];
}
else
{
seconds = secnds[0];
}
String latitudeStr = splits[0] + "/1," + splits[1] + "/1," + seconds + "/1";
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latitudeStr);
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, lat>0?"N":"S");
double lon = location.getLongitude();
double alon = Math.abs(lon);
dms = Location.convert(alon, Location.FORMAT_SECONDS);
splits = dms.split(":");
secnds = (splits[2]).split("\\.");
if(secnds.length==0)
{
seconds = splits[2];
}
else
{
seconds = secnds[0];
}
String longitudeStr = splits[0] + "/1," + splits[1] + "/1," + seconds + "/1";
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, longitudeStr);
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, lon>0?"E":"W");
exif.saveAttributes();
}

Write/Geotag JPEGs (EXIF data) in Android

What I want to do:
Take a picture using my own PictureActivity* and add EXIF (geotags) data
*: Implementing SurfaceHolder.Callbackand using Camera
What is not working:
Adding the EXIF GPS data
What I've tried:
Using the ExifInterface and manually setting Camera.Parameters (both with the specific methods for setting GPS meta-data and by using params.set(String, Value)).
I'm uploading the pictures to Flickr using FlickrJ (yes, I've set Flickr to import GPS data -- other pictures work fine), however this tool also says there is no GPS data in the EXIF: http://regex.info/exif.cgi
What am I missing?
(Android 2.2, HTC Desire)
Edit:
- The camera is set to Geotag photos: On
- I've tried with hardcoded dummy GPS positions
Here is the code for manually setting parameters (tried both with and without first removing the GPS data, and as mentioned also with set(String, Value)):
#Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(p.getPreviewSize().width, p.getPreviewSize().height);
Log.e("PictureActivity", "EXIF: "+AGlanceLocationListener.getLatitude());
p.removeGpsData();
p.setGpsLatitude( AGlanceLocationListener.getLatitude() );
p.setGpsLongitude( AGlanceLocationListener.getLongitude() );
p.setGpsAltitude( AGlanceLocationListener.getAltitude() );
p.setGpsTimestamp( AGlanceLocationListener.getTime() );
mCamera.setParameters(p);
}
Here is the code for using the ExifInterface:
//Save EXIF location data to JPEG
ExifInterface exif;
try {
exif = new ExifInterface("/sdcard/DCIM/"+filename+".jpeg");
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE,
String.valueOf(AGlanceLocationListener.getLatitude()));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE,
String.valueOf(AGlanceLocationListener.getLongitude()));
exif.saveAttributes();
} catch (IOException e) {
Log.e("PictureActivity", e.getLocalizedMessage());
}
Here is the code for writing the JPEG file to the SDCARD:
Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c)
{
// Bitmap pic = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
String day = String.valueOf(Calendar.getInstance().getTime().getDay());
String hour = String.valueOf(Calendar.getInstance().getTime().getHours());
String minute = String.valueOf(Calendar.getInstance().getTime().getMinutes());
String second = String.valueOf(Calendar.getInstance().getTime().getSeconds());
filename = "Billede"+day+hour+minute+second;
try {
FileOutputStream fos = new FileOutputStream(new File("/sdcard/DCIM/"+filename+".jpeg"));
fos.write(imageData);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
if(imageData != null){
Intent mIntent = new Intent();
setResult(0,mIntent);
PictureActivity.this.showDialog(0);
}
}
};
Also tried writing the image from a Bitmap (didn't work), plus another question here report writing using a FileOutputStream worked
Unfortunately, this works on a quarter of the hemisphere only. East of Greenwich and North of the equator. That's how I guessed you must live there:). Your 'Math.floor' will make all negative values wrong (like -105 into -106). Here's the same thing, that should work even in the US.
public void loc2Exif(String flNm, Location loc) {
try {
ExifInterface ef = new ExifInterface(flNm);
ef.setAttribute(ExifInterface.TAG_GPS_LATITUDE, dec2DMS(loc.getLatitude()));
ef.setAttribute(ExifInterface.TAG_GPS_LONGITUDE,dec2DMS(loc.getLongitude()));
if (loc.getLatitude() > 0)
ef.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "N");
else
ef.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "S");
if (loc.getLongitude()>0)
ef.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "E");
else
ef.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "W");
ef.saveAttributes();
} catch (IOException e) {}
}
//-----------------------------------------------------------------------------------
String dec2DMS(double coord) {
coord = coord > 0 ? coord : -coord; // -105.9876543 -> 105.9876543
String sOut = Integer.toString((int)coord) + "/1,"; // 105/1,
coord = (coord % 1) * 60; // .987654321 * 60 = 59.259258
sOut = sOut + Integer.toString((int)coord) + "/1,"; // 105/1,59/1,
coord = (coord % 1) * 60000; // .259258 * 60000 = 15555
sOut = sOut + Integer.toString((int)coord) + "/1000"; // 105/1,59/1,15555/1000
return sOut;
}
... and once you got me started, here's the reverse
public Location exif2Loc(String flNm) {
String sLat = "", sLatR = "", sLon = "", sLonR = "";
try {
ExifInterface ef = new ExifInterface(flNm);
sLat = ef.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
sLon = ef.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
sLatR = ef.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
sLonR = ef.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
} catch (IOException e) {return null;}
double lat = dms2Dbl(sLat);
if (lat > 180.0) return null;
double lon = dms2Dbl(sLon);
if (lon > 180.0) return null;
lat = sLatR.contains("S") ? -lat : lat;
lon = sLonR.contains("W") ? -lon : lon;
Location loc = new Location("exif");
loc.setLatitude(lat);
loc.setLongitude(lon);
return loc;
}
//-------------------------------------------------------------------------
double dms2Dbl(String sDMS){
double dRV = 999.0;
try {
String[] DMSs = sDMS.split(",", 3);
String s[] = DMSs[0].split("/", 2);
dRV = (new Double(s[0])/new Double(s[1]));
s = DMSs[1].split("/", 2);
dRV += ((new Double(s[0])/new Double(s[1]))/60);
s = DMSs[2].split("/", 2);
dRV += ((new Double(s[0])/new Double(s[1]))/3600);
} catch (Exception e) {}
return dRV;
}
... and one day, I'll start to write pretty looking code. Happy geotagging, sean
Found the problem:
Looking at the original images from the SDCARD showed:
The images contained EXIF GPS data if the EXIFInterface is used. The GPS data, however, was wrong (see below) -- which probably is why Flickr won't show it.
Using the method that sets GPS coordinates through the camera parameters do NOT write EXIF GPS data (this was using dummy hardcoded coordinates, I haven't tested with an actual GPS fix). I haven't looked more into why this is.
The Android API for EXIFInterface has this documentation:
public static final String TAG_GPS_LONGITUDE
Since: API Level 5
String. Format is "num1/denom1,num2/denom2,num3/denom3".
Constant Value: "GPSLongitude"
The problem with my original code is that I was passing the GPS coordinates in Decimal Degrees -- the coordinates you get from calling getLatitude/getLogitude on a Location object is in Decimal Degrees. The EXIFInterface expects the coordinates in Degrees Minutes Seconds and then written as rationals (this is part of the EXIF specification). More on GPS coordinate formats and conversion here.
Here is another question/answer that explains how to convert from Decimal Degrees to Degrees Minutes Seconds.
Using this code, the GPS coordinates gets written correctly in the EXIF and Flickr have no problem importing the data:
ExifInterface exif;
double latitude = AGlanceLocationListener.getLatitude();
double longitude = AGlanceLocationListener.getLongitude();
try {
exif = new ExifInterface("/sdcard/DCIM/"+filename+".jpeg");
int num1Lat = (int)Math.floor(latitude);
int num2Lat = (int)Math.floor((latitude - num1Lat) * 60);
double num3Lat = (latitude - ((double)num1Lat+((double)num2Lat/60))) * 3600000;
int num1Lon = (int)Math.floor(longitude);
int num2Lon = (int)Math.floor((longitude - num1Lon) * 60);
double num3Lon = (longitude - ((double)num1Lon+((double)num2Lon/60))) * 3600000;
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, num1Lat+"/1,"+num2Lat+"/1,"+num3Lat+"/1000");
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, num1Lon+"/1,"+num2Lon+"/1,"+num3Lon+"/1000");
if (latitude > 0) {
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "N");
} else {
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "S");
}
if (longitude > 0) {
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "E");
} else {
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "W");
}
exif.saveAttributes();
} catch (IOException e) {
Log.e("PictureActivity", e.getLocalizedMessage());
}
Note: When using Degrees Minutes Seconds you also need to set the GPS reference attributes (N, S, E, W).
This solution will cater for negative and positive lat/lng values:
static public boolean setGeoTag(File image, LatLng geoTag) {
if (geoTag != null) {
try {
ExifInterface exif = new ExifInterface(
image.getAbsolutePath());
double latitude = Math.abs(geoTag.latitude);
double longitude = Math.abs(geoTag.longitude);
int num1Lat = (int) Math.floor(latitude);
int num2Lat = (int) Math.floor((latitude - num1Lat) * 60);
double num3Lat = (latitude - ((double) num1Lat + ((double) num2Lat / 60))) * 3600000;
int num1Lon = (int) Math.floor(longitude);
int num2Lon = (int) Math.floor((longitude - num1Lon) * 60);
double num3Lon = (longitude - ((double) num1Lon + ((double) num2Lon / 60))) * 3600000;
String lat = num1Lat + "/1," + num2Lat + "/1," + num3Lat + "/1000";
String lon = num1Lon + "/1," + num2Lon + "/1," + num3Lon + "/1000";
if (geoTag.latitude > 0) {
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "N");
} else {
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "S");
}
if (geoTag.longitude > 0) {
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "E");
} else {
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "W");
}
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, lat);
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, lon);
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
return false;
}
} else {
return false;
}
return true;
}

Android Show Map location when Longitude/ Latitude values are in DMS Format

In my Android application I need to load Google map and show the location according to the Latitude and the Longitude values provided.
I referred the following tutorial and its completely ok. Work fine.
Link to the tutorial I followed
Problem is Latitude and Longitude values are stored in SQLite database in the DMS Fromat. If those values were in the Decimal Degrees format then No problem, as I can do the way it was in that tutorial.
I need to Show the exact place by adding Overlay Item(I have given the Longitude and Latitude values by DMS Format).
[Example values: 36°7'59''N, 5°25'59''W]
Thanks...
I'm sorry for misunderstanded the question. `doit("36°7'59''N");
public void doit(String lat) {
String str = lat;
String [] temp = null;
String dtemp = null;
String [] pass = new String[4];
//temp = str.split("[\"]|\"[\']");
temp = str.split("[\"]|[\']" );
System.out.println("temptemptemptemp "+temp);
dtemp = str.replace("\"", "°");
System.out.println("dtempdtempdtemp "+dtemp);
System.out.println("Formated DCM---------- : "+dtemp);
String [] temp1 = temp[0].split("°");
System.out.println("\ndegree temp: "+temp1[0]);
System.out.println("\nminutes temp: "+temp1[1]);
pass[0] = temp1[0];
pass[1] = temp1[1];
pass[2] = temp[1];
dump(pass);
}
public void dump(String []s) {
for (int i = 0 ; i < s.length ; i++) {
System.out.println("\ndegree : "+s[0]);
System.out.println("\nminutes : "+s[1]);
System.out.println("\nsecond : "+s[2]);
String deg = s[0] ;
int ndeg = Integer.parseInt(deg);
String min = s[1] ;
double nmin = Double.parseDouble(min);
String sec = s[2] ;
double nsec = Double.parseDouble(sec);
double decimaldms = (ndeg+(nmin/60)+(nsec/3600));
System.out.println("\nfinaldecimal : "+decimaldms);
}
}
`
I think this is help for u.
If u want to convert latitude longitude value to degree minutes format then code is here...
String locLat, locLng;
locLat = Double.toString(location.getLatitude());
locLng = Double.toString(location.getLongitude());
String locLatTodeg = DoubleToDeg(locLat);
String locLngTodeg = DoubleToDeg(locLng);
private String DoubleToDeg(String locLng) {
// TODO Auto-generated method stub
String retStringLoc = null;
try {
String firString = locLng.replace(".", ";");
String[] firLocArr = firString.split(";");
Float deg = new Float("." + firLocArr[1]);
Float Cnvtddeg = deg * 60;
String secString = new Float(Cnvtddeg).toString().replace(".", ";");
String[] secLocArr = secString.split(";");
Float min = new Float("." + secLocArr[1]);
Float Cnvtdmin = min * 60;
String tirString = new Float(Cnvtdmin).toString().replace(".", ";");
String[] tirLocArr = tirString.split(";");
retStringLoc = firLocArr[0] + "°" + secLocArr[0] + "'"
+ tirLocArr[0] + "''";
} catch (Exception e) {
// Log.i("Exception", e.toString());
}
return retStringLoc;
}
I think this is helpful for u....

Categories

Resources