2

I have image 3264х2448.

I load it in bitmap crudeImage = BitmapFactory.decodeFile(picturePath); then set to the ImageView imageCrop.setImageBitmap(crudeImage); the problem is that it very big(3264х2448) and my library cropper

work very slowly with this image. I want reduce the image to a smaller size. but to preserve the quality and proportion. how can this be done?

ip696
  • 6,574
  • 12
  • 65
  • 128

3 Answers3

2

You should read Loading Large Bitmaps Efficiently.

Essentially, calculate the sample size first by

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

then load the image using the sample size:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}
goofyz
  • 243
  • 4
  • 10
  • maybe it's silly, but I can not understand. I have a ready bitmap. How do I fix method decodeSampledBitmapFromResource? I want to give him a bitmap – ip696 Apr 30 '15 at 03:58
  • Use `BitmapFactory.decodeFile(path, options)` instead. You can read other related methods of `BitmapFactory` from the [doc](http://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeFile%28java.lang.String%29) – goofyz Apr 30 '15 at 04:20
0

I use this to resize my bitmap's. Maybe can be useful for you.

public Bitmap resizeBitmap(Bitmap bitmap, int newWidth, int newHeight)
{
    //bitmap it's the bitmap you want to resize
    //newWidth and newHeight are the with and height that you want to the new bitmap
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) /height;

    Matrix matrix = new Matrix();
    matrix.postScale(scaleWidth, scaleHeight);

    Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
    return resizedBitmap;
}

I hope this help you.

Alberto Alegria
  • 1,023
  • 10
  • 26
  • int newWidth, int newHeight - Here's the problem. I do not know what to put. because on the big screen on a powerful phone need such as the old 1280x720 800x600 – ip696 Apr 30 '15 at 03:48
0

If you read the tutorial here you'll see google gives you a very comprehensive guide on how to scale bitmaps without excessive memory usage.

In particular, these two methods (from the tutorial):

public static Bitmap decodeSampledBitmapFromResource(File file, int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(file, options);

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(file, options);
}

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

Will accomplish your scaling whilst preserving aspect ratio.

The trick with these two methods is that the first decode operation is set to only decode the image's properties (dimensions and other information) as set by:

options.inJustDecodeBounds = true;

in which the new scale factor is calculated proportionally by the method calculateInSampleSize().

Then the image is decoded again, this time with

options.inJustDecodeBounds = false;

as well as the scale factor set, so the bitmap factory automatically scales whilst decoding, reducing the memory footprint.

Regarding what resolution the image needs to be decoded to, that really depends on your use-case. But, if the particular image does not need to be zoomed in later, you need no more than the device's physical screen size, which can be obtained via:

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);

in which object size will hold the device's screen size.

initramfs
  • 8,275
  • 2
  • 36
  • 58