[Android] SurfaceView 이용하여 카메라 촬영
2023. 8. 8. 14:37ㆍAndroid
728x90
Android SurfaceView 개발 기록
1. 일단 SurfaceView class 생성
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder holder;
Camera camera = null;
private int CAMERA_FACING = Camera.CameraInfo.CAMERA_FACING_FRONT;
public CameraSurfaceView(Context context) {
super(context);
init(context);
}
public CameraSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
//초기화를 위한 메소드
holder = getHolder();
holder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//만들어지는시점
camera = Camera.open(CAMERA_FACING);//카메라 객체 참조
try{
camera.setPreviewDisplay(holder);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
//변경
camera.startPreview(); //렌즈로 부터 들어오는 영상을 뿌려줌
camera.stopPreview();
// camera.setDisplayOrientation(90);//카메라 미리보기 오른쪽 으로 90 도회전
camera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//소멸
camera.stopPreview();//미리보기중지
camera.release();
camera = null;
}
public boolean capture(Camera.PictureCallback callback){
if(camera != null){
camera.startPreview();
camera.enableShutterSound(false);
camera.takePicture(null,null,callback);
return true;
}
else{
return false;
}
}
}
2. xml 파일 - 웹뷰로 앱을 만들었는데 메인화면 WebView 위에 CardView 올리고 그 안에 내가만든 SurfaceView를 넣었다.
** 화면 왼쪽 하단부분에 동그랗게 카메라 미리보기를 보이게하기위해 CardView안에 SurfaceView를 넣었다.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".activity.MainActivity">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="20dp"
app:cardCornerRadius="100dp">
<kr.co.nton.skycode.webview.CameraSurfaceView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="@+id/surfaceView" />
</androidx.cardview.widget.CardView>
</FrameLayout>
3. MainActivity에서 타이머 돌리기
public TimerHandler getTimerHandler() {
return timerHandler;
}
public class TimerHandler extends Handler {
public void startTimer() {
this.removeMessages(MESSAGE_TIMER_START);
Log.d("aa", "시작");
capture();
this.sendEmptyMessageDelayed(MESSAGE_TIMER_START, TIMER_DELAY);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MESSAGE_TIMER_START:
// 타이머를 다시 시작
startTimer();
break;
}
}
}
4. 사진 촬영 후 이미지를 저장하거나 뷰로 보여줄 수 있다.
카메라 방향조정, 이미지 압축 가능
public void capture() {
surfaceView.capture(new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//카메라 방향 조정
int rotation = MainActivity.this.getWindowManager().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 = (90 - degrees + 360) % 360;
camera.setDisplayOrientation(result);
//bytearray 형식으로 전달
//이걸이용해서 이미지뷰로 보여주거나 파일로 저장
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8; // 1/8사이즈로 보여주기
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); //data 어레이 안에 있는 데이터 불러와서 비트맵에 저장
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = 600;
int newHeight = 480;
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
// matrix.postScale(scaleWidth, scaleHeight);
//전면카메라 좌우반전
matrix.setScale(-1, 1);
matrix.postTranslate(newWidth, 0);
matrix.postRotate(result);
//1차로 좌우반전 회전 적용
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
//2차로 크기 600x480 적용
Bitmap scaledBitmap = Bitmap.createScaledBitmap(resizedBitmap, newWidth, newHeight, true);
BitmapToString(scaledBitmap);
Log.d("base64", String.valueOf(scaledBitmap));
// imageView.setImageDrawable(new BitmapDrawable(scaledBitmap));//이미지뷰에 사진 보여주기
// @SuppressLint("SimpleDateFormat")
// String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
// String imageFileName = timeStamp;
//
// //사진저장코드
// String imageSaveUri = MediaStore.Images.Media.insertImage(getContentResolver(), scaledBitmap, imageFileName, "저장되었습니다.");
// Uri uri = Uri.parse(imageSaveUri);
// sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri));
// Toast.makeText(getApplicationContext(), "찍은 사진이 저장되었습니다.", Toast.LENGTH_SHORT).show();
//
camera.startPreview();
}
});
}
//이미지 압축 및 base64로 변환
public void BitmapToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
byte[] bytes = baos.toByteArray();
String temp = Base64.encodeToString(bytes, Base64.NO_WRAP);
Log.d("base64", temp);
}
5. 이제 원하는곳에 타이머 시작, 멈춤을 하면된다. WebViewClient class onPageFinished 에서 url이 변할때 url를 보고 타이머를 실행하는 구조이다.
MainActivity 타이머를 사용하기위해 timerHandler = (MainActivity) view.getcontext()).getTimerHadler();
xml에서 CardView안에 넣었던 SurfaceView 카메라 미리보기를 숨겼다 보였다 하기위해 MainActivity mainActivity = (MainActivity) view.getContext();
private MainActivity.TimerHandler timerHandler;
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//MainActivity 함수 사용하기 위해
MainActivity mainActivity = (MainActivity) view.getContext();
timerHandler = ((MainActivity) view.getContext()).getTimerHandler();
if (url.equals("https://test.co.kr")) {
mainActivity.setSurfaceViewVisibility(View.VISIBLE);
timerHandler.sendEmptyMessageDelayed(MESSAGE_TIMER_START, TIMER_DELAY);
} else {
mainActivity.setSurfaceViewVisibility(View.GONE);
timerHandler.removeMessages(MESSAGE_TIMER_START);
}
}
** MainActivity Activity
activity_main.xml에 SurfaceView 를 다른 클래스에서도 사용할 수 있게 함수를 만들어서 사용했다.
CameraSurfaceView surfaceView;
public void setSurfaceViewVisibility(int visibility) {
surfaceView.setVisibility(visibility);
}
728x90
'Android' 카테고리의 다른 글
[Android] webView 하단버튼 키보드 위로 올라오는 현상_해결 (0) | 2023.08.25 |
---|---|
[Android] targetSdk 33 apk파일 설치 시 네트워크 연결 오류_버전문제 해결 (0) | 2023.08.25 |
[Android] OkHttpClient 사용하여 url로 이미지 전송 (0) | 2023.08.04 |
[안드로이드 스튜디오] jks 키를 이용해 aab파일 만들고 앱 게시 (0) | 2023.02.24 |
[안드로이드 스튜디오] 앱 서명 키(jks) 만들기 (0) | 2023.02.22 |