Large source ImageView animation - android

What's the best image file format for Android in terms of memory? PNG is recommended for iOS as xCode does some magic with it.. Is it the same for Android?
I'm currently developing a big app with multiple animations going on (sliding in screens, fading etc etc). All works well so far! However I have noticed the view animation where the view contains an ImageView with a (quite large) PNG as the source is a bit laggy.
Obviously I can make the PNG smaller, but is there anything extra I can do to reduce the amount of memory the ImageView takes up/makes the animation smooth? I know PNG has a much larger file size than JPEG, but I can't see this being a problem, the JPEG or PNG (I assume) is eventually stored as an array of colours, so they would both take up the same memory. PNG is probably better for loading due to less cycles uncompressing. Again I only assume, my knowledge of image file formats is null.
Alternatively is there anything else causing the lag? Is the bitmap scaled to fit the view each onDraw() during the animation so should I scale the bitmap in code before giving it to the ImageView?
Thanks,

The formats supported by Android are: PNG, JPG and GIF (also 9.png).
The recomendated is PNG as said in dev guide
All of them are stored in memory as a Bitmap, so the most important thing is the color deph, like this:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon, options);
More info: stackoverflow

and add (after honeycomb):
<application
android:largeHeap="true"
...
to your manifest file :=)
thanks to my dear friend :)

Related

Android ImageView.setImage* vs. BitmapFactory.decode*

I'm currently facing several performance issues (out-of-memory) when handling a vast amount of bitmaps. As this is just a problem that can be fixed I'm wondering if anybody can explain me the difference in using the following methods.
If I only want to load an image into an ImageView I usually use:
imageView.setImageDrawable(getResources.getDrawable(R.drawable.id));
If I want to sample the drawable beforehand I usually use (here without sampling):
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.id);
imageView.setImageBitmap(bm);
My question is related to performance optimisation. I'm wondering whether it is better to provide as many drawables as possible using the different drawable folders (so these drawables nearly fit the required resolution for the different devices) or if it is better to sample high-quality drawables? What is setImageDrawable doing internally? Does it decode the resources using the BitmapFactory, just without sampling? There seems to be a trade-off between the actual size of the app and the cpu- and memory-load during runtime.
if you're concerned about apk size, then having as many drawables as possible is not the ideal way to go. but dont forget, when you decode a bitmap, you can pass a sample size so it will scale down to the screen size and only give you the pixels you need, so older phones with smaller screens wont need to decode 8mp images.
check BitmapFactory.Options and here

Resource to bitmap conversion results in poor quality

I never really noticed it before but when I change the image of an imageview using setImageBitmap, using a bitmap which is decoded from resources using BitmapFactory, then the quality of image deteriorates and I don't know why.
I even played around with BitmapFactoryOptions like options.inPreferredConfig, options.inJustDecodeBounds, options.inDither, but the results were pretty much the same; a poor quality image.
On the other if I just use setImageResource, the image doesn't deteriorates and is in best quality possible.
So basically these two codes
Bitmap b=BitmapFactory.decodeResource(getResources(), R.drawable.keypad,options); iv.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.keypad))
iv.setImageResource(R.drawable.messages);
results in different image quality.
Can anybody explain why? And how to solve this quality issue using code 1.
If you have blurry images using the BitmapFactory.decodeResource method, you can use this code:
Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap b = BitmapFactory.decodeResource(getResources(), path, options);
iv.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.keypad));
Setting the inScaled parameter of BitmapFactory.Options class to false, will prevent blurry images on low screen resolutions since it will prevent scalling as mentioned in the answer of this previous SO question. Maybe you have already tried this but i thought worth mentioning.

Bitmap density on openGL ES textures (Android)

I'm having trouble with loading textures regarding their resolution on openGL for Android. If the texture is 256x256 everything works perfectly, but if it's other resolution, the program throws this exception on start:
android.content.res.Resources$NotFoundException: Resource ID #0x........
I found a code on the internet that changes the density of the bitmap this way:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = 240;
and by doing this, I can load 512x512 textures. But I'm not able to load for example 128x128 bitmaps, because I don't know which density I have to use. I'm not sure either that this is the normal procedure to load textures, because I don't found many information on the internet.
Thank you for reading!
You dont need to specify the density, you just have to make sure the image is a power of 2, which you seem to have done. I would leave out the density option and just specify Config.ARGB_8888;
If this doesnt fix the problem can you show your code for loading the texture
If anyone has this problem, or the textures show up messed up (like ones being another, or other weird things) I was able to solve it by deleting all the items on the "drawable" folder and putting them in again. It seems the pointers to the images were corrupted or something.

OutOfMemory error while joining large images

