Write/Geotag JPEGs (EXIF data) in Android

前端 未结 3 1032
盖世英雄少女心
盖世英雄少女心 2020-12-04 22:36

What I want to do:
Take a picture using my own PictureActivity* and add EXIF (geotags) data
*: Implementing SurfaceHolder.Callbackand using Camera

3条回答
  •  我在风中等你
    2020-12-04 23:25

    Found the problem:

    Looking at the original images from the SDCARD showed:

    1. 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.

    2. 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).

提交回复
热议问题