26

我正在将 GPS 坐标写入我的 JPEG 图像,并且坐标是正确的(如我的 logcat 输出所示),但它似乎以某种方式被损坏了。读取 exif 数据会导致 null 值,或者在我的 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/336855033619970/65540, 14811136/3368550。我做错了吗?

编辑:

所以,问题是我没有以正确定义的格式对其进行编码,就像你在这里看到的那样:

在此处输入图像描述

谁能解释一下这种格式是什么?显然第一个数字是 22/1 = 22 度,但我不知道如何计算那里的小数。

4

5 回答 5

25

GPS纬度

表示纬度。纬度表示为三个 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

于 2011-03-12T05:02:26.000 回答
18

这是我为我的图片地理标记所做的一些代码。它还没有经过大量测试,但似乎没问题(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();
    }
}
于 2013-05-30T12:03:48.887 回答
4

其他答案提供了很好的背景信息,甚至是一个例子。这不是问题的直接答案,但我想添加一个更简单的示例,而无需进行任何数学运算。Location类提供了一个不错的转换函数

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

于 2015-11-02T10:32:57.923 回答
1
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;
}
于 2019-03-20T01:19:15.913 回答
-1

检查android源代码:https ://android.googlesource.com/platform/frameworks/base/+/android-4.4.2_r2/core/java/android/hardware/Camera.java

/** * 设置 GPS 经度坐标。这将存储在 JPEG EXIF * 标头中。* * @param longitude GPS 经度坐标。*/ public void setGpsLongitude(double longitude) { set(KEY_GPS_LONGITUDE, Double.toString(longitude)); }

所以这是直接打印,我的日志也支持:ExifInterface.TAG_GPS_LONGITUDE:-121.0553966

我的结论是直接打印就可以了。

于 2014-04-11T01:12:36.763 回答