为什么画质下降了?

Why quality of the picture decreased?

我在屏幕上显示图片:

 Bitmap bitmap = decodeSampledBitmapFromResource(data, 100, 100);

decodeSampledBitmapFromResource() 方法如下所示:

 public static Bitmap decodeSampledBitmapFromResource(String path,
                                                         int reqWidth, int reqHeight) {

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

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

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

使用Matrix将图片旋转90度后,图片质量下降:

Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap bitmap = decodeSampledBitmapFromResource(data, 100, 100);
bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

为什么显示的图片质量下降?以及如何以正常质量制作它?

旋转前的图片:

旋转后的图片:

看起来您几乎是直接从 documentation 中提取代码,这很好,但您需要了解该代码的作用。以此代码为例:

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

我猜这与您的 calculateInSampleSize() 方法相同。此方法计算应用于缩放图像以最佳匹配给定尺寸的除数。

在您的例子中,您为宽度和高度提供了 100px。这意味着如果起始图像是 680 x 600 像素,您的 inSampleSize 将是 2,因此生成的图像将是 340 x 300 像素,这是质量损失。如果您不需要显示完整分辨率,这有助于减小图像尺寸,但在您的情况下,您似乎确实需要使用原始图像尺寸以您需要的分辨率显示它。

并不意味着您应该放弃计算inSampleSize,它只是意味着您应该提供一个与您的[=17=更匹配的所需宽度和高度]尺寸。

int requiredWidth = imageView.getMeasuredWidth();
int requiredHeight = imageView.getMeasureHeight();

Note: this will not work if the ImageView width and/or height is set to wrap_content, as the width and height will not be measured until a source image is provided.

在你的情况下,我也会在你计算 inSampleSize 时交换所需的宽度和高度,因为你正在将图像旋转 90°:

options.inSampleSize = calculateInSampleSize(options, requiredHeight, requiredWidth);

最后,请确保您的 ImageView.ScaleType 而不是 设置为 FIT_XY,因为这会扭曲图像,导致质量下降。其他缩放类型也可以 增加 图像的大小,使其超出原始尺寸,这也会导致感知到的质量下降。


最后,如果您的应用程序显示大量图片,我建议您使用图片加载库来为您加载图片。这些库将处理缩放图像以适应 ImageView,并且大多数也支持 wrap_contentGlide, Picasso and Fresco 是一些很好的例子。