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
Related
I am not able to get GEO Exif infos from picture taken from camera.
This is the code, and the "oldExif" variable does have almost all values NULL (also GEO infos).
The "uri" variable is the uri of the image taken and created.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != AppCompatActivity.RESULT_OK) {
return;
}
if (requestCode == REQUEST_IMAGE_CAPTURE) {
try {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
InputStream in = getContentResolver().openInputStream(uri);
ExifInterface oldExif = new ExifInterface(in);
// oldExif does have almost all values NULL
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
My android version is 5.0 and I already enabled the set of the camera about localization.
Indeed if I get a picture out of my app and show infos, I see geo data.
There is no Intent action that:
Causes a third-party camera app to offer the user to take a picture, and
Forces that camera app to add any particular EXIF tags
Your choices are:
Live without the EXIF tags
Add those tags yourself (e.g., find the user's location and put the geotags in the image), if they are missing
In my code I allow user to upload photos from gallery or from camera. Then image is stored into the server through retrofit. When retrieved the photo is always rotated 90 degrees if the photo is taken using the phone's camera (regardless whether it is from invoked through the app or invoked through the camera directly). If the images are not taken using the camera, the orientation is correct. How do I resolve this?
I know if I tried to display the image directly without storing it in server, and it was possible to be in the right orientation because I could rotate it before displaying. I am doing something similar to the codes here: https://gist.github.com/Mariovc/f06e70ebe8ca52fbbbe2.
But because I need to upload to the server and then retrieve from the server again. How do I rotate it before storing to the server so that when I retrieve it, it is already in the right orientation?
Below is some parts of my codes (just some usual handling of images and displayAvatarInProfile() is called after the service finished the downloading of image):
public void displayAvatarInProfile(String filePath) {
if(filePath != null && filePath != ""){
int targetW = mProfilePicImageView.getWidth();
int targetH = mProfilePicImageView.getHeight();
Bitmap bm = ImageStorageUtils.resizePic(filePath, targetW, targetH);
mProfilePicImageView.setImageBitmap(bm);
} else {
mProfilePicImageView.setImageBitmap(null);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == Activity.RESULT_OK) {
Uri fileUri = null;
String filePath = null;
switch(requestCode) {
case REQUEST_PICK_IMAGE:
fileUri = data.getData();
break;
case REQUEST_CAPTURE_IMAGE:
File imageFile = ImageStorageUtils.getFile(
getActivity().getResources().getString(R.string.ApptTitle),
"avatar_" + mUser.getLogin());
filePath = imageFile.getAbsolutePath();
fileUri = ImageStorageUtils.getUriFromFilePath(mContext.get(), filePath);
break;
default:
break;
}
if(fileUri != null) {
getActivity().startService(ProfileService.makeIntentUploadAvatar(
mContext.get(), mUser.getId(), fileUri));
}
}
}
public void pickImage() {
final Intent imageGalleryIntent =
new Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI)
.setType("image/*")
.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
// Verify the intent will resolve to an Activity.
if (imageGalleryIntent.resolveActivity(getActivity().getPackageManager()) != null)
// Start an Activity to get the Image from the Image Gallery
startActivityForResult(imageGalleryIntent,
DisplayProfileFragment.REQUEST_PICK_IMAGE);
}
public void captureImage() {
Uri captureImageUri = null;
try {
captureImageUri = Uri.fromFile(ImageStorageUtils.createImageFile(
mContext.get(),
getActivity().getResources().getString(R.string.ApptTitle),
"avatar_" + mUser.getLogin()));
} catch (IOException e) {
e.printStackTrace();
}
// Create an intent that will start an Activity to get
// capture an image.
final Intent captureImageIntent =
new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
.putExtra(MediaStore.EXTRA_OUTPUT, captureImageUri);
// Verify the intent will resolve to an Activity.
if (captureImageIntent.resolveActivity(getActivity().getPackageManager()) != null)
// Start an Activity to capture an image
startActivityForResult(captureImageIntent,
DisplayProfileFragment.REQUEST_CAPTURE_IMAGE);
}
Update 1
Was commented that I needed more description:
When I am uploading a file, I do this:
boolean succeeded = mImpatientServiceProxy.uploadAvatar(userId, new TypedFile("image/jpg", imageFile));
When I download, I get a retrofit.client.Response object, which I then get the InputStream from the Response and write the data to a file using an Output Stream.
final InputStream inputStream = response.getBody().in();
final OutputStream outputStream = new FileOutputStream(file);
IOUtils.copy(inputStream, outputStream);
Update 2
This is not a duplicate of existing solution because the user can upload from gallery, you do not know if it is a photo taken from resources online or from camera, so you cannot rotate the image when you display it.
Use camera api instead of intent. When you capture image using intents it displays rotated. In camera api there are methods by which you can change the rotation of the camera as well as the captured photo too.
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);
I had the orientation issue when working with ACTION_IMAGE_CAPTURE activity. I have used the TAG_ORIENTATION so that I would rotate the picture accordingly. But now we found that on some newer devices this doesn't work. In fact it returns 1 for all orientations.
Here's the list of devices we observed this on;
Samsung Infuse 4G (2.3.3)
Samsung Galaxy SII X (2.3.5)
Sony Xperia Arc (2.3.3)
Interesting thing is that once this image is the gallery it shows up properly and if I select it, the TAG_ORIENTATION is populated properly. So somehow the OS fills this information properly but not on ActivityResult.
What's the most reliable way to figure the orientation? Someone on another question suggested comparing height and width but when getting these, they are properly switched based on orientation (another mystery)
EDIT: It seems that this could be connected to another bug where the OS duplicates the image taken in the gallery (it's only supposed to save the image in the URL specified by us), the thing is this image in gallery has the ORIENTATION information while the one in the specified location doesn't.
This is the bug; http://code.google.com/p/android/issues/detail?id=19268
EDIT-2: I've filed a new bug with Android. I'm pretty sure this is an OS bug related the aforementioned bug.
http://code.google.com/p/android/issues/detail?id=22822
Ok guys, it seems like this bug for android won't be fixed for a while. Although I found a way to implement the ExifInformation so that both devices (ones with proper Exif tag, and also improper exif tags work together)..
So the issue is on some (newer) devices, there's a bug that makes the picture taken saved in your app folder without proper exif tags while a properly rotated image is saved in the android default folder (even though it shouldn't be)..
Now what I do is, i record the time when I'm starting the camera app from my app. THen on activity result, I query the Media Provider to see if any pictures were saved after this timestamp I saved. That means that, most likely OS saved the properly rotated picture in the default folder and of course put a entry in the media store and we can use the rotation information from this row. Now to make sure we are looking at the right image, i compare the size of this file to the one I have access to (saved in my own app folder);
int rotation =-1;
long fileSize = new File(filePath).length();
Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] {MediaStore.Images.ImageColumns.ORIENTATION, MediaStore.MediaColumns.SIZE }, MediaStore.MediaColumns.DATE_ADDED + ">=?", new String[]{String.valueOf(captureTime/1000 - 1)}, MediaStore.MediaColumns.DATE_ADDED + " desc");
if (mediaCursor != null && captureTime != 0 && mediaCursor.getCount() !=0 ) {
while(mediaCursor.moveToNext()){
long size = mediaCursor.getLong(1);
//Extra check to make sure that we are getting the orientation from the proper file
if(size == fileSize){
rotation = mediaCursor.getInt(0);
break;
}
}
}
Now if the rotation at this point is still -1, then that means this is one of the phones with proper rotation information. At this point, we can use the regular exif orientation on the file that's returned to our onActivityResult
else if(rotation == -1){
rotation = getExifOrientationAttribute(filePath);
}
You can easily find out how to find exif orientations like the answer in this question Camera orientation issue in Android
Also note that ExifInterface is only supported after Api level 5.. So if you want to support phones before 2.0, then you can use this handy library I found for java courtesy of Drew Noakes; http://www.drewnoakes.com/code/exif/
Good luck with your image rotating!
EDIT: Because it was asked, the intent I've used and how i started was like this
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//mediaFile is where the image will be saved
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
startActivityForResult(intent, 1);
you can go this way too:
Matrix matrix = new Matrix();
// rotate the Bitmap (there a problem with exif so we'll query the mediaStore for orientation
Cursor cursor = getApplicationContext().getContentResolver().query(selectedImage,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor.getCount() == 1) {
cursor.moveToFirst();
int orientation = cursor.getInt(0);
matrix.preRotate(orientation);
}
Indeed a problematic bug! I'm not sure I like the suggested workaround, so here's another :)
The key is to use EXTRA_OUTPUT and query it when the image has been captured! Obviously, this only works if you allow yourself to specify the filename.
protected void takePictureSequence() {
try {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, UUID.randomUUID().toString() + ".jpg");
newPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, newPhotoUri);
startActivityForResult(intent, ActivityResults.TAKE_NEW_PICTURE_RESULT);
} catch (Exception e) {
Toast.makeText(this, R.string.could_not_initalize_camera, Toast.LENGTH_LONG).show();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ActivityResults.TAKE_NEW_PICTURE_RESULT) {
if (resultCode == RESULT_OK) {
try {
String[] projection = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(this, newPhotoUri, projection, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
// Rotation is stored in an EXIF tag, and this tag seems to return 0 for URIs.
// Hence, we retrieve it using an absolute path instead!
int rotation = 0;
String realPath = cursor.getString(column_index_data);
if (realPath != null) {
rotation = ImageHelper.getRotationForImage(realPath);
}
// Now we can load the bitmap from the Uri, using the correct rotation.
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int getRotationForImage(String path) {
int rotation = 0;
try {
ExifInterface exif = new ExifInterface(path);
rotation = (int)exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL));
} catch (IOException e) {
e.printStackTrace();
}
return rotation;
}
What I've learned recently is that if you resize the image, it usually loses its EXIF information. So you want to give the new file the old EXIF information.
Source.
My solution for this. Tested on LG G2 mobile. I noticed that when I use camera and take new picture everything works fine. ExifInterface returns right orientation. So it must be something in the path because my path was null in this line of code:
exif = new ExifInterface(path);
but when i used absolute path my app crash. But the solution is in this method below, because it depends on your sdk version. One more note to mention I used absolute path only for selecting gallery picture because if i used it for Camera my app crashed. Im new in programing and just lost 2 days to solve this. Hope it will help someone.
public String getRealPathFromURI(Uri uri) {
if(Build.VERSION.SDK_INT >= 19){
String id = uri.getLastPathSegment().split(":")[1];
final String[] imageColumns = {MediaStore.Images.Media.DATA };
final String imageOrderBy = null;
Uri tempUri = getUri();
Cursor imageCursor = getContentResolver().query(tempUri, imageColumns,
MediaStore.Images.Media._ID + "="+id, null, imageOrderBy);
if (imageCursor.moveToFirst()) {
return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
}else{
return null;
}
}else{
String[] projection = { MediaStore.MediaColumns.DATA };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else
return null;
}
}
So I get my ExifInterface in onActivityResult method
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
try {
exif = new ExifInterface(getRealPathFromURI(data.getData()));
} catch (IOException e) {
e.printStackTrace();
}
showImage(data.getData());
} else if (requestCode == CAMERA_IMAGE_REQUEST && resultCode == RESULT_OK) {
try {
exif = new ExifInterface(Uri.fromFile(getCameraFile()).getPath());
} catch (IOException e) {
e.printStackTrace();
}
showImage(Uri.fromFile(getCameraFile()));
}
}
and my show image method look like this
public void showImage(Uri uri) {
if (uri != null) {
try {
Bitmap bitmap = scaleBitmapDown(MediaStore.Images.Media.getBitmap(getContentResolver(), uri), IMAGE_SIZE);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
bitmap = rotateBitmap(bitmap, orientation);
if (whatPlayer.equals("Player1")) {
mImagePlayer1.setImageBitmap(bitmap);
bitmapPlayer1 = bitmap; //*save picture in static variable so other activity can use this
}
if (whatPlayer.equals("Player2")) {
mImagePlayer2.setImageBitmap(bitmap);
bitmapPlayer2 = bitmap;
}
} catch (IOException e) {
Log.d(TAG, "Image picking failed because " + e.getMessage());
Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show();
}
} else {
Log.d(TAG, "Image picker gave us a null image.");
Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show();
}
}
I'm working on an application where the user is able to select files, either a new image from the camera, an image from the gallery, or a plain old file. It then shows an icon and the name for the selected item. I have this working with one exception. The gallery application integrates picasaweb pictures. If the user selects a picture from a picasa album, I'm not able to get a thumbnail for it.
I'm using the MediaStore.Images.Thumbnails.getThumbnail() method, and it works for other images in the gallery just fine, but for the picasaweb files, I get, regardless of what "kind" of thumbnail I attempt to get (although MICRO is what I'm after):
ERROR/MiniThumbFile(2051): Got exception when reading magic, id =
5634890756050069570, disk full or mount read-only? class
java.lang.IllegalArgumentException
I noticed the URI's given for the selected files are different. The local image files look like:
content://media/external/images/media/6912
and the picasaweb urls look like:
content://com.android.gallery3d.provider/picasa/item/5634890756050069570
I attempted to use a query to get at the raw THUMB_DATA, using Thumbnails.queryMiniThumbnails(), with Thumbnails.THUMB_DATA in the projection array, but I got a "no such column" error.
Is there another method for getting thumbnails that would work better? And will I have the same problem when I try and access the full image data?
What I have found is that on my Galaxy Nexus, the images for Picassa are stored in one of subdirectories under the /sdcard/Android/data/com.google.android.apps.plus/cache directory. When the content provider is com.google.android.gallery3d.provider then the number after "item" in the URL contains the name of the image (in your example above "5634890756050069570"). This data correspondes to a file in one of the subdirectories under /sdcard/Android/data/com.google.android.apps.plus/cache with the extension ".screen". If you were to copy this image from your phone (in your case 5634890756050069570.screen) using DDMS and rename it with the extension ".jpeg" you could open it and view it on your computer.
The following onActivityResult method will check for this content provider being returned, and then will recursively search for the file in the /sdcard/Android/data/com.google.android.apps.plus/cache directory. The private member variable fileSearchPathResults is filled in by the recursive search method walkDirectoryRecursivelySearchingForFile().
private String fileSearchPathResult = null;
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
String filePath = null;
// This code is required to get the image path on content providers
// on API > 10 where the image is from a picassa web album, since Google changed
// the content provider in versions with API > 10
if (selectedImage.toString().contains("com.google.android.gallery3d.provider")) {
StringBuilder contentProviderPath = new StringBuilder(selectedImage.toString());
int beginningIndex = contentProviderPath.lastIndexOf("/");
String fileNameWithoutExt = contentProviderPath.subSequence(beginningIndex + 1,
contentProviderPath.length()).toString();
Log.i(TAG, fileNameWithoutExt);
try {
File path = new File("/sdcard/Android/data/com.google.android.apps.plus/cache");
if (path.exists() && path.isDirectory()) {
fileSearchPathResult = null;
walkDirectoryRecursivelySearchingForFile(fileNameWithoutExt, path);
if (fileSearchPathResult != null) {
filePath = fileSearchPathResult;
}
}
} catch (Exception e) {
Log.i(TAG, "Picassa gallery content provider directory not found.");
}
}
}
public void walkDirectoryRecursivelySearchingForFile(String fileName, File dir) {
String pattern = fileName;
File listFile[] = dir.listFiles();
if (listFile != null) {
for (int i = 0; i < listFile.length; i++) {
if (listFile[i].isDirectory()) {
walkDirectoryRecursivelySearchingForFile(fileName, listFile[i]);
} else {
if (listFile[i].getName().contains(pattern)) {
fileSearchPathResult = listFile[i].getPath();
}
}
}
}
}
With the filePath, you can create a Bitmap of the image with the following code:
Bitmap sourceImageBitmap = BitmapFactory.decodeFile(filePath);
ACTIVITYRESULT_CHOOSEPICTURE is the int you use when calling startActivity(intent, requestCode);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == ACTIVITYRESULT_CHOOSEPICTURE) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
final InputStream is = context.getContentResolver().openInputStream(intent.getData());
final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
is.close();
}
}
That code will load the whole image. You can adjust the sample size to something reasonable to get a thumbnail sized image.