Always Null returned after cropping a photo from a

2020-07-14 05:30发布

问题:

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.

回答1:

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.



回答2:

  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.



回答3:

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);
}


回答4:

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)