在 Android 11 (R) 中捕获和裁剪图像

Capture and crop image in Android 11 (R)

根据 android R 隐私政策更改,我想为 android R 设备执行捕获和裁剪图像功能。我尝试了以下方法,但它保存了空文件(文件在指定文件夹中创建,但大小为 0kb)。

我正在使用 Android-image-cropper 库裁剪图像。

public static File createImageFile(Context context) throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + ".jpg";

    File storageDir, image;

    if(SDK_INT >= Build.VERSION_CODES.Q){
        OutputStream outputStream;
        ContentResolver contentResolver = context.getContentResolver();
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, imageFileName);
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES +  File.separator + SD_FOLDER_NAME);
        Uri imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
        outputStream = contentResolver.openOutputStream(Objects.requireNonNull(imageUri));
        Objects.requireNonNull(outputStream);
        storageDir = new File(Environment.DIRECTORY_PICTURES +  File.separator + SD_FOLDER_NAME);
    }else{
        storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + SD_FOLDER_NAME);
    }

    if (!storageDir.exists()) {
        storageDir.mkdirs();
    }

    image = new File(storageDir, imageFileName);

    if (image.createNewFile()) {
        Log.d(TAG, ":Image file created");
    } else {
        Log.d(TAG, ":Image file not created");
    }
    return image;
}

以下是我的相机打开和拍摄功能:

 private void openCamera() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Uri photoURI = null;
        try {
            fileUri = Utils.createImageFile(requireContext());
            if(SDK_INT >= Build.VERSION_CODES.Q)
                photoURI = FileProvider.getUriForFile(requireActivity(), requireActivity().getPackageName(), fileUri);
            else
                photoURI = FileProvider.getUriForFile(requireActivity(), requireActivity().getPackageName() + ".com.enrich.salonapp.provider", fileUri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
        startActivityForResult(intent, REQUEST_CODE_CAMERA_PICTURE);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PictureSelectorDialog.REQUEST_CODE_CAMERA_PICTURE && resultCode == Activity.RESULT_OK) {
            imageCapture.onImageCaptured(fileUri.getAbsolutePath(), false);
        } else if (requestCode == PictureSelectorDialog.REQUEST_CODE_GALLERY_PICTURE && resultCode == Activity.RESULT_OK) {
            if (FileUtils.getPath(getActivity(), data.getData()) == null) {
                imageCapture.onImageCaptured(data.getData().toString(), true);
            } else {
                imageCapture.onImageCaptured(FileUtils.getPath(getActivity(), data.getData()), false);
            }
        }

        this.dismissAllowingStateLoss();
    }

此外,我没有找到如何使用文件提供程序获取 URI。

if(SDK_INT >= Build.VERSION_CODES.Q)
                photoURI = FileProvider.getUriForFile(requireActivity(), requireActivity().getPackageName(), fileUri);

在看到多个答案、开发人员文档等之后。我最终得到了下面的工作解决方案,希望这会对某人有所帮助。

AndroidManifest

 <uses-permission android:name="android.permission.CAMERA" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="29"/>

android:requestLegacyExternalStorage="true"

 <provider
     android:name=".util.GenericFileProvider"
     android:authorities="${applicationId}.provider.profile"
     android:exported="false"
     android:grantUriPermissions="true">
     <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths"/>
 </provider>

PictureSelectorDialog.java

public static final int REQUEST_CODE_CAMERA_PICTURE = 1232;
public static final int REQUEST_CODE_GALLERY_PICTURE = 1233;
private File fileUri;
private ImageCapture imageCapture;
private boolean isDenied = false;

private void openGallery() {
        Intent intent;
        intent = new Intent(Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(Intent.createChooser(intent, getString(R.string.choose_from_gallery)), REQUEST_CODE_GALLERY_PICTURE);
    }

    private void openCamera() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            Uri photoURI = null;
            try {
                fileUri = Utils.createImageFile(requireContext());
                photoURI = FileProvider.getUriForFile(requireContext(), BuildConfig.APPLICATION_ID + ".provider.profile", fileUri);
            } catch (IOException e) {
                e.printStackTrace();
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(intent, REQUEST_CODE_CAMERA_PICTURE);
    }



  @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PictureSelectorDialog.REQUEST_CODE_CAMERA_PICTURE && resultCode == Activity.RESULT_OK) {
                imageCapture.onImageCaptured(fileUri.getAbsolutePath(), false);
        } else if (requestCode == PictureSelectorDialog.REQUEST_CODE_GALLERY_PICTURE && resultCode == Activity.RESULT_OK) {
            if (FileUtils.getPath(getActivity(), data.getData()) == null) {
                Uri uri = data.getData();
                ParcelFileDescriptor parcelFileDescriptor;
                try {
                    parcelFileDescriptor = requireContext().getContentResolver().openFileDescriptor(uri, "r");
                    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                    parcelFileDescriptor.close();

                    File tempFile = createImageFile(requireContext());

                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    image.compress(Bitmap.CompressFormat.JPEG, 100 , bos);
                    byte[] bitmapData = bos.toByteArray();

                    FileOutputStream fos = new FileOutputStream(tempFile);
                    fos.write(bitmapData);

                    imageCapture.onImageCaptured( tempFile.getAbsolutePath(), true);

                    fos.flush();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                imageCapture.onImageCaptured(FileUtils.getPath(getActivity(), data.getData()), false);
            }
        }

        this.dismissAllowingStateLoss();
    }

public interface ImageCapture {
        void onImageCaptured(String path, boolean isGooglePhotoURI);
    }

Utils.java

public static File createImageFile(Context context) throws IOException {
        String timeStamp = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS_FOR_IMAGE_NAMING, Locale.getDefault()).format(new Date());
        String imageFileName = "PROFILE_PICTURE_" + timeStamp;
        File image, storageDir;

        if (SDK_INT < Build.VERSION_CODES.Q) {
            storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + YOUR_FOLDER_NAME);
            if (!storageDir.exists()) {
                storageDir.mkdirs();
            }
            image = new File(storageDir, imageFileName + ".jpg");
            image.createNewFile();
        } else {
            storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES + File.separator + YOUR_FOLDER_NAME);
            image = File.createTempFile(imageFileName, ".jpg", storageDir);
            String currentPhotoPath = image.getAbsolutePath();
        }

        return image;
    }