How to save GPS coordinates in exif data on Android?

前端 未结 5 1394
借酒劲吻你
借酒劲吻你 2020-12-02 20:43

I am writing GPS coordinates to my JPEG image, and the coordinates are correct (as demonstrated by my logcat output) but it appears that it\'s being corrupted somehow. Readi

相关标签:
5条回答
  • 2020-12-02 21:21

    GPSLatitude

    Indicates the latitude. The latitude is expressed as three RATIONAL values giving the degrees, minutes, and seconds, respectively. If latitude is expressed as degrees, minutes and seconds, a typical format would be dd/1,mm/1,ss/1. When degrees and minutes are used and, for example, fractions of minutes are given up to two decimal places, the format would be dd/1,mmmm/100,0/1.

    https://docs.google.com/viewer?url=http%3A%2F%2Fwww.exif.org%2FExif2-2.PDF

    The Android docs specify this without explanation: http://developer.android.com/reference/android/media/ExifInterface.html#TAG_GPS_LATITUDE

    Exif data is standardized, and GPS data must be encoded using geographical coordinates (minutes, seconds, etc) described above instead of a fraction. Unless it's encoded in that format in the exif tag, it won't stick.

    How to encode: http://en.wikipedia.org/wiki/Geographic_coordinate_conversion

    How to decode: http://android-er.blogspot.com/2010/01/convert-exif-gps-info-to-degree-format.html

    0 讨论(0)
  • 2020-12-02 21:27

    Here is some code I've done to geotag my pictures. It's not heavily tested yet, but it seems to be ok (JOSM editor and exiftool read location).

    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();
    

    And class GPS is here. (method could be shorter, but it's readable at least)

    /*
     * @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();
        }
    }
    
    0 讨论(0)
  • 2020-12-02 21:32
    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()));
    

    Convertor double to String

     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 讨论(0)
  • 2020-12-02 21:36

    Other answers delivered nice background info and even an example. This is not a direct answer to the question but I would like to add an even simpler example without the need to do any math. The Location class delivers a nice convert function:

    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";
    }
    

    I stored the return value in my image and the tag is parsed fine. You can check your image and the geocoordinates inside here: http://regex.info/exif.cgi

    Edit

    @ratanas comment translated to code:

    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;
    }
    

    Here are some nice LatLong converter: latlong.net

    0 讨论(0)
  • check android source code: https://android.googlesource.com/platform/frameworks/base/+/android-4.4.2_r2/core/java/android/hardware/Camera.java

    /** * Sets GPS longitude coordinate. This will be stored in JPEG EXIF * header. * * @param longitude GPS longitude coordinate. */ public void setGpsLongitude(double longitude) { set(KEY_GPS_LONGITUDE, Double.toString(longitude)); }

    So it's a direct print, my log supports it as well: ExifInterface.TAG_GPS_LONGITUDE : -121.0553966

    My conclusion is setting it as direct print is fine.

    0 讨论(0)
提交回复
热议问题