티스토리 뷰
Intent 객체를 사용하여 카메라 어플을 실행한 뒤 사진을 찍는 방법은 그리 복잡하지 않다. 또한 단말의 카메라 앱을 사용하기 때문에 단말의 카메라 앱이 기본으로 제공하는 기능을 그대로 사용할 수 있다. 하지만 단순히 사진만 찍는 것이 아닌 화면에 증강현실이나 그래픽 등을 보여주려고 한다면, Intent 객체로 어플을 실행시키는 것 이외에 다른 작업이 필요하다.
카메라 미리보기 코드를 작성하여, 제작한 앱에서 직접 사진을 찍도록 구성할 수도 있다. 이 때는 일반 View가 아니라 SurfaceView 객체를 사용하는데, 우선 이 SurfaceView객체에 대하여 알아보도록 하자.
SurfaceView 객체는 아래 그림처럼 SurfaceHolder에 의해 제어되며, SurfaceHolder는 setPreviewDisplay(Surface sv) 메서드로 미리 보기를 설정해주는 역할을 한다.
필요한 초기화 작업이 종료되면, 카메라 객체의 startPreview() 메서드를 호출할 수 있으며 이 때부터 카메라로 입력된 영상을 SurfaceView로 화면에 보여준다. 이 때 Type은 반드시 SURFACE_TYPE_PUSH_BUFFERS 가 되어야 한다.
SURFACE_TYPE_PUSH_BUFFERS이 SurfaceView의 타입일 때는 미리보기 화면 위에 어떤 그래픽을 그리는 동작이 제한된다. 때문에 별도의 뷰를 하나 더 생성하여 그래픽을 처리하고 그 배경을 투명하게 하는 중첩을 주로 사용한다.
이제 예제를 한번 확인해보자.
우선, 권한 설정부터 해주자.
◎AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.samplecapture2" >
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.camera" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SampleCapture2" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity는 아래와 같이 작성하여 Camera 미리보기를 확인하며 버튼을 클릭했을 때 해당 화면을 파일로 저장하도록 한다.
◎MainActivity.java
package com.example.samplecapture2;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import android.view.*;
import android.widget.Button;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;
public class MainActivity extends AppCompatActivity {
CameraSurfaceView cameraView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AndPermission.with(this)
.runtime()
.permission(Permission.READ_EXTERNAL_STORAGE,
Permission.WRITE_EXTERNAL_STORAGE,
Permission.CAMERA
)
.start();
FrameLayout previewFrame = findViewById(R.id.previewFrame);
cameraView = new CameraSurfaceView(this);
previewFrame.addView(cameraView);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePicture();
}
});
}
public void takePicture() {
// PictureCallback 인터페이스를 구현하는 부분: 사진을 찍은 결과를 처리하는 코드를 작성
// onPictureTaken() 메서드가 자동으로 호출되며, 캡처한 이미지가 Byte[] 의 형태로 인자로 들어온다.
cameraView.capture(new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
try{
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
// insertImage() 메서드의 인자로 내용 제공자를 제어할 ContentResolve 객체,
// bitmap 데이터를 넣어 간단한 방법으로 이미지 추가가 가능
String outUriStr = MediaStore.Images.Media.insertImage(
getContentResolver(),
bitmap,
"Captured Image",
"Captured Image using Camera"
);
if(outUriStr == null) {
Log.d("SampleCapture", "Image insert failed.");
return;
} else {
Uri outUri = Uri.parse(outUriStr);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, outUri));
}
camera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera camera = null;
// 생성자: SurfaceHolder 객체 참조 후 설정
public CameraSurfaceView(Context context) {
super(context);
// SurfaceHolder 참조
mHolder = getHolder();
// 이 클래스에서 구현된 Callback 객체를 지정
mHolder.addCallback(this);
}
// SurfaceView 가 생성될 때 카메라 객체를 참조한 후 미리보기 화면으로 Holder 객체 설정
public void surfaceCreated(@NonNull SurfaceHolder holder) {
// 카메라 켜기
camera = Camera.open();
// 가로 -> 세로로 카메라 모드 변경
setCameraOrientation();
try{
// 카메라 객체에서 참조할 SurfaceHolder 지정
camera.setPreviewDisplay(mHolder);
} catch(Exception e) {
e.printStackTrace();
}
}
// SurfaceView 의 화면 크기가 바뀌는 등의 변경 시점에 미리보기 시작
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
// 미리보기 시작
camera.startPreview();
}
// SurfaceView 가 없어질 때 미리보기 중지
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
// 카메라 객체의 takePicture() 메서드를 호출하여 사진 촬영
public boolean capture(Camera.PictureCallback handler) {
if(camera != null) {
camera.takePicture(null, null, handler);
return true;
} else {
return false;
}
}
// 카메라의 미리보기 Default 값이 가로이기 때문에 세로 모드로 수정해줘야 한다.
public void setCameraOrientation() {
if (camera == null) {
return;
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(0, info);
WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
int rotation = manager.getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
}
}
'Mobile > Android' 카테고리의 다른 글
[Android] Multi Media 4: 동영상 재생하기 (0) | 2022.04.20 |
---|---|
[Android] Multi Media 3: 오디오 재생 (0) | 2022.04.20 |
[Android] Multi Media 1: 카메라로 사진 찍어 저장 (0) | 2022.04.19 |
[Android] Graphic 4: Bitmap 그리기 (0) | 2022.04.17 |
[Android] Graphic 3: Drawable 그리기 (0) | 2022.04.16 |
- 정보보안기사 #실기 #정리
- javascript
- Async
- react-native
- react
- 이탈리안 레스토랑
- redux
- 인천 구월동 이탈리안 맛집
- await
- 파니노구스토
- AsyncStorage
- 인천 구월동 맛집
- 맛집
- redux-thunk
- Promise
- Total
- Today
- Yesterday