前文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()) {//获取代表摄像头特征类characteristicscharacteristics = 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<Integer> 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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);}
也欢迎关注个人公众号,移动开发,音视频,图形图像,大厂内推,不定时更新