在 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;
}
根据 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;
}