I am joining two images using the code below but it throws an OutOfMemory error my images are around 1MB each.
private Bitmap overlayMark(String first, String second)
{
Bitmap bmp1, bmp2;
bmp1 = BitmapFactory.decodeFile(first);
bmp2 = BitmapFactory.decodeFile(second);
if (bmp1 == null || bmp2 == null)
return bmp1;
int height = bmp1.getHeight();
if (height < bmp2.getHeight())
height = bmp2.getHeight();
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth() + bmp2.getWidth(), height,
Bitmap.Config.ARGB_8888);// Out of memory
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bmp1, 0, 0, null);
canvas.drawBitmap(bmp2, bmp1.getWidth(), 0, null);
bmp1.recycle();
bmp2.recycle();
return bmOverlay;
}
Update: I tried below two answers but it still not allwoing me to create bitmap of such big size the problem is that the resultant bitmap is too large in size around 2400x3200 so its going out of memory.
How can I join large images without running out of memory?
Without loading the image into memory, you CAN get the size of the image, using inJustDecodeBounds. The Bitmap returns null, but all the parameters are set. You can scale down the image accordingly.
If your JPEG images are 1 MiB each, conversion to a BMP will take a lot of memory indeed. You can easily calculate its BMP equivalent by the dimensions of the image. Conversion of such a large image is expected to crash indeed. Android limits its apps to 16 MiB VM only.
Also use RGB_565 instead of ARGB_8888.
So your only solution is:
(a) To use BitmapFactory.Options.inSampleSize to scale down the image
or
(b) Use Android NDK where the 16 MiB limit isn't there.
I use this simple rule of the thumb:
the heavy lifting (both memory/CPU) is done on the server.
So write some servlet that takes the image, resizes it to a specified dimension (probably reduces the pixel depth too) and returns the result.
Piece of cake and it works on any mobile device you need.
Good luck!
I think a solution sort of like Sumon suggests might work.
Figure out the size of the final
image based on what will fit on the
screen.
Get the size of the first image using
the inJustDecodeBounds technique.
Figure out the size of the first
image in the final image. Calculate
re-sizing parameters.
Resize image, loading into memory.
Write resized image back to disk.
Recycle the bitmap. (This will help
when resizing the 2nd image)
Repeat for the second image, only you
can skip the writing to disk part.
Load first image.
If you only need to display, then just do that. If not then you can combine into a single bitmap at this point and write to disk. If this is the case, it may be difficult because you wil have essentially 2x the screen size in memory. In that case I would recommend resizing smaller. If you can't go smaller, then you will have to go the NDK route, thought I'm not sure how much that will help. Here's an amusing intro to the NDK and JNI. Finally, I would highly recommend developing this using a phone running Android 2.3+ since its use of heap-allocated bitmaps will make debugging much easier. More about those here.
It's not necessary that the space taken by in-memory representation of bitmaps correspond closely with file size. So even if you have 3mb memory available to jvm, you might still get OutOfMemoryException.
Your code is creating three in-memory images simultaneously. If you can find the size of both images without reading the complete files, you can modify the code in a way to have only one of the source images in memory at a time. If even that doesn't prove to be sufficient you might need some sort of streaming method of reading the images.
you may get some idea from here.
Are you trying to display this super large image or are you just trying to save it?
If your trying to display it. Cut the images into tiles. Then only display the tiles that are being viewed. If the user zooms out you need to reduce the size of the bitmap before showing the whole thing.
If your trying to save it, try saving it in sections to the same file by cutting the image up.
Loading 2 1m files in memory then creating a 2m file leaves you with 4M in memory for your images alone. Dynamically loading and unloading the memory solves this issue similar to tiles on Google maps or dynamic zooming in other map oriented solutions.
If you need to return that huge 2400x3200 bitmap as your result, there is no way to actually realize this goal. The reason is that 2400*3200*4 bytes ~ 30 Mb! How can you hope to implement this method, when even you can't even fit the return value into your limited heap space (ie 16Mb)?
And even if you used 16-bit color, it would still fail because you would end up using about 15MB, which would not leave you enough space for the language run time.

Android - noise in saved images

My Android application loads images, does some processing and saves the processed images on the SD card. I save temporary files to the SD card instead of using buffers. For example, reading a background, scrolling the image, drawing an annotation, merging background and annotation in a saved temp file to use as next background, and so forth. Typical snippets:
bitmap = Bitmap.createBitmap(imageSizeX, imageSizeY, Bitmap.Config.ARGB_8888);
bitmap = BitmapFactory.decodeFile(path, options);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
Everything works fine but in some cases the saved images have added noise similar to that described in this post:
Bitmap resizing and rotating: linear noise
The author of the post cited solved the problem by subsampling, but I don't wish to do that.
I have tried the solutions suggested here:
http://www.curious-creature.org/2010/12/08/bitmap-quality-banding-and-dithering/#more-1218
which if I understand correctly should be achieved by setting:
getWindow().setFormat(PixelFormat.TRANSLUCENT);
to force 32 bit.
which does not change much. Setting or not setting the dither flag does not seem to change much either. Any other ideas?
In answer to my own question:
The noise disappears, or at least the result is way better, by compressing to .png instead of .jpg
bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
The same sky which looks like a carpet texture in .jpg looks smooth and clean in .png. Since the difference is much more evident than the usual difference between the same image compressed to .png and .jpg, I guess it depends on the Android implementation. Setting explicitly TRANSLUCENT and DITHER does not make much difference one way or another.

Categories

Resources