Reputation: 221
I am experimenting with the camera2 api
and I have made an app that can take an a photo from the camera. Now I want to add exif
data to the captured image. I have a question on where or how to put the exif information
.
Should I create an Exif interface in the onCaptureCompleted()
function or what is the best way to do it?
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session,
CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(MainActivity.this, "Saved:"+file, Toast.LENGTH_SHORT).show();
ExifInterface exifTags = null;
try {
exifTags = new ExifInterface(file.getCanonicalPath());
exifTags.setAttribute(ExifInterface.TAG_GPS_LATITUDE, Double.toString(cur_lat));
exifTags.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, Double.toString(cur_long));
exifTags.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
}
//System.out.println(file.getCanonicalPath());
System.out.println("Exif Test: " + Double.toString(cur_lat) + " " + Double.toString(cur_lat));
}
};
When I do this I get an error:
"ImageReader_JNI﹕ Unable to acquire a lockedBuffer, very likely client tries to lock more than maxImages buffers"
What is the best way to do this? Any suggestion would be very helpful.
Upvotes: 2
Views: 5049
Reputation: 324
hi you can save Exif to image on Imageavaliable like this
this on image avaliable :
@Override
public void onImageAvailable(ImageReader reader) {
try {
if (latitude == null || longitude == null){
imageview.setVisibility(View.GONE);
/*deleteImage(file.getPath());*/
Toast.makeText(ShotActivity_camera2API.this,"Waiting.. try to get location result.",Toast.LENGTH_LONG).show();
//get location
myLocation.getLocation(ShotActivity_camera2API.this,locationResult);
return;
}else {
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Image Project");
if (!dir.exists())
dir.mkdir();
file = new File(dir, currentDate + ".jpg");
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
try {
saveMetaData(file);
} catch (IOException e) {
e.printStackTrace();
}
saveImageFile(bytes);
/*mBackgroundHandler.post(new ImageSaver(reader.acquireLatestImage(),file));*/
//close image to fix crash second time capture
image.close();
}
} catch (Exception e) {
e.printStackTrace();
} /*catch (IOException e) {
e.printStackTrace();
}*/
}
this method to save Exiv :
private void saveMetaData(File file) throws IOException {
ExifInterface exif = new ExifInterface(file.getCanonicalPath());
Log.e(TAG,""+file.getAbsolutePath());
//add Latitude to metadata
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, gpsParse.convert(latitude));
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, gpsParse.latitudeRef(latitude));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, gpsParse.convert(longitude));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, gpsParse.longitudeRef(longitude));
exif.saveAttributes();
Log.i(TAG, "" + latitude + "," + longitude);
Log.i(TAG, "" + gpsParse.convert(latitude) + "," + gpsParse.longitudeRef(longitude));
Log.i(TAG, "" + gpsParse.latitudeRef(latitude) + "," + gpsParse.longitudeRef(longitude));
}
and this my GPS parse latitude longitude to Exif :
package com.example.PT107.task107_imagesqilte.Helper;
public class gpsParse { private static StringBuilder sb = new StringBuilder(20);
/**
* returns ref for latitude which is S or N.
* @param latitude
* @return S or N
*/
public static String latitudeRef(double latitude) {
return latitude<0.0d?"S":"N";
}
public static String longitudeRef(double longitude) {
return longitude<0.0d?"W":"E";
}
/**
* convert latitude into DMS (degree minute second) format. For instance<br/>
* -79.948862 becomes<br/>
* 79/1,56/1,55903/1000<br/>
* It works for latitude and longitude<br/>
* @param latitude could be longitude.
* @return
*/
synchronized public static final String convert(double latitude) {
latitude=Math.abs(latitude);
int degree = (int) latitude;
latitude *= 60;
latitude -= (degree * 60.0d);
int minute = (int) latitude;
latitude *= 60;
latitude -= (minute * 60.0d);
int second = (int) (latitude*1000.0d);
sb.setLength(0);
sb.append(degree);
sb.append("/1,");
sb.append(minute);
sb.append("/1,");
sb.append(second);
sb.append("/1000,");
return sb.toString();
}
}
i hope this help someone :)
Upvotes: 0
Reputation: 1389
What image format you try to capture? If JPEG, then all Exif tags are should be already written in image. The result image is delivered in OnImageAvailableListener.onImageAvailable(), not in CameraCaptureSession. onCaptureCompleted(). Try to add your custom tags in onImageAvailable method.
EDIT:
@Override
public void onImageAvailable(ImageReader reader) {
Log.e("TAG", System.currentTimeMillis() + "");
Image mImage = reader.acquireNextImage();
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
output.write(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
ExifInterface exif = new ExifInterface(mFile.getAbsolutePath());
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, "10");
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, "10");
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
}
}
Upvotes: 2