views:

1525

answers:

2

Hi!

I'm having issues with BitmapFactory.decodeStream(inputStream). When using it without options, it will return an image. But when I use it with options as in .decodeStream(inputStream, null, options) it never returns Bitmaps.

What I'm trying to do is to downsample a Bitmap before I actually load it to save memory. I've read some good guides, but none using .decodeStream.

Here

And here

And here

WORKS JUST FINE

URL url = new URL(sUrl);
HttpURLConnection connection  = (HttpURLConnection) url.openConnection();

InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);   

DOESNT WORK

InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);  

InputStream is = connection.getInputStream();    

Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

BitmapFactory.decodeStream(is, null, options);

Boolean scaleByHeight = Math.abs(options.outHeight - TARGET_HEIGHT) >= Math.abs(options.outWidth - TARGET_WIDTH);

if(options.outHeight * options.outWidth * 2 >= 200*100*2){
// Load, scaling to smallest power of 2 that'll get it <= desired dimensions
    double sampleSize = scaleByHeight
    ? options.outHeight / TARGET_HEIGHT
    : options.outWidth / TARGET_WIDTH;
    options.inSampleSize = 
        (int)Math.pow(2d, Math.floor(
        Math.log(sampleSize)/Math.log(2d)));
}

  // Do the actual decoding
  options.inJustDecodeBounds = false;
  Bitmap img = BitmapFactory.decodeStream(is, null, options);
+1  A: 

I think the problem is with the "calculate-scale-factor" logic because rest of the code looks correct to me (assuming of course that inputstream is not null).

It would be better if you can factor out all the size calculation logic from this routine into a method(call it calculateScaleFactor() or whatever) and test that method independently first.

Something like:

// Get the stream 
InputStream is = mUrl.openStream();

// get the Image bounds
BitmapFactory.Options options=new BitmapFactory.Options(); 
options.inJustDecodeBounds = true;

bitmap = BitmapFactory.decodeStream(is,null,options);

//get actual width x height of the image and calculate the scale factor
options.inSampleSize = getScaleFactor(options.outWidth,options.outHeight,
                view.getWidth(),view.getHeight());

options.inJustDecodeBounds = false;
bitmap=BitmapFactory.decodeStream(mUrl.openStream(),null,options);

and test getScaleFactor(...) independently.

It will also help to surround the entire code with try..catch{} block, if not done already.

Samuh
Thanks alot for the answer!I tried setting a final int value like 'options.inSampleSize = 2'.But it results in the same issues. Logcat reads 'SkImageDecoder::Factory returned null', for every image that i tried to decode.Running the code inside a try/catch block wouldn't help me as it isn't throwing anything, right?However BitmapFactory.decodeStream does return null if it can't create an img, which it cant when i try to use a sampleSize.
Robert Foss
This is strange. Can you try to resize some Bitmap bundled in your resource? Like open a resource file and try to decode it. If you can do that maybe there is some problem with the remote stream which is causing the decode to fail.
Samuh
BitmapFactory.decodeResource(this.getResources(), R.drawable.icon, options) == null) works fine with re-sampling.The first BitmapFactory.decodeStream with options.inJustDecodeBounds = true works and returns options just fine.But the following BitmapFactory.decodeStream with options.inJustDecodeBounds = false fails every time.
Robert Foss
I am afraid this is beyond me ... I would be interested to know what could possibly go wrong here because I am using similar code and it works just fine for me.
Samuh
Ok. I've solved it. The issue lies in the http-connection.When you've read from the input-stream provided by the HttpUrlConnection once, you can't read from it again, and have to reconnect to do the second decodeStream().
Robert Foss
btw, I just edited the issue to reflect that i use a HttpUrlConnection.I should've posted that in the issue. Sorry about that.And thanks alot for your help!Greets from Sweden.
Robert Foss
Glad that you found an answer; thank you for sharing your findings...cheers!
Samuh
+2  A: 

The problem was that once you've used an InputStream from a HttpUrlConnection, you can't rewind and use the same InputStream again. Therefore you have to create a new InputStream for the actual sampling of the image.

  Options options = new BitmapFactory.Options();
  options.inJustDecodeBounds = true;

  BitmapFactory.decodeStream(is, null, options);

  Boolean scaleByHeight = Math.abs(options.outHeight - TARGET_HEIGHT) >= Math.abs(options.outWidth - TARGET_WIDTH);

  if(options.outHeight * options.outWidth * 2 >= 200*200*2){
         // Load, scaling to smallest power of 2 that'll get it <= desired dimensions
        double sampleSize = scaleByHeight
              ? options.outHeight / TARGET_HEIGHT
              : options.outWidth / TARGET_WIDTH;
        options.inSampleSize = 
              (int)Math.pow(2d, Math.floor(
              Math.log(sampleSize)/Math.log(2d)));
     }

        // Do the actual decoding
        options.inJustDecodeBounds = false;

        is.close();
        is = getHTTPConnectionInputStream(sUrl);
        Bitmap img = BitmapFactory.decodeStream(is, null, options);
        is.close();
Robert Foss