This answer is summarized from the article Loading large bitmaps Efficiently,
which explains how to use inSampleSize
to carry a bitmap
low-scale
In particular, Pre-scaling bitmaps explains the details of various methods,
including how to combine them, and which ones are more efficient for device memory.
There are three dominant paths to resize a bitmap on Android, where each has different memory properties:
createScaledBitmap API
This API will take on an existing bitmap and create a NEW bitmap with the exact dimensions you selected.
On the plus side, you can get exactly the image size you are looking for. The downside is that this API requires a bitmap
existing to work. That is, the image would have to be loaded, decoded and a bit map created, before being able to create a new version , smaller .
This procedure is ideal for obtaining its exact dimensions , but horrible in terms of additional memory overload. Most application developers who tend to worry about memory avoid using this method.
inSampleSize flag
BitmapFactory.Options
has a property referenced as inSampleSize
which will resize your image and decode it at the same time, to avoid the decoding process for a bitmap
temporary.
The value whole used here will load the image reducing to half its size. Basically, the result will always be a factor of 2 times smaller than your source image.
When we talk about memory, inSampleSize
is an extremely fast operation. Effectively, it will decode every pixel of your image. However, there are two major problems when using inSampleSize
:
You will not have exact resolutions. This function only reduces the size of your bitmap by a factor of 2.
This function does not produce the best resizing quality. Many resize filters produce great-looking images by reading pixel blocks, and then weighing them to produce the pixel in question. inSampleSize
avoids all this just by reading each pixel. The result is high performance and low memory, but the quality remains to be desired.
If you are only dealing with reducing your image by a small factor, and filtering is not a problem, then you will not find such an efficient method of memory as the inSampleSize
.
inScaled, inDensity, inTargetDensity flags
If you need to resize an image to a dimension that is not reachable with the factor of 2, then you will need to use the flags of the BitmapOptions
: inScaled
, inDensity
and inTargetDensity
. When inScaled
is set, the system will fetch the appropriate scale value to apply to your bitmap by dividing the values of inTargetDensity
for inDensity
.
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// este método carrega e redimensiona a imagem para a dimensão de 1/inSampleSize
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
Using this method will resize your image and also apply a resize filter. The result will apparently be much better due to the additional math involved during the resize step. But pay attention: This extra step requires longer processing time, and can quickly solve problems for large images resulting in smaller dimensions and extra memory allocation for the filter.
It is generally not a good idea to apply this technique to an image that is significantly larger than the desired size due to the extra cost of filter memory.
Combining Memory and Performance
From the point of view of memory and performance, it is possible combine these options for best results. (Setting the flags inSampleSize
, inScaled
, inDensity
and inTargetDensity
).
inSampleSize
will be the first to be applied to the image, making it close to the factor of 2 times larger than the target size. Then, inDensity
& inTargetDensity
will be used to scale the result to the exact dimensions you want, applying an operation filter to clean the image.
Combining these two makes the operation much faster, since inSampleSize
will reduce the number of pixels where the filter needs to be applied.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// carrega e redimensiona a imagem para ser da dimensão de 1/inSampleSize
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
If you need to fit an image into specific dimensions and adding good image filters, so this technique is the best way to get the correct size, but done quickly and consuming little memory during operation.
Getting the image dimensions
Getting the image size without having to decode it completely.
To be able to resize your bitmap
, you will need to know the input dimensions. You can use the flag inJustDecodeBounds
to help you take the image dimensions without the need to decode the data.
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
// agora redimensione a imagem para o tamanho que você deseja
You can use this flag to decode the size first, then calculate the appropriate values to scale the resolution of your target image.
Do you know the Picasso? For those who deal with image, it is an essential library. Maybe he even optimises all this for you, I don’t know.
– Erick Filho