When trying to get the ExifInterface I keep seeing a Raw image not detected error message.
ExifInterface exifInterface = new ExifInterface(filepath);
int rotation=exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_UNDEFINED);
Does anyone know what could be causing this?
I am getting it from a Uri but I know the filepath exists
Those statements are mutually contradictory. A Uri is not a file. If the scheme of the Uri is file, then and only then can you get a filesystem path to the file, by means of getPath(). If the scheme is anything else, such as content, then you cannot get a filesystem path, because there is no requirement that there be a file. For example, a Uri of http://stackoverflow.com/questions/42930509/exifinterface-jni-raw-image-not-detected-error does not mean that the Android device has a file at /questions/42930509/exifinterface-jni-raw-image-not-detected-error.
The ExifInterface from com.android.support:exifinterface (e.g., where the current latest version is 25.3.0) has a constructor that takes an InputStream. Create a ContentResolver (via getContentResolver() on a Context, such as your Activity). Call openInputStream() on that ContentResolver, supplying the Uri (works for both file and content schemes). Pass that InputStream to the library's ExifInterface constructor. This simultaneously ensures that you do not cause security problems for your users and avoids having to worry about getting a filesystem path for the content that you wish to examine.
Long story short, apply the below example to your code:
Uri uri = Uri.fromFile(f);
// where f of type File
in = context.getApplicationContext().getContentResolver().openInputStream(uri);
// context should refer to your context app
ExifInterface exifInterface = new ExifInterface(in);
// you'll need "exifInterface"
And don't forget to close your input stream
in.close();
Related
I want to create a file from uri in the ActivityResultCallback in android 11. I use uri.getPath() to convert the incoming uri to a file. but, it won't work in android 11. here is my codes:
private void launchGallery (){
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
launcherGallery.launch(intent);
}
ActivityResultLauncher<Intent> launcherGallery = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();
if (data != null) {
Uri imageUri = data.getData();
// ---> getPath() won't work in android 11 <---
File file = new File(imageUri.getPath());
// I don't want to display the image in an ImageView.
// I need a file object to pass it to this method to encrypt it
encryptImage(file);
}
}
});
so, how can I create a file from uri in android 11?
simply: you can't. if Uri would be always a File then there would be no purpose of both class existance. Uri is a "pointer" to a file, which can be read as InputStream
InputStream inputStream = getContentResolver().openInputStream(uri);
you have to read all these bytes and if you REALLY need a File then store this data in your apps Scoped Storage. if you are shure that this is an image (its declared in calling Intent) then you may try to convert this data to Bitmap.
edit: I see you've added encryptImage(..) method call, so for shure you can read Bitmap "straight from" Uri instead of a File without taking users storage space, even for a while
check out such case: note that when you run a file picker launchGallery() then inside of it you can switch folders. there is a possibility to pick file from e.g. Google Drive, or if you have installed, other web-storages (OneDrive, Dropbox etc.). you will get an Uri as a result, but this isn't a real File on local storage. so you can stream it (as through web/network) for reading entirelly, it isn't ready and available at the moment of result callback call (just after picking and returning to your app)
btw. such possibility isn't limited to Android 11 and above, it was there way earlier. just handle Uri as "pointer", do not assume it is pointing on (local) File. in some cases even if user pick local file you will get an Uri pointing on it through some ContentResolver (so use own for read data), thus this won't be a file path (won't be starting with file://)
I'm using the FileProvider pattern for creating content:// uri to files, with the
FileProvider.getUriForFile(this, "com.myapp.provider", file)
function. I have the manifest, provider_paths and everything set the standard way, It creates an uri like content://com.myapp.provider/external_files/music/mysong.mp3.
My issue is that if I try getting the real file path in another app, it doesn't work as the _data column doesn't exist (to be specific the error in logs is E/CursorWindow: Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 0 columns.). For fetching the real path I'm using the also pretty much standard function
final String column = MediaStore.Files.FileColumns.DATA;
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
If I use a different app for sharing the same file it generates an uri like content://com.otherapp.provider/external_files/music/mysong.mp3, from which I can already retrieve the real file path. Any ideas what do I have to do to make sure that my app properly inserts the given uri to ContentResolver? Manual contentResolver.insert(...) functions are not allowed. I've tried different versions of provider_paths.xml and granting all possible read/write permissions to the given uri, but I could never retrieve the real path.
The uri itself generated by me works fine as I can read the file or play the song, my issue is just that I cannot retrieve the real file path that I need.
Thanks
My issue is that if I try getting the real file path in another app
The other app should not be trying to do this.
For fetching the real path I'm using the also pretty much standard function
That works for very few Uri values.
If I use a different app for sharing the same file it generates an uri like content://com.otherapp.provider/external_files/music/mysong.mp3, from which I can already retrieve the real file path.
That is not guaranteed.
Any ideas what do I have to do to make sure that my app properly inserts the given uri to ContentResolver?
You don't. You fix the client app, which should not be attempting to get a "real file path" from a Uri.
my issue is just that I cannot retrieve the real file path that I need.
Instead, for a Uri with a content scheme:
Step #1: Get a ContentResolver, by calling getContentResolver() on some Context (e.g., an activity)
Step #2: Call openInputStream() on the ContentResolver, passing in your Uri, to get an InputStream on that content
Step #3: Consume the content via that InputStream
If you are using some third-party library that can only work with files, copy the data from that InputStream to some FileOutputStream, then use the resulting file with that library.
This way, no matter where the content is coming from (a file that you could access, a file that you cannot access, a BLOB column in a database, etc.), you will have code that works.
See also:
Getting the Absolute File Path from Content URI for searched images
onActivityResult's intent.getPath() doesn't give me the correct filename
Android - Get real path of a .txt file selected from the file explorer
I am having a problem with selecting image file from external storage using file picker in Android. This question is the consequence of this question - No such file or diectory error in image file upload using Retrofit in Android. What my problem is opening and reading file from external storage on activity result. I want to convert result URI into File.
I read a pdf file from download folder on activity result
Uri bookUri = data.getData();
if(bookUri!=null)
{
String filePath = bookUri.toString();//bookUri.toString()
String mime = app.getMimeType(filePath);
if(mime!=null && !mime.isEmpty() && (mime.toLowerCase()=="application/pdf" || mime.toLowerCase()=="application/txt" || mime.toLowerCase()=="application/text"))
{
bookFile = new File(bookUri.getPath());
ivBookFile.setImageResource(R.drawable.book_selected);
}
else{
Toast.makeText(getBaseContext(),"Unable to process file you have chosen.",Toast.LENGTH_SHORT).show();
}
}
As you can see I used new File(bookUri.getPath()); to convert into File. The above code works well. It is working. The problem is now I am trying to open an image file in DCIM/Camera folder on activity result.
This is the code I used
Uri selectedImageUri = data.getData();
if(selectedImageUri!=null)
{
try{
bmpCoverImage = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImageUri);
imageFile = new File(selectedImageUri.getPath());
if(bmpCoverImage!=null)
{
ivCoverImage.setImageBitmap(bmpCoverImage);
}
}
catch (IOException e)
{
Toast.makeText(getBaseContext(),"An error occurred with the file selected",Toast.LENGTH_SHORT).show();
}
}
As you can see I used new File(selectedImageUri.getPath()); like I did in reading pdf file. This time the code is not working. When I do operation with the file like in previous question, it gives me error.
I used this way also
imageFile = new File(Environment.getExternalStorageDirectory(),selectedImageUri.getPath());
I got the same error. How can I open the image file correctly from external storage? How can I convert the chosen file URI from external storage into File?
I am having a problem with selecting image file from external storage using file picker in Android
If you are referring to the code that you are using in this question, you are not "using file picker". You are using ACTION_GET_CONTENT, which has never been a "file picker", nor will it ever be a "file picker".
I want to convert result URI into File.
Usually, that is not necessary. But, if that is what you want to do:
use ContentResolver and openInputStream() to get an InputStream on the content represented by the Uri
create a FileOutputStream on your desired file
use Java I/O to copy the bytes from the InputStream into the FileOutputStream
The above code works well. It is working.
It works for the small number of devices that you tested, for the specific activities that the user chose to handle the ACTION_GET_CONTENT request. It will not work on most Android devices, and it will not work in most circumstances. The only time that code will work is if the Uri has a file scheme. Most of the time, it will not. Instead, it will have a content scheme, representing content supplied by a ContentProvider.
Please how can I open the image file correctly from external storage?
If you wish to continue using ACTION_GET_CONTENT, please understand that this has nothing to do with external storage specifically. You are not getting a file, on external storage or elsewhere. You are getting a Uri. This is akin to a URL, such as the URL for this Web page. Just as a URL does not necessarily point to a file on your hard drive, a Uri does not necessarily point to a file on the filesystem. Use a ContentResolver and DocumentFile to work with the Uri and the content that it identifies.
If you want to always get files on external storage (and nowhere else), then use an actual file picker library.
I have a situation in Lollipop where I have:
Directory tree (DocumentFile) which is granted from user.
A collection of audio files that need to modify retrieved from media provider.
Uri mediaUri = Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
"45");
Then, how to write a stream into one of those files?
I think, this https://stackoverflow.com/a/30514269/615025 gives a work around. Copy bytes of the file to cache directory, do modification on the temporary file and then copy the bytes back to the original file.
DocumentFile is a new mechanism which allows us to modify files in Lollipop. It is not the same case with this post how to get contact photo URI
Thanks
You can open an outputStream directly from a Uri using ContentResolver.openOutputStream(Uri)
For example,
OutputStream fos;
fos = new BufferedOutputStream(context.getContentResolver().openOutputStream(uri));
Optionally, openOutputStream takes a string to specify mode.
i.e
openOutputStream(uri, "w");
to write or
openOutputStream(uri, "wa");
to append.
I am trying to get a FileInputStream object on an image that the user selects from the picture gallery. This is the android URI returned by android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI
content://media/external/images/media/3
When I try to construct a java URI object from this object, I get an IllegalArgumentException with the exception description Expected file scheme in URI: content://media/external/images/media/3 whereas the android URI shows the scheme as content
Update:
Never found a solution for the original question. But if you want the byte stream of an image in the pictures gallery, this piece of code will do that.
Bitmap bitmap = Media.getBitmap(getContentResolver(), imageUri);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(bytes.toByteArray());
You could use the toString method of the android Uri in combination of the String based constructor of the Java URI.
android.net.Uri auri = new android.net.Uri(what ever);
java.net.URI juri = new java.net.URI(auri.toString());
Android URI |
Java URI
Found the correct way to open InputStream from content URI:
InputStream fileInputStream=yourContext.getContentResolver().openInputStream(uri);
That's all!
There is a solution to your original question (convert Uri to URI):
Get the real file path (look this code: Get filename and path from URI from mediastore)
Get the URI using the real path and the constructor: URI(String uri)
If you need more details, look here:
How to delete a video recorded using an Intent with ACTION_VIDEO_CAPTURE?
I voted for jgilrincon's answer. I can't comment due to low reputation, and here goes some additional info - you can use FileHelper.java from Apache Cordova project, it has functions that you need for file handling from Uri strings, considering mediastore as well (and app assets folder)
Particularly this method provides InputStream from Uri:
public static InputStream getInputStreamFromUriString(String uriString, Activity cordova)
Since the String constructing doesn't work have you tried just constructing it your self?
android.net.URI auri = new android.net.URI(what ever);
java.net.URI juri = new java.net.URI(auri.getSchema(),
auri.getSchemaSpecificPart(),
auri.getFragment());
You might also want to double check that your getting valid data out of Android URI class. The docs as listed in my other answer discuss how it does pretty much no error checking. If there is infact an error the class just spits out garbage anyway and doesn't throw any exceptions. Which could very likely be why the java class which does do validation is throwing an exception.