如何在不首先读取整个图像的情况下就地缩放流式位图?

emm*_*mby 11 streaming android bitmap scale

我有一个非常图片密集的Android应用程序.我目前正在使用Bitmap.createScaledBitmap()将图像缩放到所需的大小.但是,这种方法要求我已经在内存中有原始位图,这可能非常大.

如何在不首先将整个内容写入本地内存或文件系统的情况下缩放我正在下载的位图?

emm*_*mby 23

此方法将从图像中读取标题信息以确定其大小,然后读取图像并将其缩放到所需的大小,而不为完整原始大小的图像分配内存.

它还使用BitmapFactory.Options.inPurgeable,这似乎是一个稀疏文档,但在使用大量位图时可以防止OoM异常.更新:不再使用inPurgeable,请参阅Romain的此注释

它通过使用BufferedInputStream来读取图像的头信息,然后通过InputStream读取整个图像.

/**
 * 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 ) {}
    }

}
Run Code Online (Sandbox Code Playgroud)