이전에 있던 Camera2 프리뷰 기능에 캡쳐기능을 추가하였다.


우선 코드는 책(빛과 소리의 향연 안드로이드 프로그래밍, 박헌재)의 코드를 사용하였다.


코드가 간단할 뿐만 아니라, 블로그에 있던 코드와 거의 흡사하여 적용이 용이하다.


기존의 코드에서 takePicture함수만 추가되었다.


코드 설명에 앞서 Camera2의 특징은 출력을 여러가지로 할 수 있다.


하나의 카메라의 출력을 프리뷰, 사진, 동영상으로 전송할 수 있다.


각각의 출력을 surface라고 한다.


여러 surface를 지정하여 다른 해상도의 사진을 동시에 촬영 가능하다.


또한 동영상을 촬영하는 동안 사진을 저장할 수 있다.


그럼 코드를 보자


protected void takePicture() {
if(null == mCameraDevice) {
Log.e(TAG, "mCameraDevice is null, return");
return;
}

try {
Size[] jpegSizes = null;
if (map != null) {
jpegSizes = map.getOutputSizes(ImageFormat.JPEG);
}
int width = 640;
int height = 480;
if (jpegSizes != null && 0 < jpegSizes.length) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}

ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture()));

final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

// Orientation
int rotation = ((Activity)mContext).getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));

final File file = new File(Environment.getExternalStorageDirectory()+"/DCIM", "pic.jpg");

ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
reader.close();
}
}
}

private void save(byte[] bytes) throws IOException {
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes);
} finally {
if (null != output) {
output.close();
}
}
}
};

HandlerThread thread = new HandlerThread("CameraPicture");
thread.start();
final Handler backgroudHandler = new Handler(thread.getLooper());
reader.setOnImageAvailableListener(readerListener, backgroudHandler);

final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session,
CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(mContext, "Saved:"+file, Toast.LENGTH_SHORT).show();
startPreview();
}

};

mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, backgroudHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

@Override
public void onConfigureFailed(CameraCaptureSession session) {

}
}, backgroudHandler);

} catch (CameraAccessException e) {
e.printStackTrace();
}
}


중간에 outputSurface를 설정하여 이곳에서 출력을 사진과 프리뷰를 설정하였다.


사진을 찍는 동시에 프리뷰를 보는 동작을 하기 위해서이다.


찍은 사진은 ImageReader클래스를 이용하여 출력을 한다.


ImageReader에서 출력된 사진은 JPEG 형식으로 저장된다.



좀 더 복잡한 코드는 다음과 같다.


Camera2Basic : https://github.com/googlesamples/android-Camera2Basic


mCaptureCallback을 이용하여 최적화가 잘 되어있다. 



GitHub : https://github.com/pchan1401-ICIL/picture2.git









+ Recent posts