Always Null returned after cropping a photo from a Uri in Android Lollipop?
Asked Answered
A

4

5

I tried to crop an image from a Uri after taking a photo or picking a picture. And my codes are like these:

public static void cropImage(Uri uri, Activity activity, int action_code) {
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(uri, "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    intent.putExtra("outputX", 600);
    intent.putExtra("outputY", 600);
    intent.putExtra("scale", true);
    intent.putExtra("return-data", true);
    if (intent.resolveActivity(activity.getPackageManager()) != null) {
        activity.startActivityForResult(intent, action_code);
    } else {
        Toast.makeText(activity, "No Crop App Available", Toast.LENGTH_SHORT).show();
    }
}

And overridding onActivityResult() like this:

if (resultCode == Activity.RESULT_OK && requestCode == Utils.CODE_CROP_IMAGE) {
    Bundle extras = data.getExtras();
    showCenterToast("ccc");
    if (extras != null) {
        showCenterToast("CCC");
        Bitmap photo = extras.getParcelable("data");
        ivAvatar.setImageBitmap(photo); // display image in ImageView
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(Utils.AVATAR_FILE);
            photo.compress(Bitmap.CompressFormat.PNG, 100, fos);// (0-100)compressing file
            showCenterToast("DDD");
            Utils.AVATAR_FILE_TMP.delete();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
           IoUtil.closeSilently(fos);
        }
    }
}

On devices in Android Pre-Lollipop, I was able to obtain Bitmap photo and display it in an ImageView. But, on Android Lollipop, I always got null from data.getExtras();.

I googled a lot but got few useful things about cropping an image on Android Lollipop.

Android changed its returning mechanism of cropping of com.android.camera.action.CROP on Lollipop. So, what is the new mechanism? How could I get the returned Bitmap after cropping on Lollipop?

Any tips will be appreciated. Thanks in advance.

Algar answered 7/7, 2015 at 7:14 Comment(5)
I have never worked on CROP, but can you check if you get soemthing from data.getData()? It might be a URI?Etiquette
I got a Uri by data.getData() after picking a picture, and succeeded converting into a Uri after taking a picture. I used this Uri to crop, but got nothing after cropping process finished by Bitmap photo = extras.getParcelable("data"); as recommended.Algar
I meant check everything in data when requestCode == Utils.CODE_CROP_IMAGE. May be there is Uri in it, may be the cropped image is in content provider too.Etiquette
I tried Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), data.getData()); when current version is equal or greater than Lollipop, but NPE is thrown. On Lollipop, I sure think data is returned, but I don't know where it is and how to get it.Algar
did you got any solution for this?Secluded
S
9

I think that your problem has nothing to do with Android version but the image you want to be cropped. Cropping image processed in class com.android.gallery3d.filtershow.crop.CropActivity#BitmapIOTask. When the image is too large to return, it will try to return the thumb of the image, and will return null sometimes. To avoid this, you can get the uri of cropped image instead of bitmap by setting intent.putExtra(MediaStore.EXTRA_OUTPUT, tmpUri); where tmpUri is an uri created to hold the result. And then you can get the bitmap from tmpUri.

Sample code:

private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";//temp file
private static Uri tmpUri = Uri.parse(IMAGE_FILE_LOCATION);//The Uri to store the big bitmap

public static void cropImage(Uri uri, Activity activity, int action_code) {
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(uri, "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    intent.putExtra("outputX", 600);
    intent.putExtra("outputY", 600);
    intent.putExtra("scale", true);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, tmpUri);
    if (intent.resolveActivity(activity.getPackageManager()) != null) {
        activity.startActivityForResult(intent, action_code);
    } else {
        Toast.makeText(activity, "No Crop App Available", Toast.LENGTH_SHORT).show();
    }
}

And in function onActivityResult:

if (resultCode == Activity.RESULT_OK && requestCode == Utils.CODE_CROP_IMAGE) {
    // Bundle extras = data.getExtras();
    Uri uri = data.getData();
    showCenterToast("ccc");
    if (uri != null) {
        showCenterToast("CCC");
        // Bitmap photo = null;
        // if (tmpUri != null) {
        //     photo = decodeBitmapFromUri(tmpUri); // Get bitmap from uri.
        // }

        Bitmap photo = decodeUriAsBitmap(uri);
        ivAvatar.setImageBitmap(photo); // display image in ImageView
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(Utils.AVATAR_FILE);
            photo.compress(Bitmap.CompressFormat.PNG, 100, fos);// (0-100)compressing file
            showCenterToast("DDD");
            Utils.AVATAR_FILE_TMP.delete();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
           IoUtil.closeSilently(fos);
        }
    } else {
        showCenterToast("Uri is NULL");
    }
}

private Bitmap decodeUriAsBitmap(Uri uri){
    Bitmap bitmap = null;
    try {
        bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        return null;
    }
    return bitmap;
}

I have not test whether my code was correct, but I think you can fix the bugs.

