Rescaling a image with Android tutorial method - android

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);
}

Related

Getting Full sized image from camera, Memory Issue

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);
}

Image Processing (need pixel value of an image)

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.

Bitmap memory managemant Android

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..

Android - Does an ImageView resizes the image (and doesn't save the original)?

Quite a simple questions, can't find an answer..
I'm asking in order to know if even though the ImageView shows a smaller version of the original image - does it still use the full memory size of the original .. ?
(I refer to an image which was loaded from the SD-card and not from resources)
Yes, it will use the original size. You have to resize all your bitmaps before assign then to an ImageView, otherwise you will have a lot of problems with Out Of Memory Error.
You should also calculate the final size of you ImageView and resize the Bitmap.
Some code to get you going.
private static Bitmap createBitmap(#NonNull String filePath, int width )
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath , options );
// Getting original image properties
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
int scale = -1;
if ( imageWidth < imageHeight ) {
scale = Math.round( imageHeight / width );
} else {
scale = Math.round(imageWidth / width);
}
if ( scale <= 0 )
scale = 1;
options.inSampleSize = scale;
options.inJustDecodeBounds = false;
// Create a resized bitmap
Bitmap scaledBitmap = BitmapFactory.decodeFile(filePath , options);
return scaledBitmap;
}
You should also consider:
Maintain all Bitmap operations outside the main Thread.
Handle Concurrency correctly
Make use of some open source lib, like this one

java.lang.OutOfMemoryError for small images

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.

Categories

Resources