android - calculateInSampleSize,当宽度>时,为什么Math.round处理高度(height / reqHeight)?高度?

时间:2012-12-04 04:37:27

标签: android bitmapfactory

我正在'developer.android.com'上缩小我的位图文件,我发现了一件我不理解的事情。所以我感谢你给我一点帮助。

以下是developer.android.com的snippet

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) {
    if (width > height) {
      inSampleSize = Math.round((float)height / (float)reqHeight);
    } else {
      inSampleSize = Math.round((float)width / (float)reqWidth);
    }
  }
  return inSampleSize;
}
在if语句中,当“if(width> height)”为什么计算“(float)height /(float)reqHeight”?

例如,width = 600,height = 800,reqWidth = 100,reqHeight = 100.

在这种情况下,inSampleSize为6,计算的尺寸为width = 100,height = 133。身高仍然高于reqHeight ..

那么,有人可以解释一下这个吗?抱歉复杂的解释但是 我希望有人给我一个想法。 :)

5 个答案:

答案 0 :(得分:3)

我只能说他们的逻辑错了:(无论如何这种方法相当简单,所以你应该用正确的条件重新实现它不应该是一个很大的问题!我的意思是当你看一看decodeSampledBitmapFromResource,它只想减少Bitmap以使其适合所需的边界,所以这必须是一个错误。

编辑::对于我来说,这看起来更糟,在某些情况下它不会起作用。假设你有宽度= 200和高度= 600.你设置你的最大边界宽度= 100和高度= 500.你有高度>宽度,但如果你想要它们都适合返回结果inSampleSize必须是200/100而不是600/500。 所以基本上如果你重新实现这个方法,我会这样做:

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 stretch_width = Math.round((float)width / (float)reqWidth);
    int stretch_height = Math.round((float)height / (float)reqHeight);

    if (stretch_width <= stretch_height) 
        return stretch_height;
    else 
        return stretch_width;
}

但这看起来像他们的代码太多问题让我相信我理解它的观点正确!

答案 1 :(得分:3)

好吧,在对缩放内容有很多问题后,我想我得到了自己的答案:

使用http://developer.android.com/training/displaying-bitmaps/load-bitmap.html中的“有效加载大位图”我想发布一些结果(原始代码):

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

我目前在横向模式下使用1280 x 752分辨率的Galaxy-Tab 7.7。想象一下具有以下规格的图像:

1920 x 1200 ..会发生什么?

heighRatio = 1920/1280 = 1.5 且widthRatio = 1200/752 = 1.59

这两个数字都会转到 2 ,所以如果我理解了一切,图像将按比例缩小2倍。这将导致图像为1920/2 = 960 * 600 ,这比我所要求的 1280 * 752 的分辨率要低。

我通过逐层替换来解决这个问题:

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

这实际上会阻止某些我的图片缩小太多。我目前仍在调查 inSampleSize 参数,看看是否可以使用“fractions”。目前,所有尺寸为1280x752(* 2)= 2560 * 1504的图像都会进行缩放。我正在写的imageView是图像的详细视图,因此它现在不应该是一个大问题。

我将修改后的代码版本与以下内容结合使用:

returnview.setAdjustViewBounds(true);

这样可以防止比我的屏幕大的图像变得混乱的边界框。如果您将颜色背景设置为实际图像,则可以看到它。此外,使用现在修复的代码,我可以实现一些onClick Handler来检测用户是否在我的图像外部点击以关闭图像。

答案 2 :(得分:3)

上述问题中的代码严重过时。如BitmapFactory.Options reference中所述(自2013年3月8日起)inSampleSize将向下舍入到最接近2的幂。

  

如果设置为值&gt; 1,请求解码器对原始进行二次采样   图像,返回较小的图像以节省内存。样本量是   任一维度中对应于单个像素的像素数   解码后的位图中的像素。例如,inSampleSize == 4返回一个   图像是原稿宽度/高度的1/4,和1/16   像素数。任何值&lt; = 1都被视为1.注意:   解码器使用基于2的幂的最终值,任何其他值都将   向下舍入到最接近2的幂。

自2013年3月8日起

BitmapFactory.Options reference

因此,计算inSampleSize的正确代码为Loading Large Bitmaps

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

然而,上述代码可以进一步优化。由于halfWidthhalfHeight已经被2除,因此可以重写循环以将图像更大或相等返回到请求的大小范围。

        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }

必须适合800x800像素的图像大小为100x100像素的原始代码将返回4的inSampleSize - &gt;返回的图像将是200x200像素,修改后的代码将返回8的inSampleSize - >返回的图像将是100x100像素。

注意:使用inSampleSizeBitmapFactory.decodeXXX方法下采样图像的主要功能是在加载显着大于显示目的所需图像时保留内存。与上述代码结合使用的这些方法将始终为您提供与请求的边界相比较大(或相等)的最小图像(按2的幂缩放),而不是适合该边界的图像。

答案 3 :(得分:1)

他们的逻辑不仅仅是错误的,而且实际上是错误的。图像中你需要的东西不是缩小它,直到一个参数小于所需的值,如果它被分成两半,而是确保没有尺寸大于2048.在那之上,很多时候你可以' t渲染纹理或显示图像。如果你有一个像4000x1300的图像,你说你想要至少768.它实际上不能削减1300的一半而不低于该值。所以它没有做任何事情并退出。试图加载失败的4000幅图像。

public static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
    int height = options.outHeight;
    int width = options.outWidth;
    int inSampleSize = 1;
    while (height > maxHeight || width > maxWidth) {
        height /= 2;
        width /= 2;
        inSampleSize *= 2;
    }
    return inSampleSize;
}

答案 4 :(得分:0)

我找到了他们的逻辑

if (height > reqHeight || width > reqWidth) {
    if (width > height) {
        inSampleSize = Math.round((float)height / (float)reqHeight);
    } else {
        inSampleSize = Math.round((float)width / (float)reqWidth);
    }
}

也让人困惑。我会采取一种更简单的方法。我的逻辑是如果图像是水平图像则在宽度上缩放图像并忽略所需的高度,如果图像是垂直图像则在高度上缩放图像并忽略所需的宽度。

if (height > reqHeight || width > reqWidth) {
        if (width > height) {
            inSampleSize = Math.round((float) width / (float) reqWidth);
        } else {
            inSampleSize = Math.round((float) height / (float) reqHeight);
        }
    }