Springs answered 7/7, 2015 at 9:52 Comment(5)
@Algar Hava you got an uri in onActivity? If the uri is not empty, you can just get the absolute path of the file and decode bitmap from the file.Springs
Yes, I tried. BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)) or BitmapFactory.decodeFile(filePath), neither worked.Algar
I have edit my code a little and test it, which works well. Have you add the permission android.permission.WRITE_EXTERNAL_STORAGE to AndroidManifest.xml?Springs
This is nice answer. It solved my problem. Thanks a lot :)Grot
wow! it really worked but im still confuse why this was happening! the uri when you sets to a imgview it worked but if you try to BitmapFactory.decodeFile(image_url, bitmapOptions decode this was giving you a file not found or null exception.and as you mention about large bitmap then in this case how could we do such functions? By the way i think the openstream funct is one of the best in bitmap cases.Junk
U
2

I Solved It and Working Now

Basically when cropping image in fragment the issue is here, when you use activity you should pass intent in this way in on activity result for best approach to cropping follow this library

compile 'com.theartofdev.edmodo:android-image-cropper:2.5.+'.

 CropImage.activity(imageUri)
                            .setGuidelines(CropImageView.Guidelines.ON)
                            .start(getActivity());

When you use Fragment you should use:

 Uri selectedImageUri = data.getData();
                CropImage.activity(selectedImageUri)
                        .setGuidelines(CropImageView.Guidelines.ON)
                        .start(getContext(), this);

Sometimes getcontext requires api 23 this is because you using app.fragment, so use android.support.v4.app.

Cropping Image with activity and Fragment is Different, see here i have Successfully Implement this thing.follow the link here, for guideline. how cropping image with in activity and fragment !!!

I was feeling difficulty while cropping image in fragment so its not solved. First you take image from camera or gallery.

private void openGallery() {

    Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
    photoPickerIntent.setType("image/*");
    startActivityForResult(photoPickerIntent, REQUEST_CODE_GALLERY);
}

In case of taking image from camera don't forget to include file provider Manifest fil , if you fee trouble then before doing next follow this link.

Android - file provider - permission denial

    private String mCurrentPhotoPath;
private void openCameranoughat() {

    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
        Uri photoURI = null;
        try {
            File photoFile = createImageFile();
            path = photoFile.getAbsolutePath();
            photoURI = FileProvider.getUriForFile(getActivity(),
                    BuildConfig.APPLICATION_ID + ".provider",
                    createImageFile());

        } catch (IOException ex) {
            Log.e("TakePicture", ex.getMessage());
        }
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
            takePictureIntent.setClipData(ClipData.newRawUri("", photoURI));
            takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        startActivityForResult(takePictureIntent, REQUEST_CODE_CAPTURE);
    }
}

private File createImageFile() throws IOException {

    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";

    File path = Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES);
    File file = new File(path, "DemoPicture.jpg");

    try {
        // Make sure the Pictures directory exists.
        path.mkdirs();
    } catch (Exception e) {

    }

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = "file:" + file.getAbsolutePath();
    return file;
}

Now on activity result for Fragment Activity you have to write this code.

 @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (resultCode != RESULT_OK) {
        return;
    }

    switch (requestCode) {
        case ACTION_REQUEST_EDITIMAGE://
            handleEditorImage(data);
            break;

        case REQUEST_CODE_GALLERY:

            if (mCurrentPhotoPath == null) {

                Uri selectedImageUri = data.getData();
                CropImage.activity(selectedImageUri)
                        .setGuidelines(CropImageView.Guidelines.ON)
                        .start(getContext(), this);
            }

            break;

        case REQUEST_CODE_CAPTURE:

            try {
                Uri imageUri = Uri.parse(mCurrentPhotoPath);
                if (imageUri == null) {

                } else {
                    CropImage.activity(imageUri)
                            .setGuidelines(CropImageView.Guidelines.ON)
                            .start(getContext(), this);
                    MediaScannerConnection.scanFile(getActivity(),
                            new String[]{imageUri.getPath()}, null,
                            new MediaScannerConnection.OnScanCompletedListener() {
                                public void onScanCompleted(String path, Uri uri) {
                                }
                            });
                    mCurrentPhotoPath = null;
                }

            } catch (Exception e) {

            }

            break;

        case CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE:
            CropImage.ActivityResult result = CropImage.getActivityResult(data);
            Uri resultUri = result.getUri();
            if (resultUri != null) {
                path = resultUri.getPath();
                if (TextUtils.isEmpty(path)) {
                    return;
                }
                Intent it = new Intent(getActivity(), EditImageActivity.class);
                it.putExtra(EditImageActivity.FILE_PATH, path);
                File outputFile = FileUtils.getEmptyFile("tietu"
                        + System.currentTimeMillis() + ".jpg");
                it.putExtra(EditImageActivity.EXTRA_OUTPUT,
                        outputFile.getAbsolutePath());
                startActivityForResult(it,
                        ACTION_REQUEST_EDITIMAGE);

            }

            break;

        case CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE:
            Toast.makeText(getActivity(), "error in cropping", Toast.LENGTH_SHORT).show();
            break;
    }
    super.onActivityResult(requestCode, resultCode, data);
}
Underwear answered 24/1, 2018 at 6:38 Comment(0)
K
0
  1. Use intent to get image:

    Intent pickImageIntent = new Intent(Intent.ACTION_PICK, 
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    pickImageIntent.setType("image/*");
    startActivityForResult(pickImageIntent, 100);
    
  2. Use Activity Result to receiver data and get Uri.

  3. Use android-crop to crop and get image.

Kassey answered 5/6, 2017 at 4:45 Comment(0)
M
0

On Lollipop, the cropped image is returned as a String reference to a uri in the result data action. Example:

final String action = data.getAction();
Uri imageUri = Uri.parse(action)
Macrocosm answered 6/7, 2018 at 18:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.