views:

2937

answers:

8

For my current application I collect images from different "event providers" in Spain.

  Bitmap bmp=null;
  HttpGet httpRequest = new HttpGet(strURL);

  long t = System.currentTimeMillis();
  HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
  Log.i(TAG, "Image ["+ strURL + "] fetched in [" + (System.currentTimeMillis()-t) + "ms]");

     HttpEntity entity = response.getEntity();
     InputStream instream = entity.getContent();
     bmp = BitmapFactory.decodeStream(instream);

     return bmp;

However, when downloading images from salir.com I get the following logcat output:

13970     Gallery_Activity  I  Fetching image 2/8 URL: http://media.salir.com/_images_/verticales/a/0/1/0/2540-los_inmortales_la_trattoria-marc_aureli_27_29_no.jpg
13970     ServiceHttpRequest  I  Image [http://media.salir.com/_images_/verticales/a/0/1/0/2540-los_inmortales_la_trattoria-marc_aureli_27_29_no.jpg] fetched in [146ms]
13970     skia  D  --- decoder->decode returned false

A search for that error message didn't provide much useful results.

Anyone an idea what the problem could be?

Gracias!


Update 1:

After inquiring a bit more and testing different stuff I figured out that the problem seems to lie somewhere else. Even though my logcat output says

13970     ServiceHttpRequest  I  Image [http://media.salir.com/_images_/verticales/a/0/1/0/2540-los_inmortales_la_trattoria-marc_aureli_27_29_no.jpg] fetched in [146ms]
getContentLength(): 93288

which is the correct length of the image in bytes it seems that there's something wrong with the stream or HTTP connection.

My original code (above) is taking advantage of the ThreadSafeClientConnManager. If I replace it with just a simple URLConnection it works perfectly:

URL url = new URL(strURL);
URLConnection conn = url.openConnection();
conn.connect();
InputStream instream = conn.getInputStream();
bmp = BitmapFactory.decodeStream(instream);

So, I'm wondering now why does my ThreadSafeClientConnManager work flawlessly (at least it seems it does) with all my other connections (mostly exchanging JSONObjects) but not with images from some specific websites (e.g. salir.com - for most other websites it works, though). Is there a HTTP parameter I'm missing?

My current setup is:

HttpParams parameters = new BasicHttpParams();
HttpProtocolParams.setVersion(parameters, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(parameters, HTTP.UTF_8);
HttpProtocolParams.setUseExpectContinue(parameters, false); // some webservers have problems if this is set to true
ConnManagerParams.setMaxTotalConnections(parameters, MAX_TOTAL_CONNECTIONS);
HttpConnectionParams.setConnectionTimeout(parameters, CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(parameters, SOCKET_TIMEOUT);

SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", 
     PlainSocketFactory.getSocketFactory(), HTTP_PORT));

ClientConnectionManager conMgr = new ThreadSafeClientConnManager(parameters,schReg);

DefaultHttpClient http_client = new DefaultHttpClient(conMgr, parameters);

Update 2:

Now, the strange thing is, that it actually does work with the ThreadSafeClientConnManager -sometimes-. If I keep trying downloading the image and decoding it for a couple of times in a row it might work after 15-30 trials. Very strange.

I hope there's a solution to that since I would prefer using the ThreadSafeClientConnManager instead of URLConnection.


Update 3:

As suggest by Mike Mosher below, it seems that by using BufferedHttpEntity the decoding error doesn't appear any more. However now, even though less often than before, I get a SkImageDecoder::Factory returned null error.

A: 

I was having a similar problem, and the root issue was due to timeouts when requesting some images. I switched to using a Background Image Loader and have had no problems since. Hope this helps

Bob.T.Terminal
Timeout doesn't seem to be the problem for me. As posted in my logcat output already I successfully fetched my image.
znq
Okay, after doing some more testing it seems that the ThreadSafeClientConnManager is the problem. However, I don't know why.
znq
+13  A: 

Stefan,

I've had the same issue, and didn't find much searching the internet. Many people have had this issue, but not alot of answers to solve it.

I was fetching images using URLConnection, but I found out the issue doesn't lie in the download, but the BitmapFactory.decodeStream was having an issue decoding the image.

I changed my code to reflect your original code (using httpRequest). I made one change, which I found at http://groups.google.com/group/android-developers/browse%5Fthread/thread/171b8bf35dbbed96/c3ec5f45436ceec8?lnk=raot (thanks Nilesh). You need to add "BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity); "

Here was my previous code:

     conn = (HttpURLConnection) bitmapUrl.openConnection(); 
     conn.connect();
     is = conn.getInputStream();
     //bis = new BufferedInputStream(is);
     //bm = BitmapFactory.decodeStream(bis);
     bm = BitmapFactory.decodeStream(is);

And her is the code that works:

            HttpGet httpRequest = null;

 try {
  httpRequest = new HttpGet(bitmapUrl.toURI());
 } catch (URISyntaxException e) {
  e.printStackTrace();
 }

 HttpClient httpclient = new DefaultHttpClient();
     HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);

     HttpEntity entity = response.getEntity();
     BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity); 
     InputStream instream = bufHttpEntity.getContent();
     bm = BitmapFactory.decodeStream(instream);

