*중요
*.1 Manifest에 주가해야되는 권한
- <uses-permission android:name="android.permission.CAMERA"/>
//카메라 사용
- <uses-permission android:name="android.permission.FLASHLIGHT"/>
//카메라 플레쉬 사용
1. 카메라 미리보기 주요과정
1.1 카메라 미리보는 SurfaceView를 사용함 따라서, SurfaceView 사용 패턴을 그대로 사용한다.(SurfaceHolder를 이용한 SurfaceView 컨트롤)
1.2 카메라에게 서피스뷰를 알려주는 메서드
camera.setPreviewDisplay(mHolder);
1.3 미리보기에 시작 메서드
camera.startPreview();
2. 카메라 캡처 주요과정
- 이부분은 주관적인 부분으로 정확하지않을수 있습니다.
2.1 카메라 셔터를 눌렀을때 일어나는 이벤트를 정의한 인터페이스를 재정의한다.
Camera.ShutterCallback suttercallback = new Camera.ShutterCallback() {
public void onShutter() {...}
};
2.2 카메라 캡처후 사진데이터가 Raw 혹은 JPEG 형식으로 메모리에 적제되면 그것을 어떻게 처리할것인지 처리하는 인터페이스를 제정의한다.
Camera.PictureCallback picturecallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {...}
};
2.3 카메라 캡처 이벤트가 발생한곳(버튼이거나 뷰 등등)에 메서드를 넣어준다. 그리고 2.1 / 2.2 에서 생성한 객체들을 매개변수에 넣어준다
camera.takePicture(suttercallback , null , picturecallback);
3. SurfaceView 재정의 주요과정(전형적인 패턴)
-가끔 디테일한 설정이 필요할때는 SurfaceView를 재정의 해서 사용한다.
3.1 클래스 재정의 할때 SurfaceView 와 SurfaceView 의 상태컨트롤을 위한 SurfaceHolder.Callback를 상속받아서 정의한다
class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback
3.2 재정의된 SurfaceView를 컨트롤할 내부 변수 SurfaceHolder 객체를 선언하고 생성자나 다른 함수를 안에서 SurfaceHolder 객체를 생성한다.
private SurfaceHolder mHolder;
mHolder = getHolder();
3.3 카메라가 SurfaceView를 독점하기 위해선 SurfaceHolder의 타입은 항상SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS로 설정한다.
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
3.4 SurfaceView 의상태(메모리 유무 ,사이즈변화 등등)는 SurfaceHolder.Callback 인터페이스 에 정의된 메서드로 처리한다.(기존 다른 리스너 방식과 유사)
-mHolder.addCallback(this); //콜백 인터페이스 홀더에 설정
-public void surfaceCreated(SurfaceHolder holder) // SurfaceView가 생성됬을때 호출된다
-public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) //SurfaceView 크기가 변화될때 호출된다
-public void surfaceDestroyed(SurfaceHolder holder) //SurfaceView 메모리 헤제됬을때 호출된다
4. 예제
android version = jelly bean
import android.app.Activity;
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.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;
// SurfaceView를 이용해 미리보기 화면을 만든 후 사진찍기를 하는 방법에 대해 알 수 있습니다.
public class MainActivity extends Activity {
// 캡처한 사진파일 저장할 이름
public static String IMAGE_FILE = "capture.jpg";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// FrameLayout에 재정의한 CameraSurfaceView 추가
final CameraSurfaceView cameraView = new CameraSurfaceView(
getApplicationContext());
FrameLayout previewFrame = (FrameLayout) findViewById(R.id.previewFrame);
previewFrame.addView(cameraView);
// 버튼을 눌렀을때 캡처
Button saveBtn = (Button) findViewById(R.id.saveBtn);
saveBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// cameraView에 있는 capture() 메서드 실행
cameraView.capture(new Camera.PictureCallback() {
// JPEG 사진파일 생성후 호출됨
// 찍은 사진을 처리
// PictureCallback 인터페이스 에 있는 onPictureTaken() 메서드
// byte[] data - 사진 데이타
public void onPictureTaken(byte[] data, Camera camera) {
try {
// 사진데이타를 비트맵 객체로 저장
Bitmap bitmap = BitmapFactory.decodeByteArray(data,0, data.length);
// 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));
}
Toast.makeText(getApplicationContext(),"카메라로 찍은 사진을 앨범에 저장했습니다.",Toast.LENGTH_LONG).show();
// 다시 미리보기 화면 보여줌
camera.startPreview();
} catch (Exception e) {
Log.e("SampleCapture", "Failed to insert image.", e);
}
}
});
}
});
}
// 카메라 미리보기를 위해 SurfaceView 클래스 재정의
private class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceView를 컨트롤할 SurfaceHolder 객체 선언
private SurfaceHolder mHolder;
// 미리보기를 위한 카메라 객체 선언
private Camera camera = null;
public CameraSurfaceView(Context context) {
super(context);
// SurfaceHolder 객체 생성 getHolder()는 SurfaceView 내부 함수
mHolder = getHolder();
// SurfaceHolder.Callback 인터페이스 장착
mHolder.addCallback(this);
// 카메라가 SurfaceView를 독점하기 위한 타입 설정
// 버퍼를 사용하지않음
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
// SurfaceView 가 메모리에 생성될때 호출된다.
public void surfaceCreated(SurfaceHolder holder) {
// 카메라를 사용할려고 한다는 설정
camera = Camera.open();
try {
// 미리보기를 설정
camera.setPreviewDisplay(mHolder);
} catch (Exception e) {
Log.e("CameraSurfaceView", "Failed to set camera preview.", e);
}
}
// 보통 SurfaceView가 보여지기전 과 사이즈가 변화가있을때 호출된다.
// 그래서 보여지기전인 surfaceCreated()가 호출된 다음 호출된다.
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// 카메라의 파라미터 값을 가져와서 미리보기 크기를 설정한다
Camera.Parameters parameters= camera.getParameters();
parameters.setPreviewSize(width, height);
camera.setParameters(parameters);
// 미리보기화면을 뿌려준다
camera.startPreview();
}
// SurfaceView의 메모리가 해제되었을때 호출된다.
// SurfaceView가 화면에 표시되지않을때(액티비티가 비활성화 될때) 호출된다.
public void surfaceDestroyed(SurfaceHolder holder) {
// 미리보기 중지
camera.stopPreview();
// 메모리 해제
camera.release();
camera = null;
}
// 사진을 찍을때 호출되는 함수 (스냅샷)
public boolean capture(Camera.PictureCallback handler) {
if (camera != null) {
// 셔터후
// Raw 이미지 생성후
// JPE 이미지 생성후
camera.takePicture(null, null, handler);
return true;
} else {
return false;
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}