10

我正在寻找“developer.android.com”来缩小我的位图文件,但我发现了一件事我不明白。所以我很感谢你给我一点帮助。

这是来自 developer.android.com的片段

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”?

例如,宽度=600,高度=800,reqWidth=100,reqHeight=100。

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

那么,有人可以解释一下吗?对不起复杂的解释,但我希望有人给我一个想法。:)

4

5 回答 5

4

我只能说他们的逻辑看起来是错误的 :( 无论如何,这个方法相当简单,所以用正确的条件重新实现它应该不是什么大问题!我的意思是当你看一下 decodeSampledBitmapFromResource 时,它只想减少位图以使其适合所需的范围,所以这一定是一个错误。

编辑 :: 这对我来说看起来更糟,它在某些情况下不起作用。假设您有宽度 = 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;
}

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

于 2012-12-04T08:34:11.070 回答
4

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

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

2013 年 3 月 8 日的BitmapFactory.Options 参考

所以正确的计算代码inSampleSize加载大位图

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 循环以返回大于或等于请求大小范围的图像。

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

800x800必须适合pix的图像大小 pix 的原始代码100x100将返回inSampleSize4 -> 返回的图像将是200x200pix,修改后的代码将返回inSampleSize8 -> 返回的图像将是100x100pix。

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

于 2015-03-08T13:49:19.093 回答
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 ..会发生什么?

高度比 = 1920/1280 = 1.5和宽度比 = 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以查看是否可以选择使用“分数”。目前,尺寸不超过 1280x752 (*2) = 2560*1504 的所有图像都不会被缩放。我正在写的 imageView 是图像的详细视图,因此现在应该不是太大的问题。

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

returnview.setAdjustViewBounds(true);

这将防止比我的屏幕大的图像得到一个混乱的边界框。如果为实际图像设置颜色背景,则可以看到它。此外,使用现在固定的代码,我可以实现一些 onClick 处理程序来检测用户是否在我的图像之外单击以关闭图像。

于 2013-03-14T23:40:01.520 回答
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;
}
于 2017-02-04T21:12:06.587 回答
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);
        }
    }
于 2013-04-02T16:17:24.950 回答