2012-05-10 2 views
9

Что я хочу сделать:
Сфотографируйте, используя свой собственный PictureActivity * и добавить EXIF ​​(Геотэги) данные
*: Реализация SurfaceHolder.Callback и использование CameraЗапись/Геотег JPEGs (EXIF данных) в Android

Что не работает:
Добавление данных EXIF ​​GPS

Что я пробовал:
Использование ExifInterface и ручной настройки Camera.Parameters (как с конкретными методами для настройки GPS метаданных и с использованием params.set(String, Value)).

Я закачка фотографий на Flickr с помощью FlickrJ (да, я установил Flickr импортировать данные GPS - другие изображения работают отлично), однако этот инструмент также говорит, что нет никаких данных GPS в EXIF: http://regex.info/exif.cgi

Что мне не хватает?

(Android 2.2, HTC Desire)

Edit:
- Камера установлена ​​в Geotag photos: On
- Я пытался с закодированными фиктивными позициями GPS

Вот код для ручной настройки параметров (пробовал и с и без первого удаления данных GPS, и, как упоминалось также с set(String, Value)):

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    mCamera = Camera.open();  

    Camera.Parameters p = mCamera.getParameters(); 
    p.setPreviewSize(p.getPreviewSize().width, p.getPreviewSize().height); 
    Log.e("PictureActivity", "EXIF: "+AGlanceLocationListener.getLatitude()); 
    p.removeGpsData(); 
    p.setGpsLatitude(AGlanceLocationListener.getLatitude()); 
    p.setGpsLongitude(AGlanceLocationListener.getLongitude()); 
    p.setGpsAltitude(AGlanceLocationListener.getAltitude()); 
    p.setGpsTimestamp(AGlanceLocationListener.getTime()); 
    mCamera.setParameters(p); 
} 

Her е код для использования ExifInterface:

//Save EXIF location data to JPEG 
ExifInterface exif; 
try { 
    exif = new ExifInterface("/sdcard/DCIM/"+filename+".jpeg"); 
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, 
     String.valueOf(AGlanceLocationListener.getLatitude())); 

    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, 
     String.valueOf(AGlanceLocationListener.getLongitude())); 

    exif.saveAttributes(); 

} catch (IOException e) { 
    Log.e("PictureActivity", e.getLocalizedMessage()); 
} 

Вот код для записи файла JPEG на SDCARD:

Camera.PictureCallback jpegCallback = new Camera.PictureCallback() { 
    public void onPictureTaken(byte[] imageData, Camera c) 
    { 
     //  Bitmap pic = BitmapFactory.decodeByteArray(imageData, 0, imageData.length); 

     String day = String.valueOf(Calendar.getInstance().getTime().getDay()); 
     String hour = String.valueOf(Calendar.getInstance().getTime().getHours()); 
     String minute = String.valueOf(Calendar.getInstance().getTime().getMinutes()); 
     String second = String.valueOf(Calendar.getInstance().getTime().getSeconds()); 

     filename = "Billede"+day+hour+minute+second; 

     try { 
      FileOutputStream fos = new FileOutputStream(new File("/sdcard/DCIM/"+filename+".jpeg")); 
      fos.write(imageData); 
      fos.flush(); 
      fos.close(); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     if(imageData != null){ 
      Intent mIntent = new Intent(); 
      setResult(0,mIntent); 
      PictureActivity.this.showDialog(0); 
     } 
    } 
}; 

попытался также записи образа из Bitmap (не работает) , плюс еще один вопрос здесь написание отчета с использованием FileOutputStream работал

ответ

10

Нашли проблему:

Глядя на исходные изображения F ROM SDCARD показал:

  1. Изображения, содержащие данные EXIF ​​GPS, если используется EXIFInterface. Однако данные GPS были неправильными (см. Ниже) - вероятно, именно поэтому Flickr не покажет его.

  2. Используя метод, который устанавливает GPS-координаты через параметры камеры, НЕ записывайте данные EXIF ​​GPS (это использовало фиктивные жестко закодированные координаты, я не тестировал их с фактическим GPS-исправлением). Я больше не смотрел, почему это так.

Андроида API для EXIFInterface имеет this documentation:

общественности статической конечной строки TAG_GPS_LONGITUDE
С: Уровень API 5
String. Формат «num1/denom1, num2/denom2, num3/denom3».
Константа Значение: «GPSLongitude»

Проблема с моим оригинальным кодом, что я проходил мимо GPS-координаты в десятичных градусах - координаты вы получаете от вызова getLatitude/getLogitude на объект Location находится в десятичных градусах , EXIFInterface ожидает координаты в градусах минут секунд, а затем записывается как рациональные (это часть спецификации EXIF). Подробнее о форматах координат GPS и преобразовании here.

Here - это еще один вопрос/ответ, который объясняет, как конвертировать из десятичных градусов в градусы минут секунд.

Используя этот код, координаты GPS будет написана правильно в EXIF ​​и Flickr нет никаких проблем с импортом данных:

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

Примечание: При использовании Градусы Минуты Секунды Вы также должны установить опорные GPS атрибуты (N, S, E, W).

+1

Для отрицательных широт и долгот код выше будет кодировать отрицательные значения, а не положительные. Например (-40.00, -73.00) будет закодирован как -40 градусов по широте на юг вместо +40 градусов к югу. -73 будет кодироваться как -73 градуса долготы на запад вместо +73 градусов долготы на запад). – Theo

