728x90
안녕하세요 오늘은 Camera2를 사용하여서 사진을 찍는 예제를 만들어 보겠습니다.
이전 포스트 에서 이어집니다. 이전 포스트 읽고와주세요
https://stickode.tistory.com/1079
MainActivity.java
public class MainActivity extends AppCompatActivity {
// 카메라 미리보기를 위한 TextureView
private TextureView textureView;
// 카메라 디바이스를 참조하기 위한 객체
private CameraDevice cameraDevice;
// 캡처 요청을 만들기 위한 Builder
private CaptureRequest.Builder captureRequestBuilder;
// 카메라 캡처 세션
private CameraCaptureSession cameraCaptureSession;
String fileName = "IMG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".jpg";
// 카메라 사용 권한 요청 코드
private static final int REQUEST_CAMERA_PERMISSION = 200;
// TextureView의 상태를 감지하는 리스너
private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// 텍스쳐뷰가 사용 가능할 때 카메라를 여는 함수 호출
openCamera();
}
// 텍스처 크기가 변경될 때 호출
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
// 텍스쳐가 파괴될 때 호출
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
// 텍스쳐가 업데이트될 때 호출
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
// 카메라 상태 콜백
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
// 카메라가 성공적으로 열리면 CameraDevice 인스턴스를 할당하고 미리보기 시작
cameraDevice = camera;
createCameraPreview();
}
@Override
public void onDisconnected(CameraDevice camera) {
// 카메라 연결이 끊기면 닫음
cameraDevice.close();
}
@Override
public void onError(CameraDevice camera, int error) {
// 에러 발생시 카메라 닫고 null 할당
cameraDevice.close();
cameraDevice = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textureView = findViewById(R.id.textureView);
// TextureView에 리스너 설정
textureView.setSurfaceTextureListener(textureListener);
Button takePictureButton = findViewById(R.id.btn_takepicture);
takePictureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 사진 촬영 버튼 클릭 이벤트
takePicture(); // 사진 촬영 메소드 호출
}
});
}
// 카메라 미리보기를 생성하는 메소드
private void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
// 텍스처의 크기를 카메라 미리보기 크기로 설정
texture.setDefaultBufferSize(1920, 1080);
Surface surface = new Surface(texture);
// 미리보기를 위한 CaptureRequest.Builder 설정
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
// 카메라 캡처 세션 생성
cameraDevice.createCaptureSession(Collections.singletonList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
// 카메라가 이미 닫혔다면 아무 작업도 수행하지 않음
if (cameraDevice == null) {
return;
}
// 캡처 세션 시작
cameraCaptureSession = session;
updatePreview();
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
// 구성 실패시 Toast 메시지 출력
Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
// 카메라를 여는 메소드
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId = manager.getCameraIdList()[0];
// 카메라 권한 체크
if (ActivityCompat.checkSelfPermission(this, "android.permission.CAMERA") != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{"android.permission.CAMERA"}, REQUEST_CAMERA_PERMISSION);
return;
}
// 카메라 오픈, 상태 콜백과 핸들러 설정
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
// 카메라 미리보기를 업데이트하는 메소드
private void updatePreview() {
if (cameraDevice == null) {
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
return;
}
// 자동 모드로 미리보기 설정
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
try {
// 미리보기 요청을 반복하여 캡처 세션에 제출
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
protected void onPause() {
// 액티비티가 일시정지되면 카메라를 닫음
super.onPause();
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
}
private void takePicture() {
if (cameraDevice == null) return;
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
// 이미지 사이즈 설정
int width = 480;
int height = 640;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
// 이미지 저장을 위한 ImageReader 설정
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
// 캡처 요청 생성
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
String path = getCacheDir() + "/" + fileName;
// 파일 생성
File file = new File(path);
// 이미지 저장 리스너
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();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes);
} finally {
if (null != output) {
output.close();
}
}
}
};
reader.setOnImageAvailableListener(readerListener, null);
// 캡처 세션 종료 후 이미지 저장
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(MainActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
// 여기에서 다른 화면으로 전환
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
intent.putExtra("img",path);
startActivity(intent);
}
};
// 캡처 세션 시작
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
MainActivity2
public class MainActivity2 extends AppCompatActivity {
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
imageView = findViewById(R.id.imageView);
String img = getIntent().getStringExtra("img");
Bitmap bitmap = BitmapFactory.decodeFile(img);
// Matrix 객체 생성
Matrix matrix = new Matrix();
// 오른쪽으로 90도 회전
matrix.postRotate(90);
// 새로운 Bitmap 생성
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// ImageView에 설정
imageView.setImageBitmap(rotatedBitmap);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="@+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/btn_takepicture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Take Picture" />
</RelativeLayout>
activity_main2.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity2">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>
결과 화면입니다.
'안드로이드 자바' 카테고리의 다른 글
[Android][Java] Camera2 API를 사용하여 사진찍기 (2) | 2024.01.28 |
---|---|
[Android][Java] 카메라X 프리뷰 보여주기 (0) | 2024.01.21 |
[Android][Java] Intent 사용해서 유튜브 앱 열기 (0) | 2024.01.15 |
[Android][Java] 앱 아이콘, 앱 이름 변경하기 (0) | 2024.01.12 |
[Android][Java] Camera2 API를 사용하여 카메라 미리보기 생성하기 (0) | 2024.01.10 |