2012-05-10 36 views
9

Lo que quiero hacer:
tomar una fotografía con mi propia PictureActivity * y añadir EXIF ​​(etiquetas geográficas) de datos
*: Implementación SurfaceHolder.Callback y el uso de Cameraescritura/Etiqueta geográfica imágenes JPEG (datos EXIF) en Android

Lo no está funcionando:
Adición de los datos EXIF ​​GPS

lo que he intentado:
Utilizando el ExifInterface y establecer manualmente Camera.Parameters (ambos con los métodos específicos para la configuración del GPS meta-datos y usando params.set(String, Value)).

estoy subiendo las imágenes a Flickr usando FlickrJ (sí, me he fijado en Flickr para importar datos GPS - otras imágenes funcionan bien), sin embargo esta herramienta también dice que no hay datos GPS en el EXIF: http://regex.info/exif.cgi

¿Qué me estoy perdiendo?

(Android 2.2, HTC Desire)

Editar:
- La cámara se ajusta a Geotag photos: On
- He tratado con posiciones GPS ficticias codificados

Aquí está el código para parámetros de ajuste manualmente (tratado con y sin quitar primero los datos del GPS, y como se mencionó también con 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); 
} 

Su e es el código para utilizar el 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()); 
} 

Este es el código para escribir el archivo JPEG a la 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); 
     } 
    } 
}; 

también trató de escribir la imagen de un Bitmap (no funcionó) , además de otra pregunta aquí informe escrito utilizando un FileOutputStream trabajaron

Respuesta

10

encontrado el problema:

en cuanto a las imágenes originales f rom la SDCARD mostró:

  1. Las imágenes contenían datos de GPS EXIF ​​si se usa la interfaz EXIF. Sin embargo, los datos del GPS estaban equivocados (ver más abajo), que probablemente es la razón por la cual Flickr no lo mostrará.

  2. Utilizando el método que establece las coordenadas de GPS a través de los parámetros de la cámara NO escriba datos de GPS EXIF ​​(esto fue usando coordenadas ficticias duras, no he probado con un arreglo de GPS real). No he investigado más sobre por qué es esto.

La API de Android para EXIFInterface tiene this documentation:

pública final TAG_GPS_LONGITUDE static String
desde: Nivel 5 de la API
cadena. El formato es "num1/denom1, num2/denom2, num3/denom3".
Valor fijo: "GPSLongitude"

El problema con mi código original es que yo estaba pasando las coordenadas del GPS en grados decimales - las coordenadas que recibe de llamar getLatitude/getLogitude en un objeto ubicación es en grados decimales . EXIFInterface espera las coordenadas en Degrees Minutes Seconds y luego se escriben como racionales (esto es parte de la especificación EXIF). Más sobre formatos de coordenadas GPS y conversión here.

Here es otra pregunta/respuesta que explica cómo convertir de Grados decimales a Grados Minutos Segundos.

Usando este código, las coordenadas GPS se escribe correctamente en el EXIF ​​y Flickr no tienen ningún problema al importar los datos:

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

Nota: Cuando se utiliza Grados Minutos Segundos también es necesario para establecer los atributos de referencia GPS (N, S, E, W).

+1

Para latitudes negativos y las longitudes el código anterior codificará valores negativos en lugar de los positivos. Por ejemplo (-40.00, -73.00) se codificará como -40 grados de latitud sur en lugar de +40 grados sur. -73 se codificará como -73 grados de longitud oeste en lugar de +73 grados de longitud oeste). – Theo

+1

Generalmente, no se debe considerar la respuesta correcta, ya que el código es defectuoso (problema matemático del piso, etc.) – seanpj

12

Lamentablemente, esto solo funciona en la cuarta parte del hemisferio. Al este de Greenwich y al norte del ecuador. Así es como supuse que debes vivir allí :). Su 'Math.floor' hará que todos los valores negativos sean incorrectos (como -105 en -106). Aquí está lo mismo, eso debería funcionar incluso en los Estados Unidos.

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

... y una vez que me inició, aquí está la inversa

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

... y un día, voy a empezar a escribir código de mirada bonita. geoetiquetado feliz, sean

3

Esta solución se atienden a valores lng/lat negativos y positivos:

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