0

Using the following code to load a jpg into a bitmap and draw it on a canvas

File extStore = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File myFile = new File(extStore.getAbsolutePath() + "/MyPicture.jpg");

        if(myFile.exists()){
            Toast.makeText(getBaseContext(),"yes",Toast.LENGTH_LONG).show();
        }


        Bitmap b1 = BitmapFactory.decodeFile(myFile.toString());
        canvas.drawBitmap (b1, 0,  0, null);

The App crashes with 2 errors

BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/Pictures/MyPicture.jpg: open failed: EACCES (Permission denied)

and further down it says

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.isRecycled()' on a null object reference

I have permissions set in manaifest as follows

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

App is targeting API 19 so shouldnt matter

The check to see if the file exist works so it is the correct location

It just wont work any ideas where im going wrong

Thanks in advance

Mark

Mark A Barr
  • 77
  • 1
  • 10

1 Answers1

0

You hit a file not found exception because the file was not found. There is no image file at /storage/emulated/0/Pictures/MyPicture.jpg

You should if you are going that way perhaps make a really basic alert dialog and have it able to select the file.

Choose File Dialog

That actually has a pretty nice setup that is delightfully easy to use, but then you could actually navigate a bit and find your proper file. Then load that and have it actually exist.

The recycled is because it didn't actually load the image, so it recycled it. You can check after the load fails if the image is recycled I think the command is isRecycled() and then exit out.


You might feel better about it if you throw the error yourself. Rather than do file.toString() which should be getCanonicalPath() properly if toString() works it's by chance rather than design and might even be your entire bug.

But you can open the file yourself and pass BitmapFactory the inputstream which will likely throw the error earlier, namely when you tried to open the non-existent file.


Here's the internal source its using for that decodeFile() bit.

386    public static Bitmap More ...decodeFile(String pathName, Options opts) {
387        Bitmap bm = null;
388        InputStream stream = null;
389        try {
390            stream = new FileInputStream(pathName);
391            bm = decodeStream(stream, null, opts);
392        } catch (Exception e) {
393            /*  do nothing.
394                If the exception happened on open, bm will be null.
395            */
396            Log.e("BitmapFactory", "Unable to decode stream: " + e);
397        } finally {
398            if (stream != null) {
399                try {
400                    stream.close();
401                } catch (IOException e) {
402                    // do nothing here
403                }
404            }
405        }
406        return bm;
407    }

In theory if you look in the logcat you might well see the Log.e() it sent out but it doesn't throw the error, it catches it internally. Try opening the file yourself. That way you can better debug where it's messing up and which specific IO error it threw.

Community
  • 1
  • 1
Tatarize
  • 10,238
  • 4
  • 58
  • 64
  • Thats the first thing I thought but the Fie.exists lne says it is there it is a jpg picture and if I put it in drawables and load it it works cant figure it out I will try the file chooser to see what that says – Mark A Barr May 16 '16 at 06:47
  • if I remove the canvas.drawBitmap Line it works without error but obviously does not draw it on the canvas which says to me it it loading in but not drawing or am i completely misreading this – Mark A Barr May 16 '16 at 07:47
  • It's not. It failed and recycled the bitmap. If you don't try to use the bitmap then it won't point out that there's no bitmap there. You can make sure it's not recycled, which is good because there's a couple other reasons that might happen anyway. But, no, my best guess is it could be the path thing .toString() is not a path. But, you could certainly catch the error easier yourself if you just tried to open the file instream yourself and then you'd have finer grain control over where it failed rather than letting the loader thing catch it internally and recycle your bitmap. – Tatarize May 16 '16 at 18:45
  • I found out the issue My phone has just upgraded to android 6.0 which has a whole new permissions structure. to test I manually changed storage permision on the phone and it works Now I just need to work out what code i need to add to make this worlk properly any ideas??? – Mark A Barr May 21 '16 at 07:44
  • The setup there isn't too hard. And it's set in the compatibility libraries so you're actually good. https://blog.xamarin.com/requesting-runtime-permissions-in-android-marshmallow/ has a pretty good rundown. Though, with the latest library you only need to check the self-permissions in the compatibility bit. It checks the version and whether you have them set and calls it a day. – Tatarize May 22 '16 at 05:55
  • Also, http://stackoverflow.com/questions/33666071/android-marshmallow-request-permission You just need to delegate back to the system to check if you have them. Pre-marshmallow it'll just say yes if you required them in your manifest file. After marshmallow it'll ask the user for them at that point. – Tatarize May 22 '16 at 06:05