Android 打开相册、拍照、裁剪图片的坑
关于Android 7.0所需要做的权限适配
Android 7.0 之后对读取文件操作做了限制,如果不处理一个应用获取file://格式的URI的话,应用会抛出FileUriExposedException。这时我们需要用到Fileprovider,关于Fileprovider的用法 参考 这篇文章
Android 7.0 Uri适配:
Uri uri;
if (Build.VERSION.SDK_INT >= 24) {
uri = FileProvider.getUriForFile(context, "com.hjl.android7.fileprovider", file);
} else {
uri = Uri.fromFile(file);
}
调用系统摄像头关键代码
imageUri: 需要传入适配后的Uri 这个Uri 保存拍照后的照片,可以在Activity 里面直接调用此方法,并且在 onActivityResult 回调方法中对Uri里的照片进行操作
public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
//调用系统相机 imageUri: 需要传入适配后的Uri 这个Uri 保存拍照后的照片
Intent intentCamera = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
}
intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
//将拍照结果保存至photo_file的Uri中,不保留在相册中
intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
if (activity!=null){
activity.startActivityForResult(intentCamera, requestCode);
}
}
调用系统摄像头关键代码
public static void openPic(Activity activity, int requestCode) {
Intent albumIntent = new Intent(Intent.ACTION_PICK, null);
albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
activity.startActivityForResult(albumIntent, requestCode);
}
在 onActivityResult 回调方法中得到选取的图片Uri:
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
Uri uri = data.getData();
... //拿到uri后就可以进行相应的处理了
}
拿到uri后就可以进行相应的处理了,例如转换成bitmap对象并缓存到本地:
File file = new File(FileUtils.getSDCachePath(),"test.png");
//缓存文件路径
try {
OutputStream fos = new FileOutputStream(file);
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream( data.getData() ));
bitmap.compress(Bitmap.CompressFormat.PNG,100,fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
裁剪图片关键代码
/**
* @param activity 当前activity
* @param orgUri 剪裁原图的Uri
* @param desUri 剪裁后的图片的Uri
* @param aspectX X方向的比例
* @param aspectY Y方向的比例
* @param width 剪裁图片的宽度
* @param height 剪裁图片高度
* @param requestCode 剪裁图片的请求码
*/
public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
Intent intent = new Intent("com.android.camera.action.CROP");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intent.setDataAndType(orgUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
intent.putExtra("outputX", width);
intent.putExtra("outputY", height);
intent.putExtra("scale", true);
//将剪切的图片保存到目标Uri中
intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
intent.putExtra("noFaceDetection", true);
intent.putExtra("scaleUpIfNeeded", true);//去除黑边
activity.startActivityForResult(intent, requestCode);
}
注意:
- 第一个坑:
desUri 保存裁剪后的图片: 这个desUri是要使用Uri.fromFile(file)生成的,而不是使用 FileProvider.getUriForFile,否则会显示:“无法保存经过裁剪的图片”
并且设置 intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri); 输出的Uri之后,在onActivityResult 里通过 data.getData() 获取的Uri 会为空 - 第二个坑:
如果裁剪的图片像素过低,会出现黑边,解决方法:在上面的调用裁剪方法中加上下面两句
裁剪图片后出现黑边:
intent.putExtra("scale", true);//去除黑边
intent.putExtra("scaleUpIfNeeded", true);//去除黑边