Как сохранить GPS-координаты в exif-данных на Android? - PullRequest
23 голосов
/ 12 марта 2011

Я записываю 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.Я делаю это неправильно?

РЕДАКТИРОВАТЬ:

Итак, проблема в том, что я не кодирую его в правильно определенном формате, как вы видите здесь:

enter image description here

Может кто-нибудь объяснить, что это за формат?Очевидно, что первое число 22/1 = 22 градуса, но я не могу понять, как вычислить там десятичное число.

Ответы [ 5 ]

23 голосов
/ 12 марта 2011

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-степень-format.html

11 голосов
/ 30 мая 2013

Вот код, который я сделал для геотегирования моих фотографий.Он еще не был тщательно протестирован, но, похоже, все в порядке (редактор 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();
    }
}
4 голосов
/ 02 ноября 2015

Другие ответы предоставили хорошую справочную информацию и даже пример. Это не прямой ответ на вопрос, но я хотел бы добавить еще более простой пример, не прибегая к какой-либо математике. Класс 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

0 голосов
/ 20 марта 2019
ExifInterface exif = new ExifInterface(compressedImage.getPath());
        exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE,gpsTracker.dec2DMS(gpsTracker.getLatitude()));
        exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE,gpsTracker.dec2DMS(gpsTracker.getLongitude()));

Преобразователь двойной в строку

 String dec2DMS(double coord) {
    coord = coord > 0 ? coord : -coord;  
    String sOut = Integer.toString((int)coord) + "/1,";   
    coord = (coord % 1) * 60;         
    sOut = sOut + Integer.toString((int)coord) + "/1,";   
    coord = (coord % 1) * 60000;             
    sOut = sOut + Integer.toString((int)coord) + "/1000";   
    return sOut;
}
0 голосов
/ 11 апреля 2014

проверить исходный код 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 (longitude)); }

Так что это прямая печать, мой журнал также поддерживает это: ExifInterface.TAG_GPS_LONGITUDE: -121.0553966

Мой вывод заключается в том, что прямая печать в порядке.

...