How to read files at a specific path in android? - android

I am developing an application in which I open the file explorer and select any file of my choice and retrieve its contents. The default path that opens is /storage/sdcard0 . I am able to read contents of any file that resides directly in this path. However, for any file that in contained in any folder inside /storage/sdcard0/. is inaccessible. The program gives a file not found error. Also, I cannot understand the path that these files have, like for example, if a file resides in path:
/storage/sdcard0/DCIM/100ANDRO/DSC_0001.jpg
,
the logcat shows the path to be:
content:/media/external/images/media/84290/DSC_0001.jpg
How to access this file in my Java code?
Below is the code snippet:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "requestCode received: "+requestCode+" result code: "+resultCode);
if (requestCode == 1 && resultCode == RESULT_OK) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
String folderPath = "Anant";
String filePath = "image.jpg";
String imagePath = saveToInternalStorage(thumbnail, folderPath,
sImageName);
Log.i(TAG, "DeviceAPIS:actual path :: "
+ imagePath.trim().toString());
sendCameraData(imagePath.toString().trim(),
ptrAppContainerForCamera);
}
else if (requestCode == REQUEST_PATH){
if (resultCode == RESULT_OK) {
// Get the Uri of the selected file
Uri uri = data.getData();
Log.d(TAG, "data.getData() result line 742: " + uri);
String uriString = uri.toString();
File myFile = new File(uriString);
String path = myFile.getAbsolutePath();
String base64 ="Error";
byte[] bytesRead = base64.getBytes();
String displayName = null;
String fileName = null;
if (uriString.startsWith("content://")) {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
displayName = path + "/" + displayName;
Log.d(TAG, "BEFORE REPLACE: "+displayName);
int index = displayName.indexOf(':');
fileName = displayName.substring(index + 1, displayName.length());
Log.d(TAG,"displayName line 762 " + Part);
}
} finally {
cursor.close();
}
} else if (uriString.startsWith("file://")) {
Log.d(TAG, "FILE BLOCK LINE 768");
displayName = myFile.getName();
Log.d(TAG,"displayName 11" + displayName);
}
try{
File sdcard = Environment.getExternalStorageDirectory();
File readFile = new File(sdcard, fileName);
// File readFile = new File(uri);
int length = (int)readFile.length();
byte[] bytes = new byte[length];
FileInputStream in = new FileInputStream(readFile);
try{
in.read(bytes);
}finally {
in.close();
}
String contents = new String(bytes);
Log.d(TAG,"contents read :: \\n" + contents);
//convert to Base64
bytesRead = contents.getBytes("UTF-8");
base64 = Base64.encodeToString(bytesRead,Base64.DEFAULT);
}catch (Exception e){
Log.d(TAG, "THROWING EXCEPTION");
Log.e(TAG,e.getMessage(),e);
}
}
The exception thrown is java.io.FileNotFoundException. Any help is greatly appreciated.

