I need to get the width and height of a bitmap but using this gives an out of memory exception:
Resources res=getResources();
Bitmap mBitmap = BitmapFactory.decodeResource(res, R.drawable.pic);
BitmapDrawable bDrawable = new BitmapDrawable(res, mBitmap);
//get the size of the image and the screen
int bitmapWidth = bDrawable.getIntrinsicWidth();
int bitmapHeight = bDrawable.getIntrinsicHeight();
I read the solution at the question Get bitmap width and height without loading to memory but what would be the inputStream here?
You need to specify some BitmapFactory.Options as well:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
bDrawable will not contain any bitmap byte array. Taken from here: Setting the inJustDecodeBounds property to true while decoding avoids memory allocation, returning null for the bitmap object but setting outWidth, outHeight and outMimeType. This technique allows you to read the dimensions and type of the image data prior to construction (and memory allocation) of the bitmap.
Use this
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
see http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Related
I want resize image without loosing quality and aspect ratio and use this code :
String filePath = "/sdcard/download/0.jpg";
BitmapFactory.Options Options = new BitmapFactory.Options();
Options.inSampleSize = 4;
Options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(filePath, Options);
int newWidht = 600;
int originalWidth = Options.outWidth;
int originalHeight = Options.outHeight;
float AspectRatio = (float)originalWidth / originalHeight;
float tempnewHeight = newWidht/ AspectRatio;
int newHeight = (int)tempnewHeight;
Bitmap resized = Bitmap.createScaledBitmap(bmp, newWidth, newHeight, false);
ContextWrapper cw = new ContextWrapper(getApplicationContext());
File mypath=new File("/sdcard/download/","1.jpg");
FileOutputStream fos = null;
fos = new FileOutputStream(mypath);
resized.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
But this method reduce quality or cant good work for deference resolution and My saved pic is very bad and hatch.
i see some post about this and cant find solution.
I think Bitmap.createScaledBitmap() reduce quality
Please help me
thankyou
best quality and smaller size.
this line is answer
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Steps my application performs:-
Download a large no of images and save them on the SDCard.
Load every image into Bitmap and resize them, after resizing replace this resized image with the original one.
My code:-
Bitmap myimage = loadimage(path+temppos+".jpg");
Bitmap finalimage = getResizedBitmap(myimage,width,height);
//save image
.....
//recyclebitmap
myimage.recycle();
finalimage.recycle();
loadimage:-
public Bitmap loadimage(String path)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inDither=true;
options.inPurgeable=true;
options.inInputShareable=true;
return BitmapFactory.decodeFile(path, options);
}
Now I' populating these images on gridview.
Output(Before):-
Output (After):-
Where Before corresponds to initially when only a few images are downloaded.
And After corresponds to after all the images are downloaded.
Now, I think it is happening maybe because of Bitmap.recycle() method but don't know the reason. Please correct me if I am wrong and point out the error here.
Edit: I must add the grid view shows around 50 downloaded images, but only the first three images are becoming unrecognizable.
Thanks.
For getting your resized Bitmap you can use the below code: (taken from this tutorial)
public static Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
return bmp;
}
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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
You can also take a look at the official site for getting a hint on loading Bitmaps
Edit
Try to change bitmap configuration to ARGB_8888 for best quality
because RGB_565 configuration can produce slight visual artifacts depending on the configuration of the source (taken from docs)
Update
I think you can take a look at this answer , I think this would solve your problem
I'm trying to get the width and height of an image, which I load from an image I pick from the gallery.
For testing, I used images from the drawable folder, I used this code:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
Now I got a bitmap that doesn't come from my drawable folder I can't do this:
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
What would be the proper way to retrieve the w/h.
There is a similar method working with an InputStream: BitmapFactory.decodeStream.
Assuming you have a File with your image (exceptions ommitted) :
BitmapFactory.decodeStream(new FileInputStream(myImageFile), null, options);
(this method works for any InputStream)
I'm facing a crash every time with a Galaxy S5 when trying to show a background image.
This background is located in xxhdpi resource folder, the size is the same as the S5 screen (1080x1920) so I don't need to call "createScaledBitmap" for scaling it. The resolution of this image is JPG 96dpi.
And when calling decodeResource... crash!!! How is this possible? Is the only bitmap I'm loading in this "super-powerful" device.
Thanks!!!
Below my code (scale = 1 for S5):
public static Bitmap decodeBitmapFromResource(Resources res, int resId, float scale) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options,
(int)(options.outWidth*scale),
(int)(options.outHeight*scale));
options.inJustDecodeBounds = false;
if (scale > 1) {
Bitmap bitmap = BitmapFactory.decodeResource(res, resId);
return Bitmap.createScaledBitmap(bitmap, (int)(options.outWidth*scale),
(int)(options.outHeight*scale), true);
}
return BitmapFactory.decodeResource(res, resId, options);
}
i too faced this problem many times...
try using this code..
private Bitmap decodeFile(File f) throws IOException {
Bitmap b = null;
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
o.inDither = false; // Disable Dithering mode
o.inPurgeable = true; // Tell to gc that whether it needs free memory,
// the Bitmap can be cleared
o.inInputShareable = true;
FileInputStream fis = new FileInputStream(f);
BitmapFactory.decodeStream(fis, null, o);
fis.close();
int scale = 1;
if (o.outHeight > metrics.heightPixels
|| o.outWidth > metrics.widthPixels) {
scale = (int) Math.pow(
2,
(int) Math.ceil(Math.log(metrics.heightPixels
/ (double) Math.max(o.outHeight, o.outWidth))
/ Math.log(0.5)));
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
fis = new FileInputStream(f);
b = BitmapFactory.decodeStream(fis, null, o2);
fis.close();
return b;
}
and take care of few things like make every bitmap null after its use etc.
try this
public static Bitmap decodeBitmapFromResource(String pathName, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
// return BitmapFactory.decodeResource(res, resId, options);
return BitmapFactory.decodeFile(pathName, 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) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
Add this line in your Manifest file in the application tag. It doesn't solve the problem just allows your app to have more memory:
android:largeHeap="true"
UPDATE:
However using largeHeap is not a good solution. here is the google's doc about this.
However, the ability to request a large heap is intended only for a
small set of apps that can justify the need to consume more RAM (such
as a large photo editing app). Never request a large heap simply
because you've run out of memory and you need a quick fix—you should
use it only when you know exactly where all your memory is being
allocated and why it must be retained. Yet, even when you're confident
your app can justify the large heap, you should avoid requesting it to
whatever extent possible. Using the extra memory will increasingly be
to the detriment of the overall user experience because garbage
collection will take longer and system performance may be slower when
task switching or performing other common operations.
And about loading bitmaps:
When you load a bitmap, keep it in RAM only at the resolution you need
for the current device's screen, scaling it down if the original
bitmap is a higher resolution. Keep in mind that an increase in bitmap
resolution results in a corresponding (increase2) in memory needed,
because both the X and Y dimensions increase.
It's not bad to take a look at this page, it explains ways of managing memory:
How Your App Should Manage Memory
So I think my last answer is not a good solution and You might rethink your strategy in loading images. Hope this answer helps you ;)
How to scale bitmaps at runtime to a very small size and then storing them in internal storage? how to call the scaled bitmaps into the program from the storage at runtime and if its not there, call it from drawable folder, scale it, write it to storage and then bind it to the view.
If you want to scale the bitmap you could use Bitmap.createScaledBitmap
To scale an arbitrary bitmap to 32x32 you could do it as follows:
Bitmap smallBitmap = Bitmap.createScaledBitmap( fullSizeBitmap, 32, 32, true );
You can use BitmapFactory.Options class to crop image to any size.
You can use following:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = 8; // 1/8th of actual image.
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Here, when you use a Bitmap, always call its bmp.recycle() method, since GC can't clear the memory held by Bitmap, if your bitmap is not getting garbage collected, then also you get the OME.