12

やりたいこと:
自分の PictureActivity* を使用して写真を撮り、EXIF (ジオタグ) データを追加する
*: 実装SurfaceHolder.Callbackして使用するCamera

何が機能していないか:
EXIF GPS データの追加

私が試したこと:および手動設定の使用(GPS メタデータを設定するための特定の方法と を使用した両方
) 。ExifInterfaceCamera.Parametersparams.set(String, Value)

FlickrJ を使用して写真を Flickr にアップロードしています (はい、GPS データをインポートするように Flickr を設定しました。他の写真は問題なく動作します)。しかし、このツールは、EXIF に GPS データがないことも示しています: http://regex. info/exif.cgi

私は何が欠けていますか?

(Android 2.2、HTC デザイア)

編集:
- カメラは次のように設定されてい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);
}

を使用するためのコードは次の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ます

4

3 に答える 3

15

残念ながら、これは半球の 4 分の 1 でしか機能しません。グリニッジの東、赤道の北。それがあなたがそこに住んでいるに違いないと私が推測した方法です:)。「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;
}

...そしていつの日か、見栄えの良いコードを書き始めるでしょう。幸せなジオタグ、ショーン

于 2013-03-26T19:40:57.237 に答える
12

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

于 2012-05-21T12:57:35.870 に答える
4

このソリューションは、負および正の緯度/経度の値に対応します。

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;
}
于 2015-02-06T09:13:00.300 に答える