You can try as below:
String path = null;
Uri originalUri = data.getData();
try {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = this.managedQuery(originalUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
} catch (Exception e) {
} finally {
cursor.close();
}
And if path is null, you can get bitmap first and then copy it to your local path.
ContentResolver resolver = this.getContentResolver();
Bitmap photo = MediaStore.Images.Media.getBitmap(resolver, originalUri);
.... // copy photo to your local path

you can try this,
1. make sure you have added permission in you manifest file
2. Settings -> Apps -> Your App -> Permissions -> Storage = true/enabled
I had faced a same issue of FileNotFound and i was able to resolve it by #2 above.

Related

How do I retrieve the file size of an image selected from my gallery?

I've tried the answers on every other post out there and they all seem to return 0.0 as the file size of my image which cannot be true. I think the file path is what's causing it to return the incorrect file size. Here is my code:
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
imageUri = data.getData();
textViewImageAttachmentStatus.setText("File has been attached");
textViewImageAttachmentStatus.setTextColor(Color.parseColor("#008577"));
Picasso.get().load(imageUri).into(imageViewPreviewImage);
String imagePath = imageUri.getPath();
File imageFile = new File(imagePath);
long imageSize = imageFile.length() / 1024;
System.out.println(imageSize);
}
}
Better use Cursor its much robust , Try this
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mediaPath1 = cursor.getString(columnIndex);
cursor.close();
File file = new File(mediaPath);
int file_size = Integer.parseInt(String.valueOf(file.length() / 1048576));
System.out.println(file_size);
You can try this code
Import below packages
import java.io.File;
import java.text.DecimalFormat;
put below code when it requires
private static final DecimalFormat format = new DecimalFormat("#.##");
private static final long MiB = 1024 * 1024;
private static final long KiB = 1024;
public static String getFileSize(File file) {
if (!file.isFile()) {
throw new IllegalArgumentException("Expected a file");
}
final double length = file.length();
if (length > MiB) {
return format.format(length / MiB) + " MB";
}
if (length > KiB) {
return format.format(length / KiB) + " KB";
}
return format.format(length) + " Bytes";
}
Call the above function
String fileSize = getFileSize(imageFile);
Here is code for get file size from choose from Gallery
case AppConstant.REQUEST_GALLERY_IMAGE:
if (resultCode == Activity.RESULT_OK) {
long dataSize = 0;
File f = null;
Uri uri = data.getData();
String scheme = uri.getScheme();
System.out.println("Scheme type " + scheme);
if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
try {
InputStream fileInputStream = getApplicationContext().getContentResolver().openInputStream(uri);
dataSize = fileInputStream.available();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("File Size Length", dataSize + ""); // Here get file sizw
} else if (scheme.equals(ContentResolver.SCHEME_FILE)) {
String path = uri.getPath();
try {
f = new File(path);
} catch (Exception e) {
e.printStackTrace();
}
Log.e("File Size Length", f.length() + ""); // here get file size
}
}
break;
Here the value is returned, for example, if you want not to upload a file larger than 5 megabytes
public boolean MaxSizeImage(String imagePath){
long file_size = new File(imagePath).length() / 1024;//"kB"
if (file_size <= 5000){ //5M
return true;
}
return false;
}
//Here the path is fetched
public static String getFilePath(Context context, Uri uri) {
String imagePath;
String[] filePath = {MediaStore.Images.Media.DATA};
Cursor c = context.getContentResolver().query(uri, filePath, null, null, null);
assert c != null;
c.moveToFirst();
int columnIndex = c.getColumnIndex(filePath[0]);
imagePath = c.getString(columnIndex);
c.close();
return imagePath;
}
Here's a simpler and more sofisticated way of getting the size of a file that the user has just selected. Please see if this snippet might helps.
Uri returnUri = intent.getData();
Cursor returnCursor = getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String selectedFileName = returnCursor.getString(nameIndex);
Long selectedFileSize = Long.toString(returnCursor.getLong(sizeIndex));
Full documentation here where you can also find this snippet written in Kotlin.

Image path return null in Android

I want to get image path and upload to the server.
Here i successfully read image from gallery and set into image view but image path return null.
public void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
// Get the url from data
Uri selectedImageUri = data.getData();
if (null != selectedImageUri) {
// Get the path from the Uri
String path = getRealPathFromURI(getActivity(), selectedImageUri);
Log.i(TAG, "IMAGE" + path);
Log.d("INFO", selectedImageUri.toString());
// Set the image in ImageView
profilepicture.setImageURI(selectedImageUri);
}
}
}
}
/* Get the real path from the URI */
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
Delete getRealPathFromURI(), as it is not going to work reliably.
Instead, use your favorite image-loading library (e.g., Picasso, Glide) to load the image from the Uri.
Or, in a worst-case scenario, use getContentResolver().openInputStream() to get an InputStream on the content identified by the Uri, then pass that stream to BitmapFactory.decodeStream(). Just do this I/O on a background thread, please (which image-loading libraries will handle for you, among other benefits).
Update your method getRealPathFromURI:
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String imagePath = cursor.getString(column_index);
if (imagePath == null) {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "New");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File file;
String path = "img_" + timeStamp + ".jpg";
file = new File(mediaStorageDir.getPath() + File.separator + path);
imagePath = file.getAbsolutePath();
ParcelFileDescriptor parcelFileDescriptor = null;
try {
parcelFileDescriptor = context.getContentResolver()
.openFileDescriptor(contentUri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory
.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
saveBitmapToPath(image, imagePath);
} catch (IOException e) {
e.printStackTrace();
}
}
return imagePath;
} finally {
if (cursor != null) {
cursor.close();
}
}
}
Use this function to convert String URL to Bitmap
public Bitmap getImage(String url) {
try {
BufferedInputStream bis = new BufferedInputStream(new
URL(url).openStream(), BUFFER_IO_SIZE);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(baos,
BUFFER_IO_SIZE);
copy(bis, bos);
bos.flush();
return BitmapFactory.decodeByteArray(baos.toByteArray(), 0,
baos.size());
} catch (IOException e) {
Log.d(TAG, "loadImageFromArrayList: IMAGE DOWNLOAD FAILED!" +e);
}
return null;
}
try this
String path = yourAndroidURI.toString() // "/mnt/sdcard/FileName.mp3"
File file = new File(new URI(path));

