仅在太大时才调整位图大小

Resize Bitmap only if too large

只有当照片太大(例如,宽度 > 2048 像素)时,我才想调整每张用相机拍摄的照片的大小。

我在官方文档上看到了

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

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

但是这段代码涉及到我知道最终尺寸。 我想做的是,如果它真的太大,则减少 50%,如果位图不是太大,则只减少 20%,等等(取决于智能手机的相机...)

calculateInSampleSize() 方法似乎做我想做的事,文档说“例如,分辨率为 2048x1536 的图像用 4 的 inSampleSize 解码产生大约 512x384 的位图”但我不想设置最终 width/height.

然后,当我得到较小的位图时,我想制作一个

scaledBitmap.compress(CompressFormat.JPEG, 80, out);

再次优化。

请问我该如何解决?

您可以获得位图的宽度和高度,如bitmap.getWidth()bitmap.getHeight()。获得宽度和高度后,检查哪个值较小。如果宽度小于高度,将 width 存储在一个名为 value 的变量中,否则存储 height.

然后您可以通过检查值来压缩位图,如下所示。

Bitmap bitmap = your bitmap;

int width = bitmap.getWidth();
int height = bitmap.getHeight();

int value;
if (width < height) {
    value = width;
} else {
    value = height;
}

Bitmap scaledBitmap;

if (value > 5000) {
    scaledBitmap = bitmap.compress(CompressFormat.JPEG, 80, out);
} else if (value > 4000) {
    scaledBitmap = bitmap.compress(CompressFormat.JPEG, 60, out);
} else if (value > 3000) {
    scaledBitmap = bitmap.compress(CompressFormat.JPEG, 40, out);
} else if (value > 2048) {
    scaledBitmap = bitmap.compress(CompressFormat.JPEG, 20, out);
}

最后我选择了另一个解决方案:

public static void resizeBitmapOnFileSystem(String originalPath, File photoCompressedFile) throws IOException {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(originalPath, options);

    int minimalLengthSide = 300; //Minimal length of the shorter side of the picture. Used to calculate the best 'scale' value.
    int scale = calculateInSampleSize(options, minimalLengthSide, minimalLengthSide);

    ByteArrayOutputStream out = null;
    FileOutputStream fo = null;
    Bitmap scaledBitmap = null;
    try {
        out = new ByteArrayOutputStream();
        fo = new FileOutputStream(photoCompressedFile);

        scaledBitmap = loadScaledBitmap(originalPath, scale);
        if (scaledBitmap != null) {
            scaledBitmap.compress(CompressFormat.JPEG, 75, out);
            fo.write(out.toByteArray());
        }
    } finally {
        IOUtils.closeQuietly(out);
        IOUtils.closeQuietly(fo);
        recycleQuietly(scaledBitmap);
    }
}

/**
 * From offical Android documentation
 * @param options
 * @param reqWidth
 * @param reqHeight
 * @return
 */
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;
}

即使 resizeBitmapOnFileSystem() 方法不是很 "handy",技巧是 minimalLengthSide 变量。我设置了我想要的短边的最小长度(这里是 300px),方法 calculateInSampleSize() 会自动计算出合适的比例。

比率 width/height 保持不变,我不使用 Bitmap.createScaledBitmap(realImage, width, height, filter) 效率可能 "costly" 或更低。