views:

669

answers:

3

I am using BitmapFactory.decodeFile to load Bitmaps of images into my application. However, the function returns null on large images (such as those from the camera). The filepath is definitely correct, I just can't figure out why it would return null. I tried supersampling, but it didn't seem to help.

Does anyone have any idea why it would do this or how I could more easily load images taken from the camera into a Bitmap?

Here's the code I am using:

public static Bitmap loadBitmap(String filePath){
    Bitmap result = BitmapFactory.decodeFile(filePath);

    if(result == null){
        if(filePath.contains(".jpg") || filePath.contains(".png")){
            //This is the error that occurs when I attempt to load an image from the Camera DCIM folder or a large png I imported from my computer.
            Utils.Toast("Could not load file -- too big?"); 
        } else {
            Utils.Toast("Could not load file -- image file type is not supported");
        }
    }
    return result;
}

Thanks.

+3  A: 

You will need to provide more info about your problem, such as a snippet of code that you are using. If you want to know when/why the BitmapFactory.decodeFile method would return null, you can read directly its source code: http://casidiablo.in/BitmapFactory

For example, one of the reasons that causes BitmapFactory.decodeFile to return null is if there's a problem while openning the file. Curiously, the developers dont't log anything with such a problem... look at the comment "do nothing. If the exception happened on open, bm will be null."

public static Bitmap decodeFile(String pathName, Options opts) {
    Bitmap bm = null;
    InputStream stream = null;
    try {
        stream = new FileInputStream(pathName);
        bm = decodeStream(stream, null, opts);
    } catch (Exception e) {
        /*  do nothing.
            If the exception happened on open, bm will be null.
        */
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                // do nothing here
            }
        }
    }
    return bm;
}

As you can see, the BitmapFactory.decodeFile does not work standalone... but it uses some other methods of the BitmapFactory class (for instance, BitmapFactory.decodeStream, BitmapFactory.nativeDecodeStream, BitmapFactory.finishDecode, etc.). The problem could be on one of those methods, so if I were you, I would try to read and understand how they work so that I could know in which cases they return null.

Cristian
I just posted the code (probably while you were typing up the reply). I'll look into some of those methods like you suggested. Thanks!
GuyNoir
Well alright, I simply tried out the FileInputStream method instead and it actually does say that the file does not exist. Which is very strange considering there is a file there.I'll keep fiddling.
GuyNoir
Alright, it seems that the name of the file is the problem. I can actually load the images when I rename them to "image.jpg" rather than the name based on the timestamp of the photo. Thanks for the help. Of course I get an OOM exception now, but that's something else to handle.Do you happen to know where I could find the source for the Gallery application (or any for that matter). I just need to figure out how they can get around the small heap size issue when loading and displaying large images.
GuyNoir
A: 

Maybe inSampleSize option can help you? http://stackoverflow.com/questions/477572/android-strange-out-of-memory-issue/823966#823966

Fedor
I'm not getting an out of memory error, and superSampling didn't seem to help when I tried it.
GuyNoir
A: 

It may sound obvious, but check that your filePath actually points to a file. You mention that you are using a file manager to select the image to open - it's possible that the file manager is returning a path to a content provider instead of a file.

There is a more robust way to open files using the ContentResolver class, which can open an InputStream to a content provider, file, or resource, without you needing to know in advance what kind of path you are passing it.

The only catch is that you need to pass a Uri object on the call to openInputStream() instead of a String.

public static Bitmap loadBitmap(String filePath, Context c) {
    InputStream inStream;

    try {
        inStream = c.getContentResolver().openInputStream( Uri.parse(filePath) );
    } catch (FileNotFoundException e) {
        // handle file not found
    }

    return BitmapFactory.decodeStream(inStream);
}

This also happens to be how the ImageView widget attempts to load images when you use its setImageURI method.

Alex W