OutOfMemory Exception when decoding bitmap [duplicate] - java

This question already has answers here:
OutOfMemory exception when loading bitmap from external storage
(12 answers)
Closed 8 years ago.
My app uses images from the web to set wallpapers. However, when I try to use decodeStream using the BitmapFactory, some users on slower phones get an OutOfMemory exception. This image is never displayed on the app, it is just loaded, and then set as a wallpaper. I've searched online, but I've been unable to find any resources which help solve the problem.
Code:
public void setWallpaperMethod() {
InputStream in = null;
try {
in = new java.net.URL(urldisplay).openStream();
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
final Bitmap bitmap = BitmapFactory.decodeStream(in);
myWallpaperManager = WallpaperManager
.getInstance(getApplicationContext());
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
myWallpaperManager.setBitmap(bitmap);
Toast.makeText(MainActivity.this,
"Teamwork! Wallpaper set.", Toast.LENGTH_LONG)
.show();
} catch (IOException e) {
Toast.makeText(
MainActivity.this,
"Damnit, clickers! Wallpaper wasn't set. Try killing and restarting the app?",
Toast.LENGTH_LONG).show();
}
}
});
}
The variable urldisplay is a string, equal to a URL (e.g., an imgur image). Also, the method is run in a thread, so there's no risk of the UI thread locking up.
So does anyone know how to solve this OutOfMemory Exception? All help appreciated.

Currently, you are opening an input stream, reading it, decoding a full fledge bitmap, then passing it to the manager, which will convert it to png and store it for later use.
Instead, you can open the input stream, pass it to the manager, which is now in charge of simply storing it for later use.
As you can see, that's one decoding and one encoding less.
Then, the wallpaper manager will be in charge of displaying the image, handling the image size accordingly.
myWallpaperManager = WallpaperManager
.getInstance(getApplicationContext());
myWallpaperManager.setStream(in);
voila !
(That is assuming the wallpaper manager properly handles oversized images, but that is very likely the case)

look at this link..
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Android Documentation suggest that you downsample the image.. using this method to calculate the sample size:
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;
}
then you would do something like this:
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);

Related

Java Android glide resize image [duplicate]

