I am using this line of code for getting the full sized image, i am not setting this image on any view, still this line when executed takes a lot of ram, around 110-120m, any solutions ? I even tried running this code in Backgroung thread using Async Task. The picture resolution is 4008*5344.
Bitmap image = MediaStore.Images.Media.getBitmap(getContentResolver(),Uri.parse(mCurrentPhotoPath));
And the below method given in developers site, gives me Null bitmap.
private void setPic() {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
}
Related
I want to make an app, in which I want to take a picture and input x,y axis it will show me corresponding point pixel value from the captured picture .
I don't have any knowledge about image processing well . So, how can I do it ? help me .
The way I have done this in the past is by writing the image to the filesystem and then decoding it. Admittedly its a little inefficient but it's functional.
This requires a number of steps. I suggest you read over this documentation. It describes the process of taking an image and saving it to the file system which you will need to do before you can do the rest of these steps.
Next you will need to use BitmapFactory to decode the image which will give you an instance of Bitmap which you can do all sorts of things with (documented here). In this example I return the Color object for the pixel located at (50, 50) using getPixel(). This example assumes that the path the the image is mCurrentPhotoPath but should be wherever you saved the image.
private Color getColor() {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
return bitmap.getPixel(50, 50);
}
You can get RGB values from this Color object which is what I think you are wanting to do. That can be found under the Color object documentation on Android Developers as well.
About my app: Taking photos, saving them to the phone memory, using BitmapFactory.decodeFile, loading that bitmap into one fixed size, not changing, image view.
Now, i know this was asked a hundred times already. I've been all over google\android's manage memory guide , but for my task it's kind of an overkill to manage and recycle different bitmaps, since i'm only using one.
Here's my code so far:
..
Bitmap bm_thumb = null;
..
private void setPic() {
/* There isn't enough memory to open up more than a couple camera photos */
/* So pre-scale the target bitmap into which the file is decoded */
/* Get the size of the ImageView */
int targetW = imv_thumb.getWidth();
int targetH = imv_thumb.getHeight();
/* Get the size of the image */
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(PhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
bmOptions.inSampleSize = 1;
/* Figure out which way needs to be reduced less */
int scaleFactor = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW/targetW, photoH/targetH);
}
/* Set bitmap options to scale the image decode target */
bmOptions.inSampleSize = scaleFactor; //was after decode bounds
bmOptions.inJustDecodeBounds = false;
/* Decode the JPEG file into a Bitmap */
bm_thumb = BitmapFactory.decodeFile(PhotoPath, bmOptions);
/* Associate the Bitmap to the ImageView */
imv_thumb.setImageBitmap(bm_thumb);
imv_thumb.setVisibility(View.VISIBLE);
}
These lines are not in the code, as they currently confuse me.
BitmapFactory.decodeFile(PhotoPath, bmOptions);
mCurrentBitmap = Bitmap.createBitmap(bmOptions.outWidth, bmOptions.outHeight, Bitmap.Config.ARGB_8888)
bmOptions.inBitmap = bm_thumb;
Do I need to run decodeFile everytime I change my bitMapOptions?
Plus, If the decodeFile methods returns a bitMap, why do i need to also create one?
who am i supposed to give to inBitmap? i've tried both options, non seem to solve my OOM error.
My OOM started quite a long time after first installing and testing my app. My question is, how do I know I have solved the issue? If written correctly, will it fix its error, or do I need to select "clear cache" on the phone, and hope it will never happen again?
Sorry for the long post, I was really trying to remain focused..
When i capture photo in portrait mode, it is landscaped and I use this function to rotate image
private Bitmap rotateImage(String mCurrentPhotoPath, String rotationAngle){
//Set hardCode size imageView 300dp
int targetW = CommonUtils.ConvertDpTPpx(mContext, 300);
int targetH = CommonUtils.ConvertDpTPpx(mContext, 300);
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
Matrix matrix = new Matrix();
matrix.setRotate(Float.parseFloat(rotationAngle), (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2);
return Bitmap.createBitmap(bitmap, 0, 0, photoW/2, photoH/2, matrix, true);
}
When I build on device on S4, it runs right, but when it run on Sony Docomo (SO-04E) and LG LTE2, after capture photo and app crash. A bug is x + width (image) < bitmap.width. And then i edit photoW/4 and photoH/4 so Sony and LG run right but S4 image is cropped. So, at the return line, how i should fix the width and height to run right on all device.
In app I'm working on you can choose between multiple backgrounds and every time when I select background for layout I'm setting it with
relativeLayout.setBackground(getResources().getDrawable(R.drawable.background));
Each of the backgrounds have resolution of 1440x2560 pixels, but they only have around 12 KB each and bit depth 4.
Problem is that sometimes when I select background app crashes with error java.lang.OutOfMemoryError.
Why is this happening and how to fix it?
Problem is quite simple. You need to recycle the bitmap everytime you change it by clicking the button, or else it will stay in memory and eventually throw the out of memory exception.
Anyways, if you want to fix this, keep a reference to your bitmap on your activity.
private Bitmap currentBitmap;
public void changeBitmap(Bitmap bitmap){
relativeLayout.setBackgroundImage(bitmap);
if(currentBitmap != null){
/*this is where the magic happens, you
recycle your old bitmap whose reference you had stored in the global
variable*/
currentBitmap.recycle();
}
currentBitmap = bitmap;
}
Resize the image before loading
public Bitmap resizeBitmap(int targetW, int targetH) {
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
int scaleFactor = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW/targetW, photoH/targetH);
}
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
return BitmapFactory.decodeFile(photoPath, bmOptions);
}
The quckfix is android:largeHeap="true" in the AndroidManifest in <application>
But I think it needs a lot of RAM to show the Drawable on the Screen. The Dirty Fix is, when you call the garbage collector programmatically.
I am still searching for the clean fix.
I am using this tutorial as a guideline for adding a functionality to my app:
http://developer.android.com/training/camera/photobasics.html
The example coming with the tutorial is incomplete containing some "mistakes". I put the word mistakes in quotes because the main tutorial's purpouse is covered: work with the camera.
I am focusing on obtain a thumbnail photo from the big one taken. When you run the example you rapidly notice that most of the time the thumbnail for the big photo is not displayed although it is correctly stored in the denoted dir.
Doing a bit of work I discovered the following "mistakes":
1.- The image's path value is frequently lost because the activity is destroyed due to a lack of memory. I fixed that storing the path to the photo in the method onSaveInstanceState().
This way I was always able to access my image but it still did not appear. I continued making some tests and discovered:
2.- Most of the times, when asking for the imageview's measures (width and high) for rescaling the image the values were 0. I thought this could be the problem and found it was caused because you cannot obtain the measures until the view was drawn. So I fixed that with a handler and sending a delayed message (1.5'') to be executed. Now, the measures are always obtained correctly but even though the thumbnail is not displayed most of the times
So I thought the Bitmap.decodeFile method was returning a null value dispite all the variables were setting correctly. But it is not, it is returning a bitmap. So guys and girls, I recognize I am not able to find why the thumbnail is not displayed.
A bit of help would be very appreciated. Thanks!
This is the method for rescaling the image:
//Scaling the real size photo to the image view size
private void setImagenPequena()
{
Log.w("PAth: ", n_path_foto_actual);
// Get the dimensions of the View
int targetW = n_iv_foto.getMeasuredWidth();
int targetH = n_iv_foto.getMeasuredHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(n_path_foto_actual, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
Log.w("setImagenPequena: ", "photoW: " + Integer.toString(photoW));
Log.w("setImagenPequena: ", "photoH: " + Integer.toString(photoH));
Log.w("setImagenPequena: ", "targetW: " + Integer.toString(targetW));
Log.w("setImagenPequena: ", "targetH: " + Integer.toString(targetW));
if(targetW > 0 && targetH > 0)
{
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
bmOptions.inSampleSize = scaleFactor;
}
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(n_path_foto_actual, bmOptions);
if(bitmap == null)
Log.w("valor bitmap: ", "null");
else
Log.w("valor bitmap: ", "!=null");
n_iv_foto.setImageBitmap(bitmap);
}
I have got many issues as well with this tutorial, but I finally fixed it.
what I did :
Change
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
by
int scaleFactor = Math.max(photoW/targetW, photoH/targetH);
was the key thing. Before that i got blank image instead of the picture.
I put a default picture in my view. It may not be an all-around answer but I thought it gives a better user experience anyway.
You can use http://blog-emildesign.rhcloud.com/?p=590 to get a working decodeSampledBitmapFromFile example.
Otherwise use some of my code here :
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
mWidth = size.x;
mHeight = size.y;
...
private void setPic() {
int targetW = mWidth;
int targetH = mHeight;
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.max(photoW/targetW, photoH/targetH);
bmOptions.inPreferredConfig = Bitmap.Config.RGB_565;
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath,
bmOptions);
mImageView.setImageBitmap(bitmap);
}