关于java:如何在不降低质量和保持纵横比的情况下减少图像?

How to reduce image without losing quality and preserving the aspect ratio?

本问题已经有最佳答案,请猛点这里访问。

我有图像3264х2448

我将它加载到位图crudeImage = BitmapFactory.decodeFile(picturePath);然后设置为ImageView imageCrop.setImageBitmap(crudeImage);
问题是它非常大(3264х2448)和我的库裁剪器

这张图片工作得很慢。
我想将图像缩小到更小的尺寸。 但要保持质量和比例。 如何才能做到这一点?


您应该阅读有效加载大位图。

基本上,首先计算样本量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}

然后使用样本大小加载图像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
}


如果你在这里阅读教程,你会看到谷歌为你提供了一个非常全面的指南,指导如何在没有过多内存使用的情况下缩放位图。

特别是,这两种方法(来自教程):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;
}

在保持纵横比的同时完成缩放。

这两种方法的技巧是第一个解码操作设置为仅解码图像的属性(维度和其他信息),如下所示:

1
options.inJustDecodeBounds = true;

其中新的比例因子通过calculateInSampleSize()方法按比例计算。

然后再次解码图像,这次是

1
options.inJustDecodeBounds = false;

以及比例因子设置,因此位图工厂在解码时自动缩放,减少了内存占用。

关于图像需要解码的分辨率,这实际上取决于您的用例。但是,如果特定图像不需要稍后放大,则只需要设备的物理屏幕尺寸,可以通过以下方式获得:

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

其中object size将保存设备的屏幕大小。


我用它来调整我的位图的大小。也许对你有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

我希望这对你有帮助。