Search code examples
androidbitmapandroid-sdcardfileinputstream

Android Dev: Creating a Bitmap from a temp file stored on the SD card, setting an ImageView, then storing it locally


So due to the quality issues of just getting the data from the android.media.action.IMAGE_CAPTURE, I apparently needed to call the activity, save a local temporary file that I can then create a Bitmap from. This Bitmap will be cropped into a square, set to an ImageView, then stored locally; However, I'm having some problems. Everything (excluding the cropping for now) works up to setting the image (it returns a blank image) and storing it internally, at which point it crashes. I attempt to find the file on the SD card with a file manager but the folder doesn't even show up, So I don't know if the file is even really being created. Any ideas what I'm doing wrong? The code:

private static final String TAG = "AddEdit";
private final static String FOLDER_NAME = "com.ex.beerlog/Image/";
private Uri selectedImageUri = null;
private final static int CAPTURE_IMAGE_CALLBACK = 1;


switch (arg0.getId()) {
            case R.id.imageView1:

                File photo = null;
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");

                if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
                    photo = new File(android.os.Environment.getExternalStorageDirectory(), FOLDER_NAME + File.separator
                            + "temp.png");
                    Log.w(TAG, "*******Photo path set from Enviro*********");
                } else {
                    photo = new File(getCacheDir(), FOLDER_NAME + File.separator + "temp.png");
                    Log.w(TAG, "*******photo set from cache*********");
                }
                if (photo != null) {
                    Log.w(TAG, "*******Photo is not null*********");
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
                    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
                    selectedImageUri = Uri.fromFile(photo);
                    Log.w(TAG, "*******from imageUri=" + selectedImageUri + "*********");
                    startActivityForResult(intent, CAPTURE_IMAGE_CALLBACK);
                }
 break;



  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
            case CAPTURE_IMAGE_CALLBACK:
                if (resultCode == RESULT_OK) {
                    String path = selectedImageUri.toString();
                    Log.w(TAG, "*****path set =" + path + "******");
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    Log.w(TAG, "*****Bimapfactory options set******");
                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                    Log.w(TAG, "****Options defined********");
                    bmp = BitmapFactory.decodeFile(path, options);
                    Log.w(TAG, "*****Bmp is set ==> crop******");

                    brewPhoto.setImageBitmap(bmp);
                    Log.w(TAG, "******************Image is set to ButtonImage**********************");
                    // Store image
                    FileOutputStream fos;
                    Log.w(TAG, "********FileOutPutStream created*************");
                    try {
                        fos = openFileOutput(cDate, Context.MODE_PRIVATE);
                        Log.w(TAG, "********FileOutPutStream defined*************");
                        bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
                        Log.w(TAG, "********bitmap compressed*************");
                        fos.close();
                        Log.w(TAG, "*****FOS closed**********");
                    } catch (FileNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                break;
        }
    }

Here's the error log that I receive:

