Camera PreView 화면 캡처 및 배경 이미지 적용
Camera api를 사용하여 화면을 캡처하고 캡처한 화면에 배경 이미지를 적용하는 방법.
안드로이드 카메라 API문서에는 Camera2 Api사용을 권장한다고 한다.
작성자는 아래와 같은 이유로 Camera api를 사용 했다고한다.
1. Camera2 Api는 안드로이드 5.0(롤리팝)이상부터 사용 가능합니다.
저는 안드로이드 4.4(킷캣) 사용자도 사용 할 수 있게 만들었다.
2.Camera2 Api는 카메라의 많은 기능을 사용 할 수 있지만 그만큼 초기 코드 설정이 복잡합니다.
공부양이 방대하여 일단 Camera Api를 사용했습니다.
0. 상단바 제거
_style.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<!-- 타이틀 바를 안보이도록 합니다. -->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>
1.권한 설정
안드로이드 6.0(마시멜로우) 이상 버전부터는 권한 설정이 필수 입니다.
저희는 카메라 사용과 캡처된 이미지를 저장을 위한 2가지 권한이 필요합니다.
_AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
_MainActivity.kt
private val PERMISSIONS_REQUEST_CODE = 100
private val REQUIRED_PERMISSIONS =
arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
override fun onCreate(savedInstanceState: Bundle?){
super.onCreate(savedInstanceState)
//상태바를 안보이도록 합니다.
window.setFlag(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN)
//화면 켜진 상태를 유지합니다.
window.setFlag(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setContentView(R.layout.activity_main)
if(Build.Version.SDK_INT >= Build.VERSION_CODES.M){
//OS가 Marshmallow 이상일 경우 권한체크를 해야 합니다.
val permissionCheckCamera
= ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
val permissionCheckStorage
= ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
if(permissionCheckCamera == PackageManager.PERMISSION_GRANTED
&& permissionCheckStorage == PackageManager.PERMISSION_GRANTED){
//권한 있음
startCamera()
}else{
//권한 없음
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, PERMISSIONS_REQUEST_CODE)
}
}else{
// OS 가 Marshmallow 이전일 경우 권한체크를 하지 않는다.
startCamera()
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResult: IntArray){
super.onRequestPermissionsResult(requestCode, permissions, grantResult)
//grantResult[0] 거부 -> -1
//grantResult[0] 허용 -> 0 (PackManager.PERMISSION_GRANTED)
if(request == PERMISSIONS_REQUEST_CODE){
var check_result = true
for(result in grantResults){
if(result != PackageManager.PERMISSION_GRANTED){
check_result = false
break
}
}
if(check_result){
startCamera()
}else{
//권한 거부
}
}
}
위와 같은 방법으로 카메라와 저장파일 접근 권한을 획득하시면 됩니다.
2. 카메라 프리뷰 연결 하기
_activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
FrameLayout에 카메라 프리뷰를 연결합니다.
_MainActivity.kt
private var CAMERA_FACING = Camera.CameraInfo.CAMERA_FACING_FRONT
private var myCameraPreview: MyCameraPreview? = null
CAMERA_FACING은 프리뷰에 보여질 카메라의 전면, 후면을 결정하는 변수입니다.
만약 후면을 사용하고 싶으신 분은 CAMERA_FACING = Camera.CameraInfo.CAMERA_FACING_BACK변수로 변경해주시면 됩니다.
private fun startCamera(){
//create our preview view and set it as the content of our activity
myCameraPreview = MyCameraPreview(this, CAMERA_FACING)
cameraPreview.addView(myCameraPreview)
}
_MyCameraPreview.java
카메라 프리뷰의 가장 핵심이 되는 부분입니다.
안드로이드 기기 별로 카메라의 방향이 다른데 이에 맞춰 프리뷰를 설정할 수 있도록 했습니다.
public class MyCameraPreview extends SurfaceView implements SurfaceHiolder.Callback{
private final String TAG = "MyTag";
private SurfaceHolder mHolder;
private int mCameraID;
private Camera mCamera;
private Camera.CameraInfo mCameraInfo;
private int mDisplayOrientation;
public MyCameraPreView(Context context, int cameraId){
super(context);
// 0 -> CAMERA_FACING_BACK
// 1 -> CAMERA_FACING_FRONT
mCameraID = cameraId;
try{
//attempt to get a Camera instance
mCamera = Camera.open(mCameraID);
}catch(Excention e){
//Camera is Not available(in use or dose not exist)
}
//Install a SurfaceHolder.Callback so we get notified when the
//underlying surface is created and destroyed
mHolder = getHolder();
mHolder.addCallback(this);
//deprecated setting, but rquired on Android version prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//get display orientation
mDisplayOrientation = ((Activity)context).getWindowManager().getDefaultDisplay().getRotation();
}
public void surfaceCreated(SurfaceHolder holder){
//retrieve camara`s info.
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraID, cameraInfo);
mCameraInfo = cameraInfo;
//the Surface has been created, now tell the camera where to draw the preview.
try{
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}catch(IOException e){
//error setting camera preview
}
}
prublic void surfaceDestroyed(SurfaceHolder holder){
//empty. Take care of releasing the camera preview in your activity
}
public void surfaceVhanged(SurfaceHolder holder, int format, int w, int h){
//if your preview can change or rotate, take care of those events here
//Make sure to stop the preview before resizing or reformatting it
if(mHolder.getSurface() == null){
//preview surface dose not exist
return;
}
//stop preview before making changes
try{
mCamera.stopPreview();
}catch(Exception e){
//ignore: tried to stop a non-existent preview
}
//set preview size and make any resize, rotate or
//reformatting changes here
//start preview with new settings
int orientation = calcuratePreviewOrientation(mCameraInfo, mDisplayOrientation);
mCamera.setDisplayOrientation(orientation);
try{
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
//camera preview started.
}catch(Exception e){
//error starting camera preview
}
}
/**
* 안드로이드 디바이스 방향에 맞는 카메라 프리뷰를 화면에 보여주기 위해 계산합니다.
*/
public int calculatePreviewOrientation(Camera.CameraInfo info, int rotation){
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; // compensate the mirror
}else{//back -facing
result = (info.orientation - degrees + 360 ) % 360;
}
return result;
}
}
코드는 위와 같습니다.
MyCameraPreview는 SurfaceView를 상속하며 SurfaceHolder.Callback인터페이스를 가지고 있습니다.
1. MyCameraPreview(Context context, in cameraId)
생성자를 통해 Camera.open을 합니다. 이때 cameraId를 받아오는데 이 값을 통해 전면과 후면 카메라를 결정합니다.
2. surfaceCreated -> surfaceChanged순서로 동작합니다.
3. surfaceChanged에서 아래 코드를 통해 안드로이드 디바이스 별 카메라의 회전 방향을 조정해 줍니다.
int orientation = calculatePreviewOrientation(mCameraInfo, mDisplayOrientation);
mCamera.setDisplayOrientation(orientation);
위와 같이 코드를 짜면 프리뷰 화면에 카메라를 띄우는데 성공하셨을 겁니다.
참조 :
https://black-jin0427.tistory.com/84?category=727620
'안드로이드' 카테고리의 다른 글
[Android] Camera PreView 화면 캡처 및 배경 이미지 적용 (3) (0) | 2022.10.25 |
---|---|
[Android] Camera Preview를 화면 캡처 및 배경 이미지 적용 (2) (0) | 2022.10.25 |
[Android] 외부 스킴(Custom Url Scheme) 사용 방법 (0) | 2022.10.25 |
[Android] 안드로이드 앱 아이콘(App icon) 사이즈 (0) | 2022.10.25 |
디바이스를 구분하는 고유번호 ANDROID_ID 오레오 (0) | 2022.10.25 |