I have image with 543*6423 resolution, I want to display it in all devices. It is displaying in few of android phones which allows the high resolution. I tried with
android:hardwareAccelerated="false"
This is my java code for android client
File storagePath =Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS+
"abc.png");
InputStream is = this.getContentResolver().openInputStream(Uri.fromFile(storagePath));
Bitmap b = BitmapFactory.decodeStream(is, null, null);
is.close();
image.setImageBitmap(b);
This worked in my mobile (sony xperia) but few other phones are not displaying it.
Please help me how can I display this image independent of screen resolution.
Thanks,
Aman
Your image is probably too large to be displayed on most devices. So you have to load a scaled down version of the image. Look at Loading Large Bitmaps Efficiently to see how to do this and calculate an appropriate sample size.
If you need the display width / height (in case of a full screen image) you can use getResources().getDisplayMetrics().
try with
android:hardwareAccelerated="false"
android:largeHeap="true"
Well, maybe I am too late to help you but this can hopefully help others. I've recently developed an open source library that can handle large image loading. The source code and samples are available at https://github.com/diegocarloslima/ByakuGallery
The solution in the blog is wrong by a power of 2...
Here is the solution:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// Set height and width in options, does not return an image and no resource taken
BitmapFactory.decodeStream(imagefile, null, options);
int pow = 0;
while (options.outHeight >> pow > reqHeight || options.outWidth >> pow > reqWidth)
pow += 1;
options.inSampleSize = 1 << pow;
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeStream(imagefile, null, options);
The image will be scaled down at the size of reqHeight and reqWidth. As I understand inSampleSize only take in a power of 2 values.
Instead of spending hours upon hours trying to write and debug all this downsampling code manually, why not try using Picasso? It is a popular image loading library and was made for dealing with bitmaps of all types and/or sizes.
I have used this single line of code to remove my "bitmap too large...." problem:
Picasso.with(image.getContext()).load(storagePath).fit().centerCrop().into(image);
Related
I'm developing application for my android tablet that using many images.
in my activity, I use effect splash that show image (3840 x 2108 70 KB) for the opening theme.
I use another background image (3840 x 2108 69 KB).
but, when I test it on my tablet, this application's cache reached 80 MB!
For your information, I load the image from my xml file.
Can anyone help me to reduce it?
Is it wrong to load image from xml file?
Is it the size of my images that cause this problem?
//UPDATE
at the end, i didn't found a really good way to my question. I'm using xml (I put at dawable) file to replace my big size image, and this method really reduce the cache alot. My conclusion is avoid using big image, instead, just replace the color image using color.
The advantage to use color is "faste to load", it reduce lag of my application.
Android default color model is ARGB_8888. It takes 4 byte for 1 pixel. So splash and background bitmap images in memory takes 3840*2108*4*2 = 61.76MB. You could resize the images for different device dpi and put them in proper drawable folder. For example, drawable-hdpi is suitable for 240 dpi, drawable-xxhdpi is suitable for 480 dpi.
In addition, you could manually load the images with java code. The following is a method to resolve the image safely:
protected Bitmap getBitmapSafely(Resources res, int id, int sampleSize) {
// res = youractivity.getResources, id = R.drawable.yourimageid
Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inSampleSize = sampleSize;
try {
bitmap = BitmapFactory.decodeResource(res,
id, options);
} catch (OutOfMemoryError oom) {
Log.w("ImageView", "OOM with sampleSize " + sampleSize, oom);
System.gc();
bitmap = getBitmapSafely(res, id, sampleSize + 1);
}
return bitmap;
}
Your could use this method with sampleSize = 1 at first time. If there is not enough memory, it will catch OOM and increase the sampleSize until the image can be resolved.
Can the code below cause OutOfMemory ? I think it allows to exceed the application memory limit.
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);
What is the best way to rotate an image in Android ?
Allocate it in a service in a new process to get more heap?
#CommonsWare said in this link [1] that many developers think that more heap is a solution for inefficient coding.
This question indicates large heap too [2].
Is there a simpler solution ?
[1] Can you start an IntentService on a separate process?
[2] How to avoid OutOfMemory ex while rotating the image?
The short answer is, Yes, this code may cause OutOfMemory. I don't think that there is a simpler solution than increasing app heap size. I believe that #CommonsWare is right, and often OutOfMemory is an indication of wrong programming. But there are some situations when you need, ehm, huge memory. Rotation of a huge image is definitely one of such situations.
You can use native code (NDK) instead of asking for increased heap size, but this is definitely not easier. And it will still needs lots of memory, so there is no advantage in going for C++ (except that it works on 2.3).
If you wish to use an NDK based solution, I've created one here, and i've made a github project here .
this will avoid OOM by putting the data into the native C "world", recycle the old data, and return the result back, after rotation.
it doesn't require any downsampling.
OutOfMemoryException thrown when your bitmap is to large to load in memory.
Here I am giving you one solution.
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap=BitmapFactory.decodeStream(is,null,options);
Use inSampleSize attribute of BitmapFactory.Options class.
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
Here:
image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);
code operates two bitmaps, the first image is a Bitmap you previosly loaded/decoded into RAM to work with - to rotate actually. And the second one will be created by Bitmap.createBitmap() no matter you store the result into the same variable. Anyway at this line you need bitmap x2 RAM and this causes the OOM for sure (speaking of device's camera biggest possible photos).
I think that using NDK is the best solution here.
Please check my very same question here for additional possible solution (MappedByteBuffer) and it has links to NDK/JNI solutions as well.
I'm developing an Android app which uses multiple large images in several of its activities. Each image is around 1280x800 and I load about 2-4 of these images for each Activity. I realize that these images are very large in terms of the memory that is allocated to each individual app on a device, but how can I display them at their original resolution without running into a java.lang.OutOfMemory error? I need these images to be displayed at their full size on a screen (scaling is done automatically by xml when the screen is smaller than the image). I saw several solutions involving shrinking down images into thumbnails and storing those into memory, but wouldn't that cause the image to lose it's original size/resolution? Thanks for your help!
There are a few things you can do about this.
The first thing that comes to mind is that 1280x800 is (probably) your entire screen, so you should only need to display one at a time. Don't hold the others in memory while you do that.
Still a 1280x800 image at 4 bytes per pixel is only 4MB, and tablets seem to all offer 48MB of heap these days. You should be able to hold a few in memory if you need to. If you're running out of memory, it's possible you're leaking. If you watch in DDMS, does your memory usage continue to grow as you change activities?
A common source of leaks is the bitmaps themselves. Be sure to call Bitmap#recycle when you're done with them.
If it really comes down to it, and you cannot fit into the heap space provided, you can also try adding android:largeHeap="true" to the application tag in your manifest. This will request the system offer you more heap space - up to 256MB on some devices. This should be a last resort, though, as it will vary by device, and be completely ignored on some (the original Kindle Fire comes to mind).
You can see just how much total heap space you have with Runtime.getRuntime().maxMemory();. See this answer for a more detailed explanation. It's trickier to see just how much you're using, but there is a description here if you want to tackle that beast.
Finally, there may be a better way to load your images than specifying them in xml. Be sure to read this developer guide page. Even if you must leave them in xml, I have seen marked improvement in memory usage by splitting the image assets into the drawable-hdpi, drawable-mdpi, etc. directories rather than just dumping them in drawable.
This article describes pretty well how to create a heap dump and analyze it using Eclipse MAT. This will help you find the most likely suspects for memory leaks pretty quickly.
Again I point you to this great link I found from another SO Question that has tutorials of how to properly over come the problem.
Image needs to scaled before loading the image using BitmapFactory or related methods.
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) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// 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);
}
whole thing is explained in Android developer site, Loading Large Bitmaps Efficiently
I have a photo on disk with dimensions 2560 x 1920. This is often too large to load into memory, so I'm trying to use BitmapFactory.Options.inSampleSize to conserve memory. From the docs:
inSampleSize: If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
This is how I use it:
BitmapFactory.Options optsDownSample = new BitmapFactory.Options();
optsDownSample.inSampleSize = 3;
Bitmap bmp = BitmapFactory.decodeFile(path, optsDownSample);
but the app still sometimes crashes on the last line there, and from logcat I can see it's trying to allocate ~5mb, and I suspect this is because the downsampling is not really being honored.
Anyone else know what could be going on here, am I using inSampleSize incorrectly?
Thanks
I'm also struggling understanding how to use the BitmapFactory.Options, based on all the documentation I've read I believe you are just missing the optsDownSample.inJustDecodeBounds = false; as indicated on the Android Developers site.
Best of lucks!
This question already has answers here:
Strange OutOfMemory issue while loading an image to a Bitmap object
(44 answers)
Closed yesterday.
I am getting the following error after creating bitmap second time around:
04-17 18:28:09.310: ERROR/AndroidRuntime(3458): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
this._profileBitmap = Bitmap.createBitmap(_profileBitmap, xCoor, yCoor, width, height);
From log:
04-17 18:27:57.500: INFO/CameraCropView(3458): Original Photo Size: W 1536 x H 2048
04-17 18:28:06.170: INFO/CameraCropView(3458): xCoor: 291
04-17 18:28:06.170: INFO/CameraCropView(3458): yCoor: 430
04-17 18:28:06.170: INFO/CameraCropView(3458): Width: 952
04-17 18:28:06.170: INFO/CameraCropView(3458): Height: 952
Since the image is huge I get the error. But the interesting thing is the error does not happen the first time, only when I take the picture the second time, which makes me believe this profileBitmap is NOT destroyed. How do I clean this up?
I had the same problem and fix it this way:
My app was ~18MB size, and when I see how much memory left free I was shocked - 654KB (on 1GB RAM!). So I just deleted almost all images from project and downloaded them from the internet on first start, and use pics from SD card when needed.
To check total/free memory for your app use:
Runtime.getRuntime().totalMemory();
Runtime.getRuntime().freeMemory();
EDIT: I forgot the main thing - add in your manifest, between application tag, this line:
android:largeHeap="true"
There are many problems with memory exceptions with bitmaps on Android, many of which are discussed on stackoverflow. It would probably be best if you went through the existing questions to see if yours matches one of the existing ones, then if not, write up what makes your situation different.
Some examples:
Out of memory exception due to large bitmap size
Android: out of memory exception in Gallery
Android handling out of memory exception on image processing
etc:
https://stackoverflow.com/search?q=android+out+of+memory+exception+bitmap
I have explained it in this blog post: android bitmap processing tips
Now here are tips which you can follow and can avoid out of memory exception in your Android Application.
Always use Activity context instead of Application context. because Application context cannot be garbage collected. And release resources as your activity finishes. (life cycle of object should be
same as of activity).
2 . When Activity finishes. Check HEAP DUMP (memory analysis tool in Android studio).
If there are objects in HEAP DUMP from finished activity there is memory leak. review your
code and identify what is causing memory leak.
Always use inSampleSize
Now what is inSampleSize ?
with the help of inSampleSize you are actually telling the decoder not to grab every pixel in memory, instead sub sample image.
This will cause less number of pixels to be loaded in memory than the original image. you can tell decoder to grab every 4th pixel or every second pixel from original image.
if inSampleSize is 4. decoder will return an Image that is 1/16 the number of pixels in original image.
so how much memory you have saved ? calculate :)
Read Bitmap Dimensions before loading into memory.
How reading bitmap dimensions before loading image into memory can help you avoid out of
memory error ? Let's Learn
use inJustBounds = true
here is technique with the help of which you can get image dimension beore loading it in memory
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Above code snippet will not give us any image/bitmap. it will return null for bitmap Object.
but it will definitely return width and height of that image. which is R.id.myimage.
Now you have width and height of Image. you can scale up or scale down image based on these factors:
ImageView size which will be used to display Image.
Available amount of memory. you can check available amount of memory using ActivityManager and getMemoryClass.
Screen size and density of device.
Use appropriate Bitmap Configuration
Bitmap configurations is color space/color depth of an Image. Default bitmap Configuration in Android is RGB_8888 which is 4 bytes per pixel.
If you use RGB_565 color channel which use 2 Bytes per pixel. half the memory allocation for same resolution :)
Use inBitmap property for recycling purpose.
Do not make static Drawable Object as it cannot be garbage collected.
Request large heap in in manifest file.
Use multiple processes if you are doing lot of image processing(memory intensive task) or use NDK (Native Development using c, c++)
You can try calling recycle() on the bitmap when you are done with it. This will clear all the image data and free up the memory. If anything tries to draw the bitmap after this then your app will crash. If you do get a crash it may help you find out what is still holding onto your bitmap.
This happens because you are loading the bitmap directly,which consumes a lot of memory.
Instead use a scaled down version of the picture in _profileBitmap.
This guy explains it pretty well.
http://androidcocktail.blogspot.in/2012/05/solving-bitmap-size-exceeds-vm-budget.html
With Larger images it can be avoided by sampling them into smaller size.
Use below example -
File f = new File(selectedImagePath);
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, 720, 1280); //My device pixel resolution
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmpPic = BitmapFactory.decodeStream(new FileInputStream(f), null, options);
Bitmap bmpPic1 = Bitmap.createBitmap(bmpPic, 0, 0, bmpPic.getWidth(), bmpPic.getHeight(), mat, true);
img.setImageBitmap(bmpPic1); //img is your ImageView
Reference-
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
You could use a vector Drawable . It uses an xml file to describe your image , so it consumes less memory.
To do that you should use the SVG format for your images and then generate the xml file using one of these 2 solutions :
Solution 1 : Use the vector asset studio in Android Studio : right click on Drawable file in your project -> new -> vector asset
Solution 2 : Use the svg2android website : https://inloop.github.io/svg2android
Check out this link for further information:
https://developer.android.com/studio/write/vector-asset-studio.html
I had the same issue when the phone was powered off and back on. Simply setting the bitmaps to null and calling System.gc(); fixed all the problems.
I had this issue because I was modifying a bitmap once, and then modifying the modified version a second time, resulting in three versions of the same bitmap (original, plus the two modified versions) being in memory at the same time.
I fixed it by changing my image-editing code to apply both modifications to the same bitmap as a kind of batch process, halving the number of modified versions that my app had to hold in memory.