-
[ Android ] 사진 미리보기 - Camera 이용Android/멀티미디어 2020. 3. 17. 17:02
CatServant
옆의 사진은 카메라 미리보기를 구현한 사진입니다.
현재는 android.hardware.Camera 가 deprecated 되어서 Camera2를 이용해야 합니다.
그리고 카메라 화면이 회전되어서 나오기 때문에 똑바르게 회전되어 나오도록 코드를 추가해 주었지만 미리보기 화면은 회전되지 않은 상태로 나옵니다.
SurfaceView 카메라 미리 보기를 추가하고 싶은 경우 SurfaceView를 사용하면 됩니다.
SurfaceView를 상속하는 새로운 클래스를 만들고 해당 클래스가 SurfaceHolder의 Callback Interface를 구현하도록 합니다. 여기서 SurfaceView는 껍데기 역할만 하고 실제 컨트롤은 SurfaceHolder가 담당합니다. 그리고 뷰의 상태 변화를 알 수 있도록 Callback Interface를 제공합니다.
Callback Interface는 뷰가 생성되었을 때 ( surfaceCreated - surface 객체가 메모리에 만들어질 때 자동으로 호출됨 ), 변경될 때 ( surfaceChanged - 뷰의 크기가 변경되는 시점 ), 없어질 때 ( surfaceDestroyed - 뷰가 메모리에서 사라지는 시점 ) 자동으로 메소드가 호출됩니다.
Code
- AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-feature android:name="android.hardware.camera" android:required="true"/>
여기서 아래의 코드는 "하드웨어 카메라가 있는 경우 그것을 사용하겠다." 는 의미입니다.
<uses-feature android:name="android.hardware.camera" android:required="true"/>
- build.gradle ( Module.app ) → 위험 권한 추가하기
allprojects { repositories { maven { url 'https://jitpack.io' } } } dependencies { implementation 'com.github.pedroSG94:AutoPermissions:1.0.3' }
- CameraSurfaceView.java
Camera 객체를 이용하고 있기 때문에 사진을 찍을 수도 있습니다.
import android.app.Activity; import android.content.Context; import android.hardware.Camera; import android.util.AttributeSet; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; private Camera camera = null; private int mCameraID; private Camera.CameraInfo mCameraInfo; private int mDisplayOrientation; public CameraSurfaceView(Context context) { super(context); init(context); } public CameraSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public void init(Context context) { holder = getHolder(); holder.addCallback(this); // 0 -> CAMERA_FACING_BACK // 1 -> CAMERA_FACING_FRONT mCameraID = 0; // get display orientation mDisplayOrientation = ((Activity)context).getWindowManager() .getDefaultDisplay().getRotation(); } @Override public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(mCameraID); // retrieve camera's info. Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); Camera.getCameraInfo(mCameraID, cameraInfo); mCameraInfo = cameraInfo; /** * 카메라를 오픈하고 프리뷰 디스플레이를 설정하겠다 * 프리뷰 디스플레이는 holder 쪽으로 설정하겠다. * * 하드웨어 카메라를 통해 들어온 영상이 홀더 쪽으로 전달되고 * 홀더에 의해 서피스뷰에 표시가 됩니다. **/ try { camera.setPreviewDisplay(holder); } catch (Exception e) { Log.e("CameraSurfaceView", "Failed to set camera preview.", e); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings int orientation = calculatePreviewOrientation(mCameraInfo, mDisplayOrientation); camera.setDisplayOrientation(orientation); camera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); camera = null; } public boolean capture(Camera.PictureCallback callback) { if (camera != null) { camera.takePicture(null, null, callback); return true; } else { return false; } } /** * 안드로이드 디바이스 방향에 맞는 카메라 프리뷰를 화면에 보여주기 위해 계산합니다. */ 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; } }
- MainActivity.java
import com.pedro.library.AutoPermissions; public class MainActivity extends AppCompatActivity { CameraSurfaceView cameraSurfaceView; ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); FrameLayout container = findViewById(R.id.container); cameraSurfaceView = new CameraSurfaceView(this); container.addView(cameraSurfaceView); Button button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { capture(); } }); // 시작되는 시점에 위험권한을 요청 AutoPermissions.Companion.loadAllPermissions(this, 101); } public void capture() { cameraSurfaceView.capture(new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { try { // 사진을 byte array로 전달해줌 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); // 화면에 표시해줌 imageView.setImageBitmap(bitmap); camera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } }); } }
출처
'Android > 멀티미디어' 카테고리의 다른 글
[ Android ] 임시 파일 생성해서 외부 앱으로 찍은 사진 받기 (0) 2020.09.16 [ Android ] 음성 녹음하기 (1) 2020.03.26 [ Android ] 음악 재생하기 (0) 2020.03.25 [ Android ] 동영상 파일 재생하기 (0) 2020.03.24 [ Android ] 사진 찍기 (0) 2020.03.16