前文Android Camera2.0 API实现摄像头预览并获取人脸关键坐标已经介绍了Camera2.0的基础内容,在2.0的API中,要想实现拍照功能,则要借助于ImageReader。
首先在自定义的TextureView.SurfaceTextureListener的实现类中,维护ImageReader的引用
private ImageReader mImageReader ;
然后在setUpCamera方法中对ImageReader进行初始化
/**
* 设置camera2.0的初始化参数
*/
private void setUpCamera() {
cameraManager = (CameraManager)mContext.getSystemService(Context.CAMERA_SERVICE);
try{
for (String id : cameraManager.getCameraIdList()) {
//获取代表摄像头特征类characteristics
characteristics = cameraManager.getCameraCharacteristics(id);
//如果是前置摄像头
if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
mCameraId = id ;
StreamConfigurationMap streamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
sizes = streamConfigurationMap.getOutputSizes(SurfaceHolder.class);
//设置预览大小
mPreviewSize = sizes[0];
//imageReader初始化
mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(),
mPreviewSize.getHeight(),
ImageFormat.JPEG,
2 );
mImageReader.setOnImageAvailableListener(onImageAvailableListener , mBackgroundHandler);
//获取人脸检测参数
int[] FD =characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);
int maxFD=characteristics.get(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT);
if (FD.length>0) {
List fdList = new ArrayList<>();
for (int FaceD : FD
) {
fdList.add(FaceD);
Log.e(TAG, "setUpCameraOutputs: FD type:" + Integer.toString(FaceD));
}
Log.e(TAG, "setUpCameraOutputs: FD count" + Integer.toString(maxFD));
if (maxFD > 0) {
mFaceDetectSupported = true;
mFaceDetectMode = Collections.max(fdList);
}
}
}
}
} catch ( CameraAccessException e ){
e.printStackTrace();
}
}
然后将ImageReader的Surface添加进CaptureRequest.Builder中
在startPreview()方法中添加
previewRequestBuilder.addTarget(mImageReader.getSurface());
接下来创建一个类实现ImageReader.OnImageAvailableListener接口,在其中获取每一帧的Image对象,并生成一个Bitmap,并对该Bitmap进行镜像和旋转操作,因为摄像头获取的原始图像和预览中见到的图像是并不一样
/**
*OnImageAvailableListener实现类
*/
private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireNextImage() ;
ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
try {
Bitmap temp = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
Bitmap newBitmap = Bitmap.createBitmap(mPreviewSize.getWidth(),mPreviewSize.getWidth(),temp.getConfig());
Canvas canvas = new Canvas(newBitmap);
Paint paint = new Paint();
Matrix matrix = new Matrix();
//图片镜像并旋转90度
matrix.setScale(-1, 1);
matrix.postTranslate(temp.getWidth(), 0);
matrix.postRotate(90 ,temp.getWidth()/2,temp.getHeight()/2);
matrix.postTranslate(0,(temp.getWidth()-temp.getHeight())/2);
canvas.drawBitmap(temp, matrix , paint );
File newFile = new File( Environment.getExternalStorageDirectory() , "345.jpg");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
newBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
temp.recycle();
newBitmap.recycle();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
image.close();
byteBuffer.clear();
}
image.close();
}
};
上面做的是用ImageReader获取每一帧实时图像,要想实现拍照,调用CameraCaptureSession的capture方法即可
public void captureStillImage(){
try {
CaptureRequest.Builder captureStillBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureStillBuilder.addTarget(mImageReader.getSurface());
// 设置自动对焦模式
captureStillBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 设置自动曝光模式
captureStillBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
int rotation = ((Activity)mContext).getWindowManager().getDefaultDisplay().getRotation();
captureStillBuilder.set( CaptureRequest.JPEG_ORIENTATION ,
ORIENTATIONS.get(rotation));
CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(mContext,"Image Captured" , Toast.LENGTH_SHORT).show();
}
};
captureSession.stopRepeating();
captureSession.capture( captureStillBuilder.build() , captureCallback , null );
captureSession.setRepeatingRequest(captureRequest, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
}
},mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
在成员变量中设置ROTATION
//设置Surface旋转角
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0,90);
ORIENTATIONS.append(Surface.ROTATION_90,0);
ORIENTATIONS.append(Surface.ROTATION_180,270);
ORIENTATIONS.append(Surface.ROTATION_270,180);
}