I recently read an article on how to load bitmaps into memory in an efficient manner from here. Obviously, there are a lot of libraries that can care of this but I felt that knowing the theory behind it was helpful for me and I wanted to summarize the key points from the article here:
-
How to load bitmap into Memory: We can decode an image using
BitmapFactory
class.Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); imageView.setImageBitmap(bitmap);
- The above code will fetch an image from the
Drawable
folder, load it into memory and display in theImageView
. This means that when you check the image size when loaded into memory, you can see that it will be larger than the image size on disk. - You can use
bitmap.getByteCount()
to check the image size. - This is because the image is compressed when it is on disk (stored in a JPG, PNG, or similar format). Once you load the image into memory, it is no longer compressed and takes up as much memory as is necessary for all the pixels.
- In order to get the size of the image without loading it into memory: we can use
BitmapFactory.Options
.BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // -> We set inJustDecodeBounds to true to make sure that the image is not loaded to memory BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);
- The above code will fetch an image from the
-
How to reduce Image size in Memory: We can use
inSampleSize
from theBitmapFactory.Options
. For instance, if we have an image with size 1000x1000 and if we set theinSampleSize
to 2, then the image will be scaled to 500x500.BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; options.inSampleSize = 3; // -> We can set a value to inSampleSize to scale the image BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);
This step is done because: it’s not worth loading a 1024x768 pixel image into memory if it will eventually be displayed in a 128x96 pixel thumbnail in an ImageView. Instead of providing a constant value (which might not work since our images might be of different sizes), we can also calculate the
inSampleSize
value:public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
Now we need to set the
inJustDecodeBounds
value to true again before we can display it in theImageView
. The full code for the above implementation:BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; options.inSampleSize = calculateInSampleSize(options, 500,500); options.inJustDecodeBounds = false; Bitmap smallBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options); imageView.setImageBitmap(smallBitmap);
Now if you check the bitmap size again, you will notice that it will have reduced significantly.
-
How to reduce the size of image in disk: We can use the
compress
method in theBitmap
class. We can pass the bitmap type, the quality and theByteArrayOutputStream
to thecompress
method.ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); byte[] bitmapdata = bos.toByteArray();
Note: The value 100 means the quality is not changed. If we set the value to 50, the image size would reduce significantly. Note: Also, please keep in mind that quality cannot be changed in png format, only in jpeg format.