I guess this question could be applied to both iphone and and android.
When I want to show smaller image,
I can set imageView to smaller size and let iphone handle the resizing to fit in the view.
Or
I can actually resize the image itself.(using opengl call, or such as wrapper call createScaledBitmap in android)
I find option 1 is faster.
I always wondered why?
I also wondered the memory consumed by the image is governed by the size of imageView or image?
This is good question, I think when we resize the imageView to smaller that And image(UIImage) is greater that time memory consumption is more because of that image (UIImage) size is more respect to display in imageView. I think second option would be good to save memory .
Image resizing need extra CPU cycles.So Its better to manually resize the image.
Related
I'm taking whole screenshot of a WebView and display the bitmap on an ImageView. The bitmap can be 7 screen height. (E.g. 1440x14000 px)
I'm frequently face with
OutOfMemoryError.
I've seen this
This says that load a scaled down version into memory but I don't want to lose image quality. There are the same approaches on the web.
Is there any way to handle OutOfMemoryError without loading scaled down version?
The bitmap can be 7 screen height. (E.g. 1440x14000 px)
Note that this means that the user cannot see the whole image at once at full resolution.
I'm frequently face with OutOfMemoryError
On most devices, you will have a very difficult time loading an image that large, as you cannot get a single contiguous memory block that big.
This says that load a scaled down version into memory but I don't want to lose image quality
To some extent, you do not have much of a choice. If you want the user to see the full extent of the picture at once, the image has to be scaled to fit the screen.
Is there any way to handle OutOfMemoryError without loading scaled down version?
There are ImageView replacements that offer pan and zoom. Some of those, such as this one, handle loading in pieces of the image at a time, with whatever scaling is necessary for the current zoom level, to make it more likely that you will be able to show the user the entire image.
It is not a solution, of course, but I'm also not familiar with your exact needs, so maybe this may help you a little - you can try to play with bitmap options during decoding. Try to use Bitmap.Config.inPreferredConfig as RGB_565 - this will reduce size of your bitmap twice comparing to default ARGB_8888. But, of course, if you use complex images in your web page this may reduce their quality.
As far as I know, if image is too big, it can't be displayed in some fixed size ImageView. My question is how can I find out maximum size of image that can be displayed if I know width and height of ImageView.
Android can display bitmaps up to 2048x2048 pixels. It dependents on OpenGL implementation.
But the main issue with big images is a insufficient memory problem. Big images takes more memory and leads to OutOfMemoryError and app crash.
The best way is scale image before displaying to ImageView size. There is a lot of image loading frameworks that can help you. For example Fresco, Glide
So, I have been using this amazing library Glide for showing native images in my gallery app. I am using ViewPager with FragmentStatePagerAdapter to show full size images. The pager's off screen limit is 1 (default to save memory). I am using this code to load images into ViewPager in my fragment:
Glide.with(getActivity())
.loadFromMediaStore(uri)
.asBitmap()
.signature(new MediaStoreSignature(mimeType, dateModified,
.into(mImageView);
Now, I am facing some issues here like:
Images take quite some amount of time to load (if not cached). So, while user is scrolling through the viewpager blank screen is shown while image is loading which is what I want to avoid. Is there any way I can do this? Maybe by precaching images?
Sometimes, while scrolling through large size images (mainly Camera photos) OOM Exception is thrown and user is left with blank screen as no image is loaded. This also happens when I am shifting from potrait to landscape mode. So, I tried to use methods like atMost() -- which degrade the quality of image further as images are already loaded in RGB_565 and approximate() which is also causing OOM. How can I achieve maximum image quality without getting OOM exceptions?
For the second issue, I was thinking to load lesser quality images for the off screen items and then enhance quality when they come on-screen. Is it possible?
I have also tried to use ARGB_8888 but the result was same: OOM exception.
TL;DR
Make sure the ImageView has match_parent or fixed dp as dimensions
wrap_content makes Glide load full resolution Bitmaps.
.placeholder() shows an image instead of empty space while loading large bitmap
.thumbnail(float) loads a downsampled version fast while the bigger image is loading in the background
Also look around the Glide issues, maybe you find something helpful.
Details
I would be curious what the xml is for the ImageView, because my guess is it's wrap_content which results in loading images at full resolution into Bitmaps (using a lot of memory). If that's the case I would suggest using match_parent or fixed dp to lower the resolution. Note: you won't use detail, because currently the image is downsampled at render time anyway, just pulling that forward to decoding phase.
You also have to make sure that your app doesn't have constraints for memory usage. Can you load 3 (off screen limit = 1 means 1+current+1 pages) camera photos into Bitmaps without Glide? Again, assuming this is full resolution, it should be possible to store 3 screen size amount of bytes in memory with or without Glide, but you have to guide Glide to not load at full resolution.
You can load smaller sized image via .thumbnail(), it accepts a full Glide.with... not including .into() OR there's a shorthand parameter which is just a percentage (in 0.0 ... 1.0), try the latter first. It should decode the image much faster, especially with a really small number like 0.1 and then when higher quality one finishes it's replaced.
So the simpler option is to add .thumbnail() to your current load. A more convoluted one involves to start loading a lower resolution image with .sizeMultiplier() at the same time the Fragment's view is created and then start loading the high resolution one when the ViewPager has changed page. This helps with peeking the pages.
Alternatively you can just use a .placeholder() while the image is loading so it's not empty space, but "something" there.
Regarding using ARGB_8888 (32 bit per pixel): if you increase the memory consumed by Bitmaps (compared to RGB_565 (16 bit per pixel) don't expect to get run out of memory later. Once you get it working with 565 you can try increasing, but until then it's futile trying.
Also look around the Glide issues, maybe you find something helpful.
I know that ,according to android docs, that if you have a big image. Then you scale it down to size of the image view you are loading it to (using the decodeResources and Options class).
Now my question is, lets say you want to load background picture and the source image is of similar size, do you just load the image? Or do you actually scale it down a bit and then using the FITXY to stretch it?
I am trying to avoid Out Of Memory exceptions here
Thank you
I am writing a Android app which need to display some high quality picture(took from professional DSLR). The problem is it can't be display from gallery.
I choose a photo in Gallery first. The target picture is 2464*1632 JPEG, roughly 4.5M;
Then I just need to compress it to 800*600 and display it in imageview:
image.setImageBitmap(this.bmp);
Thing is that I have tested other image I downloaded form internet(really low quality), and it works without any problem. Can anybody tell me why it can't be displayed? I will be really appericiated
Large images are tricky to handle due to limited memory. You have several choices:
Use a WebView (this allows you to have pinch and zoom functionality to make use of those extra pixels
Decode the image down to the size of the display and then put it in an ImageView using BitmapOpts http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html and changing inSampleSize. It seems you may be having difficulty with that, so consider using createScaledBitmap which just needs the dest width and height.