6

I am trying to display a jpg file from a server into an imageView. When I try to load a smaller image (300x400), there are no problems. But when I try to load a full size picture (2336x3504), the image will not load. The file size of the image is only 2mb. I do not get any errors in logcat and there are no exceptions thrown. It simply won't load the image. I also tried using this:

BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap=BitmapFactory.decodeStream(is,null,options);

This doesn't do anything to help load the large files, but it does resize the smaller image (like it is suppose to). I did add the large picture to my resources and tested it as if it was embedded in the app and it worked fine, just won't work on the server. I have been working all day on this and can't seem to figure out how to load these large pictures. Can anyone help me out with this? Thanks for any info.

Here is the link where I found the above code and have been playing with the other examples but still not getting it to work.

EDIT:

Here is the code I'm using, to load the image:

public static Bitmap getBitmapFromURL(String src) {
    Bitmap bmImg;
    URL myFileUrl = null;

    try {
        myFileUrl = new URL(src);

        HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
        conn.setDoInput(true);
        conn.connect();
        InputStream is = conn.getInputStream();

        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inSampleSize = 16;

        bmImg = BitmapFactory.decodeStream(is, null, options);
        return bmImg;
    } catch (Exception e) {
        // TODO Auto-generated catch block
        Log.d("Error", e.toString());
        return null;
    }
}

Here is the logcat screenshot (couldn't figure out how to copy the text appropriately in eclipse) I cleared the log right before I hit the button to load the image. So all you see is what happens when I hit that button. I erased the company and app names (where you see "com.", assume its "com.mycompany.myapp". Logcat Screenshot

Community
  • 1
  • 1
Brian
  • 819
  • 4
  • 20
  • 35

3 Answers3

8

It is not uncommon for BitmapFactory.decodeFromStream() to give up and just return null when you connect it directly to the InputStream of a remote connection. Internally, if you did not provide a BufferedInputStream to the method, it will wrap the supplied stream in one with a buffer size of 16384. One option that sometimes works is to pass a BufferedInputStream with a larger buffer size like:

BufferedInputStream bis = new BufferedInputStream(is, 32 * 1024);

A more universally effective method is to download the file completely first, and then decode the data like this:

InputStream is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, 8190);

ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
    baf.append((byte)current);
}
byte[] imageData = baf.toByteArray();
BitmapFactory.decodeByteArray(imageData, 0, imageData.length);

FYI, the buffer sizes in this example are somewhat arbitrary. As has been said in other answers, it's a fantastic idea not to keep an image that size in memory longer than you have to. You might consider writing it directly to a file and displaying a downsampled version.

Hope that helps!

devunwired
  • 62,780
  • 12
  • 127
  • 139
  • Thanks for the help. But now I am getting the Out of Memory error when I put your code in. Any thoughts? – Brian Feb 14 '11 at 21:13
  • Not sure which method you chose, but we'll assume it's the latter. If it's too big to fit in memory at once, then it's too big to decode on the fly. I would recommend writing it directly to a file location (basically writing to a FileOutputStream instead of a ByteArrayBuffer), and then using the BitmapFactory decode options you have to read in a downsampled version. – devunwired Feb 14 '11 at 21:22
  • Not typically one to suggest brute force methods, but if your only object is to download an image and display it, you may be able to load the image into a WebView and let WebKit handle all this for you. – devunwired Feb 14 '11 at 21:32
  • I actually tried both methods. I guess I'm just not seeing why its a memory problem. The one image is pretty much the only thing my application is storing. But I guess I will use the temporary file. After I save the file, and then decode it into the view, how do you delete the file from where I save it (i guess the SD card)? – Brian Feb 14 '11 at 21:40
  • Actually, I even need help downloading the file straight to the file itself. I have been saving pictures to external storage by using a stored bitmap. If this is indeed a memory problem, then I cannot save the image that way. If you could help me out here, I would greatly appreciate it. – Brian Feb 14 '11 at 22:01
  • Most devices has a maximum heap size around 16-24MB. As Rich mentioned, when turning this image into a Bitmap, it will try to create a data structure north of 32MB. My guess is the OutOfMemoryError happens at this point, not while downloading. Anyway, you can create a file on internal storage using `Context.openFileOutput()` and `Context.openFileInput()` to write/read and avoid using the SD card. The other advantage of these convenience methods is you can also use `Context.deleteFile()` to get rid of it. Of course, there's always WebView or scaling the image on the server (if possible). – devunwired Feb 14 '11 at 22:06
  • Thanks for the help. I actually found another method of saving the files, but for some reason, the picture would not load from the SD card. It did save it to the SD card correctly, so I'm not sure what the deal was. So I ended up just shrinking the images a little bit to reduce the size (file sizes went from around 3mb to around 300kb. So now, there are no problems. Thanks for all your help. – Brian Feb 16 '11 at 15:37
  • Excellent. Making the images more mobile friendly is definitely the preferred option when you have control. Cheers! – devunwired Feb 16 '11 at 19:29
2

Devunwired's answer is right but out of memory error can occur if image size is too large, in that case we will have to scale down image, here is the code to scale down image after DevunWired's download image code

    final BitmapFactory.Options options = new BitmapFactory.Options();

    BufferedInputStream bis = new BufferedInputStream(is, 4*1024);
    ByteArrayBuffer baf = new ByteArrayBuffer(50);
    int current = 0;
    while ((current = bis.read()) != -1) {
        baf.append((byte)current);
    }
    byte[] imageData = baf.toByteArray();

    BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
    options.inJustDecodeBounds = true;
    options.inSampleSize = 2; //calculateInSampleSize(options, 128, 128);
    options.inJustDecodeBounds = false;
    Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
Farooq
  • 426
  • 2
  • 12
0

Does it silently fail, or does it throw an exception or OutOfMemory error? Btw, if a jpeg is 2MB that doesn't mean it'll take up 2MB of memory. 2MB is the compressed size, and since Android is working with a Bitmap, the 2336 x 3504 will take up approximately 2336 x 3504 x 4 bytes in memory. (2336 x 3504 x 4 = 32,741,376). Downsampling 8 times still might not be enough, especially if you have other bitmaps in memory at the time.

Rich
  • 36,270
  • 31
  • 115
  • 154
  • Thanks for the reply. I don't get any sign of failure. In my catch blocks, I use Log.d("Error", "Error loading image"); to show if anything threw an exception and it never gets thrown. I've even tried downsampling 32 times (which should be plenty small enough) and it didn't help either. Originally, I had another thread loading the next image. But for now, I commented all of that out. I am simply trying to load a single image. There are no other bitmaps in memory, so I wouldn't think memory would be a problem. Again I'm not getting the Out of Memory Exception. Any other pointers? – Brian Feb 14 '11 at 19:57
  • OutOfMemoryError doesn't derive from Exception, so you wouldn't catch it the normal way, it derives from Throwable: http://developer.android.com/reference/java/lang/OutOfMemoryError.html. Does the Debug window or DDMS show anything like that? What about testing with several different sizes of Bitmap and seeing if there's a certain threshold at which it fails? If it's failing, there should be something in the Debug/DDMS/LogCat windows – Rich Feb 14 '11 at 20:26
  • I edited my original post and added some code and logcat output. Have a look. – Brian Feb 14 '11 at 20:49