Android Getting file name and path from onActivityResult

What I am trying to achieve. I have a button, when the button is clicked the app opens a file picker and the user selects a file. The app then uses a FileInputStream to read the file and generates a byte[]. I have a TextView below the button which will then simply display the byte[].length. Here is the code in the button.onClick() event:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
requestFilePickerCode = parent.registerActivityResultListener(this);
try
{
parent.startActivityForResult(intent, requestFilePickerCode);
}
catch (ActivityNotFoundException e)
{
Toast.makeText(task.getParent(), "Please install a file manager", Toast.LENGTH_SHORT).show();
}
Now this code works and I have confirmed that it fires onActivityResult when the file is chosen. I simply print a Log to display data.toString() which produces the following output:
11-02 15:14:36.196 2535-2535/? V/class za.co.gpsts.gpsjobcard.utility.handlers.PebbleTypeHandlerBinary: -----> content:/com.android.providers.downloads.documents/document/1
So it seems to be getting the selected file. When I run the app and I select a file it throws my custom error:
11-02 15:14:36.196 2535-2535/? E/class za.co.gpsts.gpsjobcard.utility.handlers.PebbleTypeHandlerBinary: -----> File does not exist
This obviously indicates that I am not getting the file. Here is my code:
#Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data)
{
byte[] fileContent;
// check that data is not null and assign to file if not null
if (data != null)
{
Uri uri = data.getData();
String uriString = uri.toString();
file = new File(uriString);
Log.v(PebbleTypeHandlerBinary.class.toString(), "-----> " + file.toString());
// declare file input stream and read bytes
// write to string variable to test and test output
FileInputStream fin = null;
try
{
fin = new FileInputStream(file);
fileContent = new byte[(int) file.length()];
fin.read(fileContent);
String test = new String(fileContent);
Log.v(PebbleTypeHandlerBinary.class.toString(), "=====> " + test);
}
catch (FileNotFoundException e)
{
Toast.makeText(task.getParent(), "File not found", Toast.LENGTH_SHORT).show();
Log.e(PebbleTypeHandlerBinary.class.toString(), "-----> File does not exist");
}
catch (IOException e)
{
Toast.makeText(task.getParent(), "Error reading file", Toast.LENGTH_SHORT).show();
Log.e(PebbleTypeHandlerBinary.class.toString(), "-----> Error while reading the file");
}
finally
{
// close the file input stream to stop mem leaks
try
{
if (fin != null)
{
fin.close();
}
} catch (IOException e)
{
Log.e(PebbleTypeHandlerBinary.class.toString(), "-----> Error closing the stream");
}
}
Log.v(PebbleTypeHandlerBinary.class.toString(), data.toString());
}
return false;
}
Please can you guys review my code and help me to get this working. Any help would be appreciated.
/* you can get just name and size with this method.
use Cursor .
Uri uri = data.getData();
get data from onActivityResult()
*/;
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
cursor.moveToFirst();
String name = cursor.getString(nameIndex);
String size = Long.toString(cursor.getLong(sizeIndex));
Toast.makeText(this, "name : "+name+"\nsize : "+size, Toast.LENGTH_SHORT).show();
I managed to fix it as follows:
I used inputStream = task.getParent().getContentResolver().openInputStream(uri); to get an InputStream. Then used a ByteArrayOutputStream to write to a byte[]. See code below.
#Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data)
{
Uri uri = data.getData();
byte[] fileContent;
InputStream inputStream = null;
try
{
inputStream = task.getParent().getContentResolver().openInputStream(uri);
if (inputStream != null)
{
fileContent = new byte[(int)file.length()];
inputStream.read(fileContent);
fileContent = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read;
while((read=inputStream.read(fileContent))>-1) baos.write(fileContent,0,read);
fileContent = baos.toByteArray();
baos.close();
Log.v(PebbleTypeHandlerBinary.class.toString(), "-----> Input Stream: " + inputStream);
Log.v(PebbleTypeHandlerBinary.class.toString(), "-----> Byte Array: " + fileContent.length);
}
else
{
Log.e(PebbleTypeHandlerBinary.class.toString(), "-----> Input Stream is null");
}
}
catch (FileNotFoundException e)
{
Log.e(PebbleTypeHandlerBinary.class.toString(), "-----> File not found", e);
}
catch (IOException e)
{
Log.e(PebbleTypeHandlerBinary.class.toString(), "-----> Error reading file", e);
}
finally
{
if (inputStream != null)
{
try
{
inputStream.close();
}
catch (IOException e)
{
Log.e(PebbleTypeHandlerBinary.class.toString(), "-----> Error reading file", e);
}
}
}
return false;
}
Thanks for all your help.
U can search converting uri to filepath.
GetData() retruns a uri.
But new File() need a filepath param;
Like this:
public static String getRealFilePath( final Context context, final Uri uri ) {
if ( null == uri ) return null;
final String scheme = uri.getScheme();
String data = null;
if ( scheme == null )
data = uri.getPath();
else if ( ContentResolver.SCHEME_FILE.equals( scheme ) ) {
data = uri.getPath();
} else if
( ContentResolver.SCHEME_CONTENT.equals( scheme ) ) {
Cursor cursor = context.getContentResolver().query( uri, new String[] { ImageColumns.DATA }, null, null, null );
if ( null != cursor ) {
if ( cursor.moveToFirst() ) {
int index = cursor.getColumnIndex( ImageColumns.DATA );
if ( index > -1 ) {
data = cursor.getString( index );
}
}
cursor.close();
}
}
return data;
}
1. File Name:
You can get the file name with the following method:
public static String getFileName(Context context, Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
cursor.close();
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
You will call it inside onActivityResult() and pass to it the context and uri. and you can find the uri through the intent you get from the onActivityResult which is mostly called "data", you will get the Uri from it like this:
data.data
which ".data" is the Uri.
Ex:
Utils.getFileName(this, data!!.data)
And finally it will return the file name as a String.
2. File Path:
Simply to get the file path you can get it from the data intent uri like this:
data!!.data!!.path.toString()
It will get you the path of the file as a String.

Problems with picture uploading

I have this activity in which the user can either choose one image from Gallery or just take a picture and (along with other data) upload it to a website.
So far I've encountered 2 different problems:
1) If I try it with a picture from the gallery, I get an IOException with message
/external/images/media/2305: open failed: ENOENT (No such file or directory)
That happens when it comes to open the file stream.
2) If I try it by taking the picture, it goes ok, but the encoded data string is composed of "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" (really longer, but only A's) and I guess that's not a good sign. This is only a guess since I still cannot properly upload it to the website, but different pictures showing the same data string just smells funny.
The code here
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PICTURE:
if (resultCode == Activity.RESULT_OK) {
//Uri selectedImage = imageUri;
loadImage(imageUri);
}
break;
case SELECT_PHOTO:
if(resultCode == Activity.RESULT_OK){
imageUri = data.getData();
loadImage(imageUri);
}
}
}
This is how I load the image (either pic taken or from the gallery) onto the ImageView. It works ok.
public void loadImage(Uri selectedImage){
mActivity.getContentResolver().notifyChange(selectedImage, null);
ContentResolver cr = mActivity.getContentResolver();
Bitmap bitmap;
try {
bitmap = android.provider.MediaStore.Images.Media
.getBitmap(cr, selectedImage);
ivPicture.setImageBitmap(bitmap);
ivPicture.setVisibility(View.VISIBLE);
mActivity.croutonInfo(selectedImage.toString());
} catch (Exception e) {
mActivity.croutonAlert("Failed to load");
e("Camera " + e.toString());
}
}
This is the method I use to mock the data upload. When I get the API it will have an asynctask to deal with the http transfer, so far it only puts the data into a logicless transfer object
public void uploadTapa() throws IOException{
mActivity.croutonInfo("subiendo tapa ");
d("uploadTapa new ");
TapaUploadParametros tup = new TapaUploadParametros();
d("uploadTapa bar: " + nombreBar);
tup.setBarNombre(etBarName.getText().toString());
d("uploadTapa tapa: " + nombreTapa);
tup.setNombre(etTapaName.getText().toString());
d("uploadTapa municipio: " + municipio);
tup.setLocalidad(municipio);
d("uploadTapa provincia: " + provincia);
tup.setProvincia(provincia);
d("uploadTapa tipologiaId: " + tipologiaId);
tup.setTipo(tipologiaId);
d("uploadTapa precioId: " + precioId);
tup.setPrecio(precioId);
String encodedImage = encodeImgForHTTP(imageUri);
d("uploadTapa encoded image: " + encodedImage);
tup.setPic(encodedImage);
d("uploadTapa direccionBar: " + direccionBar);
tup.setBarDireccion(direccionBar);
}
And this is the method to encode the image for http transfer. Images from gallery fail just after "before opening stream"
private String encodeImgForHTTP (Uri imageUri) throws IOException{
ContentResolver cr = mActivity.getContentResolver();
d("encodeImgForHTTP before opening stream ");
FileInputStream fis = new FileInputStream(imageUri.getPath());
d("encodeImgForHTTP after opening stream ");
// Get binary bytes for encode
byte[] imageBytes = new byte[fis.available()];
d("encodeImgForHTTP after getting byte array ");
// base 64 encode for text transmission (HTTP)
d("encodeImgForHTTP pre 64: " + imageBytes);
String data_string = Base64.encodeToString(imageBytes, Base64.URL_SAFE);
d("encodeImgForHTTP before returning the encoded data string " + data_string);
return data_string;
}
What am I doing wrong with the gallery images? Why does the encoding of different pictures look the same?
I think you should buffer your input stream into smaller byte arrays, and not use the available function as it is an estimate, in your encoding function, to start with.
In order to take a picture you have to determine a path where you would like the image saved and pass that as an extra in the intent, for example:
private void capture(){
String directoryPath = Environment.getExternalStorageDirectory() + "/" + IMAGE_DIRECTORY + "/";
String filePath = directoryPath+Long.toHexString(System.currentTimeMillis())+".jpg";
File directory = new File(directoryPath);
if (!directory.exists()) {
directory.mkdirs();
}
this.capturePath = filePath; // you will process the image from this path if the capture goes well
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra( MediaStore.EXTRA_OUTPUT, Uri.fromFile( new File(filePath) ) );
startActivityForResult(intent, REQUEST_CAPTURE);
}
I guess I finally got it to work. First I used Emil's advice and saved the image. DCIM_PATH is the path to the DCIM folder.
public void takePhoto() {
String directoryPath = DCIM_PATH;
d("takePhoto directoryPath: " + directoryPath);
this.pictureFileName = Long.toHexString(System.currentTimeMillis())+".jpg";
String filePath = directoryPath + pictureFileName ;
File directory = new File(directoryPath);
if (!directory.exists()) { // in case there's no DCIM folder
directory.mkdirs(); // just create it
}
d("takePhoto filePath: " + filePath);
this.imageUri = Uri.parse(filePath);
d("takePhoto imageUri: " + filePath);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// here's where I tell the intent where to save the file
intent.putExtra(
MediaStore.EXTRA_OUTPUT,Uri.fromFile( new File(filePath) )
);
startActivityForResult(intent, TAKE_PICTURE);
}
I had to use two different methods for loading the picture to the imageview. If it's a picture just taken, I use this one:
public void loadImageJustTaken(Uri selectedImage) {
mActivity.getContentResolver().notifyChange(selectedImage, null);
Bitmap bitmap =
BitmapFactory.decodeFile(imageUri.getPath());
ivPicture.setImageBitmap(bitmap);
ivPicture.setVisibility(View.VISIBLE);
}
But to use one from the gallery I have to use the contentResolver
public void loadImage(Uri selectedImage){
imageUri = selectedImage;
mActivity.getContentResolver().notifyChange(selectedImage, null);
ContentResolver cr = mActivity.getContentResolver();
Bitmap bitmap;
try {
bitmap = android.provider.MediaStore.Images.Media
.getBitmap(cr, imageUri);
ivPicture.setImageBitmap(bitmap);
ivPicture.setVisibility(View.VISIBLE);
mActivity.croutonInfo(imageUri.getPath());
} catch (Exception e) {
e("Camera " + e.toString());
}
}
When I want to upload the image, I have to encode it. This method works as long as you provide it with the right file path
private String encodeImgForHTTP (Uri imageUri) throws IOException{
String realPicPath = getPath(imageUri);
d("encodeImgForHTTP before opening stream " + realPicPath);
FileInputStream fis = new FileInputStream(realPicPath);
d("encodeImgForHTTP after opening stream ");
// Get binary bytes for encode
byte[] imageBytes = IOUtils.toByteArray(fis);
d("encodeImgForHTTP after getting byte array ");
// base 64 encode for text transmission (HTTP)
//String data_string = Base64.encodeToString(data, Base64.URL_SAFE);
d("encodeImgForHTTP pre 64: " + imageBytes);
String data_string = Base64.encodeToString(imageBytes, Base64.URL_SAFE);
d("encodeImgForHTTP before returning the encoded data string " + data_string);
return data_string;
}
And here's how I get the "real path" for the picture:
public String getPath(Uri uri) throws IOException {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = mActivity.
managedQuery(uri, projection, null, null, null);
if (cursor == null){ // with pictures just taken, the uri returned by the onActivityResult makes cursor to be null. Following method takes care of that
uri = saveMediaEntry(imageUri.getPath(), pictureFileName, "");
d("cursor nulo, segundo cursor con uri " + uri.getPath());
cursor = mActivity.
managedQuery(uri, projection, null, null, null);
}
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
The method saveMediaEntry creates an entry to the device's media database returning its Uri. Using that Uri, the cursor now will point to the picture file we want
private Uri saveMediaEntry(
String imagePath,String title,String description) throws IOException {
ExifInterface exif = new ExifInterface(imagePath);
ContentValues v = new ContentValues();
v.put(Images.Media.TITLE, title);
v.put(Images.Media.DISPLAY_NAME, title);
v.put(Images.Media.DESCRIPTION, description);
v.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
v.put(Images.Media.DATE_TAKEN, exif.getAttribute(ExifInterface.TAG_DATETIME));
//v.put(Images.Media.DATE_MODIFIED, dateTaken) ;
v.put(Images.Media.MIME_TYPE, "image/jpeg");
v.put(Images.Media.ORIENTATION, exif.getAttribute(ExifInterface.TAG_ORIENTATION));
File f = new File(imagePath) ;
File parent = f.getParentFile() ;
String path = parent.toString().toLowerCase() ;
String name = parent.getName().toLowerCase() ;
v.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
v.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, name);
v.put(Images.Media.SIZE,f.length()) ;
f = null ;
v.put(Images.Media.LATITUDE, exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE));
v.put(Images.Media.LONGITUDE, exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE));
v.put("_data",imagePath) ;
ContentResolver c = mActivity.getContentResolver() ;
return c.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, v);
}
After all this, pictures get loaded OK, and the Base64.encodeToString returns are different for different pictures :)
Hope it helps someone :)

