Retrieve EXIF data from gallery image in onActivityResult - android

Currently I am getting an image back from the gallery and populating an imageField with it. I am attempting to pull location information from the image, assuming it exists, but all I keep getting is null values.
I know the image I am testing with has entries for latitude and longitude in its EXIF data.
I've tried everything I can find online and nothing is working. I believe the problem lies in the improper parameter being sent to the ExifInterface. Here's what I've got right now:
...
else if (requestCode == REQUEST_IMAGE_FROM_GALLERY) {
try {
Uri selectedImage = data.getData();
String currentImage = selectedImage.getPath()
+ File.separator + getFileName(selectedImage);
....
Then initialize the ExifInterface:
....
try {
ExifInterface ei = new ExifInterface(currentImage);
imageLatitude = ei.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
imageLongitude = ei.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
....
But imageLatitude and imageLongitude are returning null. I've even gone so far as to replace the parameter sent into ExifInterface as the full path to the image (/storage/emulated/0/DCIM/Camera/IMG_20150119_170010.jpg) but still getting null values.
What exactly is supposed to be passed into ExifInterface and, if I'm passing in the correct parameter, why am I getting null values?

I ended up getting it to work using this method:
private String getRealPathFromURI(Uri contentURI, Activity activity) {
Cursor cursor = activity.getContentResolver()
.query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file
// path
return contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}
}
See it in use here:
if (requestCode == REQUEST_IMAGE_FROM_GALLERY) {
try {
Uri selectedImage = data.getData();
String currentImageFile = getRealPathFromURI(selectedImage, this);
ExifInterface ei = new ExifInterface(currentImageFile);
This provided a proper ExifInterface that allowed me to pull the desired data from the image (where it existed).
Thanks for the input everyone.

Maybe the image path you passed to ExifInterface is invalid, you can check it by using the code:
File file = new File(currentImage);
if(file.exists()){
// print file exist
}else{
// print file not exist.
}
If it's the problem, you can solve it by pass a valid image path. If it's not the problem you can debug your code and see the attributes in the ExifInterface ei object by adding a breakpoint before the following code:
imageLatitude = ei.getAttribute(ExifInterface.TAG_GPS_LATITUDE);

Related

Getting path to URI is always null?

So i am using retrofit to upload images to our server, and am using gallery chooser to choose the image. I am trying to get the path of the image, because uri.getPath() returns file not found exception. I have literally seen almost every stackoverflow article on this subject, and still have no answer. The following code that I have is similar to everything I have seen online, and it ALWAYS returns null, and I have no idea why. PLEASE HELP
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
try {
android.net.Uri selectedImage = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImage);
// Log.d(TAG, String.valueOf(bitmap));
ImageView imageView = (ImageView) findViewById(R.id.expandedProfilePic);
imageView.setImageBitmap(bitmap);
String[] filePathColumn = {MediaStore.Images.Media.DATA};
android.database.Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
if (cursor == null)
return;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();
// is always null
System.out.println("FILE PATH " + filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I am trying to get the path of the image, because uri.getPath() returns file not found exception
Assuming that by "gallery chooser", you mean ACTION_GET_CONTENT or possibly ACTION_PICK, there is no path, because a Uri is not a file.
I have literally seen almost every stackoverflow article on this subject
No, you have not. Specifically, you have not read any of the dozens that I have contributed to, such as this one or this one or this one or this one or this one or this one or this one or this one or this one or this one or this one or this one or this one. And those are just from 2017.
The following code that I have is similar to everything I have seen online
And that code will not work for most Uri values.
Use a ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri. Ideally, you would just use the InputStream. In the case of Retrofit, while I have not tried uploading content with it, my guess is that it insists upon a file. In that case, use the InputStream and a FileOutputStream on some file that you control to make a copy of the content. Then, upload the copy, deleting it when you are done.

How to get latitude and longitude from captured image -- Android

I am writing code to retrieve lat and long from image capture. I can able to take image using camera event and onActivityResult.
eprotected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri _uri = null;
Cursor cursor = null;
try {
final int PICK_IMAGE = 1;
if (requestCode == PICK_IMAGE && data != null
&& data.getData() != null) {
_uri = data.getData();
if (_uri != null) {
// User had pick an image.
cursor = getContentResolver()
.query(_uri,
new String[] { android.provider.MediaStore.Images.ImageColumns.DATA },
null, null, null);
cursor.moveToFirst();
// Link to the image
final String imageFilePath = cursor.getString(0);
// Toast.makeText(getApplicationContext(), imageFilePath,
// Toast.LENGTH_LONG).show();
imageLocation= imageFilePath;
File imgFile = new File(imageFilePath);
if (imgFile.exists()) {
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
captureImage.setImageBitmap(myBitmap);
}
cursor.close();
} else {
// Toast.makeText(getApplicationContext(), getSdCard,
// Toast.LENGTH_LONG).show();
}
}
super.onActivityResult(requestCode, resultCode, data);
} catch (Exception e) {
if (cursor == null || cursor.equals("")) {
String getSdCard = _uri.getPath();
imageLocation= getSdCard;
File imgFile = new File(getSdCard);
if (imgFile.exists()) {
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
captureImage.setImageBitmap(myBitmap);
}
}
e.printStackTrace();
}
}
From this how come we get the latitude and longitude from the image. i searched a while, i cant able to get the location.
What Monkeyless suggested is right, use the Exifinterface. There is a working example in the accepted answer to here:
How to get the latititude and longitude of an image in sdcard to my application?
The camera may or may not capture location data with the image, that depends on the user's camera app and whatever settings they are using (you can disable geo tagging photos, by default on most android phones it is disabled). If any location data is attached to the image, you can find it either using ExifInterface with the path to the image, or using the MediaStore.Images.Media database using the lat/lng columns.
You can never guarantee that you will always get location data for any photo. Providers (gps/wifi/cell) might be disabled, geo tagging might be disabled, and even if both are enabled, the phone may not be able to acquire a recent enough and accurate enough geo point.
When you are capturing an image through your mobile device, it usually use only the date and time of the captured moment to save the image on your mobile. If you want to add coordinates to the picture, you have to use the LocationManager class from Android during the capture. By this you can obtain the long/lat coordinates of a captured image.
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
Please note that you have to include the next permission in the Android manifest file if you want to use the above snippet
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
read more here : android location strategies

Monodroid setting imageview to image stored on sdcard

How do I take a photo and save it to a specific folder. I know it saves to the sdcard/DCIM/etc
But I don't want it there, I want it to be stored in a folder in /sdcard/Camera
I have made the directory with the following :
String destPath = Android.OS.Environment.ExternalStorageDirectory + "/Camera";
Then I launch the camera intent and try point the save file to the path I made.
Intent launchCamera = new Intent(Android.Provider.MediaStore.ActionImageCapture);
launchCamera.PutExtra(MediaStore.ExtraOutput, destPath);
This isn't working. Images still get saved to /sdcard/dcim/etc
Ideas?
From what I gathered when I developed an application using Monodroid is that the camera is very buggy and does not do what you want it to most of the time. This includes specifying the destination where images capture are to be saved.
To my knowledge these issues aren't specific to Monodroid and do occur with the java android sdk.
A work around to this issue that you may want to look at is capturing the image without specifying a destination, then in the OnActivityResult method retrieve the latest image saved to the gallery. Once you get the latest image you can then move it to your preferred destination.
Here is some example code from within OnActivityResult.
Retrieve the filename of the captured image
Android.Net.Uri targetUri = data.Data;
String origin = "";
String [] proj = { MediaStore.MediaColumns.Data.ToString (), BaseColumns.Id };
var qry = ManagedQuery (MediaStore.Images.Media.ExternalContentUri, proj, null, null, "date_added DESC");
qry.MoveToFirst ();
origin = qry.GetString (qry.GetColumnIndexOrThrow (MediaStore.MediaColumns.Data.ToString ()));
Move the image to your desired destination
System.IO.File.Move (origin, "yourdestinationfilenamehere");
I'd like to add to lanks's solution.
Let's say you use the following code to take a picture
var uri = ContentResolver.Insert(MediaStore.Images.Media.ExternalContentUri,
new ContentValues());
var intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, uri);
StartActivityForResult(intent, ACTIVITY_RESULT_PICTURE_TAKEN);
pictureUri = uri;
Where the ACTIVITY_RESULT_PICTURE_TAKEN is just a simple value you can use in the
OnActivityResult to check which activity was completed.
Your OnActivityResult could look something like this:
protected override void OnActivityResult(int requestCode,
Result resultCode, Intent data)
{
if (resultCode == Result.Ok && requestCode == ACTIVITY_RESULT_PICTURE_TAKEN)
{
string picturePath = GetRealPathFromURI(pictureUri);
//Do something with the file
}
}
The Uri you got earlier is something specific to android and needs to be translated.
It looks like "//content://media/external/media/11917" which is not a
valid path.
Which is exactly what the GetRealPathFromURI function does:
public string GetRealPathFromURI(Android.Net.Uri contentUri)
{
var mediaStoreImagesMediaData = "_data";
string[] projection = { mediaStoreImagesMediaData };
Android.Database.ICursor cursor = this.ManagedQuery(contentUri, projection,
null, null, null);
int columnIndex = cursor.GetColumnIndexOrThrow(mediaStoreImagesMediaData);
cursor.MoveToFirst();
return cursor.GetString(columnIndex);
}
Once you've got the real path, you can move it to wherever you want as lanks suggested.

How can I verify image URI is valid in Android?

I am building my own contact picker, because I needed multi-select support. Everything is working fine, except for one small problem with the contact images.
For contacts who don't have images I am showing a "no image" image. This works fine for contacts in the phone's address book. I am having a problem however when it comes to images from my google contacts.
Most of my google contacts do not have photos. However, when i query the Contacts database for photos, it still returns a URI for them of the form of content://com.android.contacts/contacts/657/photo (which is the same format as for contacts who do have a photo.
Then when I try to assign the photo to a QuickContactBadge, using bdg.setImageURI(pic); it sets it to essentially a blank picture, and logs a silent INFO message stating:
INFO/System.out(3968): resolveUri failed on bad bitmap uri:
content://com.android.contacts/contacts/657/photo
I need to know how I can either
a) validate the URI or
b) catch the INFO message above
c) query the imageview/badge to see if it found a valid image
so that i can assign these contacts my "no image" image.
How can I go about doing this?
EDIT 20110812.0044
I have tried adding this to my code as per Laurence's suggestion (which he's since removed):
// rv is my URI variable
if(rv != null) {
Drawable d = Drawable.createFromPath(rv.toString());
if (d == null) rv = null;
}
While the google contacts now get my "no image" image, ... so do all the other contacts, including ones that do in fact have images.
Okay, I figured out how to do this after poking through the ImageView source code. It is actually using the QuickContactBadge's own methods, but if necessary, one could always extract the relevant code from the Badge/ImageView control here.
After setting the QCB's image, I check to see if its drawable is null, instead of trying my own (as per Laurence's suggestion). This works better, because there is actually a whole slew of checking code the ImageView widget uses.
Here is my final code:
bdg.setImageURI(pic);
if(bdg.getDrawable() == null) bdg.setImageResource(R.drawable.contactg);
This works perfectly as I was hoping and expecting.
Just to answer the question on how to check the (data) value in the MediaStore:
ContentResolver cr = getContentResolver();
String[] projection = {MediaStore.MediaColumns.DATA}
Cursor cur = cr.query(Uri.parse(contentUri), projection, null, null, null);
if(cur != null) {
cur.moveToFirst();
String filePath = cur.getString(0);
if (filePath == null || filePath.isEmpty()) {
// data not set
} else if((new File(filePath)).exists()){
// do something if it exists
} else {
// File was not found
// this is binary data
}
} else {
// content Uri was invalid or some other error occurred
}
Inspiration taken from: https://stackoverflow.com/a/7649784/621690 and others.
There is also the column SIZE that might be checked: http://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html#SIZE
It sounds like it should contain 0 if there is no data value. But I wouldn't know what it contains if data is a file path.
It could be that the images are not downloaded. I faced a similar problem with whatsapp images.
One way to go about this could be like below:
InputStream is = null;
try {
is = context.getContentResolver().openInputStream(myuri);
}catch (Exception e){
Log.d("TAG", "Exception " + e);
}
if(is==null)
//Assign to "no image"
Based on the code (http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/widget/ImageView.java) my solution for checking Uri:
public static Uri checkUriExists (Context mContext,Uri mUri) {
Drawable d = null;
if (mUri != null) {
if ("content".equals(mUri.getScheme())) {
try {
d = Drawable.createFromStream(
mContext.getContentResolver().openInputStream(mUri),
null);
} catch (Exception e) {
Log.w("checkUriExists", "Unable to open content: " + mUri, e);
mUri = null;
}
} else {
d = Drawable.createFromPath(mUri.toString());
}
if (d == null) {
// Invalid uri
mUri = null;
}
}
return mUri;
}
I am using this code for Uri that has file:// authority
Uri resimUri = Uri.parse(path_str);
File imgFile = new File(resimUri.getPath());
if (imgFile.exists()) {
// file exists
}else {
// file is not there
}

