본문 바로가기
개발/android

카메라 위에 스킨을 넣어 찍어보자~

by 매몰 2016. 5. 30.

 

 

카메라 사진 위에 그림이나 글자를 넣어 찍고 싶다면??

의외로 간단하다... 아래를 보시라~

 

 

 

사진을 찍을려면 먼저 카메라를 연동해야 한다.

이부분은 비록 복잡해 보이지만 어차피 안드로이드 샘플 예제에 다 나오는 내용이다.

그런데 룰리팝 이후로 카메라 연동방법이 바뀌는 바람에 다시 삽질좀 하며 작성했다ㅎㅎ 

 

이글의 주제는 카메라 연동이 아니니 참고만... 설명도 생략...

 

 

private CameraManager mCameraManager;
private CameraDevice mCameraDevice;
private Camera mCamera;
private Size mPreviewSize;
private CaptureRequest.Builder mPreviewBuilder, mPictureBuilder;
private CameraCaptureSession mCaptureSession;
private ImageReader mImageReader;

 

private void createTextureView() {

    TextureView view = findViewById(R.id.TextureView);

 

    mCameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);

 

    view.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {

        @Override
       
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {

            openCamera();

        }

 

        @Override
       
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            

        }

 

        @Override
       
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {

            closeCamera();

            return false;

        }

 

        @Override
       
public void onSurfaceTextureUpdated(SurfaceTexture surface) {

           
       
}

    });

 

}

 

 

private void openCamera() {

    try {

        String[] ids = mCameraManager.getCameraIdList();

 

        int length = ids.length;

        for (int i = 0; i < length; i++) {

 

            CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(ids[i]);

            if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) {

                StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

 

                mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[i];

                Size size = map.getOutputSizes(ImageFormat.JPEG)[i];

 

                ImageReader reader = ImageReader.newInstance(size.getWidth(), size.getHeight(), ImageFormat.JPEG, 1);

                reader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {

 

                    @Override
                   
public void onImageAvailable(ImageReader reader) {                      

                        ByteBuffer buffer = reader.acquireLatestImage().getPlanes()[0].getBuffer();

                        byte[] bytes = new byte[buffer.capacity()];

                        buffer.get(bytes);

 

//여기서 사진데이터를 받아

 이미지를만듬

                        makeImage(bytes);

                    }

 

                }, mPictureHandler);

 

                mImageReader = reader;

 

                mCameraManager.openCamera(ids[i], mCameraStateCallback, null);

            }

        }

 

    } catch (CameraAccessException e) {

        e.printStackTrace();

    }

 

}

 

 

private CameraDevice.StateCallback mCameraStateCallback = new CameraDevice.StateCallback() {
    @Override
   
public void onOpened(CameraDevice camera) {
        mCameraDevice = camera;
        try {
            SurfaceTexture texture = mTextureView.getSurfaceTexture();
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            Surface surface = new Surface(texture);

            CaptureRequest.Builder builder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            builder.addTarget(surface);
            mPreviewBuilder = builder;

            camera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {

                @Override
               
public void onConfigured(CameraCaptureSession session) {
                    mCaptureSession = session;
                    setPreview(session);
                }

                @Override
               
public void onConfigureFailed(CameraCaptureSession session) {
     
                }
            }, null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    @Override
   
public void onDisconnected(CameraDevice camera) {

    }

    @Override
   
public void onError(CameraDevice camera, int error) {

    }
};

 

private void closeCamera() {
   
if (mCaptureSession != null) {
        mCaptureSession.close();
        mCaptureSession = null;
    }

    if (mCameraDevice != null) {
        mCameraDevice.close();
        mCameraDevice = null;
    }

    if (mImageReader != null) {
        mImageReader.close();
        mImageReader = null;
    }
}

 

private void setPreview(CameraCaptureSession session) {
    mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

    HandlerThread thread = new HandlerThread("CameraPreview");
    thread.start();
    Handler backgroundHandler = new Handler(thread.getLooper());

    try {
        session.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
    } catch (CameraAccessException e) {

        e.printStackTrace();
    }
}

 

 

 

 

 

찍은 사진데이터를 비트맵으로 변경하면서 그 위에 스킨을 넣는 부분이다.

그냥 스킨이 되는 레이아웃뷰들의 캡쳐이미지를 가져와 사진이미지에 덮어주기만 하면된다.

이 기본원리로 다양한 응용이 가능할 것이다...

 

 

private Bitmap makeImage(byte[] datas) {

    //카메라 사진데이터를 이용해 비트맵이미지를 만든다 
   
Bitmap cameraimage;
    try {
        cameraimage = BitmapFactory.decodeByteArray(datas, 0, datas.length);

    } catch (OutOfMemoryError e) {
        //보통 사진데이터가 크기 때문에 메모리오류가 나면 크기를 줄인다
       
BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;

        cameraimage = BitmapFactory.decodeByteArray(datas, 0, datas.length, options);
    }

    if (cameraimage != null) {
        //이미지나 글자가 포함된 레이아웃의 갭쳐이미지를 불려온다
       
View view = findViewById(R.id.SkinLayout);
        view.setDrawingCacheEnabled(true);
        Bitmap skinimage = view.getDrawingCache();

        //세로모드일때는 카메라 사진을 회전시켜준다(기종에 따라 다를수 있다)
       
Matrix matrix = new Matrix();
        matrix.setRotate(90);
        cameraimage = Bitmap.createBitmap(cameraimage, 0, 0, cameraimage.getWidth(), cameraimage.getHeight(), matrix, false);
       
        //카메라 사진위에 레이아웃 갭쳐이미지를 덮어 그린다
       
Canvas canvas = new Canvas(cameraimage);
        canvas.drawBitmap(skinimage, 0, 0, null);
        skinimage.recycle();

 

        return cameraimage;

    }

 

    return null;
}

 

 

 

 

 

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">

    <
TextureView android:id="@+id/TextureView"
       
android:layout_width="match_parent" android:layout_height="match_parent"/>

    <
LinearLayout android:id="@+id/SkinLayout"
       
android:layout_width="match_parent" android:layout_height="match_parent">

       
<!-- 여기에 이미지나 글자를 -->

   
</LinearLayout>

</
RelativeLayout>

 

 

 

 

 

 

 

 

 

 

도움이 되셨다면~ 정성으로 빚은 저희 앱!  많은 이용 바래요:)

 

https://meorimal.com/index.html?tab=spaceship

 

우주선 - 방치형 인공지능 투자 체험기

미리 맛보는 인공지능 투자!

(주)머리말 meorimal.com

 

https://meorimal.com/subway.html

 

지하철어디있니

더이상 고민하지 마세요. 뛸지 말지 딱 보면 알죠.

(주)머리말 meorimal.com

 

 

 

사업자 정보 표시
주식회사 머리말 | 고영진 | 서울특별시 송파구 중대로 135 서관 10층 (가락동, 아이티벤처타워) | 사업자 등록번호 : 524-88-00727 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2017-서울강남-03941호 | 사이버몰의 이용약관 바로가기