(210518 수정)
카메라는 우리가 스마트폰 앱을 사용하면서 가장 많이 사용하는 앱 중 하나이다.
그래서 이번에는
카메라 미리보기(Camera Preview)를 통해 사진을 촬영하고
촬영한 사진이 이미지뷰에 나타나는 기능을 구현해볼 것이다.
카메라 미리보기 기능은
스마트폰 단말에 있는 기본 카메라 앱을 사용하기 때문에
기본 카메라 앱이 제공하는 기능을 그대로 사용할 수 있어서 편리하다.
그리고 카메라를 촬영하기 전 미리보기 화면 구현은
'서피스뷰(SurfaceView)' 라는 것을 이용해야하기 때문에
우선 서피스뷰부터 알아보겠다.
서피스뷰(SufaceView)란?
간단하게 말해서 그리기 전용의 화면을 제공하는 뷰(View)이다.
서피스뷰를 만든 이유는 UI와는 독립적으로 애플리케이션에게 그림을
그릴 수 있는 화면(별도의 스레드, 별도의 스케치북이라고 생각)은 제공하는 것이다.
서피스뷰를 사용하면 UI가 만들어질 때까지 기다리지 않아도 된다.
무슨말이냐면, 화면에 직접 그리는 것이 아니라
먼저 서피스뷰가 그리고 이것을 안드로이드 시스템이 화면으로 복사하는 것이다.
그런데 서피스뷰는 사실 껍데기일 뿐이고 실제로는 서피스 홀더 객체가 컨트롤을 한다.
이것에 집중하면서 서피스뷰를 이용한 카메라 프리뷰 기능을 공부해보겠다.
activity_main.xml
----------생략------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<FrameLayout
android:layout_width="412dp"
android:layout_height="580dp"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@+id/imageView"
tools:layout_editor_absoluteX="0dp"
tools:ignore="MissingConstraints">
<com.example.cameracapturetest.CameraSurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
|
cs |
FrameLaylout을 추가하고 그 안에 서피스뷰를 넣을 것이다.
그러면 서피스뷰가 껍데기인채로 추가가 될 것이다.
이제 독립적인 서피스뷰 클래스를 만들고
서피스 홀더를 이용해서 서피스뷰를 컨트롤 해보겠다.
CameraSurfaceView.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public class CameraPreView extends SurfaceView implements SurfaceHolder.Callback {
// 서피스뷰는 껍데기만 있는 것이기 때문에 실제 컨트롤은 서피스 홀더가 해줌
SurfaceHolder holder; // 서피스 홀더 객체
Camera camera = null; // 카메라 객체에 밑줄이 그어져 있는 이유는 카메라2가 나오면서 지원이 중단됨
public CameraPreView (Context context) {
super(context);
init(context);
}
public CameraPreView (Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) { // 초기화를 위한 메서드
holder = getHolder(); // 서피스뷰 내에 있는 서피스홀더 객체를 참조할 수 있음
holder.addCallback(this); // 콜백 인터페이스 등록
}
@Override
public void surfaceCreated(SurfaceHolder holder) { // 서피스뷰가 메모리에 만들어지는 시점에 호출됨됨
camera = Camera.open(); // 카메라 오픈 -> 카메라 객체 참조
try {
camera.setPreviewDisplay(holder); // 참조한 카메라 객체에 서피스홀더 객체를 지정 -> 카메라 객체에 이 서피스뷰를 미리보기로 쓸 것임
} catch (IOException e) {
e.printStackTrace();
}
}
@Override // 서피스뷰가 변경되는 시점에 호출됨, 화면에 보여지기 전에 크기가 결정되는 시점
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
camera.startPreview(); // 미리보기 화면을 뿌리기 시작
}
@Override // 서피스뷰가 없어질 때 호출됨
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview(); // 미리보기 화면은 많은 리소스를 잡아 먹기 때문에 멈추고
camera.release(); // release를 통해 리소스를 없앰
camera = null; // 카메라 해제
}
public boolean capture(Camera.PictureCallback callback) { // 서피스뷰에서 사진을 찍는 메서드
if(camera != null) {
camera.takePicture(null, null , null, callback); // 사진 촬영
return true;
} else {
return false;
}
}
} |
cs |
그리고 이 앱은 카메라를 접근하므로
매니페스트에 권한을 추가해줘야 한다.
AndroidManifest.xml
-------------생략---------------
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
-------------생략---------------
이제 메인 액티비티에서 카메라 미리보기 화면으로
사진을 찍을 수 있게 해주면 끝!
MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public class MainActivity extends AppCompatActivity {
ImageView iv;
CameraPreView preView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView)findViewById(R.id.iv);
preView = (CameraSurfaceView)findViewById(R.id.surfaceView);
Button btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePicture();
}
});
}
public void takePicture() {
preView.capture(new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) { // 사진이 찍어지면 여기에 byte[]가 전달됨
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8; // 파일로 저장한 다음에 로딩할 때와 동일한 상황이 됨, 비트맵 객체는 1/8크기로 생성됨
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); // 데이터를 가지고 비트맵 객체 생성
iv.setImageBitmap(bitmap); // 비트맵을 이미지뷰에 설정해서 보여주기
// 사진을 찍으면 미리보기가 중지가 되기 때문에
camera.startPreview(); // 미리보기를 다시 시작함
}
});
}
}
|
cs |
(기본 모드가 가로화면이라서 뒤집어져서 보이게 된다.
세로 모드는 추후에 업로드 예정.)
피드백은 언제나 환영입니다.
'프로그래밍(programming) > 안드로이드(android)' 카테고리의 다른 글
[210504] 안드로이드 카드뷰(CardView) (0) | 2021.05.04 |
---|---|
안드로이드 진동(Vibrate)과 소리내기(Ringtone) (210501) (0) | 2021.05.01 |
안드로이드 스피너(Spinner) (210427) (0) | 2021.04.27 |
안드로이드 Volley를 사용한 웹 요청과 응답 / Volley 라이브러리(210425) (0) | 2021.04.25 |
안드로이드 스크롤뷰(ScrollView)로 화면 스크롤하기 (210423) (0) | 2021.04.23 |