Android, MediaStore.EXTRA_OUTPUT, stores two images [duplicate]

I'm currently developing an app which uses the built-in Camera.
I call this snippet by clicking a button :
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
path += "/myFolder/myPicture.jpg";
File file = new File( path );
//file.mkdirs();
Uri outputFileUri = Uri.fromFile( file );
//String absoluteOutputFileUri = file.getAbsolutePath();
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, 0);
After taking the picture with the camera, the jpg is well stored in sdcard/myFolder/myPicture.jpg, but it is also stored in /sdcard/DCIM/Camera/2011-06-14 10.36.10.jpg, which is the default path.
Is there a way to prevent the built-in Camera to store the picture in the default folder?
Edit : I think I will use the Camera class directly
Another way, tested on android 2.1, is take the ID or Absolute path of the gallery last image, then you can delete the duplicated image.
It can be done like that:
/**
* Gets the last image id from the media store
* #return
*/
private int getLastImageId(){
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
if(imageCursor.moveToFirst()){
int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
Log.d(TAG, "getLastImageId::id " + id);
Log.d(TAG, "getLastImageId::path " + fullPath);
imageCursor.close();
return id;
}else{
return 0;
}
}
And to remove the file:
private void removeImage(int id) {
ContentResolver cr = getContentResolver();
cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media._ID + "=?", new String[]{ Long.toString(id) } );
}
This code was based on the post: Deleting a gallery image after camera intent photo taken
While the answer from "Ilango J" provides the basic idea.. I thought I'd actually write in how I actually did it.
The temporary file path that we were setting in intent.putExtra() should be avoided as it's a non standard way across different hardwares. On HTC Desire (Android 2.2) it did not work, And i've heard it works on other phones. It's best to have a neutral approach which works every where.
Please note that this solution (using the Intent) requires that the phone's SD Card is available and is not mounted onto the PC. Even the normal Camera app wouldn't work when the SD Card is connected to the PC.
1) Initiate the Camera Capture intent. Note, I disabled temporary file writes (non-standard across different hardware)
Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(camera , 0);
2) Handle callback and retrieve the captured picture path from the Uri object and pass it to step#3
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CAPTURE_PIC: {
if (resultCode == RESULT_OK && data != null) {
Uri capturedImageUri = data.getData();
String capturedPicFilePath = getRealPathFromURI(capturedImageUri);
writeImageData(capturedImageUri, capturedPicFilePath);
break;
}
}
}
}
public String getRealPathFromURI(Uri contentUri) {
String[] projx = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(contentUri, projx, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
3) Clone and delete the file. See that I used the Uri's InputStream to read the content.
The same can be read from the File of the capturedPicFilePath too.
public void writeImageData(Uri capturedPictureUri, String capturedPicFilePath) {
// Here's where the new file will be written
String newCapturedFileAbsolutePath = "something" + JPG;
// Here's how to get FileInputStream Directly.
try {
InputStream fileInputStream = getContentResolver().openInputStream(capturedPictureUri);
cloneFile(fileInputStream, newCapturedFileAbsolutePath);
} catch (FileNotFoundException e) {
// suppress and log that the image write has failed.
}
// Delete original file from Android's Gallery
File capturedFile = new File(capturedPicFilePath);
boolean isCapturedCameraGalleryFileDeleted = capturedFile.delete();
}
public static void cloneFile(InputStream currentFileInputStream, String newPath) {
FileOutputStream newFileStream = null;
try {
newFileStream = new FileOutputStream(newPath);
byte[] bytesArray = new byte[1024];
int length;
while ((length = currentFileInputStream.read(bytesArray)) > 0) {
newFileStream.write(bytesArray, 0, length);
}
newFileStream.flush();
} catch (Exception e) {
Log.e("Prog", "Exception while copying file " + currentFileInputStream + " to "
+ newPath, e);
} finally {
try {
if (currentFileInputStream != null) {
currentFileInputStream.close();
}
if (newFileStream != null) {
newFileStream.close();
}
} catch (IOException e) {
// Suppress file stream close
Log.e("Prog", "Exception occured while closing filestream ", e);
}
}
}
try this code:
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
path += "/myFolder/myPicture.jpg";
File file = new File( path );
//file.mkdirs();
Uri outputFileUri = Uri.fromFile( file );
//String absoluteOutputFileUri = file.getAbsolutePath();
intent.putExtra("output", outputFileUri);
startActivityForResult(intent, 0);

Categories

Resources