안드로이드는 카메라 기능을 사용할 수 있게 API를 제공한다.
증강현실 같은 앱도 카메라 기능을 필요로 한다.
카메라 기능이 필요한 것들중에 기초가 되는것이 바로 Camera Preview이다. 카메라 프리뷰는 SurfaceView를 사용하여 구현된다.
이 기초가 되는 카메라 프리뷰에 대해 알아본다.
* MainActivity.java
package com.studio572.samplecamerapreview;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private static CameraPreview surfaceView;
private SurfaceHolder holder;
private static Button camera_preview_button;
private static Camera mCamera;
private int RESULT_PERMISSIONS = 100;
public static MainActivity getInstance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 카메라 프리뷰를 전체화면으로 보여주기 위해 셋팅한다.
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 안드로이드 6.0 이상 버전에서는 CAMERA 권한 허가를 요청한다.
requestPermissionCamera();
}
public static Camera getCamera(){
return mCamera;
}
private void setInit(){
getInstance = this;
// 카메라 객체를 R.layout.activity_main의 레이아웃에 선언한 SurfaceView에서 먼저 정의해야 함으로 setContentView 보다 먼저 정의한다.
mCamera = Camera.open();
setContentView(R.layout.activity_main);
// SurfaceView를 상속받은 레이아웃을 정의한다.
surfaceView = (CameraPreview) findViewById(R.id.preview);
// SurfaceView 정의 - holder와 Callback을 정의한다.
holder = surfaceView.getHolder();
holder.addCallback(surfaceView);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public boolean requestPermissionCamera(){
int sdkVersion = Build.VERSION.SDK_INT;
if(sdkVersion >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA},
RESULT_PERMISSIONS);
}else {
setInit();
}
}else{ // version 6 이하일때
setInit();
return true;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
if (RESULT_PERMISSIONS == requestCode) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 권한 허가시
setInit();
} else {
// 권한 거부시
}
return;
}
}
}
카메라 프리뷰는 "<uses-permission android:name="android.permission.CAMERA"/>" 권한을 필요로한다.
메니페스트에 권한을 추가하고 또, 안드로이드 버전이 6.0 이상에서는 requesPermission()메소드로 권한을 획득해야한다.
* CameraPreview.java
package com.studio572.samplecamerapreview;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.util.List;
/**
* Created by Administrator on 2017-08-14.
*/
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback{
private Camera mCamera;
public List<Camera.Size> listPreviewSizes;
private Camera.Size previewSize;
private Context context;
// SurfaceView 생성자
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
mCamera = MainActivity.getCamera();
if(mCamera == null){
mCamera = Camera.open();
}
listPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
}
// SurfaceView 생성시 호출
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
// 카메라 객체를 사용할 수 있게 연결한다.
if(mCamera == null){
mCamera = Camera.open();
}
// 카메라 설정
Camera.Parameters parameters = mCamera .getParameters();
// 카메라의 회전이 가로/세로일때 화면을 설정한다.
if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
parameters.setRotation(90);
} else {
parameters.set("orientation", "landscape");
mCamera.setDisplayOrientation(0);
parameters.setRotation(0);
}
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(surfaceHolder);
// 카메라 미리보기를 시작한다.
mCamera.startPreview();
// 자동포커스 설정
mCamera.autoFocus(new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
}
}
});
} catch (IOException e) {
}
}
// SurfaceView 의 크기가 바뀌면 호출
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int w, int h) {
// 카메라 화면을 회전 할 때의 처리
if (surfaceHolder.getSurface() == null){
// 프리뷰가 존재하지 않을때
return;
}
// 프리뷰를 다시 설정한다.
try {
mCamera .stopPreview();
Camera.Parameters parameters = mCamera .getParameters();
// 화면 회전시 사진 회전 속성을 맞추기 위해 설정한다.
int rotation = MainActivity.getInstance.getWindowManager().getDefaultDisplay().getRotation();
if (rotation == Surface.ROTATION_0) {
mCamera .setDisplayOrientation(90);
parameters.setRotation(90);
}else if(rotation == Surface.ROTATION_90){
mCamera .setDisplayOrientation(0);
parameters.setRotation(0);
}else if(rotation == Surface.ROTATION_180){
mCamera .setDisplayOrientation(270);
parameters.setRotation(270);
}else{
mCamera .setDisplayOrientation(180);
parameters.setRotation(180);
}
// 변경된 화면 넓이를 설정한다.
parameters.setPreviewSize(previewSize.width, previewSize.height);
mCamera .setParameters(parameters);
// 새로 변경된 설정으로 프리뷰를 시작한다
mCamera .setPreviewDisplay(surfaceHolder);
mCamera .startPreview();
} catch (Exception e){
e.printStackTrace();
}
}
// SurfaceView가 종료시 호출
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if(mCamera != null){
// 카메라 미리보기를 종료한다.
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
// 화면이 회전할 때 화면 사이즈를 구한다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (listPreviewSizes != null) {
previewSize = getPreviewSize(listPreviewSizes, width, height);
}
}
public Camera.Size getPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
activity_main 레이아웃에 들어갈 SurfaceView 클래스를 정의한다. 이 클래스가 SurfaceView를 상속받아 카메라 화면을 띄워 줄것이다.
// SurfaceView 생성시 호출
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
// 카메라를 크기,화면회전 등을 셋팅하고 프리뷰 화면을 띄워주는 작업을 한다.
}
// SurfaceView 의 크기가 바뀌면 호출
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int w, int h) {
// 카메라 화면에 변동이 있을 때 작업을 한다,
}
// SurfaceView가 종료시 호출
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
// 카메라를 종료시 호출되고 카메라 리소스를 반환하는 작업을 한다.
}
* activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="com.studio572.samplecamerapreview.MainActivity">
<com.studio572.samplecamerapreview.CameraPreview
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"/>
</RelativeLayout>
위에서 SurfaceView 를 상속받는 클래스를 정의한 CameraPreview를 셋팅한다
<com.studio572.samplecamerapreview /> 여기는 여러분이 만든 CameraPreview 패키지 경로를 써 넣으면 된다.
.
'프로그래밍 > 안드로이드' 카테고리의 다른 글
[안드로이드] ImageView에 이미지 출력하기 (1) | 2017.08.21 |
---|---|
[안드로이드] Thread(쓰레드)에서 UI 변경하기 - runOnUiThread 사용하기 (2) | 2017.08.20 |
[안드로이드] 상태바, 타이틀바 숨기기(제거), 전체화면 - StatusBar,TitleBar , Full Screen (0) | 2017.08.18 |
[안드로이드] Intent (인텐트) 에 대해 알아보자 (0) | 2017.08.17 |
[안드로이드] Android 6.0 Marshmallow (마시멜로우)에서 권한 처리작업 (0) | 2017.08.16 |
댓글