我有一个图像密集型的 Android 应用程序。我目前正在使用 Bitmap.createScaledBitmap()
将图像缩放到所需的大小。但是,此方法要求我在内存中已有原始位图,这可能相当大。
如何在不先将整个位图写入本地内存或文件系统的情况下缩放正在下载的位图?
最佳答案
此方法将从图像中读取 header 信息以确定其大小,然后读取图像并将其缩放到所需的大小,而无需为完整的原始大小的图像分配内存。
它还使用 BitmapFactory.Options.inPurgeable ,这似乎是一个记录稀疏但可取的选项,可以在使用大量位图时防止 OoM 异常。 更新:不再使用 inPurgeable,参见 this note来自罗曼
它的工作原理是在通过 InputStream 读取整个图像之前使用 BufferedInputStream 读取图像的 header 信息。
/**
* Read the image from the stream and create a bitmap scaled to the desired
* size. Resulting bitmap will be at least as large as the
* desired minimum specified dimensions and will keep the image proportions
* correct during scaling.
*/
protected Bitmap createScaledBitmapFromStream( InputStream s, int minimumDesiredBitmapWith, int minimumDesiredBitmapHeight ) {
final BufferedInputStream is = new BufferedInputStream(s, 32*1024);
try {
final Options decodeBitmapOptions = new Options();
// For further memory savings, you may want to consider using this option
// decodeBitmapOptions.inPreferredConfig = Config.RGB_565; // Uses 2-bytes instead of default 4 per pixel
if( minimumDesiredBitmapWidth >0 && minimumDesiredBitmapHeight >0 ) {
final Options decodeBoundsOptions = new Options();
decodeBoundsOptions.inJustDecodeBounds = true;
is.mark(32*1024); // 32k is probably overkill, but 8k is insufficient for some jpgs
BitmapFactory.decodeStream(is,null,decodeBoundsOptions);
is.reset();
final int originalWidth = decodeBoundsOptions.outWidth;
final int originalHeight = decodeBoundsOptions.outHeight;
// inSampleSize prefers multiples of 2, but we prefer to prioritize memory savings
decodeBitmapOptions.inSampleSize= Math.max(1,Math.min(originalWidth / minimumDesiredBitmapWidth, originalHeight / minimumDesiredBitmapHeight));
}
return BitmapFactory.decodeStream(is,null,decodeBitmapOptions);
} catch( IOException e ) {
throw new RuntimeException(e); // this shouldn't happen
} finally {
try {
is.close();
} catch( IOException ignored ) {}
}
}
关于android - 如何在不首先读取整个图像的情况下就地缩放流式位图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7051025/