ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ 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();
                    }
                }
            });
        }
    }

     

     

     

    출처

     

    [LECTURE] 1) 사진 찍어 저장하기 : edwith

    들어가기 전에 멀티미디어는 음악 파일 재생, 동영상 재생, 음성 녹음과 사진찍기에 이르기까지 다양한 기능을 포함합니다. 그중에서도 사람들이 가장 많이 사용하는 기능으로 사진찍기를 ... - 부스트코스

    www.edwith.org

     

    [Android, Camera] 1. 카메라 프리뷰를 이용한 화면 캡처 및 배경 이미지 적용

    안녕하세요. 블랙진입니다. Capture the camera preview with image in android 이번에는 Camera api 를 사용하여 화면을 캡처하고 캡처한 화면에 배경 이미지를 적용하는 방법에 대해 포스팅 해보겠습니다. 안드..

    black-jin0427.tistory.com

     

    댓글

Designed by Tistory.