I'm downloading images from the internet and then displaying them scaled on the screen. The idea is to use inSampleSize so I can scale large images while decompressing and prevent OutOfMemory exception. But in order to find inSampleSize I need to know image resolution. It can be obtained using inJustDecodeBounds option.
The problem is that I can't pass it the stream and download the image from the internet directly, because it will be downloaded twice (first to get the size, then to get the scaled Bitmap). I can't download the image and store it in RAM, because image size may be large. The only solution left is to download the image to SD card / internal memory and read it from there, but when user has no space left bad things are going to happen.
The question is - is there any way to do it without relying on the storage and RAM memory which doesn't require the image to be downloaded twice? Or maybe BitmapFactory doesn't download whole image when it's using inJustDecodeBounds, but just headers?
Thanks
If you're downloading a PNG, GIF or JPG it should be possible to read the file headers to determine the width and height, which should mean you avoid having to download the entire file.
This post has some C# code for reading the width and height from the headers for the above format which you could port to Java for use in Android.
Related
I'm trying to resize large images (16MP) on Android down to smaller but still large (8MP) images. I tried some approaches I've found on SO with sampled or scaled loads into memory, but neither one of these sizes fits into a decoded bitmap in memory reliably.
Is there a way I go straight from input file to output file while using a minimal amount of memory? Some sort of streaming decode/encode?
Our application is image resource heavy. Currently we don't have provision of sending images depending on device resolution from the server. The images sent from the server are generally of high resolution (around 900 X 900). I have few queries :
1) Will the image downloaded and stored in file disk cache will be of same size as the original size in server.
2) Once the image is saved in file disk cache, how is the image processed to bring it in the in-memory cache. Are the bitmap image stored in in-memory cache will be transformed to lower resolution depending on device resolution?
3) If the target image height and width is not known then how can we scale down the bitmap image as per device resolution? As per our requirement, it is not possible to give fixed width and height to imageview. There is resize(int, int) method but the problem is, we can't change the image height and width in some cases. Ideally, there should be some solution to downscale the image size by % (lets say 20%).
Crash does not occur always as it depends of memory.
You can use android:largeHeap="true" to request a larger heap size, but this will not work on any pre Honeycomb devices. On pre 2.3 devices, you can use the VMRuntime class, but this will not work on Gingerbread and above.
The only way to have as large a limit as possible is to do memory intensive tasks via the NDK, as the NDK does not impose memory limits like the SDK.
Alternatively, you could only load the part of the model that is currently in view, and load the rest as you need it, while removing the unused parts from memory. However, this may not be possible, depending on your app.
Example:
<application android:largeHeap="true" ....</application>
We need to downsample image received from InputStream. It is an image received from some URL and it can be either pretty small or very large. To fit this image in memory we have to downsample it. First we retrieve image size with the help of inJustDecodeBounds and calculate necessary sample. Then we create downsampled bitmap by specifying this sample in BitmapFactory.Options.inSampleSize. This 2-steps decoding needs two calls of decodeStream() and works just fine.
This works just fine for files from SD card. But in our case input stream cannot be reset so we can't call decodeStream() twice. Cloning of input stream is also not an option because of its huge size. Alternatively, we can create 2 HTTP requests to the same URL: first to get image size, and then to decode actual image with downsampling, but this solution seems to be rather ugly.
Can we reuse stream which cannot be reset? Or please propose some known workarounds for this problem.
If you wan't to reuse the stream it is obviously must be saved to either RAM or the SD-card, because network InputStream (let's imagine it is not Buffered) is not keeping downloaded data.
So the option to workaround this as said before is to save image directly to the sd-card (maybe in some temp directory) if image could really huge.
I am building a simple wallpaper app. I store the wallpaper images(.jpg) as resources in the res folder. I show the user a grid of thumbnails, which I store separately as resources(.jpg) too in res. I want the scrolling through this grid to be smooth and fast. My question is that when I load the gridview using the adapter, In the getView method I convert the resource to a bitmap and then load it in each imageView in the Grid. Would it be faster if I stored the thumbnails as .bmp in the res folder in the first place? Also I've manually created the thumbnails, rather than manipulating the large wallpapers making them at run-time. Each thumbnail is made to scale to width of 120pixels and the grid consists of 120x120 imageviews. So I was wondering how I could load these images quickly and effectively?
Im setting the adapter to the gridview inside Asyntask, but I dont notice an improvement.
Jpeg, which is lossy image compression, usually provides the best quality to size trade-off.
If you're trying to store high quality images then you're almost certainly going to want to use Jpeg.
PNG does has useful features such as allowing you to work with transparency, and, for simple block colour images outputs really small file sizes.
However, the moment you start to create photo quality images, such as wallpapers, as PNG, you're going to see monster file sizes, which on a mobile device is not going to be much fun or much appreciated by the end user.
Also larger files tend to require more system resources (CPU time and RAM), and on a mobile devices these resources are at a premium.
I would suggest that perhaps for thumbnails you might use PNG, and for the full size image use JPEG, but you might do well to see which creates the smallest file, because that is likely to give an good indication of the rendering efficiency i.e. it takes little resources to render a 800b PNG.
Changing your images to the bmp file format could make a little improvement in performance (because JPG is a compressed bitmap image that needs to be decompressed when rendered), but it's usually not worth the major increase in filesize.
I would recommend using the PNG bitmap format because it's light in both rendering and filesize.
As for the rendering in the ListView, you might want to take a look at this question and this code project.
In android when Bitmap is downloaded from the Internet using BitmapFactory.Options with inSampleSize > 1, its quality is reduced and it takes less memory. Does this mean that less data is downloaded?
My goal is to create thumbnails of large images and show them in GridView. I want to download as less data as possible. Don't want to download full size images.
No, it only means that less data is loaded in memory, usually to avoid the notorious OutOfMemoryError. The data is downloaded with its original size but a scaled down version is loaded in memory.