这个答案总结自Loading large bitmaps Efficiently
它解释了如何使用 inSampleSize 加载缩小的位图
版本。
特别Pre-scaling bitmaps解释了各种细节
方法,如何组合它们,哪些是最节省内存的。
在 Android 上调整位图大小的三种主要方法具有不同的内存属性:
createScaledBitmap API
此 API 将采用现有位图,并创建一个具有您选择的确切尺寸的新位图。
从好的方面来说,您可以准确地获得所需的图像尺寸(无论其外观如何)。但缺点是,这个 API 需要一个现有的位图才能工作。这意味着必须先加载、解码图像并创建位图,然后才能创建新的较小版本。这在获得精确尺寸方面是理想的,但在额外的内存开销方面却很糟糕。因此,对于大多数注重内存的应用程序开发人员来说,这是一种破坏交易
inSampleSize flag
BitmapFactory.Options 有一个标记为inSampleSize 的属性,它将在解码图像时调整图像大小,以避免需要解码为临时位图。此处使用的这个整数值将以 1/x 的缩小尺寸加载图像。例如,将inSampleSize 设置为 2 会返回一个大小为一半的图像,而将其设置为 4 会返回一个大小为 1/ 4 的图像。基本上图像尺寸总是比你的源尺寸小一些二次方。
从内存的角度来看,使用inSampleSize 是一个非常快速的操作。实际上,它只会将图像的每 X 个像素解码为生成的位图。 inSampleSize 有两个主要问题:
如果您只是将图像缩小一些 pow2 大小,并且过滤不是问题,那么您找不到比 inSampleSize 更节省内存(或性能效率)的方法。
inScaled, inDensity, inTargetDensity flags
如果您需要将图像缩放到不等于 2 的幂的尺寸,那么您将需要 BitmapOptions 的 inScaled、inDensity 和 inTargetDensity 标志。设置inScaled 标志后,系统将通过将inTargetDensity 除以inDensity 值来推导出缩放值以应用于您的位图。
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
使用此方法将重新调整图像大小,并对其应用“调整大小过滤器”,也就是说,最终结果会更好看,因为在调整大小的步骤中已经考虑了一些额外的数学运算。但请注意:额外的过滤器步骤需要额外的处理时间,并且可以快速添加大图像,导致调整速度缓慢,并为过滤器本身分配额外的内存。
由于额外的过滤开销,将此技术应用于明显大于所需尺寸的图像通常不是一个好主意。
魔法组合
从内存和性能的角度来看,您可以结合使用这些选项以获得最佳效果。 (设置inSampleSize、inScaled、inDensity 和inTargetDensity 标志)
inSampleSize 将首先应用于图像,使其比您的目标大小大的下一个二次幂。然后,inDensity 和inTargetDensity 用于将结果缩放到您想要的精确尺寸,应用过滤操作来清理图像。
将这两者结合起来是一个更快的操作,因为inSampleSize 步骤将减少生成的基于密度的步骤需要应用其调整大小过滤器的像素数量。
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
如果您需要使图像适合特定尺寸,和一些更好的过滤,那么这种技术是获得正确尺寸的最佳桥梁,但在快速、低内存的情况下完成足迹操作。
获取图片尺寸
在不解码整个图像的情况下获取图像大小
为了调整位图的大小,您需要知道传入的尺寸。您可以使用inJustDecodeBounds 标志来帮助您获取图像的尺寸,而无需实际解码像素数据。
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
您可以使用此标志先解码尺寸,然后计算适当的值以缩放到您的目标分辨率。