Retrieve Picasa Image for Upload from Gallery

I am working on an activity and associated tasks that allow users to select an image to use as their profile picture from the Gallery. Once the selection is made the image is uploaded to a web server via its API. I have this working regular images from the gallery. However, if the image selected is from a Picasa Web Album nothing is returned.
I have done a lot of debugging and narrowed the problem down to this method.
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
//cursor is null for picasa images
if(cursor!=null)
{
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
else return null;
}
Picasa images return a null cursor. MediaStore.Images.Media.DATA is not null for them, however. It only returns an #id, so I am guessing that there is no actual bitmap data at the address. Are Picasa images stored locally on the device at all?
I also noticed from the documentation that MediaStore.Images.ImageColumns.PICASA_ID exists. This value exists for selected picasa images but not other gallery images. I was thinking I could use this value to get a URL for the image if it is not store locally but I can not find any information about it anywhere.
I have faced the exact same problem,
Finally the solution I found, was to launch an ACTION_GET_CONTENT intent instead of an ACTION_PICK, then make sure you provide a MediaStore.EXTRA_OUTPUT extra with an uri to a temporary file.
Here is the code to start the intent :
public class YourActivity extends Activity {
File mTempFile;
int REQUEST_CODE_CHOOSE_PICTURE = 1;
(...)
public showImagePicker() {
mTempFile = getFileStreamPath("yourTempFile");
mTempFile.getParentFile().mkdirs();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTempFile));
intent.putExtra("outputFormat",Bitmap.CompressFormat.PNG.name());
startActivityForResult(intent,REQUEST_CODE_CHOOSE_PICTURE);
}
(...)
}
You might need to mTempFile.createFile()
Then in onActivityResult, you will be able to get the image this way
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
case REQUEST_CODE_CHOOSE_PICTURE:
Uri imageUri = data.getData();
if (imageUri == null || imageUri.toString().length() == 0) {
imageUri = Uri.fromFile(mTempFile);
file = mTempFile;
}
if (file == null) {
//use your current method here, for compatibility as some other picture chooser might not handle extra_output
}
}
Hope this helps
Then you should delete your temporary file on finish (it is in internal storage as is, but you can use external storage, I guess it would be better).
Why are you using the managedQuery() method? That method is deprecated.
If you want to convert a Uri to a Bitmap object try this code:
public Bitmap getBitmap(Uri uri) {
Bitmap orgImage = null;
try {
orgImage = BitmapFactory.decodeStream(getApplicationContext().getContentResolver().openInputStream(uri));
} catch (FileNotFoundException e) {
// do something if you want
}
return orgImage;
}

Categories

Resources