Android调用系统相机/相册并裁剪详解
Posted 我想月薪过万
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android调用系统相机/相册并裁剪详解相关的知识,希望对你有一定的参考价值。
效果展示
源码下载
android调用系统相机/相册并裁剪源码-互联网文档类资源-CSDN文库https://download.csdn.net/download/qq_41885673/34059233
关键技术
android文件管理系统
代码编写
第一步:布局文件的准备
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="相机"
android:onClick="camera"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="相册"
android:onClick="album"/>
<ImageView
android:id="@+id/iv_show_select"
android:layout_width="match_parent"
android:layout_height="400dp"/>
</LinearLayout>
第二步:相机 拍照 然后获取照片并显示
- 方法一:调用系统相机时未设置 uri
package com.wust.camerademo;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ImageView;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {
private ImageView iv_show_select;
private int CAMERA_REQ_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv_show_select = findViewById(R.id.iv_show_select);
}
public void camera(View v) {
//跳转时未设置 uri
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_REQ_CODE);
}
public void album(View v) {
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_OK) {
if (data.hasExtra("data")) {
// 方法一:没有指定 uri 时图片资源由 data.getParcelableExtra("data") 获取
iv_show_select.setImageBitmap(data.getParcelableExtra("data"));
System.out.println("拍照完成");
}
} else if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_CANCELED) {
System.out.println("拍照取消");
}
}
}
- 方法二:调用系统相机时设置了 uri
注意点一:当 android api 为 23 的时候 这个 uri 已经不能简单的由 Uri.fromFile(file) 获取了,否则会报错,如下所示:
Caused by: android.os.FileUriExposedException: file:///data/user/0/com.wust.camerademo/files/test.jpg exposed beyond app through ClipData.Item.getUri()
注意点二: 我们得使用 FileProvider ,但是别忘了在清单文件中配置
Couldn‘t find meta-data for provider with authority com.wust.camerademo_我想月薪过万的博客-CSDN博客https://blog.csdn.net/qq_41885673/article/details/120925348注意点三:Android_照相机Camera_调用系统照相机返回data为空Android_照相机Camera_调用系统照相机返回data为空_zimo2013的技术博客-CSDN博客https://blog.csdn.net/zimo2013/article/details/16916279
正确完整代码
package com.wust.camerademo;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ImageView;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {
private ImageView iv_show_select;
private int CAMERA_REQ_CODE = 1;
private Uri uri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv_show_select = findViewById(R.id.iv_show_select);
}
public void camera(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String path = getFilesDir().getAbsolutePath() + File.separator + "test.jpg"; //这里只是当前目录,如果是多级文件夹 得通过 mkdirs 创建
File file = new File(path);
//由于 Android 文件安全机制 向第三方应用提供路径的时候得使用 FileProvider,注意需要在清单文件中注册
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
uri = FileProvider.getUriForFile(MainActivity.this, "com.wust.camerademo", file);
} else {
uri = Uri.fromFile(file);
}
//这里设置了 uri 那么后面就不能使用 data.getParcelableExtra("data") 获取图片了
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, CAMERA_REQ_CODE);
}
public void album(View v) {
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_OK) {
System.out.println(data);
if (data != null && data.hasExtra("data")) {
// 方法一:没有指定 uri 时图片资源由 data.getParcelableExtra("data") 获取
iv_show_select.setImageBitmap(data.getParcelableExtra("data"));
System.out.println("data.getParcelableExtra(data) 方式获取");
} else {
// 方法二:通过 uri 方式获取
try {
InputStream is = getContentResolver().openInputStream(uri);
iv_show_select.setImageBitmap(BitmapFactory.decodeStream(is));
is.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("uri 方式获取 =》 " + uri);
}
} else if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_CANCELED) {
System.out.println("拍照取消");
}
}
}
附件:
清单文件配置
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.wust.camerademo"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
file_paths文件配置
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="test"
path="." />
</paths>
第三步:相册 获取 照片
public void album(View v) {
//跳转相册 Intent.ACTION_PICK 、Intent.ACTION_GET_CONTENT 、Intent.ACTION_OPEN_DOCUMENT 三者任选其一
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, ALBUM_REQ_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_OK) {
...
} else if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_CANCELED) {
System.out.println("拍照取消");
} else if (requestCode == ALBUM_REQ_CODE && resultCode == RESULT_OK) {
Uri uri = data.getData();
try {
InputStream is = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
iv_show_select.setImageBitmap(bitmap);
} catch (Exception e) {
}
System.out.println("相册获取");
}
}
第四步:调用系统裁剪工具对图片进行裁剪
注意点一:报错如下
Caused by: java.lang.SecurityException: UID 10221 does not have permission to content://com.android.providers.media.documents/document/image%3A681 [user 0]; you could obtain access using ACTION_OPEN_DOCUMENT or related APIs
错误原因:在进行 相册 跳转时 应该选择
Intent.ACTION_PICK 或 Intent.ACTION_OPEN_DOCUMENT
注意点二:如果报如下错误,说明创建的 uri 有问题,导致裁剪后的图片无法保存
注意点三:如下错误是由于android文件系统安全性限制导致的,修改的地方还是 uri 创建处。但是这里的修改要注意 不能使用 FileProvider ,因为这个导致裁剪后的图片无法保存;也不能使用传统的 Environment.getExternalStorageDirectory() 因为android Q 之后,外置存储环境也设置了分区,每个应用只能访问自己的分区(根据包名划分分区)。所以,综上所述,在创建 uri 的时候得使用 getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
正确代码
跳转相册部分代码
public void album(View v) {
//跳转相册 Intent.ACTION_PICK 、Intent.ACTION_GET_CONTENT 、Intent.ACTION_OPEN_DOCUMENT 三者任选其一
Intent intent = new Intent(Intent.ACTION_PICK); //这个地方会导致 报 注意一 的错误
intent.setType("image/*");
startActivityForResult(intent, ALBUM_REQ_CODE);
}
通过相册选取照片后的代码
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_OK) {
...
} else if (requestCode == CAMERA_REQ_CODE && resultCode == RESULT_CANCELED) {
System.out.println("拍照取消");
} else if (requestCode == ALBUM_REQ_CODE && resultCode == RESULT_OK) {
Uri uri = data.getData();
cropPhoto(uri);
System.out.println("相册获取");
} else if (requestCode == CROP_REQ_CODE && resultCode == RESULT_OK) {
try {
InputStream is = getContentResolver().openInputStream(uritempFile);
Bitmap bitmap = BitmapFactory.decodeStream(is);
iv_show_select.setImageBitmap(bitmap);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("图片裁剪完毕");
}
}
裁剪照片的代码
private void cropPhoto(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
//添加读写权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
//设置裁剪数据来源和类型
intent.setDataAndType(uri, "image/*");
//设置裁剪为true
intent.putExtra("crop", "true");
//设置大小
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
//不能以这种形式返回图片数据 因为现在图片很大 我们得以 uri 方式返回
//intent.putExtra("return-data", true); 配合 onActivityResult
// =》 Bundle bundle = intent.getExtras();
// =》 final Bitmap image = bundle.getParcelable("data");
//创建 uri getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) 这个地方会出现 注意点二 或 注意点三 的报错
uritempFile = Uri.parse("file://" + "/" + getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + "/" + "small.jpg");
System.out.println("uritempFile => " + uritempFile);
//设置 uri
intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
//设置格式
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(intent, CROP_REQ_CODE);
}
源码下载
Android调用系统相机/相册并裁剪源码-互联网文档类资源-CSDN文库https://download.csdn.net/download/qq_41885673/34059233
以上是关于Android调用系统相机/相册并裁剪详解的主要内容,如果未能解决你的问题,请参考以下文章
Android Studio 调用系统相机(超清)和相册的照片并显示在ImageView