Android开发实战:基于Camera API构建自定义相机应用教程
引言
在移动互联网时代,相机应用已成为智能手机的标配功能之一。无论是拍照、录像还是实时滤镜,相机应用都为用户提供了丰富的视觉体验。作为一名Android开发者,掌握Camera API的使用是必不可少的一项技能。本文将带你一步步构建一个基于Camera API的自定义相机应用,从基础设置到高级功能,让你全面掌握相机开发的精髓。
一、准备工作
1.1 创建项目
首先,打开Android Studio,创建一个新的Android项目。选择“Empty Activity”模板,命名为“CustomCameraApp”。
1.2 添加权限
在AndroidManifest.xml
文件中,添加必要的相机权限和存储权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
1.3 请求运行时权限
在MainActivity
中,请求运行时权限:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION);
}
二、布局设计
2.1 创建布局文件
在res/layout
目录下创建activity_main.xml
,设计相机预览界面:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/btnCapture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Capture"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"/>
</RelativeLayout>
三、相机预览
3.1 初始化相机
在MainActivity
中,初始化相机和SurfaceView:
private Camera camera;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height);
camera.setParameters(parameters);
camera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
}
}
});
}
四、拍照功能
4.1 捕获图片
在MainActivity
中,添加按钮点击事件,实现拍照功能:
Button btnCapture = findViewById(R.id.btnCapture);
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (camera != null) {
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
saveImageToStorage(data);
camera.startPreview();
}
});
}
}
});
4.2 保存图片
private void saveImageToStorage(byte[] data) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
Toast.makeText(this, "Image saved: " + pictureFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private File getOutputMediaFile() {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "CustomCameraApp");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
return new File(mediaStorageDir.getPath() + File.separator +
"IMG_" + timeStamp + ".jpg");
}
五、高级功能
5.1 切换摄像头
在布局中添加切换摄像头的按钮,并在MainActivity
中实现切换功能:
<Button
android:id="@+id/btnSwitchCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch Camera"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"/>
Button btnSwitchCamera = findViewById(R.id.btnSwitchCamera);
btnSwitchCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
}
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
} else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(currentCameraId);
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
});
5.2 添加滤镜
使用OpenCV或其他图像处理库,为相机预览添加滤镜效果。这里以简单的灰度滤镜为例:
private void applyGrayScaleFilter(byte[] data) {
Mat rgba = new Mat(height, width, CvType.CV_8UC4);
rgba.put(0, 0, data);
Mat gray = new Mat(height, width, CvType.CV_8UC1);
Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_RGBA2GRAY);
byte[] grayData = new byte[width * height];
gray.get(0, 0, grayData);
saveImageToStorage(grayData);
}
在onPictureTaken
回调中调用applyGrayScaleFilter
方法:
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
applyGrayScaleFilter(data);
camera.startPreview();
}
});
六、总结
七、参考资料
- Android官方文档 - Camera API
- OpenCV官方文档
- Android运行时权限处理
祝你在Android开发的道路上越走越远,创造出更多精彩的应用!