Android BitmapFactory.Options.inSampleSize 导致应用程序崩溃

3
我们正在开发一款Android应用程序,该应用程序捕获图像并将其转换为位图以发布到Rest服务。在创建位图时,我们已将 BitmapFactory.Options.isSampleSize 配置为值为4,除了HTC One之外的所有设备上都可以正常工作。但在HTC One上,图像失真了。当我们将值更改为1时,在HTC One上显示出良好的图像,但由于内存问题,所有其他设备上的应用程序都会崩溃。这个问题与可用的堆大小有关。
以下是需要回答的问题:
1. HTC One为什么会显示失真的图像? 2. 为什么S3也有相同版本16的构建,但由于堆大小不足而崩溃? 3. 所有较低版本的手机(如Droid)为什么对于采样率为4的情况都可以正常工作? 4. 检查应用程序可用内存空间并使用可用内存来处理位图的最佳方法是什么?
当我们在清单文件中配置 android:largeHeap 时,似乎可以解决此问题,但这似乎不是一个可靠的解决方案。
我能够找到使用相机参数拍摄的图片大小,然后得出位图的最佳采样率。下面的代码解决了问题。但这是正确的做法吗?还是应该计算采样率,而不是使用1和4?
private Bitmap createImaegBitmap(byte[] data)
    {
        BitmapFactory.Options opt;

        opt = new BitmapFactory.Options();
        opt.inTempStorage = new byte[16 * 1024];
        Parameters parameters = ((ReceiptCollection)getApplication()).getParams();
        Size size = parameters.getPictureSize();

        int height11 = size.height;
        int width11 = size.width;
        float mb = (width11 * height11) / 1024000;

        if (mb > 4f)
            opt.inSampleSize = 4;
        else if (mb > 3f)
            opt.inSampleSize = 1;
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,opt);
        return bitmap;
    }

HTC One 上生成的图像在设备本身上看起来扭曲(可能是布局问题),或者实际生成的 jpg/png 图像在某些查看器中查看时扭曲? - zapl
我们可以在浏览器上查看服务发布的图像,它和我在应用程序预览中看到的图像一样糟糕。 - Harshjags
1个回答

4

看这里:
http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

1:因为……直接来自文档:如果设置的值> 1,则请求解码器对原始图像进行子采样,返回一个较小的图像以节省内存。样本大小是与解码位图中单个像素对应的每个维度中的像素数。例如,inSampleSize == 4返回一个宽度/高度为原始图像的1/4,像素数量为原始图像的1/16的图像。任何值<= 1都将被视为1。注意:解码器使用基于2的幂的最终值,任何其他值都将舍入到最接近2的幂。

2:我猜是因为不是所有设备都具有相同的可用内存。 3:您需要计算样本大小而不仅仅是设置数字……

2,3:所有设备都具有不同的相机分辨率。

要解决此问题,请阅读以下内容:http://developer.android.com/training/displaying-bitmaps/index.html

    public static Bitmap lessResolution(String filePath) {
    int reqHeight = 120;
    int reqWidth = 120;
    BitmapFactory.Options options = new BitmapFactory.Options();

    // First decode with inJustDecodeBounds=true to check dimensions
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;

    return BitmapFactory.decodeFile(filePath, options);
}

private static int calculateInSampleSize(BitmapFactory.Options options,
        int reqWidth, int reqHeight) {

    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and
        // width
        final int heightRatio = Math.round((float) height
                / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will
        // guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return inSampleSize;
}

谢谢您的回复,我已经更新了我的问题中的代码,但正如您所提到的,我正在使用相机参数来查找样本大小,但仍在选择1和4之间,或者完全采用您的解决方案是否更好。 - Harshjags
根据您的需要来决定,但请记住,样本大小是用于避免在处理高分辨率图像时出现内存不足的情况... 有时候图片的分辨率太大了,将图像分辨率降低到1/4还不够。 不正确的方式是限制样本大小可以拥有的值。 - Tobiel
明白了。我会根据你的算法尝试计算样本大小。 - Harshjags

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接