Как сохранить координаты GPS в данных exif на Android?
Я пишу GPS-координаты для своего изображения в формате JPEG, и координаты правильны (как показывает мой вывод logcat), но похоже, что он каким-то образом поврежден. Чтение данных exif приводит либо к нулевым значениям, либо, в случае моего GPS: 512.976698 degrees, 512.976698 degrees
. Может ли кто-нибудь пролить свет на эту проблему?
запись:
try {
ExifInterface exif = new ExifInterface(filename);
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latitude);
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, longitude);
exif.saveAttributes();
Log.e("LATITUDE: ", latitude);
Log.e("LONGITUDE: ", longitude);
} catch (IOException e) {
e.printStackTrace();
}
и прочитав его:
try {
ExifInterface exif = new ExifInterface("/sdcard/globetrotter/mytags/"+ TAGS[position]);
Log.e("LATITUDE EXTRACTED", exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE));
Log.e("LONGITUDE EXTRACTED", exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE));
} catch (IOException e) {
e.printStackTrace();
}
Он идет (например) 37.715183
, -117.260489
и выходит 33619970/65540, 14811136/3368550
, 33619970/65540, 14811136/3368550
. Я делаю это неправильно?
EDIT:
Итак, проблема в том, что я не кодирую его в правильно определенном формате, что-то вроде того, что вы видите здесь:
![enter image description here]()
Может ли кто-нибудь объяснить, что это за формат? Очевидно, первое число 22/1 = 22 градуса, но я не могу понять, как вычислить десятичную точку там.
Ответы
Ответ 1
GPSLatitude
Указывает широту. Широта выражается в виде трех RATIONAL
значения, дающие градусы, минут и секунд соответственно. Если широта выражается в градусах, минут и секунд, типичный формат будет dd/1,mm/1,ss/1
. Когда градусы и используются минуты, и для Например, доли минут с учетом двух знаков после запятой, формат будет dd/1,mmmm/100,0/1
.
https://docs.google.com/viewer?url=http%3A%2F%2Fwww.exif.org%2FExif2-2.PDF
В документах Android указано это без объяснения: http://developer.android.com/reference/android/media/ExifInterface.html#TAG_GPS_LATITUDE
Данные Exif стандартизированы, и данные GPS должны кодироваться с использованием географических координат (минут, секунд и т.д.), описанных выше, а не фракции. Если он не закодирован в этом формате в теге exif, он не будет вставляться.
Как закодировать: http://en.wikipedia.org/wiki/Geographic_coordinate_conversion
Как декодировать: http://android-er.blogspot.com/2010/01/convert-exif-gps-info-to-degree-format.html
Ответ 2
Вот некоторый код, который я сделал, чтобы геотегить мои фотографии. Это еще не проверено, но, кажется, все в порядке (редактор чтения JOSM и место чтения exiftool).
ExifInterface exif = new ExifInterface(filePath.getAbsolutePath());
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, GPS.convert(latitude));
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, GPS.latitudeRef(latitude));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, GPS.convert(longitude));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, GPS.longitudeRef(longitude));
exif.saveAttributes();
И класс GPS здесь. (метод может быть короче, но, по крайней мере, читаемым)
/*
* @author fabien
*/
public class GPS {
private static StringBuilder sb = new StringBuilder(20);
/**
* returns ref for latitude which is S or N.
* @param latitude
* @return S or N
*/
public static String latitudeRef(double latitude) {
return latitude<0.0d?"S":"N";
}
/**
* returns ref for latitude which is S or N.
* @param latitude
* @return S or N
*/
public static String longitudeRef(double longitude) {
return longitude<0.0d?"W":"E";
}
/**
* convert latitude into DMS (degree minute second) format. For instance<br/>
* -79.948862 becomes<br/>
* 79/1,56/1,55903/1000<br/>
* It works for latitude and longitude<br/>
* @param latitude could be longitude.
* @return
*/
synchronized public static final String convert(double latitude) {
latitude=Math.abs(latitude);
int degree = (int) latitude;
latitude *= 60;
latitude -= (degree * 60.0d);
int minute = (int) latitude;
latitude *= 60;
latitude -= (minute * 60.0d);
int second = (int) (latitude*1000.0d);
sb.setLength(0);
sb.append(degree);
sb.append("/1,");
sb.append(minute);
sb.append("/1,");
sb.append(second);
sb.append("/1000");
return sb.toString();
}
}
Ответ 3
Другие ответы доставили приятную справочную информацию и даже пример. Это не прямой ответ на вопрос, но я хотел бы добавить еще более простой пример без необходимости делать математику. Класс Location обеспечивает приятную convert функцию
public String getLonGeoCoordinates(Location location) {
if (location == null) return "0/1,0/1,0/1000";
// You can adapt this to latitude very easily by passing location.getLatitude()
String[] degMinSec = Location.convert(location.getLongitude(), Location.FORMAT_SECONDS).split(":");
return degMinSec[0] + "/1," + degMinSec[1] + "/1," + degMinSec[2] + "/1000";
}
Я сохранил возвращаемое значение в моем изображении, и тег отлично разбирается. Вы можете проверить свое изображение и геокоординаты внутри: http://regex.info/exif.cgi
Изменить
Комментарий @ratanas переведен на код:
public boolean storeGeoCoordsToImage(File imagePath, Location location) {
// Avoid NullPointer
if (imagePath == null || location == null) return false;
// If we use Location.convert(), we do not have to worry about absolute values.
try {
// c&p and adapted from @Fabyen (sorry for being lazy)
ExifInterface exif = new ExifInterface(imagePath.getAbsolutePath());
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, getLatGeoCoordinates(location));
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, location.getLatitude() < 0 ? "S" : "N");
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, getLonGeoCoordinates(location));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, location.getLongitude() < 0 ? "W" : "E");
exif.saveAttributes();
} catch (IOException e) {
// do something
return false;
}
// Data was likely written. For sure no NullPointer.
return true;
}
Вот несколько хороших конвертеров LatLong: latlong.net
Ответ 4
проверить исходный код Android: https://android.googlesource.com/platform/frameworks/base/+/android-4.4.2_r2/core/java/android/hardware/Camera.java
/** * Устанавливает координату долготы GPS. Это будет сохранено в JPEG EXIF * заголовок. * * @param долгота координата долготы GPS. */ public void setGpsLongitude (двойная долгота) { set (KEY_GPS_LONGITUDE, Double.toString(долгота)); }
Итак, это прямая печать, мой журнал также поддерживает ее: ExifInterface.TAG_GPS_LONGITUDE: -121.0553966
Мое заключение заключается в том, чтобы установить его, поскольку прямая печать в порядке.