반응형
서피스뷰(SurfaceView)라는 것으로 카메라 미리보기 화면이 구현된다
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.a72_surfaceview">
<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-feature
android:name="android.hardware.camera2"
android:required="true" />
<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.A72_Surfaceview">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="사진찍기" />
<FrameLayout
android:id="@+id/previewFrame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
MainActivity
package com.example.a72_surfaceview;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
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.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;
import java.util.List;
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.CAMERA, Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE).onGranted(new Action<List<String>>() {
@Override
public void onAction(List<String> permissions) {
showToast("허용된 권한 개수 : " + permissions.size());
}
}).onDenied(new Action<List<String>>() {
@Override
public void onAction(List<String> permissions) {
showToast("거부된 권한 개수 : " + permissions.size());
}
}).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 view) {
takePicture();
}
});
}
public void takePicture() {
// CameraSurfaceView의 capture 메소드 호출
cameraView.capture(new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
// 전달받은 바이트 배열을 Bitmap 객체로 만들기
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
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);
Log.d("SampleCapture", String.valueOf(outUri));
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, outUri));
}
camera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
// SurfaceHolder에 정의된 Callback 인터페이스 구현
// 서피스뷰의 상태가 변경될 때 자동 호출되는 세가지 메소드 - surfaceCreated, surfaceChanged, surfaceDestroyed
class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
// import android.hardware.Camera;
private Camera camera = null;
public CameraSurfaceView(Context context) {
super(context);
// 생성자에서 서비스홀더 객체 참조 후 설정
mHolder = getHolder();
mHolder.addCallback(this);
}
// 서비스뷰가 만들어질 때 카메라 객체를 참조한 후 미리 보기 화면으로 홀더 객체 설정
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
camera = Camera.open();
setCameraOrientation();
try {
camera.setPreviewDisplay(mHolder);
} catch (Exception e) {
e.printStackTrace();
}
}
// 서비스뷰의 화면 크기가 바뀌는 등의 변경 시점에 미리 보기 시작
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
camera.startPreview();
}
// 서피스뷰가 없어질 때 미리 보기 중지
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
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;
}
}
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);
}
}
public void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
반응형
'안드로이드' 카테고리의 다른 글
동영상 재생 (0) | 2021.11.05 |
---|---|
음악 파일 재생 (0) | 2021.11.05 |
카메라로 사진 찍어 저장 (0) | 2021.11.04 |
멀티터치 이미지 뷰어 만들기 (0) | 2021.11.03 |
페인트보드(그림판) 만들기 (0) | 2021.11.02 |