安卓打开相机
在AndroidManifest.xml文件中manifest下添加相机权限
<!-- 相机 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 录音 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 存储卡读写 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- 获取网络状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 互联网 -->
<uses-permission android:name="android.permission.INTERNET" />
设置界面,包含一个按钮Button和一个ImageView,Button用来显示按钮,ImageView用来放置拍摄后的照片,全部代码如下:
界面代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_original"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="打开相机"
android:textColor="@color/black"
android:textSize="17sp"/>
</LinearLayout>
<ImageView
android:id="@+id/iv_photo"
android:layout_width="match_parent"
android:layout_height="360dp"
android:scaleType="fitCenter"/>
</LinearLayout>
MainActivity代码:
package com.example.ocr;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.ImageView;
import com.example.ocr.util.BitmapUtil;
import com.example.ocr.util.DateUtil;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CAMERA_PERMISSION = 100;
private ImageView iv_photo; // 声明一个图像视图对象
private Uri mImageUri;// 图片的路径对象
private ActivityResultLauncher launcherOriginal; // 声明一个活动结果启动器对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv_photo = findViewById(R.id.iv_photo);
// 注册一个善后工作的活动结果启动器,准备打开拍照界面(返回原始图)
launcherOriginal = registerForActivityResult(
new ActivityResultContracts.TakePicture(), result -> {
if (result) {
Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, mImageUri);
iv_photo.setImageBitmap(bitmap);
// 在这里处理原始照片的逻辑
}
});
findViewById(R.id.btn_original).setOnClickListener(v -> {
if (checkCameraPermission()) {
takeOriginalPhoto();
} else {
requestCameraPermission();
}
});
}
private boolean checkCameraPermission() {
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}
private void requestCameraPermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
// 显示权限说明对话框
// 可以使用一个对话框或其他方式向用户解释为什么需要相机权限,并在用户同意后请求权限
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
takeOriginalPhoto();
} else {
// 相机权限被拒绝,可以显示一条消息或执行其他操作
}
}
}
// 拍照时获取原始图片
private void takeOriginalPhoto() {
// Android10开始必须由系统自动分配路径,同时该方式也能自动刷新相册
ContentValues values = new ContentValues();
// 指定图片文件的名称
values.put(MediaStore.Images.Media.DISPLAY_NAME, "photo_" + DateUtil.getNowDateTime());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");// 类型为图像
// 通过内容解析器插入一条外部内容的路径信息
mImageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
launcherOriginal.launch(mImageUri);
}
}
BitmapUtil.java 文件代码:
package com.example.ocr.util;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import java.io.FileOutputStream;
import java.io.InputStream;
public class BitmapUtil {
private final static String TAG = "BitmapUtil";
// 把位图数据保存到指定路径的图片文件
public static void saveImage(String path, Bitmap bitmap) {
// 根据指定的文件路径构建文件输出流对象
try (FileOutputStream fos = new FileOutputStream(path)) {
// 把位图数据压缩到文件输出流中
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获得旋转角度之后的位图对象
public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree) {
Matrix matrix = new Matrix(); // 创建操作图片用的矩阵对象
matrix.postRotate(rotateDegree); // 执行图片的旋转动作
// 创建并返回旋转后的位图对象
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, false);
}
// 获得比例缩放之后的位图对象
public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio) {
int new_width = (int) (bitmap.getWidth() * scaleRatio);
int new_height = (int) (bitmap.getHeight() * scaleRatio);
// 创建并返回缩放后的位图对象
return Bitmap.createScaledBitmap(bitmap, new_width, new_height, false);
}
// 获得自动缩小后的位图对象
public static Bitmap getAutoZoomImage(Context ctx, Uri uri) {
Log.d(TAG, "getAutoZoomImage uri="+uri.toString());
Bitmap zoomBitmap = null;
// 打开指定uri获得输入流对象
try (InputStream is = ctx.getContentResolver().openInputStream(uri)) {
// 从输入流解码得到原始的位图对象
Bitmap originBitmap = BitmapFactory.decodeStream(is);
int ratio = originBitmap.getWidth()/2000+1;
// 获得比例缩放之后的位图对象
zoomBitmap = BitmapUtil.getScaleBitmap(originBitmap, 1.0/ratio);
} catch (Exception e) {
e.printStackTrace();
}
return zoomBitmap;
}
// 获得自动缩小后的位图对象
public static Bitmap getAutoZoomImage(Bitmap origin) {
int ratio = origin.getWidth()/2000+1;
// 获得比例缩放之后的位图对象
Bitmap zoomBitmap = getScaleBitmap(origin, 1.0/ratio);
return zoomBitmap;
}
// 通知相册来了张新图片
public static void notifyPhotoAlbum(Context ctx, String filePath) {
try {
String fileName = filePath.substring(filePath.lastIndexOf("/")+1);
MediaStore.Images.Media.insertImage(ctx.getContentResolver(),
filePath, fileName, null);
Uri uri = Uri.parse("file://" + filePath);
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
ctx.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
详细说明MainActivity代码
private static final int REQUEST_CAMERA_PERMISSION = 100;
private ImageView iv_photo; // 声明一个图像视图对象
private Uri mImageUri;// 图片的路径对象
private static final int REQUEST_CAMERA_PERMISSION = 100;
是用来定义请求相机权限的请求码。在Android中,当我们请求权限时,需要为每个权限请求分配一个唯一的请求码。
private ActivityResultLauncher launcherOriginal; // 声明一个活动结果启动器对象
ActivityResultLauncher launcherOriginal
是用于注册和处理拍照后返回的原始图片的活动结果启动器。
ActivityResultLauncher
是 Android Jetpack 库中的一个组件,它提供了一种方便的方式来处理活动结果(如启动相机拍照后返回的结果)。
在代码中,我们使用 registerForActivityResult()
方法来创建一个 ActivityResultLauncher
对象,并指定使用 ActivityResultContracts.TakePicture()
作为活动结果合同。这个合同定义了我们希望从活动结果中接收的数据类型和操作。
通过注册 ActivityResultLauncher
,我们可以在按钮点击事件中使用 launcherOriginal.launch(mImageUri)
来启动相机拍照,并在相机拍照完成后接收和处理返回的结果。
在 launcherOriginal
的回调中,我们可以根据结果进行逻辑处理。例如,在代码中,如果结果为 true
,则表示拍照成功,我们可以调用 BitmapUtil.getAutoZoomImage()
方法获取并处理原始照片的 Bitmap 对象,并将其显示在图像视图中。
通过使用 ActivityResultLauncher
,我们可以更方便地处理活动结果,并将逻辑封装在回调中,使代码更加清晰和易于维护。
new ActivityResultContracts.TakePicture(), result -> {
if (result) {
Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, mImageUri);
iv_photo.setImageBitmap(bitmap);
// 在这里处理原始照片的逻辑
}
});
result
是拍照操作完成后返回的结果。在使用 ActivityResultContracts.TakePicture()
合同启动相机拍照时,它将返回一个布尔值结果,表示拍照操作是否成功。
当用户完成拍照操作并返回时,系统会将结果传递给 result
参数,然后我们可以在回调中根据结果进行逻辑处理。
如果 result
为 true
,表示拍照成功。在这种情况下,我们可以继续处理原始照片的逻辑。在代码中,它调用了 BitmapUtil.getAutoZoomImage()
方法来获取并处理原始照片的 Bitmap 对象,并将其设置到 ImageView
中显示。
需要注意的是,根据具体的实现,result
的类型可能会有所不同。在 ActivityResultContracts.TakePicture()
合同中,它指定了返回的结果类型为 Boolean
,因此在回调中,result
的类型将是 Boolean
。
findViewById(R.id.btn_original).setOnClickListener(v -> {
if (checkCameraPermission()) {
takeOriginalPhoto();
} else {
requestCameraPermission();
}
});
findViewById(R.id.btn_original)
用于查找布局文件中具有 R.id.btn_original
ID 的按钮控件。这是一个点击事件监听器,当按钮被点击时,会执行相应的逻辑。
逻辑如下:
- 首先,通过
checkCameraPermission()
方法检查是否已经授予相机权限。 - 如果相机权限已经授予,则调用
takeOriginalPhoto()
方法开始拍照操作。 - 如果相机权限尚未授予,则调用
requestCameraPermission()
方法来请求相机权限。
这段代码的目的是在用户点击 “btn_original” 按钮时,检查相机权限状态,并根据权限状态执行相应的操作。如果权限已经授予,则启动拍照操作;如果权限尚未授予,则请求相机权限。这样可以确保在拍照之前获取必要的权限,以避免出现权限问题。
其中v
是一个参数名,用于表示被点击的 View(即按钮)对象。在设置点击事件的时候,Android 系统会自动将被点击的 View 对象传递给这个参数。
在点击事件的回调函数中,我们可以通过 v
参数来引用和操作被点击的 View 对象。例如,可以调用 v.getId()
方法获取被点击的 View 的 ID,或者调用 v.setVisibility(View.GONE)
来隐藏该 View。
在上述代码中,v
的作用是用来执行根据按钮点击状态执行相应的操作,如检查权限、请求权限或执行拍照操作等。
private boolean checkCameraPermission() {
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}
checkCameraPermission()
,用于检查是否已经授予相机权限。
在 Android 中,要使用敏感权限(如相机权限),需要在运行时动态请求用户授权。这个方法的作用是检查应用程序是否已经被授予了相机权限。
具体解释如下:
-
checkSelfPermission(this, Manifest.permission.CAMERA)
:通过调用ContextCompat.checkSelfPermission()
方法,检查应用程序是否已经被授予了相机权限。它接收两个参数,第一个参数是当前上下文(this
指向当前的Activity
或Context
对象),第二个参数是要检查的权限(这里是相机权限)。 -
PackageManager.PERMISSION_GRANTED
:这是一个常量,表示权限已经被授予的状态。 -
==
:比较操作符,用于比较两个值是否相等。 - 返回值:如果相机权限已经被授予,那么
checkSelfPermission()
返回值将等于PackageManager.PERMISSION_GRANTED
,因此方法返回true
。否则,返回false
,表示相机权限尚未被授予。
通过调用这个方法,我们可以在需要使用相机功能之前检查相机权限的状态,以确保应用程序具备所需的权限,从而避免在没有权限的情况下执行相机相关的操作。
private void requestCameraPermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
// 显示权限说明对话框
// 可以使用一个对话框或其他方式向用户解释为什么需要相机权限,并在用户同意后请求权限
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
}
-
shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
:通过调用ActivityCompat.shouldShowRequestPermissionRationale()
方法,检查是否应该显示权限说明对话框。它接收两个参数,第一个参数是当前上下文(this
指向当前的Activity
或Context
对象),第二个参数是要请求的权限(这里是相机权限)。- 如果返回
true
,表示此时应该向用户显示权限说明对话框。可以使用一个对话框或其他方式向用户解释为什么需要相机权限,并在用户同意后再次请求权限。 - 如果返回
false
,表示此时不应该显示权限说明对话框,可以直接请求权限。
- 如果返回
-
requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION)
:通过调用ActivityCompat.requestPermissions()
方法,请求相机权限。它接收三个参数,第一个参数是当前上下文(this
指向当前的Activity
或Context
对象),第二个参数是要请求的权限数组(这里只包含相机权限),第三个参数是请求权限的请求码(这里使用常量REQUEST_CAMERA_PERMISSION
)。- 当调用这个方法后,系统会显示一个权限请求对话框给用户,用户可以选择授予或拒绝权限。
- 结果将通过
onRequestPermissionsResult()
方法回调给当前Activity
,可以在该方法中处理用户的权限授予结果。
通过调用这个方法,我们可以在需要相机权限的时候向用户请求权限,以便应用程序能够使用相机功能。如果用户之前拒绝了权限请求,还可以在需要的时候向用户解释权限的必要性,并再次请求权限。
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
takeOriginalPhoto();
} else {
// 相机权限被拒绝,可以显示一条消息或执行其他操作
}
}
}
这是一个回调方法 onRequestPermissionsResult()
,当用户对权限请求作出响应时,系统会调用该方法。
具体解释如下:
-
requestCode == REQUEST_CAMERA_PERMISSION
:首先,检查请求码是否与相机权限请求的请求码匹配。这是为了确保在多个权限请求的情况下,正确处理相机权限的回调。 -
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
:检查授权结果数组grantResults
的长度是否大于0,并且第一个权限的授权结果是否为PackageManager.PERMISSION_GRANTED
。- 如果条件满足,表示用户授予了相机权限。
- 如果条件不满足,表示用户拒绝了相机权限。
- 如果用户授予了相机权限,可以调用
takeOriginalPhoto()
方法来执行拍照操作。- 在该方法中,会获取相机权限并执行拍照逻辑。
- 如果用户拒绝了相机权限,可以在
else
代码块中执行其他操作,比如显示一条消息告知用户相机权限被拒绝,或者执行其他逻辑。
通过实现这个方法,可以根据用户对权限请求的响应,来处理相机权限授予或拒绝的情况,并做出相应的处理操作。
private void takeOriginalPhoto() {
// Android10开始必须由系统自动分配路径,同时该方式也能自动刷新相册
ContentValues values = new ContentValues();
// 指定图片文件的名称
values.put(MediaStore.Images.Media.DISPLAY_NAME, "photo_" + DateUtil.getNowDateTime());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");// 类型为图像
// 通过内容解析器插入一条外部内容的路径信息
mImageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
launcherOriginal.launch(mImageUri);
}
- 创建一个
ContentValues
对象values
,用于存储拍照图片的相关信息。 - 使用
put()
方法向values
中添加键值对:-
MediaStore.Images.Media.DISPLAY_NAME
:指定图片文件的名称,使用当前日期和时间作为文件名的一部分。 -
MediaStore.Images.Media.MIME_TYPE
:指定图片的 MIME 类型,这里设置为 “image/jpeg”,表示图片类型为 JPEG。
-
- 通过内容解析器
getContentResolver().insert()
方法将图片的路径信息插入到外部存储器的 MediaStore 数据库中,返回一个表示图片的 Uri 对象mImageUri
。-
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
是表示外部存储器中的图片集合的 Uri。
-
- 最后,使用
launcherOriginal.launch(mImageUri)
启动拍照活动,并传递图片的 Uri 对象mImageUri
。-
launcherOriginal
是之前通过registerForActivityResult()
注册的活动结果启动器,用于处理拍照活动的结果。
-
总体来说,这段代码的作用是创建一个用于拍照的 Uri,并将其传递给 launcherOriginal
启动器,以便启动拍照活动。
详细说明BitmapUtil.java 文件代码
public static void saveImage(String path, Bitmap bitmap) {
// 根据指定的文件路径构建文件输出流对象
try (FileOutputStream fos = new FileOutputStream(path)) {
// 把位图数据压缩到文件输出流中
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
} catch (Exception e) {
e.printStackTrace();
}
}
方法签名:public static void saveImage(String path, Bitmap bitmap)
-
path
是保存图片文件的路径,为字符串类型。 -
bitmap
是要保存的位图对象。
在方法内部,通过构建文件输出流对象 FileOutputStream
,将位图数据写入到指定路径的文件中。
-
try (FileOutputStream fos = new FileOutputStream(path)) { bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos); } catch (Exception e) { e.printStackTrace(); }
-
FileOutputStream
是用于将数据写入文件的输出流。 -
compress()
方法用于将位图数据压缩到文件输出流中。 -
Bitmap.CompressFormat.JPEG
表示将位图以 JPEG 格式进行压缩。 -
80
是压缩质量的参数,取值范围为 0-100,数值越大表示质量越好,文件大小也越大。 -
fos
是通过构造方法创建的文件输出流对象。
-
总体来说,这段代码的作用是将位图对象 bitmap
的数据压缩并保存到指定路径 path
的图片文件中。
public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree) {
Matrix matrix = new Matrix(); // 创建操作图片用的矩阵对象
matrix.postRotate(rotateDegree); // 执行图片的旋转动作
// 创建并返回旋转后的位图对象
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, false);
}
方法签名:public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree)
-
bitmap
是要进行旋转的位图对象。 -
rotateDegree
是旋转的角度,以顺时针方向为正值。
在方法内部,首先创建一个用于操作图片的矩阵对象 Matrix
。
Matrix matrix = new Matrix();
使用 matrix.postRotate(rotateDegree)
方法来执行图片的旋转动作。这里的 rotateDegree
是旋转的角度。
最后,使用 Bitmap.createBitmap()
方法创建并返回旋转后的位图对象。
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
-
Bitmap.createBitmap()
方法用于根据给定的源位图和矩阵创建新的位图。 - 参数解释:
-
bitmap
:源位图对象。 -
(0, 0)
:裁剪的起始点坐标,这里表示从原始位图的左上角开始裁剪。 -
bitmap.getWidth()
:裁剪的宽度,这里表示裁剪整个宽度。 -
bitmap.getHeight()
:裁剪的高度,这里表示裁剪整个高度。 -
matrix
:用于对源位图进行操作的矩阵对象。 -
false
:是否对源位图进行原位修改。这里设置为false
,表示创建新的位图对象。
-
因此,这段代码的作用是将给定的位图对象 bitmap
进行旋转,旋转角度由 rotateDegree
参数指定,并返回旋转后的位图对象。
public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio) {
int new_width = (int) (bitmap.getWidth() * scaleRatio);
int new_height = (int) (bitmap.getHeight() * scaleRatio);
// 创建并返回缩放后的位图对象
return Bitmap.createScaledBitmap(bitmap, new_width, new_height, false);
}
方法签名:public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio)
-
bitmap
是要进行缩放的位图对象。 -
scaleRatio
是缩放比例,大于1表示放大,小于1表示缩小。
在方法内部,首先计算缩放后的新宽度和新高度。
int new_width = (int) (bitmap.getWidth() * scaleRatio);
int new_height = (int) (bitmap.getHeight() * scaleRatio);
-
bitmap.getWidth()
获取源位图的宽度。 -
bitmap.getHeight()
获取源位图的高度。 -
scaleRatio
是缩放比例。
使用 Bitmap.createScaledBitmap()
方法创建并返回缩放后的位图对象。
return Bitmap.createScaledBitmap(bitmap, new_width, new_height, false);
Bitmap.createScaledBitmap()
方法用于根据给定的源位图和目标宽高创建新的位图。文章来源:https://www.toymoban.com/news/detail-717387.html
- 参数解释:
-
bitmap
:源位图对象。 -
new_width
:目标位图的宽度。 -
new_height
:目标位图的高度。 -
false
:是否对源位图进行原位修改。这里设置为false
,表示创建新的位图对象。
-
因此,这段代码的作用是将给定的位图对象 bitmap
进行缩放操作,缩放比例由 scaleRatio
参数指定,并返回缩放后的位图对象文章来源地址https://www.toymoban.com/news/detail-717387.html
到了这里,关于安卓开发-调用相机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!