I have to use large images (about 4000x3500 pixels) and to avoid memory problem im using the lesson found on the Xamarin site to optimize the use of such images (https://developer.xamarin.com/recipes/android/resources/general/load_large_bitmaps_efficiently/).
However the resulting bitmap seems to be bigger than the original jpeg. The jpeg is about 2MB while the bitmap size i get by AllocationByteCount is about 33000000 Bytes, is it normal ? Is there something i am missing ? (im new on mobile development).
Thank you
Related
I need to reduce the bitmap size converting it from 24bpp to 1bpp-monochrome in my OCR application in Android.
I found this very good piece of software that converts the Bitmap to 1bpp-monochrome (https://github.com/acdevs/1bpp-monochrome-android). It converts to 1bpp-monochrome but the final file does not have the size reduced.
Any suggestion in how to reduce the bitmap file size converting a bitmap to 1bpp-monochrome?
Thank you in advance for your help.
The code on https://github.com/acdevs/1bpp-monochrome-android is working 100% and creating a 1bpp Bitmap with reduced size. The problem is when reading this bitmap(1bpp) in the android environment you need to choose one Bitmap.Config and Android increases the Bitmap size accordingly the Bitmap.Config. Android does not support 1bpp bitmaps.
I have 270 x 2693 pixel image in drawable folder . When i try to set that image in imagview i got Bitmap too large to be uploaded into a texture warning.
Image sets perfectly in android device < 4.0 but not sets > 4.0 device.
Please help me to resolve this issue.
Code
<ImageView
android:id="#+id/imageView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:contentDescription="#string/name"
android:src="#drawable/hindi" />
Here hindi is a image in drawable folder and its size is 270 x 2693 pixel.
Problem
This problem is usually related either to OpenGL maximum texture size or the Device Memory. The full error you are getting is probably something like
W/OpenGLRenderer(12681): Bitmap too large to be uploaded into a texture (270x2693, max=2048x2048)
Memory is generally the problem with a large scale image but in your case 270x2693 is 727110 pixels. If you are in RGBA, it's 4 bytes per pixel so 727110 * 4 = 2908440 bytes, which is approximately 2,7 megabytes. That should fit on any devices.
Thus, your problem is probably related to OpenGL. What might happen is that the Android device > 4.0 you are testing on detect that your image is too large for OpenGL and resize it for you, while older devices don't.
Edit:
In my case, the problem is that my 640x1136 splash image seems to get rezised automatically to a 1280x2272 image size to fit my device huge screen. Which also triggers the error message you are having.
If you get this error further on, it is related to the dpi that is used to load the image. As you will find on Android reference, device will load image regarding their dpi which can alter the size of image that is loaded in memory.
Solution
You don't have much choice other than detecting the device size to
load the image properly.
See how to load large bitmap in memory.
You can also use different image size for different device dpi which
can be automatically selected from the Drawable folder by Android.
See the How to support screens which tells you how to setup your
folder.
As other stated, use a smaller image or reduce its size.
Related informations
I suggest you have a look there if you need to support multiples screens.
Android also collect data which are updated every 7 days on Screens size among their users.
Also have a look to this interesting answer which points out a good website to understand Image Size in memory.
Finally, if you are already using OpenGL in your app, have a look to this answer which shows how to detect the max OpenGL texture size.
Why not reduce the size of the image? If you don't want to do that, then rather than specify the bitmap in the XML, load it from program code, and scale it to fit the display. See this guide for more information on loading large bitmaps.
try use this code
int[] maxTextureSize = new int[1];
GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);
maxTextureSize stores the size limit for decoded image such as 4096x4096, 8192x8192 . Remember to run this piece of code in the MainThread or you will get Zero.
In the attempt of performing animation with large set of images, I tried with FrameAnimation but I found of outofmemory exception with large set of images, after some exploration for the solution I found one good solution here Pinhassi's solution.
This one helps me to achieve animation but not smoothly because it taking a time to load the images. Then I decided to decode bitmap before starting the animation (giving bitmap instead of resID to ImageView). Through this I got smooth animation. But it is taking a time to decode the bitmap from the resources.
Is there any better approach to do the same? Any suggestion would be appreciated.
Details of the image
Total Number of images =30;
Image Dimension =1000x 720;
Size =180kb
Devices on which I am performing
Manufacture: Motorola
Model: MZ601
Android Version: 3.0
To decode Bitmap
Bitmap mBitmap=BitmapFactory.decodeResource(getResources(),resID);
int bitmapSize= mBitmap.getRowBytes()*mBitmap.getHeight())
The approximate bitmapSize values is 3000000 (might be it is in bytes) converting it to kilobytes 23437.5kb
Here original png file is 180kb but after decoding it, taking nearly 2MB of data. Why?
Is I am doing anything wrong in analyzing the size of bitmap?
If yes, then how to get the size of decode bitmap?
If no, then any one explain why it is taking large space?
Note: I don’t want to scale the bitmap since it is perfect to my device screen dimension which is (1280 x 752).
Thanks
In advance for valuable suggestions and solutions.
Here original png file is 180kb but after decoding it, taking nearly
2MB of data. Why?
Assuming 1 byte per pixel with three color channels(RGB) Byte size = 3X(1000X720)/(1024*1024) = 2.05 MB approx.
There is a limit such processing can reach with plain bitmap loading, that's why Video codec's exist.
I am developing an application for android and it contains several images and I have to get them from drawable, so I am using bitmap for them to avoid out of memory exception by rescaling them, but the problem is when rescaling, the resolution (/quality) of the image is reduced. How can I overcome this problem?
You can keep a reference to the original byte array and check your bitmap size against it but I would just use pngs in the appropriate drawable folders. Rescaling/reloading the image yourself and checking for quality could be much more memory hungry in a garbage collected language.
Let android do it's thing..
The only way you can avoid the loss in quality is by scaling the image proportionately in terms of width and height.
For eg : if your resolution is 100x80 try reducing it to 5x:4x . That will somewhat preserve the quality.
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.