3

I want to reduce the image file size below 100 KB while preserving the image quality like whatsapp and facebook did.

I tried almost all the code of android image compression available on stackoverflow but that doesn't work for me.

Right now i am following this blog to reduce the image size, and i am getting the image below 100 KB but image quality is poor.

Is there any way that i can reduce image size below 100 KB while preserving the quality??? (Original Image size can vary from 20 KB to 8 MB)

I tried JAI library in Java Project, and it work good.

Can i Use JAI library in android to reduce image size???

Thanks in Advance.

Source Code to compress an Image:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.media.ExifInterface;
import android.os.Environment;
import android.util.Log;

public class CompressBitmap {

    private String path;
    public CompressBitmap(String path){
        this.path= path;
    }

    public ByteArrayOutputStream getBitmap(){
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        getscaledImage(path).compress(Bitmap.CompressFormat.JPEG, 100, outStream);
        return outStream;
    }

    public ByteArrayOutputStream getBitmap(int quality){
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        getscaledImage(path).compress(Bitmap.CompressFormat.JPEG, quality, outStream);  
        return outStream;
    }

    public String getComressFile(){
        FileOutputStream out = null;
        String filename = createImageFile();
        try {
            out = new FileOutputStream(filename);
            getscaledImage(path).compress(Bitmap.CompressFormat.JPEG, 80, out);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        File file = new File(filename);
        Log.e("SIze of Image","Length"+file.length());
        return filename;
    }

    private Bitmap getscaledImage(String filePath){
        Bitmap scaledBitmap = null;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;                      
        Bitmap bmp = BitmapFactory.decodeFile(filePath,options);

        int actualHeight = options.outHeight;
        int actualWidth = options.outWidth;
        float maxHeight = 800.0f;
        float maxWidth = 600.0f;
        float imgRatio = actualWidth / actualHeight;
        float maxRatio = maxWidth / maxHeight;

        Log.v("Pictures", "Before scaling Width and height are " + actualWidth + "--" + actualHeight);

        if (actualHeight > maxHeight || actualWidth > maxWidth) {
            if (imgRatio < maxRatio) {
                imgRatio = maxHeight / actualHeight;
                actualWidth = (int) (imgRatio * actualWidth);
                actualHeight = (int) maxHeight;
            } else if (imgRatio > maxRatio) {
                imgRatio = maxWidth / actualWidth;
                actualHeight = (int) (imgRatio * actualHeight);
                actualWidth = (int) maxWidth;
            } else {
                actualHeight = (int) maxHeight;
                actualWidth = (int) maxWidth;     
            }
        }

        options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
        options.inJustDecodeBounds = false;
        options.inDither = false;
        options.inPurgeable = true;
        options.inInputShareable = true;
        options.inTempStorage = new byte[16*1024];

        try{    
            bmp = BitmapFactory.decodeFile(filePath,options);
        }
        catch(OutOfMemoryError exception){
            exception.printStackTrace();

        }
        try{
            scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
        }
        catch(OutOfMemoryError exception){
            exception.printStackTrace();
        }

        float ratioX = actualWidth / (float) options.outWidth;
        float ratioY = actualHeight / (float)options.outHeight;
        float middleX = actualWidth / 2.0f;
        float middleY = actualHeight / 2.0f;

        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);

        Canvas canvas = new Canvas(scaledBitmap);
        canvas.setMatrix(scaleMatrix);
        canvas.drawBitmap(bmp, middleX - bmp.getWidth()/2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));

        Log.v("Pictures", "After scaling Width and height are " + scaledBitmap.getWidth() + "--" + scaledBitmap.getHeight());

        ExifInterface exif;
        try {
            exif = new ExifInterface(filePath);

            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
            Log.d("EXIF", "Exif: " + orientation);
            Matrix matrix = new Matrix();
            if (orientation == 6) {
                matrix.postRotate(90);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 3) {
                matrix.postRotate(180);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 8) {
                matrix.postRotate(270);
                Log.d("EXIF", "Exif: " + orientation);
            }
            scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return scaledBitmap;
    }

    private String createImageFile(){
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",Locale.getDefault()).format(new Date());
            String imageFileName = "JPEG_" + timeStamp + "_";
            File storageDir = Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES);
            File image;
            try {
                image = File.createTempFile(
                    imageFileName,  /* prefix */
                    ".jpg",         /* suffix */
                    storageDir      /* directory */
                );
                return image.getAbsolutePath();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
    }

    private 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 heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        final float totalPixels = width * height;
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;

        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }
        return inSampleSize;
    }
}

public void getBase64() {
    CompressBitmap compressBitmap =  new CompressBitmap(picturePath);  
    //display compressBitmap in ImageView.

    byte[] bytes=null;

    File file= new File(picturePath);               

    ByteArrayOutputStream bos = compressBitmap.getBitmap();
    bytes = bos.toByteArray(); 
    base64 = Base64.encodeToString(bytes, Base64.DEFAULT);

    return base64;   // send base64 String on server
}
user3607917
  • 474
  • 4
  • 16
  • i dont know if it's available in your android version but maybe you could try this http://stackoverflow.com/questions/1069095/how-do-you-create-a-thumbnail-image-out-of-a-jpeg-in-java or use this library instead https://code.google.com/p/thumbnailator/ – Jenson Aug 11 '14 at 13:51
  • If you want to reduce (mem)size, you will always lose some information. You can crop an Image, reduce dpi or downscale it (or a combination of all). I guess what you want is downscaling without reducing dpi? Please clearify what you mean exactly with "Quality". – Fildor Aug 11 '14 at 13:55
  • Thanks jenson for your quick reply. Any answer regarding android will be very helpful to me. – user3607917 Aug 11 '14 at 13:55
  • @Flidor I don't want to crop an image. I tried with downscale the image using inSampleSize while maintaining the aspect ratio but the output image i get is either large or of poor quality. – user3607917 Aug 11 '14 at 14:05
  • Can you please show us some code? – Fildor Aug 11 '14 at 14:11
  • It's not clear from your question if you are trying to reduce the file size of an image stored on disk, or the number of bytes required for an image loaded into a bitmap. Which is it? – x-code Aug 11 '14 at 14:26
  • I want to reduce the image size so that image will take less time to upload on server and occupy less space on database. – user3607917 Aug 11 '14 at 15:16
  • @Jenson Thumbnailator is too good.. but unfortunately its not available for android. :-( As mention by developer of the Thumbnailator library "coobird" , in this link (http://stackoverflow.com/questions/11081598/is-there-any-open-source-library-is-available-in-android-for-resizing-the-image). – user3607917 Aug 11 '14 at 15:30
  • @user3607917 Did you get the output what you are expected. If yes means please share the code. It will be helpful for me – MathankumarK Feb 11 '16 at 09:02

1 Answers1

0

Missing seems:

options.inPreferQualityOverSpeed = true;
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • @ Joop Thanks for your answer. but still image quality is low for my code. Any other suggestion will be very helpful for me. – user3607917 Aug 12 '14 at 04:21