As I said, I have a page that download around 40 images, and you can refresh to see the most recent photos. I would have almost half fail with the "decoder->decode returned false error". With the above code, I have had no problems.

Thanks

Mike Mosher
Great! Thanks a lot Mike. That seems to be it. After two and a half months I finally have a solution to it :-) *very happy*
znq
Okay, after doing a bit more testing now it doesn't seem to work as perfect as it looked first. I sometimes get now: "SkImageDecoder::Factory returned null" - however, less often than before.
znq
SkImageDecoder::Factory will return null if it doesn't understand what format the image is. This is a completely different error as decoder->decode runs after the SkImageDecoder::Factory has determined the image type. It will occur either when the image is either not a supported format, or if it is not an image at all (e.g. a 404 error page)...
seanhodges
Thank you Thank you Thank you.... I wish I could give you more then one upvote
Janusz
Is there a way to tell SkImageDecoder what type of image it is?
Richard
oh yes thank you sooo much :P as Janusz said i wish i could upvote more than once...
Savvas Dalkitsis
A: 

I've tried tree diffrent ways now, the simple URLConnection you use and that seems to be working for you, the way Mike Mosher uses and also this way [http://asantoso.wordpress.com/2008/03/07/download-and-view-image-from-the-web/] they all result in decode returned false.

HOWEVER if I convert the image to a PNG all of the ways work fine!! However I tried putting the images on my work ftp homepage and then all jpgs load fine with the simple solution... So for some reason it seems that if the server isn't fast enough it parses the jpg files before they are actually fully downloaded or something.

Oskar
+2  A: 

My solution is not to use BitmapFactory.decodeStream() cause the way I look at it, it uses the SKIA decoder and it seems kind of erratic sometimes. You can try something like this.

    Bitmap bitmap = null;
    InputStream in = null;
    BufferedOutputStream out = null;
    try {
            in = new BufferedInputStream(new URL(url).openStream(),
                     IO_BUFFER_SIZE);

            final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
            out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
            copy(in, out);
            out.flush();

            final byte[] data = dataStream.toByteArray();
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);


   } catch (......){

   }        

and for the copy() function

private static void copy(InputStream in, OutputStream out) throws IOException {
    byte[] b = new byte[IO_BUFFER_SIZE];
    int read;
    while ((read = in.read(b)) != -1) {
        out.write(b, 0, read);
    }
}

and IO_BUFFER_SIZE is a constant integer with the value of 4 * 1024.

M.A. Cape
A: 

I had the exact same problem when trying to decode an image from a byte array. After some experimentation, the solution appears to be to assign some temp storage in the Options of the BitmapFactory. Try:

Options options = new Options();
options.inTempStorage = new byte[256];
Bitmap newMapBitmap = BitmapFactory.decodeStream(instream, null, options);

If the problem is not resolved straight away, try increasing the size of the temp array. I think large bitmap files need a larger buffer for decoding.

seanhodges
Gracias. I'm gonna try that and give feedback when tested extensively.
znq
A: 

Setting the default buffer in Options does help with some out of memory issues regarding BitmapFactory but certainly does not cover all of them. The underlying issue appears to be some kind of timeout when retrieving the bitmap or the bitmap header. I am now writing the stream to a temp file and then pass the temp file to BitmapFactory which is working fine.

Cross_
Using the BufferedHttpEntity approach also works around the BitmapFactory's timeout issue. However, this caches the entire download in memory, basically doubling the memory requirements for image decoding. This might explain the occassional factory returned null errors.
Cross_