Camera1 实战:拍照功能实现
好,咱们直接进入正题。Camera1 虽然老,但市面上大量设备还在用。你想想看,很多定制 ROM、低端机、甚至一些工业平板,Camera1 依然是主力。我个人习惯是,不管新 API 多香,Camera1 这套基本功必须扎实。
1. 拍照流程概览
拍照这件事,说白了就三步:打开相机、预览画面、拍下来。但中间藏着不少坑。我画了张图,你先看个全貌。
嗯,这里要注意:拍照前必须保证预览已经启动。我在项目中遇到过新手直接调 takePicture() 然后黑屏,就是因为预览没开。
2. 打开相机与预览
打开相机很简单,但有个细节——一定要在子线程里做。Camera.open() 是耗时操作,放主线程会卡界面。
private Camera mCamera;
private void openCamera() {
try {
mCamera = Camera.open(); // 默认打开后置
} catch (Exception e) {
e.printStackTrace();
// 我曾经遇到过某些设备 Camera.open() 返回 null
// 所以最好加个判空
}
}
private void startPreview(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
3. 自动对焦
自动对焦是拍照的命门。你想想看,一张照片糊了,其他参数再好也没用。Camera1 的对焦模式有好几种,我列个表给你看。
| 对焦模式 | 适用场景 | 说明 |
|---|---|---|
| FOCUS_MODE_AUTO | 普通拍照 | 单次对焦,触发后锁定 |
| FOCUS_MODE_CONTINUOUS_PICTURE | 连拍/抓拍 | 持续对焦,适合移动物体 |
| FOCUS_MODE_CONTINUOUS_VIDEO | 视频录制 | 平滑对焦,避免频繁跳动 |
| FOCUS_MODE_FIXED | 固定距离 | 不支持自动对焦的设备用 |
我个人习惯用 CONTINUOUS_PICTURE 作为默认。但要注意,不是所有设备都支持。所以设置前一定要检查一下。
private void setupAutoFocus() {
Camera.Parameters params = mCamera.getParameters();
List<String> supportedModes = params.getSupportedFocusModes();
if (supportedModes != null) {
if (supportedModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (supportedModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
}
mCamera.setParameters(params);
}
4. 触摸对焦
触摸对焦是用户交互的关键。说白了就是用户点哪里,相机就对焦到哪里。Camera1 里通过 autoFocus() 配合 MeteringAreas 实现。
嗯,这里有个坑:MeteringAreas 只在 API 14+ 支持。低版本设备只能做简单的中心对焦。
public void onTouchFocus(Rect touchRect) {
Camera.Parameters params = mCamera.getParameters();
if (params.getMaxNumMeteringAreas() > 0) {
List<Camera.Area> areas = new ArrayList<>();
areas.add(new Camera.Area(touchRect, 1000));
params.setMeteringAreas(areas);
}
if (params.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<>();
focusAreas.add(new Camera.Area(touchRect, 1000));
params.setFocusAreas(focusAreas);
}
mCamera.setParameters(params);
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
// success 表示对焦是否成功
// 我曾经遇到过某些设备永远返回 false
// 但实际画面是清晰的,所以别太依赖这个回调
}
});
}
camera.autoFocus() 触发实际对焦动作。
5. 闪光灯控制
闪光灯控制其实就三种模式:开、关、自动。但实现上有个小陷阱——拍照时闪光灯和预览时闪光灯是两回事。
| 模式 | 预览时 | 拍照时 |
|---|---|---|
| FLASH_MODE_OFF | 不亮 | 不闪 |
| FLASH_MODE_ON | 常亮(部分设备) | 拍照时闪 |
| FLASH_MODE_AUTO | 不亮 | 根据环境自动 |
| FLASH_MODE_TORCH | 常亮(手电筒模式) | 常亮 |
private void setFlashMode(String mode) {
Camera.Parameters params = mCamera.getParameters();
List<String> supportedFlashModes = params.getSupportedFlashModes();
if (supportedFlashModes != null && supportedFlashModes.contains(mode)) {
params.setFlashMode(mode);
mCamera.setParameters(params);
}
}
// 使用示例
setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
6. 相机参数调节
相机参数调节是 Camera1 最灵活也最麻烦的地方。常用的参数有:
- 图片大小:用 getSupportedPictureSizes() 获取,选一个最接近屏幕比例的
- 预览大小:同样用 getSupportedPreviewSizes(),注意要和 Surface 比例匹配
- 白平衡:AUTO、DAYLIGHT、FLUORESCENT 等
- ISO:部分设备支持,低光场景有用
- 曝光补偿:范围一般是 -3 到 +3,步长 0.5
private void setupParameters() {
Camera.Parameters params = mCamera.getParameters();
// 设置图片大小
Camera.Size pictureSize = getOptimalSize(
params.getSupportedPictureSizes(), 1920, 1080);
params.setPictureSize(pictureSize.width, pictureSize.height);
// 设置预览大小
Camera.Size previewSize = getOptimalSize(
params.getSupportedPreviewSizes(), 1280, 720);
params.setPreviewSize(previewSize.width, previewSize.height);
// 设置白平衡
params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
// 设置曝光补偿
int maxExposure = params.getMaxExposureCompensation();
int minExposure = params.getMinExposureCompensation();
if (maxExposure != 0 || minExposure != 0) {
params.setExposureCompensation(0); // 默认0
}
mCamera.setParameters(params);
}
private Camera.Size getOptimalSize(List<Camera.Size> sizes, int w, int h) {
// 这里简单实现:选第一个支持的
// 实际项目中需要根据比例和分辨率做匹配
return sizes.get(0);
}
7. 拍照与保存
最后一步,拍照。调用 takePicture() 后,会触发三个回调:
- onShutter():快门声响起时调用
- onRawPictureAvailable():原始数据回调(可选)
- onJpegPicture():JPEG 数据回调,在这里保存图片
private void takePhoto() {
mCamera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {
// 播放快门音效
}
}, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// 保存图片到文件
File pictureFile = new File(Environment
.getExternalStorageDirectory(), "photo.jpg");
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
// 拍照后预览会停止,需要重新启动
camera.startPreview();
}
});
}
8. 释放资源
最后,别忘了释放 Camera。不释放的话,其他应用就打不开相机了。
private void releaseCamera() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
好了,Camera1 拍照的核心功能就这些。说白了就是:打开、设参、预览、对焦、拍照、释放。每一步都有细节,但掌握了这些,你就能应付大部分场景了。
公众号:蓝海资料掘金营,微信deep3321