+1

Как правило, это не должно считаться правильным ответом, поскольку код имеет недостатки (проблема с math.floor и т. Д.) – seanpj

12

К сожалению, это работает только на четверть полушария. К востоку от Гринвича и к северу от экватора. Вот как я догадался, что ты должен там жить :). Ваш «Math.floor» сделает все отрицательные значения неправильными (например, -105 в -106). Вот то же самое, что должно работать даже в США.

public void loc2Exif(String flNm, Location loc) { 
    try { 
    ExifInterface ef = new ExifInterface(flNm); 
    ef.setAttribute(ExifInterface.TAG_GPS_LATITUDE, dec2DMS(loc.getLatitude())); 
    ef.setAttribute(ExifInterface.TAG_GPS_LONGITUDE,dec2DMS(loc.getLongitude())); 
    if (loc.getLatitude() > 0) 
     ef.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "N"); 
    else    
     ef.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "S"); 
    if (loc.getLongitude()>0) 
     ef.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "E");  
    else    
     ef.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "W"); 
    ef.saveAttributes(); 
    } catch (IOException e) {}   
} 
//----------------------------------------------------------------------------------- 
String dec2DMS(double coord) { 
    coord = coord > 0 ? coord : -coord; // -105.9876543 -> 105.9876543 
    String sOut = Integer.toString((int)coord) + "/1,"; // 105/1, 
    coord = (coord % 1) * 60;   // .987654321 * 60 = 59.259258 
    sOut = sOut + Integer.toString((int)coord) + "/1,"; // 105/1,59/1, 
    coord = (coord % 1) * 60000;    // .259258 * 60000 = 15555 
    sOut = sOut + Integer.toString((int)coord) + "/1000"; // 105/1,59/1,15555/1000 
    return sOut; 
} 

... и как только вы меня начали, вот обратный

public Location exif2Loc(String flNm) { 
    String sLat = "", sLatR = "", sLon = "", sLonR = ""; 
    try { 
    ExifInterface ef = new ExifInterface(flNm); 
    sLat = ef.getAttribute(ExifInterface.TAG_GPS_LATITUDE); 
    sLon = ef.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); 
    sLatR = ef.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF); 
    sLonR = ef.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); 
    } catch (IOException e) {return null;} 

    double lat = dms2Dbl(sLat); 
    if (lat > 180.0) return null; 
    double lon = dms2Dbl(sLon); 
    if (lon > 180.0) return null; 

    lat = sLatR.contains("S") ? -lat : lat; 
    lon = sLonR.contains("W") ? -lon : lon; 

    Location loc = new Location("exif"); 
    loc.setLatitude(lat); 
    loc.setLongitude(lon); 
    return loc; 
} 
//------------------------------------------------------------------------- 
double dms2Dbl(String sDMS){ 
    double dRV = 999.0; 
    try { 
    String[] DMSs = sDMS.split(",", 3); 
    String s[] = DMSs[0].split("/", 2); 
    dRV = (new Double(s[0])/new Double(s[1])); 
    s = DMSs[1].split("/", 2); 
    dRV += ((new Double(s[0])/new Double(s[1]))/60); 
    s = DMSs[2].split("/", 2); 
    dRV += ((new Double(s[0])/new Double(s[1]))/3600); 
    } catch (Exception e) {} 
    return dRV; 
} 

... и один день, я начну писать довольно глядя код. Счастливый геотэггинг, Sean

3

Это решение будет обслуживать отрицательных и положительных LAT/LNG значения:

static public boolean setGeoTag(File image, LatLng geoTag) { 
    if (geoTag != null) { 
     try { 
      ExifInterface exif = new ExifInterface(
        image.getAbsolutePath()); 

      double latitude = Math.abs(geoTag.latitude); 
      double longitude = Math.abs(geoTag.longitude); 

      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; 

      String lat = num1Lat + "/1," + num2Lat + "/1," + num3Lat + "/1000"; 
      String lon = num1Lon + "/1," + num2Lon + "/1," + num3Lon + "/1000"; 

      if (geoTag.latitude > 0) { 
       exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "N"); 
      } else { 
       exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "S"); 
      } 

      if (geoTag.longitude > 0) { 
       exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "E"); 
      } else { 
       exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "W"); 
      } 

      exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, lat); 
      exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, lon); 

      exif.saveAttributes(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
      return false; 
     } 
    } else { 
     return false; 
    } 
    return true; 
} 
Смежные вопросы