2012-05-10 31 views
9

Những gì tôi muốn làm:
Chụp ảnh bằng PictureActivity riêng tôi * và thêm EXIF ​​(thẻ địa lý) dữ liệu
*: Thực hiện SurfaceHolder.Callback và sử dụng CameraViết/Geotag JPEG (dữ liệu EXIF) trong Android

gì không hoạt động:
Thêm dữ liệu EXIF ​​GPS

những gì tôi đã cố gắng:
Sử dụng ExifInterface và tự thiết lập Camera.Parameters (cả với các phương pháp cụ thể để thiết lập GPS meta-data và bằng cách sử dụng params.set(String, Value)).

Tôi đang tải lên các hình ảnh lên Flickr sử dụng FlickrJ (vâng, tôi đã thiết Flickr để nhập dữ liệu GPS - hình ảnh khác làm việc tốt), tuy nhiên công cụ này cũng nói rằng không có dữ liệu GPS trong EXIF: http://regex.info/exif.cgi

Tôi đang thiếu gì?

(Android 2.2, HTC Desire)

Edit:
- Chiếc máy ảnh này được thiết lập để Geotag photos: On
- Tôi đã thử với vị trí GPS giả hardcoded

Đây là đoạn mã để cài đặt bằng tay các thông số (đã thử cả khi có và không xóa dữ liệu GPS lần đầu tiên và như đã đề cập với 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); 
} 

Cô ấy e là mã để sử dụng 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()); 
} 

Đây là đoạn mã để viết các tập tin 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); 
     } 
    } 
}; 

Cũng đã cố gắng viết các hình ảnh từ một Bitmap (không làm việc) , cộng với một câu hỏi ở đây báo cáo bằng văn bản sử dụng một FileOutputStream làm việc

Trả lời

10

Tìm thấy vấn đề:

Nhìn vào những hình ảnh ban đầu f rom the SDCARD hiển thị:

  1. Hình ảnh chứa dữ liệu EXIF ​​GPS nếu sử dụng EXIFInterface. Tuy nhiên, dữ liệu GPS đã sai (xem bên dưới) - đó có thể là lý do tại sao Flickr không hiển thị.

  2. Sử dụng phương pháp đặt tọa độ GPS thông qua các thông số máy ảnh KHÔNG ghi dữ liệu GPS EXIF ​​(điều này đang sử dụng tọa độ được mã hóa giả, tôi chưa thử nghiệm với bản sửa lỗi GPS thực). Tôi đã không xem xét nhiều hơn lý do tại sao điều này.

API Android cho EXIFInterface có this documentation:

public static thức Chuỗi TAG_GPS_LONGITUDE
Từ: API Level 5
String. Định dạng là "num1/denom1, num2/denom2, num3/denom3".
Giá trị không đổi: "gpslongitude"

Vấn đề với mã ban đầu của tôi là tôi đã vượt qua GPS tọa độ trong Degrees Decimal - tọa độ bạn nhận được từ gọi getLatitude/getLogitude trên một đối tượng Địa điểm là độ thập phân . EXIFInterface hy vọng các tọa độ trong Độ Phút Phút và sau đó được viết dưới dạng các lý do hợp lý (đây là một phần của đặc tả EXIF). Thông tin thêm về định dạng tọa độ GPS và chuyển đổi here.

Here là một câu hỏi/câu trả lời khác giải thích cách chuyển đổi từ Độ thập phân sang Độ Phút giây.

Sử dụng mã này, tọa độ GPS được ghi một cách chính xác trong EXIF ​​và Flickr không có vấn đề nhập dữ liệu:

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

Lưu ý: Khi sử dụng Degrees Phút Giây bạn cũng cần phải thiết lập các thuộc tính tài liệu tham khảo GPS (N, S, E, W).

+1

Đối với vĩ độ và kinh độ tiêu cực các mã trên sẽ mã hóa các giá trị tiêu cực thay vì tích cực. Ví dụ (-40.00, -73.00) sẽ được mã hóa ở vĩ độ -40 độ về phía nam thay vì +40 độ về phía nam. -73 sẽ được mã hóa là -73 độ kinh độ tây thay vì +73 độ kinh độ tây). – Theo

+1

Nói chung nó không nên được coi là câu trả lời đúng, vì mã là thiếu sót (math.floor vấn đề vv ...) – seanpj

12

Thật không may, điều này chỉ hoạt động trên một phần tư của bán cầu. Phía Đông Greenwich và phía Bắc đường xích đạo. Đó là cách tôi đoán bạn phải sống ở đó :). 'Math.floor' của bạn sẽ làm cho tất cả các giá trị âm sai (như -105 thành -106). Đây là điều tương tự, điều đó sẽ hoạt động ngay cả ở Mỹ.

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

... và một khi bạn đã cho tôi bắt đầu, đây là điều ngược lại

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

... và một ngày nào đó, tôi sẽ bắt đầu viết khá tìm mã. Chúc mừng geotagging, sean

3

Giải pháp này sẽ phục vụ cho các giá trị lng/lat tiêu cực và tích cực:

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; 
} 
Các vấn đề liên quan