Animation with large number of bitmaps - android

I've seen similar threads here but couldn't find a sufficient solution yet.
I'm working on my first Android app and trying to create an animation using large amount of images/bitmaps. I have a list of bitmaps which I like to play frame-by-frame animation
the number of images may change from few to hundreds (currently loaded from resources)
I'm using SurfaceView and using the following to load and draw my images
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), res);
canvas.drawBitmap(bitmap, x, y, null);
I tried two methods:
Pre-Loading all images and caching to memory. This results with great performance
but takes time to initialize, uses a lot of memory and works only for small amount of images
Decoding the images one-by-one. This results with poor performance and high cpu usage
I'm looking for way to boost the performance for large lists,
Is there a way to cache the decoded bitmaps or convert them to some video-stream (lossless?) to boost performance?
Any ideas?

About performance,
First do not load the hole image size, use below method to reduce size when load image:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = number; //reduce image size
Bitmap b = BitmapFactory.decodeFile(image path, options);
Also load images for current time animation not all animations, then load other animations in thread instead of finished animation.
About time in case 2, load images in a thread and show loading dialog for the user until all images loaded.

Related

Resizing and rotating an image file efficiently (with/without renderscript)

Whenever we need to rotate and resize a huge image file on Android (no bitmap allocated yet), the usual steps would be to first load the image into a resized bitmap, then do the rotation on another newly created bitmap.
If I do the rotation first I'll probably end with the dreaded OutOfMemoryError. This is quite logical and I'm OK with that.
Problem is, both approaches include having two bitmaps at once in memory at some point, and I'm on a tight memory budget here, even after implementing bitmap scaling as the official docs say (https://developer.android.com/topic/performance/graphics/load-bitmap). A typical implementation looks like this:
Bitmap bitmapResized = resizeBitmap(fSource, nTargetWidth, nTargetHeight);
Bitmap bitmapRotated = rotateBitmap(bitmapResized, nOrientation);
[recycle both bitmaps here]
Is there any way to do both steps at once in a memory lightweight fashion?
I have read about renderscript but I wasn't able to find code that does not take an already allocated bitmap.

How many pictures can i put in my app?

I have a gallery working in my app at the moment with about 8 pictures on it. Before i had a bug that use to make it crash because of overload Heap (something like that, not sure).
This was caused by my pictures being too big in file size, so i reduced them it worked. So my main question is How many picture can i actually put in to my app.
I was hoping to have about 5 screens (activities) with some scrolling pictures
I don't want to start changing my app if its just going to crash again
Also does anyone know how to add transitions when scrolling through pictures, for it too look fancy
Everything depends on the way you manage you pictures. To save the memory (and increase the number of images loaded) you should load a resized picture.
You can subsample picture while loading:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2;
BitmapFactory.decodeResource(res, id, opts);
This will load a picture scaled 1/2 of it's original size (keep in mind that subsampling works only for power of 2 values). You can load the picture smaller than the area it will be displayed in and let ImageView to upscale it.
If your loaded image is still too large, you can scale it more with Bitmap.createScaledBitmap().
You should be aware that pre-Honeycomb Android doesn't recycle bitmaps like post-Honeycomb Android does. You should call Bitmap.recycle() as soon as the bitmap is not used anymore to clear the memory.
For image scrolling you can use ViewPager.
Further reading: http://developer.android.com/training/displaying-bitmaps/index.html
There is no strict limit on the number of pictures you can include in your app. See the stock Gallery app as an example, I consider myself a relatively light picture taker, but I still have hundreds of images in my Gallery. If you follow the Bitmap best practices you shouldn't run into any memory issues, and you should be able to include as many images as you want.

Android pre-honeycomb bitmap management

For my application I need to load a bitmap which sometimes can be really large. I'm getting OutOfMemory errors even on devices like galaxy S2. I searched around and found that I need to recycle the bitmap.
Previously I was loading the bitmap with BitmapFactory, creating a new scaled bitmap, and creating a bitmapdrawable all in one line. By doing this am I loading two bitmaps into memory? Should I create the initial bitmap and then recycle it after creating the scaled bitmap?
If the activity will be launched frequently should I load the bitmap once to a static field or should I recycle and recreate every time?
Thanks
Split the process into multiple steps. If you are measuring the bitmap against the available screen space and then loading a scaled bitmap, you can do the first step without loading the bitmap into memory using BitmapFactory.Options.inJustDecodeBounds. This will give you a Bitmap object without the pixel data but with the width and height properties. Then use that to decode your scaled bitmap using BitmapFactory.Options.inSampleSize.
Google these terms and you'll find tons of sample code doing just this. And yes, don't forget to recycle when you're done with a Bitmap.
https://www.google.com/#q=BitmapFactory+Options+inJustDecodeBounds+inSampleSize

Faster image processing

Can someone suggest me a library that can do simplest operations like scale, crop, rotate without loading image fully into memory?
The situation: I need to scale image down from a very large size, but the scaled down image is still too large to be allocated in memory (if we use standard android tools). Since I only need to upload scaled down version, I thought of scaling it through native library and upload it through FileInputStream.
I've tried to use ImageMagic and it does the job, but performance is very poor (maybe there is a way to speed things up?)
Might want to check out OpenCV for Android
You can use the original Android Bitmap functionality by pulling the image into memory but allowing Android to sample the image before it is loaded.
For example:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap myBitmap = BitmapFactory.decodeStream(inputstream,null,options);
This will load your bitmap into memory with half the memory footprint of the full image. You can experiment with changing the inSampleSize to get a good fit for your application.
You can also calculate the sample size on the fly, if you know the final image size you are aiming for, you can get the current file size of the image before you load it into memory and calculate the sample size using the equation inSampleSize = OriginalSize/RequiredSize. Though sample size is best used when it is a power of 2, so you can make adjustments for this.
Edit:
A great example here https://stackoverflow.com/a/823966/637545

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.

Categories

Resources