0

I am trying to reduce the size of the bitmap after taking the picture. I am able to reduce the size to max 900kb but I wan to reduce it further as much as possible

First I do this:

public static Bitmap decodeSampledBitmapFromResource(byte[] data,
                                                     int reqWidth, int reqHeight) {
 //reqWidth is 320
//reqHeight is 480
    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeByteArray(data, 0, data.length, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    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;

        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

then this

bitmap.compress(Bitmap.CompressFormat.PNG, 10, fos);

How do i compress the bitmap further ? or Should I compress the byte[] instead? I just want to send documents, black and white.

android_eng
  • 1,370
  • 3
  • 17
  • 40

2 Answers2

2

I know that the question has some time, but I think this answer could help someone.

There are three methods to compress your picture (the "byte[] data" you have recieved from the Camera):

1) PNG format -> It's the worst choice when the image has a lot of different colors, and in general, this is the case when you take a photo. The PNG format is more useful in images like logotypes and stuff like this.

The code:

String filename = "" //THE PATH WHERE YOU WANT TO PUT YOUR IMAGE
File pictureFile = new File(filename);

try{ //"data" is your "byte[] data" 
    FileOutputStream fos = new FileOutputStream(pictureFile);
    Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
    bmp.compress(Bitmap.CompressFormat.PNG, 100, fos); //100-best quality
    fos.write(data);
    fos.close();
} catch (Exception e){
    Log.d("Error", "Image "+filename+" not saved: " + e.getMessage());
}

2) JPG format -> It's a better option with an image with a lot of colors (the algoritm to compress is very different than PNG), but it does not have the 'alpha channel' that could be necesary in some scenarios.

There is only one change from the previous code:

bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos); //100-best quality

3) WebP format -> It's the best format by far. An image of 1.0 MB in PNG could be compress to 100-200KB in JPG, and only to 30-50 KB in WebP. This format has also the 'alpha channel'. But it's not perfect: some browsers are not compatible with it. So you have to be careful about this in your project.

There is only one change from the previous code:

bmp.compress(Bitmap.CompressFormat.WEBP, 100, fos); //100-best quality

NOTES:

1) If this level of compress is not enought, you can play with the quality of the compress (the '100' that you can see in the bmp.compress() method). Be careful with the quality in the JPEG, because in some cases with a quality of 80%, you can see the impact in the image easyly. In PNG and WebP formats the loss percentage has less impact.

2) The other way to reduce the size is to resize the image. The easiest way I found is to simply create a smaller bitmap through Bitmap.createScaledBitmap method (more info).

3) And the last one method is to put the image in black and white. You can do this with this method:

Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);

PS 1 - If someone wants to have a deeper knowledge about the image compress methods in Android, I recommend this talk by Colt McAnlis in the Google I/O 2016 (link).

Pablo Insua
  • 852
  • 11
  • 19
  • Regarding the 3-rd note, I am not sure that converting an image to grayscale will reduce its size. I've tested this a while ago and for me the size of the output file was the same. – Avtontom_ Mar 13 '18 at 14:12
  • What method to compress do you use after convert the image to grayscale? – Pablo Insua Mar 14 '18 at 15:36
1

You should use jpg instead of png if the alpha channel is not needed. Also you can change the color config of your output bitmap:

// Decode bitmap with inSampleSize set
options.inPreferredConfig= Bitmap.Config.RGB_565;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(data, 0, data.length, options);
Andre Classen
  • 3,868
  • 3
  • 26
  • 36
  • are there any other options I can set to make it grayscale ? – android_eng Sep 02 '15 at 20:25
  • 1
    To convert your image to grayscale you can take a look here: http://stackoverflow.com/questions/8381514/android-converting-color-image-to-grayscale But this will not reduce your filesize. – Andre Classen Sep 02 '15 at 20:29