Decrease image size without losing its quality in android

AndroidImageBitmap

Android Problem Overview


How to decrease image size without losing its quality in android.
I have a ImageView in my project,I have to put a larger size image in it.
I am new to android.
please help.

Android Solutions


Solution 1 - Android

Below code Working for scale image as aspect ratio:

Bitmap bitmapImage = BitmapFactory.decodeFile("Your path");
int nh = (int) ( bitmapImage.getHeight() * (512.0 / bitmapImage.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(bitmapImage, 512, nh, true);
your_imageview.setImageBitmap(scaled);

Compress your image without losing quality like whatsapp

public String compressImage(String imageUri) {

        String filePath = getRealPathFromURI(imageUri);
        Bitmap scaledBitmap = null;

        BitmapFactory.Options options = new BitmapFactory.Options();

//      by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If
//      you try the use the bitmap here, you will get null.
        options.inJustDecodeBounds = true;
        Bitmap bmp = BitmapFactory.decodeFile(filePath, options);

        int actualHeight = options.outHeight;
        int actualWidth = options.outWidth;

//      max Height and width values of the compressed image is taken as 816x612

        float maxHeight = 816.0f;
        float maxWidth = 612.0f;
        float imgRatio = actualWidth / actualHeight;
        float maxRatio = maxWidth / maxHeight;

//      width and height values are set maintaining the aspect ratio of the image

        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;

            }
        }

//      setting inSampleSize value allows to load a scaled down version of the original image

        options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);

//      inJustDecodeBounds set to false to load the actual bitmap
        options.inJustDecodeBounds = false;

//      this options allow android to claim the bitmap memory if it runs low on memory
        options.inPurgeable = true;
        options.inInputShareable = true;
        options.inTempStorage = new byte[16 * 1024];

        try {
//          load the bitmap from its path
            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));

//      check the rotation of the image and display it properly
        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();
        }

        FileOutputStream out = null;
        String filename = getFilename();
        try {
            out = new FileOutputStream(filename);

//          write the compressed bitmap at the destination specified by filename.
            scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        return filename;

    }

    public String getFilename() {
        File file = new File(Environment.getExternalStorageDirectory().getPath(), "MyFolder/Images");
        if (!file.exists()) {
            file.mkdirs();
        }
        String uriSting = (file.getAbsolutePath() + "/" + System.currentTimeMillis() + ".jpg");
        return uriSting;

    }

    private String getRealPathFromURI(String contentURI) {
        Uri contentUri = Uri.parse(contentURI);
        Cursor cursor = getContentResolver().query(contentUri, null, null, null, null);
        if (cursor == null) {
            return contentUri.getPath();
        } else {
            cursor.moveToFirst();
            int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            return cursor.getString(index);
        }
    }

    public 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;
    }

Solution 2 - Android

> Create Class For CompressFile Image

    public class CompressFile {
        public static File getCompressedImageFile(File file, Context mContext) {
            try {
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
    
                if (getFileExt(file.getName()).equals("png") || getFileExt(file.getName()).equals("PNG")) {
                    o.inSampleSize = 6;
                } else {
                    o.inSampleSize = 6;
                }
    
                FileInputStream inputStream = new FileInputStream(file);
                BitmapFactory.decodeStream(inputStream, null, o);
                inputStream.close();
    
                // The new size we want to scale to
                final int REQUIRED_SIZE = 100;
    
                // Find the correct scale value. It should be the power of 2.
                int scale = 1;
                while (o.outWidth / scale / 2 >= REQUIRED_SIZE &&
                        o.outHeight / scale / 2 >= REQUIRED_SIZE) {
                    scale *= 2;
                }
    
                BitmapFactory.Options o2 = new BitmapFactory.Options();
                o2.inSampleSize = scale;
                inputStream = new FileInputStream(file);
    
                Bitmap selectedBitmap = BitmapFactory.decodeStream(inputStream, null, o2);
    
                ExifInterface ei = new ExifInterface(file.getAbsolutePath());
                int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                        ExifInterface.ORIENTATION_UNDEFINED);
    
                switch (orientation) {
    
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        selectedBitmap = rotateImage(selectedBitmap, 90);
                        break;
    
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        selectedBitmap = rotateImage(selectedBitmap, 180);
                        break;
    
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        selectedBitmap = rotateImage(selectedBitmap, 270);
                        break;
    
                    case ExifInterface.ORIENTATION_NORMAL:
    
                    default:
                        break;
                }
                inputStream.close();
    
    
                // here i override the original image file
                File folder = new File(Environment.getExternalStorageDirectory() + "/FolderName");
                boolean success = true;
                if (!folder.exists()) {
                    success = folder.mkdir();
                }
                if (success) {
                    File newFile = new File(new File(folder.getAbsolutePath()), file.getName());
                    if (newFile.exists()) {
                        newFile.delete();
                    }
                    FileOutputStream outputStream = new FileOutputStream(newFile);
    
                    if (getFileExt(file.getName()).equals("png") || getFileExt(file.getName()).equals("PNG")) {
                        selectedBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
                    } else {
                        selectedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
                    }
    
                    return newFile;
                } else {
                    return null;
                }
            } catch (Exception e) {
                return null;
            }
        }
    
        public static String getFileExt(String fileName) {
            return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
        }
    
        public static Bitmap rotateImage(Bitmap source, float angle) {
            Matrix matrix = new Matrix();
            matrix.postRotate(angle);
            return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
                    matrix, true);
        }
    }

