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

时间:2015-04-30 03:36:53

标签: java android bitmap

我有图片3264х2448

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

使用此图片工作得非常慢。 我想将图像缩小到更小的尺寸。但要保持质量和比例。怎么办呢?

3 个答案:

答案 0 :(得分:2)

您应该阅读Loading Large Bitmaps Efficiently

基本上,首先按

计算样本量
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;
}

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

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 :(得分:0)

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

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

我希望这对你有所帮助。

答案 2 :(得分:0)

如果您阅读了教程here,那么您会看到谷歌为您提供有关如何在不占用大量内存的情况下扩展位图的非常全面的指南。

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

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

在保持宽高比的同时完成缩放。

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

options.inJustDecodeBounds = true;

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

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

options.inJustDecodeBounds = false;

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

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

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

对象size将保存设备的屏幕尺寸。