前面已经对camera的API和相关知识进行了描述,下面我们就camera的实例进行讲解。
android使用camera开发拍照应用最基本的流程:
- 使用open(int cameraId)获取camera实例。
- 为camera实例设置预览类,他是一个SurfaceHolder对象,通过setPreviewDisplay(SurfaceHolder)设置。
- 调用startPreview()开始camera实例的预览
- 调用takePicture()方法进行拍照,其中可以通过Camera.PictureCallback()回调获得拍摄的Image数据。
- 当拍摄完成后,需要调用stopPreview()停止预览,并使用release()释放camera占用的资源。
以上步骤是必不可少的过程,camera没有公开的构造函数,只能通过open()方法获取camera实例,并且设置一个surfaceHolder预览类,如果这一步未实现的,将无法使用camera。待camera使用完成后,必须使用release()释放camera资源。下面便就实例进行详细的讲解。
以下实例分为这几步:
- 系统权限配置
- 相机布局
- 相机预览设置
- 相机拍照
系统权限配置
// 相机权限
<uses-permission android:name="android.permission.CAMERA" />
// 文件读写权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
// 相机自动对焦配置
<uses-feature android:name="android.hardware.camera.autofocus" />
相机布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MyCameraActivity">
<!--预览相机画面-->
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--两个按钮,取消和拍照-->
<LinearLayout
android:id="@+id/view_bottom_operate"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#FFF"
android:gravity="center"
android:orientation="horizontal"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/btn_cancle"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center"
android:text="取消"
android:textColor="#000"
android:src="@mipmap/icon_cancle"
android:textSize="18sp" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/btn_take_picture"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center"
android:text="点击拍照"
android:textColor="#000"
android:src="@mipmap/icon_take_picture"
android:textSize="18sp" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=""
android:textColor="#000"
android:textSize="18sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
相机预览设置
相机预览设置需要先获取相机以及相机预览尺寸,然后在将相机预览画面通过SurfaceView显示出来。
获取相机
/**
* 获取相机实例
*
* @param cameraId 相机编号
* @param degrees 预览旋转角度
* @return
*/
private Camera getCamera(int cameraId, int degrees) {
if (null == mCamera) {
try {
mCamera = Camera.open(cameraId);
mCamera.setDisplayOrientation(degrees);
} catch (Exception e) {
}
}
return mCamera;
}
获取最佳预览尺寸
1、获取相机支持的所有预览分辨率
// 获取相机支持的所有预览分辨率
List<Camera.Size> allSupportedSize =
mCamera.getParameters().getSupportedPreviewSizes();
2、计算合适的分辨率进行预览
这一步就是获取一个与SurfaceView同等分辨率比例的一个最大分辨率尺寸,只有这样在预览和拍照时相片才不会变形。
/**
* 获取适合的分辨率
*
* @param camera camera实例
* @param rate 预览尺寸长宽比
* @return 获取
*/
private Camera.Size getSupportedPreviewSize(Camera camera, int rate) {
Camera.Parameters camPara = camera.getParameters();
List<Camera.Size> allSupportedSize = camPara.getSupportedPreviewSizes();
for (Camera.Size tmpSize : allSupportedSize) {
if (tmpSize.width / tmpSize.height == rate) {
return tmpSize;
}
}
return null;
}
3、进行相机预览
相机预览分为三步:
- 实现surfaceHolder的回调
- 将surfaceHolder设置为camera的显示控件
- 开启相机预览
private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
@Override
public boolean isCreating() {
return false;
}
@Override
public void addCallback(Callback callback) {
}
@Override
public void removeCallback(Callback callback) {
}
@Override
public void setFixedSize(int width, int height) {
}
@Override
public void setSizeFromLayout() {
}
@Override
public void setFormat(int format) {
}
@Override
public void setType(int type) {
}
@Override
public void setKeepScreenOn(boolean screenOn) {
}
@Override
public Canvas lockCanvas() {
return null;
}
@Override
public Canvas lockCanvas(Rect dirty) {
return null;
}
@Override
public void unlockCanvasAndPost(Canvas canvas) {
}
@Override
public Surface getSurface() {
return null;
}
@Override
public Rect getSurfaceFrame() {
return null;
}
};
private void restartPreview(SurfaceHolder holder) {
if (camera != null) {
if (holder.getSurface() == null) {
return;
}
try {
camera.stopPreview();
} catch (Exception e) {
}
try {
// 将surfaceViewHolder设置为camera的显示控件
camera.setPreviewDisplay(holder);
// 开启相机预览
camera.startPreview();
if (listener != null) {
listener.onStartPreview();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
4、拍照
拍照只需要调用camera.takePicture()即可。