Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Reduce image file size

I have an URI image file, and I want to reduce its size to upload it. Initial image file size depends from mobile to mobile (can be 2MB as can be 500KB), but I want final size to be about 200KB, so that I can upload it.
From what I read, I have (at least) 2 choices:

  • Using BitmapFactory.Options.inSampleSize, to subsample original image and get a smaller image;
  • Using Bitmap.compress to compress the image specifying compression quality.

What's the best choice?


I was thinking to initially resize image width/height until width or height is above 1000px (something like 1024x768 or others), then compress image with decreasing quality until file size is above 200KB. Here's an example:

int MAX_IMAGE_SIZE = 200 * 1024; // max final file size Bitmap bmpPic = BitmapFactory.decodeFile(fileUri.getPath()); if ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) {     BitmapFactory.Options bmpOptions = new BitmapFactory.Options();     bmpOptions.inSampleSize = 1;     while ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) {         bmpOptions.inSampleSize++;         bmpPic = BitmapFactory.decodeFile(fileUri.getPath(), bmpOptions);     }     Log.d(TAG, "Resize: " + bmpOptions.inSampleSize); } int compressQuality = 104; // quality decreasing by 5 every loop. (start from 99) int streamLength = MAX_IMAGE_SIZE; while (streamLength >= MAX_IMAGE_SIZE) {     ByteArrayOutputStream bmpStream = new ByteArrayOutputStream();     compressQuality -= 5;     Log.d(TAG, "Quality: " + compressQuality);     bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpStream);     byte[] bmpPicByteArray = bmpStream.toByteArray();     streamLength = bmpPicByteArray.length;     Log.d(TAG, "Size: " + streamLength); } try {     FileOutputStream bmpFile = new FileOutputStream(finalPath);     bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpFile);     bmpFile.flush();     bmpFile.close(); } catch (Exception e) {     Log.e(TAG, "Error on saving file"); } 

Is there a better way to do it? Should I try to keep using all 2 methods or only one? Thanks

like image 207
KitKat Avatar asked Jun 16 '12 06:06

KitKat


People also ask

How do I reduce the MB size of a photo?

The Photo Compress app available at Google Play does the same thing for Android users. Download the app and launch it. Select the photos to compress and adjust the size by choosing Resize Image. Be sure to keep the aspect ratio on so the resizing doesn't distort the height or width of the photo.

How do I compress file size on Android?

Step 1: Launch ES File Explorer and navigate to the files you want to compress. Step 2: Long-press on a folder to compress the whole folder. Step 3: After you've selected all the files for your ZIP file, tap on "More," then select "Compress."


2 Answers

Using Bitmap.compress() you just specify compression algorithm and by the way compression operation takes rather big amount of time. If you need to play with sizes for reducing memory allocation for your image, you exactly need to use scaling of your image using Bitmap.Options, computing bitmap bounds at first and then decoding it to your specified size.

The best sample that I found on StackOverflow is this one.

like image 168
teoREtik Avatar answered Oct 14 '22 11:10

teoREtik


Most of the answers i found were just pieces that i had to put together to get a working code, which is posted below

 public void compressBitmap(File file, int sampleSize, int quality) {         try {            BitmapFactory.Options options = new BitmapFactory.Options();             options.inSampleSize = sampleSize;             FileInputStream inputStream = new FileInputStream(file);              Bitmap selectedBitmap = BitmapFactory.decodeStream(inputStream, null, options);             inputStream.close();              FileOutputStream outputStream = new FileOutputStream("location to save");             selectedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);             outputStream.close();             long lengthInKb = photo.length() / 1024; //in kb             if (lengthInKb > SIZE_LIMIT) {                compressBitmap(file, (sampleSize*2), (quality/4));             }              selectedBitmap.recycle();         } catch (Exception e) {             e.printStackTrace();         }     } 

2 parameters sampleSize and quality plays an important role

sampleSize is used to subsample the original image and return a smaller image, ie
SampleSize == 4 returns an image that is 1/4 the width/height of the original.

quality is used to hint the compressor, input range is between 0-100. 0 meaning compress for small size, 100 meaning compress for max quality

like image 22
Mightian Avatar answered Oct 14 '22 12:10

Mightian