03-18 21:24:50.325: W/AddEdit(8208): *****path set =file:///storage/sdcard0/com.ex.beerlog/Image/temp.png******
03-18 21:24:50.325: W/AddEdit(8208): *****Bimapfactory options set******
03-18 21:24:50.325: W/AddEdit(8208): ****Options defined********
03-18 21:24:50.325: I/System.out(8208): Not a DRM File, opening notmally
03-18 21:24:50.325: W/AddEdit(8208): *****Bmp is set ==> crop******
03-18 21:24:50.325: W/AddEdit(8208): ******************Image is set to ButtonImage**********************
03-18 21:24:50.325: W/AddEdit(8208): ********FileOutPutStream created*************
03-18 21:24:50.325: W/AddEdit(8208): ********FileOutPutStream defined*************
03-18 21:24:50.335: W/dalvikvm(8208): threadid=1: thread exiting with uncaught exception (group=0x41314438)
03-18 21:24:50.335: E/AndroidRuntime(8208): FATAL EXCEPTION: main
03-18 21:24:50.335: E/AndroidRuntime(8208): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=null} to activity {com.ex.beerlog/com.ex.beerlog.AddEdit}: java.lang.NullPointerException
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3183)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3226)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.app.ActivityThread.access$1200(ActivityThread.java:139)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1272)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.os.Handler.dispatchMessage(Handler.java:99)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.os.Looper.loop(Looper.java:137)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.app.ActivityThread.main(ActivityThread.java:4918)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at java.lang.reflect.Method.invokeNative(Native Method)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at java.lang.reflect.Method.invoke(Method.java:511)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at dalvik.system.NativeStart.main(Native Method)
03-18 21:24:50.335: E/AndroidRuntime(8208): Caused by: java.lang.NullPointerException
03-18 21:24:50.335: E/AndroidRuntime(8208):     at com.ex.beerlog.AddEdit.onActivityResult(AddEdit.java:329)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.app.Activity.dispatchActivityResult(Activity.java:5232)
03-18 21:24:50.335: E/AndroidRuntime(8208):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3179)
03-18 21:24:50.335: E/AndroidRuntime(8208):     ... 11 more

So as you can see the fileInputSteam is created but it crashes when it attempts to store the image. I've removed this segment of code and the image that gets set to the ImageView is blank (transparent). So I'm assuming it's crashing because nothing is actually there? I've attempted to setup permissions in the Manifest to allow access to the SD card. Also to note I'm testing on my Galaxy sIII, with the debugger enabled. I also unprotected the SD card and unplugged the phone to make sure the SD card was available, but it's the same result every time.

Thanks again. You all here are pretty amazing at this stuff!


Solution

  • Okay so I figured out my problem, and hopefully this will help others out there like me with this problem.

    The long and short of it is that if you want to collect the high quality information from your CAMERA intent you have to (from what I've found) save the image to the SD card. My application was returning a blank (what I thought was transparent) image, because the image never existed. You must create the file path, it is not an automatic process.

    I accomplished this by just setting a static path, and created a temp.png at that location:

    File photo = null;
    File path = new File("storage/sdcard0/Android/data/com.ex.beerlog/");
    String pathstring = path.toString();
    if (!path.exists()) {
        path.mkdirs();
        Log.w(TAG, "*******Photo Directory Created*********");
    } else { // do nothing }
    

    Finally I still wanted to store my captured photos internally, but the image size would cause an Out of Memory (OOM) exception. So to remedy this I created a matrix that scaled down the image to 350px wide (really the max size image my application requires). **You'll notice a "matrix.postrotate(90)' this is because my photos would otherwise return on their side.

     private Bitmap cropImage(Bitmap bmp2) {
         // TODO Auto-generated method stub
         int width = bmp2.getWidth();
         int height = bmp2.getHeight();
         float scale = (float) 350/bmp.getHeight();
           
         Log.w(TAG, "*********Image Wt=" + width + ", Ht=" + height + " scale" + scale + "*********");
    
         Matrix matrix = new Matrix();
         matrix.postScale(scale, scale);
         matrix.postRotate(90);
    
         // recreate the new Bitmap
         Bitmap resizedBitmap = Bitmap.createBitmap(bmp2, 0, 0, width, height, matrix, true);
         int bmpHtWidth = resizedBitmap.getWidth();
         int bmpHeight = resizedBitmap.getHeight();
         int bmpTop = (bmpHeight - bmpHtWidth) / 2;
         Log.w(TAG, "*********resizedImage HtWt=" + bmpHtWidth + ", Ht=" + bmpHeight + ", top=" + bmpTop + "*********");
    
         return resizedBitmap;
     }
    

    These essentially answered my question above. Hope it helps someone else too!

    EDIT: Oh finally I ran into a problem when I got a little photo crazy between activities, resulting in an OutOfMemoryException. To fix this I used the Bitmap.recycle() function before my activity closed and moved to the next activity. This will attempt to free up some memory between activities.