Solution 3 - Android

Use this code for compress bitmap in lower size.

BitmapFactory.Options Options = new BitmapFactory.Options();
Options.inSampleSize = 4;
Options.inJustDecodeBounds = false;
action_bitmap = BitmapFactory.decodeFile(Glob.savedImage, Options);

Glob.savedImage is String path of image.

Solution 4 - Android

// we'll start with the original picture already open to a file

File imgFileOrig = getPic(); //change "getPic()" for whatever you need to open the image file.
Bitmap b = BitmapFactory.decodeFile(imgFileOrig.getAbsolutePath());
// original measurements
int origWidth = b.getWidth();
int origHeight = b.getHeight();

final int destWidth = 600;//or the width you need

if(origWidth > destWidth){
         // picture is wider than we want it, we calculate its target height
          int destHeight = origHeight/( origWidth / destWidth ) ;
         // we create an scaled bitmap so it reduces the image, not just trim it
          Bitmap b2 = Bitmap.createScaledBitmap(b, destWidth, destHeight, false);
          ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            // compress to the format you want, JPEG, PNG... 
            // 70 is the 0-100 quality percentage
    b2.compress(Bitmap.CompressFormat.JPEG,70 , outStream);
            // we save the file, at least until we have made use of it
           File f = new File(Environment.getExternalStorageDirectory()
                    + File.separator + "test.jpg");
           f.createNewFile();
           //write the bytes in file
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(outStream.toByteArray());
           // remember close de FileOutput
    fo.close();
}

Solution 5 - Android

The accepted answer works fine when grabbing an image from gallery, but when trying to get an image from the file manager, it fails. The reason is that the Uri has a different format that getRealPathFromURI(imageUri) doesn't manage to get the real path from it.

In order to solve this issue, use the same methods of the accepted answer except for copressImage() & getRealPathFromURI() which are tweaked to support both images grabbed from file manger & gallery:

public static String compressImage(Context context, Uri uri) {

	String filePath = getRealPathFromURI(context, uri);
	Bitmap scaledBitmap = null;

	BitmapFactory.Options options = new BitmapFactory.Options();

//      by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If
//      you try the use the bitmap here, you will get null.
	options.inJustDecodeBounds = true;
	Bitmap bmp = BitmapFactory.decodeFile(filePath, options);

	int actualHeight = options.outHeight;
	int actualWidth = options.outWidth;

//      max Height and width values of the compressed image is taken as 816x612

	float maxHeight = 816.0f;
	float maxWidth = 612.0f;
	float imgRatio = actualWidth / actualHeight;
	float maxRatio = maxWidth / maxHeight;

//      width and height values are set maintaining the aspect ratio of the image

	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;

		}
	}

//      setting inSampleSize value allows to load a scaled down version of the original image

	options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);

//      inJustDecodeBounds set to false to load the actual bitmap
	options.inJustDecodeBounds = false;

//      this options allow android to claim the bitmap memory if it runs low on memory
	options.inPurgeable = true;
	options.inInputShareable = true;
	options.inTempStorage = new byte[16 * 1024];

	try {
//          load the bitmap from its path
		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));

//      check the rotation of the image and display it properly
	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();
	}

	FileOutputStream out = null;
	String filename = getFilename();
	try {
		out = new FileOutputStream(filename);

//          write the compressed bitmap at the destination specified by filename.
		scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);

	} catch (FileNotFoundException e) {
		e.printStackTrace();
	}

	return filename;

}

 public static String getRealPathFromURI(Context context, Uri uri) {
	Uri queryUri = MediaStore.Files.getContentUri("external");
	String columnData = MediaStore.Files.FileColumns.DATA;
	String columnSize = MediaStore.Files.FileColumns.SIZE;

	String[] projectionData = {MediaStore.Files.FileColumns.DATA};


	String name = null;
	String size = null;

	Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
	if ((cursor != null) && (cursor.getCount() > 0)) {
		int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
		int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);

		cursor.moveToFirst();

		name = cursor.getString(nameIndex);
		size = cursor.getString(sizeIndex);

		cursor.close();
	}

	String imagePath = "";
	if ((name != null) && (size != null)) {
		String selectionNS = columnData + " LIKE '%" + name + "' AND " + columnSize + "='" + size + "'";

		Cursor cursorLike = context.getContentResolver().query(queryUri, projectionData, selectionNS, null, null);

		if ((cursorLike != null) && (cursorLike.getCount() > 0)) {
			cursorLike.moveToFirst();
			int indexData = cursorLike.getColumnIndex(columnData);
			if (cursorLike.getString(indexData) != null) {
				imagePath = cursorLike.getString(indexData);
			}
			cursorLike.close();
		}
	}

	return imagePath;
}

Solution 6 - Android

For Compressing image using JPEG compression and maintaining transparency like PNG use this code. It worked for me.

Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
        Canvas canvas = new Canvas(newBitmap);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(bitmap, 0, 0, null);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        newBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outputStream);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMainak MukherjeeView Question on Stackoverflow
Solution 1 - AndroidJitty AandyanView Answer on Stackoverflow
Solution 2 - AndroidMohsinaliView Answer on Stackoverflow
Solution 3 - AndroidThoriya PrahaladView Answer on Stackoverflow
Solution 4 - AndroidDeepak guptaView Answer on Stackoverflow
Solution 5 - AndroidZainView Answer on Stackoverflow
Solution 6 - AndroidFaris MuhammedView Answer on Stackoverflow