This question already has answers here:
Resize images with Glide in a ImageView Android
(6 answers)
Closed 4 years ago.
I want to resize image use by glide . Now I use a picasso but I want to use a glide
private void resizeImg(Context context, final File file, int targetSize, Handler handler) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getPath(), options);
float ratio = Math.max(options.outWidth, options.outHeight) / (float) targetSize;
//don't scale image that is smaller than targetSize
if (ratio < 1) return;
int dstWidth = (int) (options.outWidth / ratio);
int dstHeight = (int) (options.outHeight / ratio);
PicassoTargetFactory.getInstance().putTarget(file, handler);
Picasso.with(context)
.load(file)
.error(R.drawable.ic_delete)
.resize(dstWidth, dstHeight)
.into(PicassoTargetFactory.getInstance().getTarget(file));
ArrayList<String> paths = new ArrayList<>();
files = new ArrayList<>();
files.add(mCurrentPhotoPath);
for (File f : files) {
paths.add(f.getAbsolutePath());
}
mdb.insertPhotos(paths);
}
How I can do this ? On piccaso sometimes I have a cut image
first, add Glide lib in Gradle. Then, u can use it like this
Glide
.with(context)
.load("your image path")
.override(600, 200) // resizes the image to these dimensions (in pixel). resize does not respect aspect ratio
.into(imageViewResize);
Override must be accessed via RequestOptions in the most recent version of Glide.
Glide
.with(context)
.load(path)
.apply(new RequestOptions().override(600, 200))
.into(imageViewResizeCenterCrop);
You can create RequestOptions class object & pass it on apply() method in Glide.
Use like,
Glide.with(context)
.load(url)
.apply(new RequestOptions().override(Your image size here))
.into(imageView);
More From here
I think you should give your methods a single responsibility. You want a method that resizes an image but yours actually does more. Please separate things
private Bitmap resizeBitmap(Bitmap b, int w, int h) {
// Your code.
return myResizedBitmap;
}
Then it will be easier to help you
private String getImgCachePath(String url) {
FutureTarget<File> futureTarget = Glide.with(getBaseContext()).load(url).downloadOnly(100, 100);
try {
File file = futureTarget.get();
String path = file.getAbsolutePath();
return path;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
100,100 is width and height of image you want to save, change it as per your need. path is the path of cached image of given resolution of image url.

SetImageUri showing no Image

I want to let a image on my phone to show up in the Imageview. But in the ANdroid Studio emulator it is working but not on my own phone.
String imgPath = getIntent().getExtras().getString("imgPath");
System.out.println(imgPath);
if(!imgPath.equals("?"))
{
File img_file = new File(imgPath);
ImageView imgView = findViewById(R.id.show_image_war);
imgView.setImageURI(Uri.fromFile(img_file));
}
The path is /storage/emulated/0/imagesWarranty/img_MyWarranty_ID1.jpg . Both on the image in my phone and the path in my code where I get the image.
It might be issue of resolution. Even I was getting error of resolution while I was displaying image from uri.
I used below code and It worked for me :
Uri imageUri = Uri.parse(imagePath);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(new File(imageUri.getPath()).getAbsolutePath(), options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
if (imageHeight > 4096 || imageWidth > 4096) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(imageUri.toString(), opts);
viewHolder.imgAvatarLogoList3.setImageBitmap(bitmap);
} else {
Picasso.with(context)
.load(new File(imageUri.getPath())) // Uri of the picture
.into(viewHolder.imgAvatarLogoList3);
}
Addition to this answer [https://stackoverflow.com/a/48354307/9255006]
In that rotation bug define the image orientation for the image using ExifInterface.
Here is the code
private void SetOrientation(){
try {
ExifInterface exif=new ExifInterface(photoURI.getPath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_UNDEFINED);
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) { orientationInDegrees=90; }
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) { orientationInDegrees=180; }
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) { orientationInDegrees=270; }
else { orientationInDegrees=0; }
Toast.makeText(this, String.valueOf(orientationInDegrees), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
You can then set this orientation to your image.
This happens when the image has a very high resolution that the system needs some additional milliseconds to display, and since this happens in the UI thread onDraw() of the image view will draw it as an empty.
The easiest way I found for this issue is to use the Picasso library this way:
Picasso.get().load(imgUri).fit().centerCrop()
.into(imageview);
The reason behind those two methods (fit(), centerCrop())
Is that fit make sure that the image fit the bound container and then crop the image which force the system to redraw the image but this time with the convenient resolution (because of fit and crop).

7165X786 size of large image could't be display in real device(Tablets)

I am having trouble of displaying the large image into android. I have tried to get this done by this custom- scrollable-image-view .
I have used full View in my class and used the 7165*786 size of image into it. And it is of only 1.11MB of image. I am able to run this code in bluestack and see the image in it but it couldn't be load in real device.
bmLargeImage = BitmapFactory.decodeResource(getResources(),
R.drawable.imagewithout);
bmlotusImage1 = BitmapFactory.decodeResource(getResources(),
R.drawable.lotus);
I am using the same canvas in onDraw methow as below.
canvas.drawBitmap(bmLargeImage, scrollRect, displayRect, paint);
canvas.drawBitmap(bmlotusImage1, 45 - newScrollRectX,
255 - newScrollRectY, paint);
i could not be able to display the bmlargeImage in my real device i can see the lotus image on Device but not the large one.
Should i have to decode or scale the image or anything else to get it display in real device?
i get the solution of not Displaying the image in real Device the problem was the simply.
I have just removed the target sdk a i get the error in webservice. It start showing the image to my real device also and also i get the solution for Displaying the image FIt to screen as below.
private static Bitmap ShrinkBitmap(String backgroundimage, int width,
int height) {
// TODO Auto-generated method stub
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(backgroundimage,
bmpFactoryOptions);
int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight
/ (float) height);
int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth
/ (float) width);
if (heightRatio > 1 || widthRatio > 1) {
if (heightRatio > widthRatio) {
bmpFactoryOptions.inSampleSize = heightRatio;
} else {
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
bmpFactoryOptions.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(backgroundimage, bmpFactoryOptions);
return bitmap;
}
And i have passed the image width adn height as the parameter in this method.
bmLargeImage = ShrinkBitmap(backgroundimage, 7165, 786);

Bitmap Memory Error Android

I am making an Android game, but when I load my Bitmaps, I get a memory error. I know that this is caused by a very large Bitmap (it's the game background), but I don't know how I could keep from getting a "Bitmap size extends VM Budget" error. I can't rescale the Bitmap to make it smaller because I can't make the background smaller. Any suggestions?
Oh yeah, and here's the code that causes the error:
space = BitmapFactory.decodeResource(context.getResources(),
R.drawable.background);
space = Bitmap.createScaledBitmap(space,
(int) (space.getWidth() * widthRatio),
(int) (space.getHeight() * heightRatio), false);
You're going to have to sample down the image. You can't "scale" it down smaller than the screen obviously, but for small screens etc it doesn't have to be as high resolution as it is for big screens.
Long story short you have to use the inSampleSize option to downsample. It should actually be pretty easy if the image fits the screen:
final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final int dimension = Math.max(display.getHeight(), display.getWidth());
final Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
InputStream bitmapStream = /* input stream for bitmap */;
BitmapFactory.decodeStream(bitmapStream, null, opt);
try
{
bitmapStream.close();
}
catch (final IOException e)
{
// ignore
}
final int imageHeight = opt.outHeight;
final int imageWidth = opt.outWidth;
int exactSampleSize = 1;
if (imageHeight > dimension || imageWidth > dimension)
{
if (imageWidth > imageHeight)
{
exactSampleSize = Math.round((float) imageHeight / (float) dimension);
}
else
{
exactSampleSize = Math.round((float) imageWidth / (float) dimension);
}
}
opt.inSampleSize = exactSampleSize; // if you find a nearest power of 2, the sampling will be more efficient... on the other hand math is hard.
opt.inJustDecodeBounds = false;
bitmapStream = /* new input stream for bitmap, make sure not to re-use the stream from above or this won't work */;
final Bitmap img = BitmapFactory.decodeStream(bitmapStream, null, opt);
/* Now go clean up your open streams... : ) */
Hope that helps.
This may help you: http://developer.android.com/training/displaying-bitmaps/index.html
From the Android Developer Website, a tutorial on how to efficiently display bitmaps + other stuff. =]
I don't understand why are you using ImageBitmap? for background. If its necessary , its okay. Otherwise please use Layout and set its background because you are using background image.
This is important. (Check Android docs. They have clearly indicated this issue.)
You can do this in following way
Drawable d = getResources().getDrawable(R.drawable.your_background);
backgroundRelativeLayout.setBackgroundDrawable(d);
In most android devices the Intent size equals 16MB. You MUST Follow these instructions Loading Large Bitmap Efficiently

Android image resize

I have images stored on sd card(size of each ~ 4MB).
I want to resize each, than set it to ImageView.
But I cannot do it using BitmapFactory.decodeFile(path) becouse Exception
java.lang.OutOfMemoryError is appeared.
How can i resize image without loading it in the memory. Is it real?
Use bitmap options:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565; //Use this if you dont require Alpha channel
options.inSampleSize = 4; // The higher, the smaller the image size and resolution read in
Then set the options in the decode
BitmapFactory.decodeFile(path, options)
Here is a good link to read through, about how to display Bitmaps effciently.
You could even write a method like this to obtain a sized image at your desired resolution.
The following method checks the size the image, then decodes from file, with in-sample size to resize your image from sdcard accordingly, while keeping memory usage at a low.
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);
}
You have to scale your Bitmap before use it, this way you could reduce memory consumption.
Take a look at this, it might help you.
And, make sure you recycle that Bitmap if you don't need him anymore.

Categories

Resources