I'm trying to open the camera from my app and get a bitmap. But this doens't work. I got this error :
E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: content:/media/external/images/media/9969: open failed: ENOENT (No such file or directory)
Here is the code :
private void openCamera()
{
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.TITLE, "New Picture");
contentValues.put(MediaStore.Images.Media.DESCRIPTION, "From the camera");
image_uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
//Camera intent
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri);
startActivityForResult(cameraIntent, IMAGE_CAPTURE_CODE);
}
When I call openCamera(), here is the activity result :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch (resultCode)
{
case RESULT_OK :
{
//imageView.setImageURI(image_uri); this works
Bitmap bitmap = null;
String photoPath = image_uri.toString();
bitmap = BitmapFactory.decodeFile(photoPath);
imageView.setImageBitmap(bitmap); //this doesnt work ! --> the bitmap is empty
}
//finish
case RESULT_CANCELED :
{
// finish();
}
default: {
//finish();
}
}
I need the bitmap to store the image after that.
It's pretty weird because the image is well saved into the gallery but I can't get it...
Ideally, you would be using Glide, Picasso, or another image-loading library, and simply have it load the image from the Uri into your ImageView.
If you insist upon using your basic approach, despite its poor performance, replace:
String photoPath = image_uri.toString();
bitmap = BitmapFactory.decodeFile(photoPath);
with:
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(image_uri));
A Uri is not a file.
Related
I'm getting Runtime Exception while getting Uri from Bitmap. BTW the same code works perfect in standalone project.
Call to Camera intent
private void openCamera() {
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent,
REQUEST_CODE_CAPTURE_IMAGE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_CAPTURE_IMAGE && resultCode == getActivity().RESULT_OK
&& null != data) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
String s = getImageUri(photo).toString();
Globals.saveImagePathToSharedPref(getActivity(), s);
setImage(Uri.parse(s));
}
}
public Uri getImageUri(Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(getActivity().getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
In getImageUri method, the path is returning null, and the exception as follows:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null,
request=327780, result=-1, data=Intent { act=inline-data (has extras) }}
to activity : java.lang.NullPointerException: uriString
You can use MediaStore.EXTRA_OUTPUT as an extra to the cameraIntent, the full sized image will then be saved to that location. The bitmap returned in the intent activity result is just a thumbnail.
You can use
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
To generate the Uri to pass in EXTRA_OUTPUT
Your getImageUri() method is poorly named, because it does more than get an Uri, it also saves the image to storage first (which is arguably the more important operation).
Look at the docs for MediaStore.Images.Media.insertImage(…):
Returns
The URL to the newly created image, or null if the image failed to be stored for any reason.
So that's (likely) the reason why you get a null path back and your code explodes.
There's nothing you can do to guarantee that saving the image always succeeds (e.g. the flash memory may be full), so you'll have to modify your code to recover from this error case, e.g. by telling the user that their image could not be saved.
I am having a problem while trying to save a photo to storage with an Android app. The app uses the devices camera to take a photo and save it as a PNG to the device.
For some reason no matter what I do or where I store the image the quality is very poor. The app is an existing project that is quite large so I was wondering if there are other factors to consider when saving images to a device or maybe another way of overriding the quality.
This is the function that was coded by the previous dev:
public String saveImageToDevice(Bitmap image) {
saveCanvasImage(image);
String root = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.app.android";
File myDir = new File(root + "/saved_images");
myDir.mkdirs();
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fname = "Image-"+ timeStamp +".png";
File file = new File (myDir, fname);
if (file.exists ()){
file.delete ();
}
try {
Toast.makeText(getActivity(), "Saving Image...", Toast.LENGTH_SHORT).show();
Log.i("Image saved", root+"/saved_images/"+fname);
FileOutputStream out = new FileOutputStream(file);
image.compress(CompressFormat.PNG, 100, out);
imageLocations.add(fname);
out.flush();
out.close();
//return myDir.getAbsolutePath() + "/" +fname;
return fname;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
And this is a function I have tried myself from an example online:
public void saveCanvasImage(Bitmap b) {
File f = new File(Environment.getExternalStorageDirectory().toString() + "/img.png");
try {
f.createNewFile(); // your mistake was at here
FileOutputStream fos = new FileOutputStream(f);
b.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
Both of these produce the same very poor images. I have posted a before and after segment below.
This is what the camera preview looks like.
This is the resulting image once it has saved.
After speaking to a few people i am including my camera intent code:
public void startCameraIntent(){
/*************************** Camera Intent Start ************************/
// Define the file-name to save photo taken by Camera activity
String fileName = "Camera_Example.png";
// Create parameters for Intent with filename
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
values.put(MediaStore.Images.Media.DESCRIPTION,"Image capture by camera");
// imageUri is the current activity attribute, define and save it for later usage
#SuppressWarnings("unused")
Uri imageUri = getActivity().getContentResolver().insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
/**** EXTERNAL_CONTENT_URI : style URI for the "primary" external storage volume. ****/
// Standard Intent action that can be sent to have the camera
// application capture an image and return it.
Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
//intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // set the image file name
startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
/*************************** Camera Intent End ************************/
}
As you can see the EXTRA_OUTPUT line is has been commented out due to it causing crashes with the below error:
12-17 13:31:37.339: E/AndroidRuntime(16123): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=65537, result=-1, data=null} to activity {}: java.lang.NullPointerException
I have also included my onActivityresult code too:
public void onActivityResult( int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
int page = mViewPager.getCurrentItem();
NotesPagerFragment note = pages.get(page);
Log.i("Request Code", ""+requestCode);
//For the ImageCapture Activity
if ( requestCode == 1) {
if ( resultCode != 0) {
/*********** Load Captured Image And Data Start ****************/
Bitmap bp = (Bitmap) data.getExtras().get("data");
//add the image to the note through a function call
note.addImage(bp);
note.saveImageToDevice(bp);
//String imageId = convertImageUriToFile( imageUri,CameraActivity);
// Create and excecute AsyncTask to load capture image
// new LoadImagesFromSDCard().execute(""+imageId);
/*********** Load Captured Image And Data End ****************/
} else if ( resultCode == 0) {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
}
}
//For the deleting an Image
if (requestCode == 2) {
String location = (String) data.getExtras().get("imageLocation");
if(data.getExtras().get("back") != null){
//just going back, don't mind me
}else {
//Toast.makeText(this.getActivity(), "BOO", Toast.LENGTH_SHORT).show();
note.removeNoteImageFromView(location);
database.removeSingleNoteImageFromSystemByLocation(location);
}
}
}
OK so after a lot of help from MelquiadesI have eventually solved this issue. The problem I had was that my intent and onActivityResult were retrieving the thumbnail of the image and scaling it up (hence the poor quality).
The line below is responsible for getting the thumbnail preview (120px x 160px):
Bitmap bp = (Bitmap) data.getExtras().get("data");
In order to access the full image I need to add EXTRA_OUTPUT to the intent which looks as follows:
public void startCameraIntent(){
/*************************** Camera Intent Start ************************/
File imageFile = new File(imageFilePath);
Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri
// Standard Intent action that can be sent to have the camera
// application capture an image and return it.
Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri); // set the image file name
startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
/*************************** Camera Intent End ************************/
}
I also declared my imageFilePath as a string at the top of my activity:
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFilePath = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.my.app/Image-"+timeStamp+".png";
I then had to change onActivityResult so it could access the full image to use:
public void onActivityResult( int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
int page = mViewPager.getCurrentItem();
NotesPagerFragment note = pages.get(page);
Log.i("Request Code", ""+requestCode);
//For the ImageCapture Activity
if ( requestCode == 1) {
if ( resultCode != 0) {
/*********** Load Captured Image And Data Start ****************/
// Decode it for real
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = false;
//imageFilePath image path which you pass with intent
Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
//rotate image by 90 degrees
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);
//add the image to the note through a function call
note.addImage(rotatedBitmap);
note.saveImageToDevice(rotatedBitmap);
//String imageId = convertImageUriToFile( imageUri,CameraActivity);
// Create and excecute AsyncTask to load capture image
// new LoadImagesFromSDCard().execute(""+imageId);
/*********** Load Captured Image And Data End ****************/
} else if ( resultCode == 0) {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this.getActivity(), " Picture was not taken ", Toast.LENGTH_SHORT).show();
}
}
//For the deleting an Image
if (requestCode == 2) {
String location = (String) data.getExtras().get("imageLocation");
if(data.getExtras().get("back") != null){
//just going back, don't mind me
}else {
//Toast.makeText(this.getActivity(), "BOO", Toast.LENGTH_SHORT).show();
note.removeNoteImageFromView(location);
database.removeSingleNoteImageFromSystemByLocation(location);
}
}
}
The key part here is:
// Decode it for real
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = false;
//imageFilePath image path which you pass with intent
Bitmap bp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);
This code decodes the image you saved at imageFilePath into a usable bitmap. From here you can use it as normal.
Sometimes (apparently this is quite common) the image comes in rotated by 90°, the next bit of code will rotate that back if you need it to:
//rotate image by 90 degrees
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), rotateMatrix, false);
I am launching the camera to capture a picture, which is stored in a new file in a specific folder, in the external storage.
The problem is that when I try to decode the image from the file using BitmapFactory.decodeFile() in my onActivityResult() method, the returned image is null. Is this because the file is not yet complete (i.e. the process of the camera has not finished to save the image)? How can I solve this problem?
Here is the code with which I am launching the camera:
private void launchCamera() {
//create folder
File imagesFolder = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
Consts.MEDIA_EXTERNAL_FOLDER);
if(!imagesFolder.exists())
imagesFolder.mkdirs();
String fileName = "pic_"+Consts.CAMERA_DATE_FORMAT.format(new Date());
File image = null;
try {
image = File.createTempFile(fileName, ".jpg", imagesFolder);
} catch(IOException e) {
Log.e(TAG, "Error creating new file.");
}
capturedImageURI = Uri.parse(image.getAbsolutePath());
//launch camera
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageURI);
startActivityForResult(intent, CAMERA_ACTION);
}
And this is when I get the image in the onActivityResult():
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CAMERA_ACTION:
getContentResolver().notifyChange(capturedImageURI, null);
File f = new File(capturedImageURI.toString());
decodedBitmap = Helper.decodeSampledBitmapFromResource(filePath);
ImageView imageView = new ImageView(this);
imageView.setImageBitmap(decodedBitmap);
break;
}
How can I solve this problem?
File, AFAIK, does not understand file:/// URL formats, which is what you will get from capturedImageURI.toString(). Rather than regenerating the File, use the one you already created.
This a rare case, i'm trying to capture an image from native camera activity on my samsung galaxy s3 and onActivityResult the file doesn't exist to read yet. If i disconnect the phone and connect again then the i can see the image on my explorer.
It likes that the camera activity writes the file with delay or something...
i have readed all questions and answers and other forums, but it is my problem; My code:
... onCreate
File file = new File( _path );
pathUri = Uri.fromFile( file );
...
protected void startCameraActivity()
{
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, pathUri);
startActivityForResult( intent, CAMERA_REQUEST_CODE );
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK)
{
// test if exits image
if((new File(_path)).exists())
... do something
}
... continue
if((new File(_path)).exists()) always retunrs FALSE, how is it possible?
Thans in advance
I have never seen this occur in my app. However, this could potentially be a workaround.
Note: Declare the Uri instance initialURI globally so you can use it throughout the Activity. You could also change the name to something that suits your naming convention.
In this, right before the Intent is triggered, I pass a specific path for the Image to be stored at along with the name for the File.
Intent getCameraImage = new Intent("android.media.action.IMAGE_CAPTURE");
File cameraFolder;
if (android.os.Environment.getExternalStorageState().equals
(android.os.Environment.MEDIA_MOUNTED))
cameraFolder = new File(android.os.Environment.getExternalStorageDirectory(),
"SOME_FOLDER_NAME/");
else
cameraFolder= StatusUpdate.this.getCacheDir();
if(!cameraFolder.exists())
cameraFolder.mkdirs();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
String timeStamp = dateFormat.format(new Date());
String imageFileName = "picture_" + timeStamp + ".jpg";
File photo = new File(Environment.getExternalStorageDirectory(),
"SOME_FOLDER_NAME/" + imageFileName);
getCameraImage.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
initialURI = Uri.fromFile(photo);
startActivityForResult(getCameraImage, ACTION_REQUEST_CAMERA);
And finally, in the onActivityResult():
Note: This I'm guessing should work. My application uses the Aviary SDK and the code for that differs vastly from the conventional work done in this method.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK) {
// USE EITHER THIS
imgView.setImageURI(initialURI);
// OR USE THIS
getContentResolver().notifyChange(initialURI, null);
ContentResolver cr = getContentResolver();
try {
// SET THE IMAGE FROM THE CAMERA TO THE IMAGEVIEW
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, initialURI);
// SET THE IMAGE USING THE BITMAP
imgvwSelectedImage.setImageBitmap(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
}
If you do not need the the Image stored on the SD-Card, you could delete it once you are done with it. This I am guessing (guessing because I have never experienced what the OP is facing problem with) this should do it for you.
Oh. Almost forgot. You will need to declare this permission in your Manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I've got a problem in saving a picture in a full size after capturing it using ACTION_IMAGE_CAPTURE intent the picture become very small , its resolution is 27X44 I'm using 1.5 android emulator, this is the code and I will appreciate any help:
myImageButton02.setOnClickListener
(
new OnClickListener()
{
#Override
public void onClick(View v)
{
// create camera intent
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//Grant permission to the camera activity to write the photo.
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
//saving if there is EXTRA_OUTPUT
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File
(Environment.getExternalStorageDirectory(), "testExtra" + String.valueOf
(System.currentTimeMillis()) + ".jpg")));
// start the camera intent and return the image
startActivityForResult(intent,1);
}
}
);
#Override
protected void onActivityResult (int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// if Activity was canceled, display a Toast message
if (resultCode == RESULT_CANCELED)
{
Toast toast = Toast.makeText(this,"camera cancelled", 10000);
toast.show();
return;
}
// lets check if we are really dealing with a picture
if (requestCode == 1 && resultCode == RESULT_OK)
{
String timestamp = Long.toString(System.currentTimeMillis());
// get the picture
Bitmap mPicture = (Bitmap) data.getExtras().get("data");
// save image to gallery
MediaStore.Images.Media.insertImage(getContentResolver(), mPicture, timestamp, timestamp);
}
}
}
Look at what you are doing:
you specify a path where your just taken picture is stored with intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File (Environment.getExternalStorageDirectory(), "testExtra" + String.valueOf (System.currentTimeMillis()) + ".jpg")));
when you access the picture you 'drag' the data out of the intent with Bitmap mPicture = (Bitmap) data.getExtras().get("data");
Obviously, you don't access the picture from its file. As far as I know Intents are not designed to carry a large amount of data since they are passed between e.g. Activities. What you should do is open the picture from the file created by the camera intent. Looks like that:
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
// Limit the filesize since 5MP pictures will kill you RAM
bitmapOptions.inSampleSize = 6;
imgBitmap = BitmapFactory.decodeFile(pathToPicture, bitmapOptions);
That should do the trick. It used to work for me this way but I am experiencing problems since 2.1 on several devices. Works (still) fine on Nexus One.
Take a look at MediaStore.ACTION_IMAGE_CAPTURE.
Hope this helps.
Regards,
Steff