Fresco. How to get image size without loading full bitmap - android

I have some local images with unknown size. Format is jpeg.
The task is resize it to fit max size 1280x960 keeping original aspect ratio and save it to new file with low memory consumption. I found out very useful method in Fresco lib: JpegTranscoder.transcodeJpeg() operating streams. It has scaleNumerator param that rules downsampling. How can I get original bitmap size with Fresco without full bitmap loading to memory to calculate scaleNumerator value? Something like inJustDecodeBounds in android BitmapFactory.Options class

You should be able to use Fresco's BitmapUtil.decodeDimensions(...) for this.

Related

Why does Android BitmapFactory.decodeFile() want 4x the memory needed?

I have an 8MB png and when I try to load it into an Android ImageView I get an OutOfMemoryError that says it tried to allocate 32MB of memory and failed.
I'm working on changing the code to downsample the image to avoid using too much memory to avoid most of these problems, so I'm not looking for answers about downsampling. I'm trying to understand why the memory needs of the image are higher than the file size would imply.
Why is Android trying to allocate 4x the memory when loading the png?
I've set my options to tell it not to scale for pixel density:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inScaled = false;
It is 2848 x 4209 pixels
At the 4 bytes/pixel rate for ARGB_8888, that will be 47,948,928 bytes as a Bitmap.
The on-disk size of images represents a red herring. The major file formats (particularly PNG and JPEG) are compressed as files. That does not matter. What matters is the resolution and bit depth of the desired decoded image.
Also note that your image is bigger than the display resolution of most Android devices. Depending on your use case, you may wish to consider widgets like this one that can load and display portions of the image at a time.

How to decode a scaled bitmap from URL efficiently

I am designing an app which has to deal with large number of bitmaps with huge size from server. There are ways to decode
Option 1:
Create a buffered inputstream from image url
Decode only the bounds
Create scale factor/sample size
Create a buffered inputstream (again since bitmapfactory closes the stream once decoding is complete)
Decode the bitmap
Option 2
Create a buffered inputstream from image url
Decode the bitmap in its original size
Use bitmap.createScaledBitmap to create desired size.
With option 1, we need to download the bitmap twice where as with 2, we have to explicitly recycle the original sized bitmap which will trigger garbage collection which is a CPU intense operation.
Are there any other methods that can achieve this efficiently?
Option 3 :
Download a file to the local file system
use Option 1
ps. Option 2 will overflow your memory eventually. Highly not recommended.
Try to use inJustDecodeBounds. Set it to TRUE and load the file as it is.
The image won't be loaded into memory. But the outheight and outwidth properties of BitmapFactory.Options will contain the actual size params of the image specified. Calculate how much u want to subsample it. like 1/2 or 1/4 or 1/8 etc. and assign 2/4/8 etc. accordingly to the inSampleSize.
Now set inJustDecodeBounds to FALSE and call BitmapFactory.decodeFile() to load the image of the exact size as calculated above.

JPEG File seems to big: OutOfMemoryError

java.lang.OutOfMemoryError: Failed to allocate a 313194252 byte allocation with 11901284 free bytes and 174MB until OOM
I got this at this line:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.handskizze);
My Picture has a size of 2480*3508 at 300dpi.
Is it maybe to big? How can I make it smaller?
Whenever there is a requirement to load any image always try to use any ImageLoader library.
There are plenty of options available.
Here are some of the best libraries that developers uses. Try anyone of them which you fill easy to implement.
Universal Image Loader: https://github.com/nostra13/Android-Universal-Image-Loader
Picasso: http://square.github.io/picasso/
Glide: https://github.com/bumptech/glide
You can find some more libraries but I feel these 3 are used most.
In manifest use below attribute with application tag
android:largeHeap="true"
Also use
BitmapFactory.Options o=new BitmapFactory.Options();
o.inSampleSize = 2; //change value from 0 to 8 as per need and image resolution
myBitMap=BitmapFactory.decodeResource(getResources(),R.drawable.handskizze, o);
First of all, i would say your image is way too big for mobile devices. You should scale it down using Photoshop (or any other image editing software) to reduce its size. By doing so you minimize the size of your .apk and the processing time it takes to downscale the image.
Additionally, i would recomment you to use an image loader library. Im using the Universal Image Loader in most of my projects. It gets the measurement of the ImageView you want to load your image into, and downscales the image to reduce its size. You should give it a try ;)

Picasso's image loading using fit() method

If I am using Picasso's fit() method in loading images from online, do I have to consider using BitmapFactory.Options.inSampleSize options to reduce the size of an image? I read from other stackoverflow's question (Here) that:
You can also make use of the BitmapFactory.Options.inSampleSize
options to reduce the size of an image while it is loaded, rather than
loading in the entire image and then creating a small copy, which
wastes time and memory.
Do I have to do it after using fit()? Or it is already done by Picasso?
Thanks a lot.
Both fit() and explicit calls to resize() (or resizeDimen) will use inSampleSize automatically when it is appropriate to do so.
Because inSampleSize should be a power of two for best performance and quality, your image needs to be at least twice as large as the target size for this to occur.

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

Categories

Resources