Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
357 views
in Technique[技术] by (71.8m points)

android - How do I scale a streaming bitmap in-place without reading the whole image first?

I have an Android application that is very image intensive. I'm currently using Bitmap.createScaledBitmap() to scale the image to a desired size. However, this method requires that I already have the original bitmap in memory, which can be quite sizable.

How can I scale a bitmap that I'm downloading without first writing the entire thing out to local memory or file system?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This method will read the header information from the image to determine its size, then read the image and scale it to the desired size in place without allocating memory for the full original sized image.

It also uses BitmapFactory.Options.inPurgeable, which seems to be a sparsely documented but desirable option to prevent OoM exceptions when using lots of bitmaps. UPDATE: no longer uses inPurgeable, see this note from Romain

It works by using a BufferedInputStream to read the header information for the image before reading the entire image in via the 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 ) {}
    }

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...