I would like to read images from InputStreams, and draw them to my canvas. Unfortunately, the images may be very large, and could easily cause out of memory exceptions. BitmapFactory allows me to provide a sample size value, which will down sample the image as it is processed and avoid the memory issues. However, image quality suffers.
Ideally, canvas would provide a paint image method which can paint from an InputStream, as opposed to from a Bitmap, but I haven't found anything of this type. Does this exist, or is there any other way to safely render arbitrarily large images from InputStreams without down sampling?
I am not sure what image format you are using but if you want to send a lossless image (or with less loss than has already occurred), It can't be compressed better than JPEG. so, use JPEG first.
Here is an example for drawing image on Canvas. Override the 'draw' method. http://www.androidsnippets.com/drawing-an-image-as-a-map-overlay2
At the end, hacking it
Probably, pre-splitting the image; compressing each individual one and restoring at the end sounds logical.
Here are few attempts,
http://kalanir.blogspot.com/2010/02/how-to-split-image-into-chunks-java.html
And
http://www.anddev.org/multimedia-problems-f28/chunk-of-a-big-big-image-t6211.html
The answer appears to be: no, there isn't.
Related
I have a project in which I capture a photo from camera (using Camera or Camera2 API) and then I have to manipulate all image pixels colors.
The image is large (4032X3024) and using Bitmap.getPixel(x,y) or Bitmap.setPixel(x,y) takes forever.
Is there a better way that I can work on the image's pixels? Is there some kind of external library I can use?
Thanks!
You could get a copy of bitmap's pixels into int[] and process it by using getPixels(). As for some performance and memory improvements you could copy only some part of bitmap into pixels and process parts of array in separate threads. Once all finished, put together the final processed pixels and call setPixels()
There is a big topic that exists for this exact reason. I would probably suggest looking into it if it is applied to your app.
I have a big resolution bitmap, and I'd like to make a thumbnail out of it (of course, it is a dynamic case, I don't have the files in advance, but just to simplify).
However, whatever I do, the bitmap always gets 'nearest neighbour' interpolated image.
I tried setting inDither flag, inPreferQualityOverSpeed, inPrefering RGB_8888 bitmap format, and God only knows what not.
Whatever I try, the image is still pixelated.
Trying to downsample it with GIMP echoed beautiful results, so the image is not faulty.
Any idea of a library or an SDK method somewhere that does downscaling with some smarter interpolation, and not nearest neighbour?
I am trying to cache big bitmaps for drawing on screen in Android. But now I am facing OutOfMemoryException, say that the bitmap allocation exceeds the VM budget.
I need to minimize the size of the bitmap but I cannot reduce the resolution. For my use case, I need to only save the shape of the bitmap and apply color later when actually drawing, so I am using ALPHA_8 as the bitmap configuration.
I want to know if there is a 1-bit pixel (either completely opaque or completely transparent) configuration in bitmap, or any similar ways to save memory?
Reducing the color depth from 8 bits to 1 would, of course, help a little. However, it doesn't really solve the problem but just postpones it. It only means that you'll get the OOME later but you'll still get it.
Consider moving your cache from RAM to disk and, optionally, add a smaller RAM-based cache on top of it to improve performance.
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.
I'm working on an image processing application for Android that recognizes music notation from pictures taken of music sheets.
I tried to load the entire image into a Bitmap using the BitmapFactory.decodeFile(imgPath) method, but because my phone doesn't have enough memory I get a "VM heap size" error. To work around this, I'd like to chop the full image into smaller pieces, but I'm not sure how to do that.
I also saw that it was possible to reduce the memory size of the Bitmap by using the inSampleSize property of the BitmapFactory.Option class, but if I do that I won't get the high resolution image I need for the music notation recognition process.
Is there anyway to handle this without going to NDK?
Android 2.3.3 has a new API called android.graphics.BitmapRegionDecoder that lets you do exactly what you want.
You would for instance do the following:
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(myStream, false);
Bitmap region = decoder.decodeRegion(new Rect(10, 10, 50, 50), null);
Easy :)
If it's from a camera the image will likely be jpeg format. You could use an external jpeg library - either in java or via the NDK, whatever you can find - to give you better control and load it a piece at a time. If you need it as an android.graphics.Bitmap then I suspect you will then need to re-encode the subimage as PNG or JPEG and pass it to BitmapFactory.decodeByteArray(). (If memory is a concern then do be sure to forget your references to the pieces of the bitmap promptly so that the garbage collector can run effectively.)
The same technique will also work if the input graphic is PNG format, or just about anything else provided you can find suitable decode code for it.
I think that by loading the image piecewise you are setting yourself an algorithmic challenge in deciding what parts of it you are really interested in the full detail of. I notice that BitmapFactory.Options includes the option to subsample, that might be useful if you want to analyse an overview of the image to decide what regions to load in full detail.
If you're dealing with JPEG images, see my answer to this question as well as this example.
I don't know how possible it is to get libijg on Android, but if it is, then it's worth a shot.