In the android app that I am making a user takes a photo which I want to display him later in few activities. I've come up to "out of memory error" while displaying currently taken photo in an image view, so I decided to use code from http://developer.android.com/training/displaying-bitmaps/load-bitmap.html to do it efficiently. Here are methods that I'm using:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
and
public static Bitmap decodeSampledBitmap(Uri mUri, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mUri.getPath(), options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(mUri.getPath, options);
};
I let the user take photo by the method:
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent(){
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(takePictureIntent.resolveActivity(getPackageManager()) != null){
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
And then receive taken picture info:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK){
Uri imageUri = null;
if(data != null){
imageUri = data.getData();
}
ImageView imageView = (ImageView)findViewById(R.id.new_photo);
imageView.setImageBitmap(decodeSampledBitmap(imageUri, imageView.getWidth(), imageView.getHeight()));
}
}
My app breaks and I get info: "File not found or no such directory".
I checked what does the imageUri.getPath() give and in my case its:
"/external/images/media/1777" (which seems quite strange to me because I'm not using SD card)
and the taken photo is actually saved in "/storage/emulated/0/DCIM/100ANDRO/DSC_0052.JPG". Do you have any ideas what am I doing wrong?
Intent Extra Max limit is 1MB approx till gingerbread..
I found a magic number 86389 in JellyBean if you send above this it will throw memory out of exception..
Solution : Pass Image Uri, dont pass complete bitmap object
Use following code just before startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());
Where getImageUri() is
private Uri getImageUri() {
// Store image in dcim
File myDir = new File(Environment.getExternalStorageDirectory()
+ "/My_App");
if(!myDir.exists())
myDir.mkdir();
File file = new File(myDir, "MyImage.png");
Uri imgUri = Uri.fromFile(file);
return imgUri;
}
Read up Android official docs regarding this for further clarification.
Related
I am trying to show the picture taken by the camera and sometimes it works but it usually gives me the error:
java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:727)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:703)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:741)
at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:847)
at com.dima.polimi.rentall.NewProduct.onActivityResult(NewProduct.java:207)
at android.app.Activity.dispatchActivityResult(Activity.java:5773)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3710)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3757)
at android.app.ActivityThread.access$1400(ActivityThread.java:170)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5635)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
at dalvik.system.NativeStart.main(Native Method)
I have tried the solutions from multiple questions but i never make it to work
This is my code:
mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dispatchTakePictureIntent();
}
});
dispatchTakePictureIntent
String mCurrentPhotoPath;
private void dispatchTakePictureIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
Log.i("", "IOException");
}
// Continue only if the File was successfully created
if (photoFile != null) {
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(cameraIntent, REQUEST_TAKE_PHOTO);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
try {
Bitmap mImageBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), Uri.parse(mCurrentPhotoPath));
mImageView.setImageBitmap(mImageBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Finally I got it to work, the solution is using bitmap like this:
Bitmap b = BitmapUtility.decodeSampledBitmapFromResource(image.getAbsolutePath(), 540, 360);
BitmapUtility:
public class BitmapUtility {
public static Bitmap decodeSampledBitmapFromResource(String path, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path,options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
} }
I have an android app in which I give the possibility to whether take a photo or choose it from library. The problem is that taking a photo with the camera works pretty well, however, when I select a photo from the library the app bugs. After checking the size of the photos I find that the size of the selected photos (thumbnails) is very very big that's why the application slows and crashes after a while when I try to store the photo in my database. For example, the size of a photo taken with camera in my app is 129600 bytes, but when I try a second time to load this same photo from library into my app I find that its size is now 8294400 (much bigger) !! which is pretty bizarre !
I am wondering if my way of handling the case of photo selection (case when requestCode == 2) is correct, and if there is an error in my code ?
Here is my full code:
private void selectImage() {
final CharSequence[] options = { "Take Photo", "Choose from Gallery","Cancel" };
AlertDialog.Builder builder = new AlertDialog.Builder(ScrollingActivity.this);
builder.setTitle("Add Photo!");
builder.setItems(options, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int item) {
if (options[item].equals("Take Photo"))
{
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
}
else if (options[item].equals("Choose from Gallery"))
{
Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 2);
}
else if (options[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == 1) {
thumbnail = (Bitmap) data.getExtras().get("data");
System.out.println("Image Byte Count: " + thumbnail.getByteCount()); // prints 129600 Bytes.
} else if (requestCode == 2) {
Uri selectedImage = data.getData();
String[] filePath = { MediaStore.Images.Media.DATA };
Cursor c = getContentResolver().query(selectedImage,filePath, null, null, null);
c.moveToFirst();
int columnIndex = c.getColumnIndex(filePath[0]);
String picturePath = c.getString(columnIndex);
c.close();
thumbnail = (BitmapFactory.decodeFile(picturePath));
System.out.println("Image Byte Count: " + thumbnail.getByteCount()); // prints 8294400 bytes!!!
}
renderImage();
}
}
Thank you in advance for your help !
I faced the same problem last week and discovered on this forum that there is an option to check the image size without loading it into memory. Have a look at BitmapFactory.options The code below is cut from Stackoverflow.
Resources res = mContext.getResources();
int allowedwidth= res.getDimensionPixelSize(R.dimen.albumart_image_width);
int allowedheight= res.getDimensionPixelSize(R.dimen.albumart_image_height);
holder.improfile.setImageBitmap(
decodeSampledBitmapFromFile(circlepicture, allowedwidth, allowedheight));
} catch (Exception e) {
e.printStackTrace();
}
public static Bitmap decodeSampledBitmapFromFile(String circlepicture,int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(circlepicture, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(circlepicture, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
What i'm doing/trying to do, is.
1. Take a photo
2. Save it
3. Load/display it into a Bitmap
Opening the Built in camera application:
public void openCamera() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory()+ File.separator + "image.jpg");
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
onActivityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data){
//Check that request code matches ours:
if (requestCode == REQUEST_IMAGE_CAPTURE){
//Get our saved file into a bitmap object:
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "image.jpg");
Bitmap image = decodeSampledBitmapFromFile(file.getAbsolutePath(), 1000, 700);
}
}
decodeSamoleBitmapFromFile:
public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight)
{ // BEST QUALITY MATCH
//First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize, Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
options.inPreferredConfig = Bitmap.Config.RGB_565;
int inSampleSize = 1;
if (height > reqHeight)
{
inSampleSize = Math.round((float)height / (float)reqHeight);
}
int expectedWidth = width / inSampleSize;
if (expectedWidth > reqWidth)
{
//if(Math.round((float)width / (float)reqWidth) > inSampleSize) // If bigger SampSize..
inSampleSize = Math.round((float)width / (float)reqWidth);
}
options.inSampleSize = inSampleSize;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
I was hoping for it to load it into a bitmap. If anyone could point me in the right direction that would be very helpful!
In order to display a Bitmap, you'll have to use an ImageView. Once you have both the bitmap and the reference to your ImageView, call ImageView.setImageBitmap(Bitmap) to display your bitmap.
I'm using code the from the examples here.
My issue is that sometimes the image doesn't load into the ImageView. I've just noticed this behavior recently. I've found that if I debug through the code it works 100% of the time.
My assumption is that the image file sometimes doesn't get created in time to be usable in the onActivityResult. Has anyone run into this issue? Suggestions on how to compensate?
May be it is mobile processing speed issue! can't tell exactly but i Tried it in this way, and it work like charm always!
public class LaunchCamera extends Activity {
ImageView imVCature_pic;
Button btnCapture;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch_camera);
initializeControls();
}
private void initializeControls() {
imVCature_pic=(ImageView)findViewById(R.id.imVCature_pic);
btnCapture=(Button)findViewById(R.id.btnCapture);
btnCapture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
/* create an instance of intent
* pass action android.media.action.IMAGE_CAPTURE
* as argument to launch camera
*/
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
/*create instance of File with name img.jpg*/
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "img.jpg");
/*put uri as extra in intent object*/
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
/*start activity for result pass intent as argument and request code */
startActivityForResult(intent, 1);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//if request code is same we pass as argument in startActivityForResult
if(requestCode==1){
//create instance of File with same name we created before to get image from storage
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "img.jpg");
//get bitmap from path with size of
imVCature_pic.setImageBitmap(decodeSampledBitmapFromFile(file.getAbsolutePath(), 600, 450));
}
}
public static Bitmap decodeSampledBitmapFromFile(String path,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
//Query bitmap without allocating memory
options.inJustDecodeBounds = true;
//decode file from path
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
//decode according to configuration or according best match
options.inPreferredConfig = Bitmap.Config.RGB_565;
int inSampleSize = 1;
if (height > reqHeight) {
inSampleSize = Math.round((float)height / (float)reqHeight);
}
int expectedWidth = width / inSampleSize;
if (expectedWidth > reqWidth) {
//if(Math.round((float)width / (float)reqWidth) > inSampleSize) // If bigger SampSize..
inSampleSize = Math.round((float)width / (float)reqWidth);
}
//if value is greater than 1,sub sample the original image
options.inSampleSize = inSampleSize;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
}
I have taken reference from this and this.
I'm trying to capture an image, but after capturing and approving, onActivityResult(int requestCode, int resultCode, Intent data) the data is always null .
This is how I call the camera:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());
startActivityForResult(intent, Consts.ACTION_JOURNEY_CAPTURE_PHOTO_PATH);
Method getImageUri():
private Uri getImageUri() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp + "_";
File albumF = helpers.getAlbumDir(getString(R.string.album_name));
File file = new File(albumF, imageFileName);
Uri imgUri = Uri.fromFile(file);
return imgUri;
}
On manifest I have :
<uses-feature android:name="android.hardware.camera" />
What am I doing wrong?
The image is stored at the path that you get with the method getImageUri(). You must keep that path and inside onActivityResult() do the following:
if (resultCode == RESULT_OK) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoPath, options);
Bitmap b = BitmapFactory.decodeFile(photoPath, options);
}
If you want to resize the image, you can set the inSampleSize of your BitmapFactory.Options, this method will be useful to calculate the inSampleSize:
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}