Resize image taken from gallery or camera, before being uploaded

10,230

Well all it needed was an if statement to check what method the user chose. file is created in the showAttachmentDialog and so the private imageUri allways has the Uri of that file. When the user chooses the camera option result also has that values whereas when he chooses gallery result has the Uri of the image chosen from the galery

if(result==this.imageUri){
            newPath=file.getAbsolutePath();}
            else{
            newPath=getRealPathFromURI(getApplicationContext(), result);}

The final code is

@Override
    //Receives the results of startActivityFromResult
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        String newPath;
        if (requestCode == FILECHOOSER_RESULTCODE) {

            if (null == this.mUploadMessage) {
                return;
            }

            Uri result;
            if (resultCode != RESULT_OK) {
                result = null;
            } else {
                result = intent == null ? this.imageUri : intent.getData(); // retrieve from the private variable if the intent is null
                Log.e("result",result.toString() );
                Log.e("intent",this.imageUri.toString() );

            }

            if(result==this.imageUri){
            newPath=file.getAbsolutePath();}
            else{
            newPath=getRealPathFromURI(getApplicationContext(), result);}

            Bitmap bMap= BitmapFactory.decodeFile(newPath);
            Bitmap out = Bitmap.createScaledBitmap(bMap, 150, 150, false);
            File resizedFile = new File(imageStorageDir, "resize.png");

            OutputStream fOut=null;
            try {
                fOut = new BufferedOutputStream(new FileOutputStream(resizedFile));
                out.compress(Bitmap.CompressFormat.PNG, 100, fOut);
                fOut.flush();
                fOut.close();
                bMap.recycle();
                out.recycle();

            } catch (Exception e) { // TODO

            }


            this.mUploadMessage.onReceiveValue(Uri.fromFile(resizedFile));
            this.mUploadMessage = null;
            //resizedFile.delete();


        }
    }

    public String getRealPathFromURI(Context context, Uri contentUri) {
          Cursor cursor = null;
          try { 
            String[] proj = { MediaStore.Images.Media.DATA };
            cursor = context.getContentResolver().query(contentUri,  proj, null, null, null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
          } finally {
            if (cursor != null) {
              cursor.close();
            }
          }
        }
Share:
10,230
magmike
Author by

magmike

Updated on June 07, 2022

Comments

  • magmike
    magmike almost 2 years

    I have a form in my site that allows the user to upload a photo. My android app uses WebView to allow users access the site. On click of the upload button the app allows the user to choose between an image already existing in the gallery or take a new photo and upload that image. The code I have used for this is

    showAttachmentDialog is called by the openFileChooser

    private void showAttachmentDialog(ValueCallback<Uri> uploadMsg) {
            this.mUploadMessage = uploadMsg;
    
            File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");
            // Create the storage directory if it does not exist
            if (! imageStorageDir.exists()){
                imageStorageDir.mkdirs();                  
            }
            File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
    
    
            this.imageUri= Uri.fromFile(file);
    
    
            final List<Intent> cameraIntents = new ArrayList<Intent>();
            final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            final PackageManager packageManager = getPackageManager();
            final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
            for(ResolveInfo res : listCam) {
                final String packageName = res.activityInfo.packageName;
                final Intent intent = new Intent(captureIntent);
                intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
                intent.setPackage(packageName);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                cameraIntents.add(intent);
            }
    
    
           // mUploadMessage = uploadMsg; 
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);  
            intent.addCategory(Intent.CATEGORY_OPENABLE);  
            intent.setType("image/*"); 
            Intent chooserIntent = Intent.createChooser(intent,"Image Chooser");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
            this.startActivityForResult(chooserIntent,  FILECHOOSER_RESULTCODE);
        }
    

    My onActivityResult

    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
            if (requestCode == FILECHOOSER_RESULTCODE) {
    
                if (null == this.mUploadMessage) {
                    return;
                }
    
                Uri result;
                if (resultCode != RESULT_OK) {
                    result = null;
                } else {
                    result = intent == null ? this.imageUri : intent.getData(); // retrieve from the private variable if the intent is null
                }
    
                this.mUploadMessage.onReceiveValue(result);
                this.mUploadMessage = null;
    
    
    
            }
        }
    

    I would like to be able to change the size of the image before I upload it and I want this to be done on the phone , not in the webpage. I also want to delete the resized image from the phone when this is done and keep the prototype. Could you suggest me a way to do this? I show several cases in SO where it is suggested to create a bitmap and resize it in the desired size with createScaledBitmap but I am not sure which is the best way to do this in my case. Where should this take place? In my onActivityResult? Thanks in advance!

    --------------------EDIT----------------------

    private File imageStorageDir,file;

    I declared these in my main Activity and added the following snippet in my onActivityResult

    String newPath=file.getAbsolutePath();
                Bitmap bMap= BitmapFactory.decodeFile(newPath);
                Bitmap out = Bitmap.createScaledBitmap(bMap, 150, 150, false);
                File resizedFile = new File(imageStorageDir, "resized.png");
    
                OutputStream fOut=null;
                try {
                    fOut = new BufferedOutputStream(new FileOutputStream(resizedFile));
                    out.compress(Bitmap.CompressFormat.PNG, 100, fOut);
                    fOut.flush();
                    fOut.close();
                    bMap.recycle();
                    out.recycle();
    
                } catch (Exception e) { // TODO
    
                }
    

    Now the image is being resized and uploaded when taking a photo with the camera but when I am using the gallery I get a NullPointerException

    05-23 10:12:50.354: E/BitmapFactory(1376): Unable to decode stream: java.io.FileNotFoundException: /storage/sdcard/Pictures/MyApp/IMG_1400854361171.jpg: open failed: ENOENT (No such file or directory)
    05-23 10:12:50.364: D/AndroidRuntime(1376): Shutting down VM
    05-23 10:12:50.414: W/dalvikvm(1376): threadid=1: thread exiting with uncaught exception (group=0x41465700)
    05-23 10:12:50.494: E/AndroidRuntime(1376): FATAL EXCEPTION: main
    05-23 10:12:50.494: E/AndroidRuntime(1376): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://media/external/images/media/76 }} to activity {com.example.sinatra19/com.example.sinatra19.Sinatra22Activity}: java.lang.NullPointerException
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3367)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3410)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.app.ActivityThread.access$1100(ActivityThread.java:141)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1304)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.os.Handler.dispatchMessage(Handler.java:99)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.os.Looper.loop(Looper.java:137)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.app.ActivityThread.main(ActivityThread.java:5103)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at java.lang.reflect.Method.invokeNative(Native Method)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at java.lang.reflect.Method.invoke(Method.java:525)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at dalvik.system.NativeStart.main(Native Method)
    05-23 10:12:50.494: E/AndroidRuntime(1376): Caused by: java.lang.NullPointerException
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:482)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at com.example.sinatra19.Sinatra22Activity.onActivityResult(Sinatra22Activity.java:158)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.app.Activity.dispatchActivityResult(Activity.java:5322)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3363)
    05-23 10:12:50.494: E/AndroidRuntime(1376):     ... 11 more
    

    -----------------------EDIT2------------------------

    This snipet

               String newPath=getRealPathFromURI(getApplicationContext(), result);
    
    
                Bitmap bMap= BitmapFactory.decodeFile(newPath);
                Bitmap out = Bitmap.createScaledBitmap(bMap, 150, 150, false);
                File resizedFile = new File(imageStorageDir, "resize.png");
    
                OutputStream fOut=null;
                try {
                    fOut = new BufferedOutputStream(new FileOutputStream(resizedFile));
                    out.compress(Bitmap.CompressFormat.PNG, 100, fOut);
                    fOut.flush();
                    fOut.close();
                    bMap.recycle();
                    out.recycle();
    
                } catch (Exception e) { // TODO
    
                }
    this.mUploadMessage.onReceiveValue(Uri.fromFile(resizedFile));
            this.mUploadMessage = null;
    

    calling

    public String getRealPathFromURI(Context context, Uri contentUri) {
              Cursor cursor = null;
              try { 
                String[] proj = { MediaStore.Images.Media.DATA };
                cursor = context.getContentResolver().query(contentUri,  proj, null, null, null);
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
              } finally {
                if (cursor != null) {
                  cursor.close();
                }
              }
            }
    

    works when the user chooses photo from gallery and crashes when taking photo from camera. I need the way to combine them