앞에서 스마트폰에 내장되어 있던 기본 camera 기능을 intent로 불러와 사진을 촬영하는 기능을 살펴보았다. 동작이 제대로 되는 것을 확인했으니 촬영한 사진 경로를 가져다가 ImageView를 받아오는 것은 간단하리라 생각했었다. 그러나 생각은 그냥 생각일 뿐, 역시나 쉽게 되지 않았다. 단순히 Imageview 변수를 선언한 뒤 imageview01.setImageBitmap("Bitmap file"); 혹은 imageview01.setImageURI("URI값");와 같은 method를 사용하면 되리라 생각하고 해당 code를 추가하고 실행해 봤더니 그런 file은 찾을 수 없다는 Log가 나를 반기며, imageview는 텅 빈 채로 출력되는 것이 아닌가?

  아무래도 App에서 직접 camera hardware에 접근하여 사진을 촬영해 저장할 때처럼 FileOutputStream으로 data를 write하고 난 후 바로 해당 파일을 Bitmap 변수로 읽어 ImageView에 반영해야 겠다는 생각이 들었다(이런 방식으로 만들었을 때는 ImageView에 사진이 반영이 안되는 문제는 없었기 때문이다). 그러기 위해 기본 camera intent가 종료된 후 동작할 onActivityResult();를 @Override 하여 다음과 같이 작성하였다.

1. 목적 : Camera App을 직접 만들어 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Android Developers - API Guide(http://developer.android.com/intl/ko/guide/topics/media/camera.html)
 2) smile8916님 블로그(http://smile8916.tistory.com/92)

4. 과정
 (시작하기에 앞서, 이전 게시글에 따른 Camera intent 관련 설정을 해주어야 한다.)
 1) activity_main.xml(layout을 설정)에 촬영 결과를 보여줄 ImageView를 다음과 같이 선언해 놓는다.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:id="@+id/imgpath"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"/>

    <ImageView
        android:id="@+id/resultview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:layout_below="@id/imgpath" />
</LinearLayout

 

 2) MainActivity.java(앞서 camera intent를 불러들였던 Activity에 해당)에 intent가 정상적으로 동작한 후에 해당 경로로 FileOutputStream을 이용하여 data를 write 할 onActivityResult()를 다음과 같이 Override 한다.


    @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) // intent 결과 정상적으로 마쳐질 경우
        {
            /* 앞서 수행한 intent request 값이 image capture와 관련된 것일 경우 다음을 수행한다. */
            if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE
            {
                ImageView resultView = (ImageView)findViewById(R.id.resultview); // .xml 에서 선언한 ImageView 변수를 Activity에도 선언한 후
                File tempImg = new File(fileUri.getPath()); // 앞서 지정한 경로에 파일의 경로에
                if(!tempImg.exists()){ // file이 존재하지 않으면
                    Log.d(TAG, "The image doesn't exist : " + tempImg.toString());
                    try {
                        FileOutputStream fos = new FileOutputStream(new File(fileUri.getPath())); // FileOutputStream 변수를 선언한 후
                        try {
                            fos.write(data.getExtras().getByte("data")); // Intent의 data 값을 write 하여 저장
                            fos.close(); // 그러고 나서 FileOutputStream을 종료한다.
                        } catch(IOException e){
                            Log.d(TAG, "IOException occur : " + e.getMessage());
                        }
                    } catch (FileNotFoundException e){
                        Log.d(TAG , "The image doesn't exist : "+ tempImg.toString());
                    }
                }
                Bitmap bm = BitmapFactory.decodeFile(fileUri.getPath()); // 해당 file을 Bitmap으로 decode 하여 저장한 후
                resultView.setImageBitmap(bm); // setImageBitmap() method로 앞서 선언한 ImageView에 촬영한 사진을 입력
                resultView.setRotation(imageViewRotation); // ImageView의 회전
            }
        }
    }

 

(위 code를 실행한 결과) 

 

 

 

 

 

 

 

 

 

 [Camera Intent 촬영 장면]

 [Camera Intent 종료 후 App 화면]

 [촬영된 사진 경로 확인]

 

 

 

 

 

 

 

  가끔 폰을 사용하다보면 Camera 기능을 여기저기에 응용해서 활용하고 있는 본인의 모습을 더러 볼 수 있을 것이다. 어떤 사람은 셀카에 포토샵처럼 보정하는 기능을 더해 사용하기도 하고, 또 어떤 사람은 놓치지 말아야 할 중요한 내용을 부랴부랴 받아 적기를 뒤로 하고 바로 사진으로 포착한다. 이렇듯 가끔 도촬이나 몰카같은 문제가 발생하지 않는다면 camera 기능은 참 유용하다는 생각이 든다. 이제 이 기능을 직접 구현하기 위해 공부해 보자. 오늘은 일단 Android 내의 기본 Camera App을 Intent로 불러다가 쓰는 방법을 살펴보려고 한다.

1. 목적 : Camera App을 직접 만들어 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료 : Android Developers - API Guide(http://developer.android.com/intl/ko/guide/topics/media/camera.html)

4. 과정

 1) AndroidManifest.xml 내 Camera 기능 활용 permission 추가
   : 먼저 카메라 기능과 촬영한 사진을 저장하기 위해 카메라와 외부 저장소에 대한 permission을 설정해 놔야 한다.


 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.zip.camaraexample" >

    <!-- intent로 불러올 기본 camera feature 설정 -->
    <uses-feature android:name="android.hardware.camera2" />
    <!-- 사진을 외부 저장소(SD Card)에 저장할 수 있도록 외부 저장소 write permission 설정 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application ...

 2) MainActivity.java 내 onCreate()에 App을 실행하자 마자 camera intent가 실행되도록 기본 intent code 추가
    : 우선 Android Developer Guide에 기재된 기본 code를 추가해 본다. 그 결과 해당 경로를 따라가면 camera로 촬영한 사진 file이 생성되어 있었다.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // create Intent to take a picture and return control to the calling application
    // 기본 내장 되어 있는 IMAGE CAPTURE 기능을 해당 app.에서 intent로 선언한다. 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    // 아래 정의한 capture한 사진의 저장 method를 실행 한 후
    fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
    // 먼저 선언한 intent에 해당 file 명의 값을 추가로 저장한다.
    
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

    // start the image capture Intent
    // 해당 intent를 시작한다. 
    startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);

}

/** Create a file Uri for saving an image or video */
/** 저장할 image file의 이름(URI)을 값을 반환. onCreate()에서 fileUri 값에 반영되는 값을 반환하도록 설계되어 있음 */
private static Uri getOutputMediaFileUri(int type){
    // 아래 capture한 사진이 저장될 file 공간을 생성하는 method를 통해 반환되는 File의 URI를 반환
    return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    // 외부 저장소에 이 App을 통해 촬영된 사진만 저장할 directory 경로와 File을 연결
    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){ // 해당 directory가 아직 생성되지 않았을 경우 mkdirs(). 즉 directory를 생성한다.
        if (! mediaStorageDir.mkdirs()){ // 만약 mkdirs()가 제대로 동작하지 않을 경우, 오류 Log를 출력한 뒤, 해당 method 종료
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    // File 명으로 file의 생성 시간을 활용하도록 DateFormat 기능을 활용
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;

    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }
    return mediaFile; // 생성된 File valuable을 반환

   (위 code의 실행 결과) 아직 App의 layout.xml을 건드리지 않은 기본 상태이기 때문에 기본 camera intent 가 finish()된 후 Hello World!가 출력된다. 그리고 App에서 지정한 경로로 접근해 보면 camera intent로 촬영한 결과 file이 생성되어 있다.

 

 

 

 

 

 

 

 

 

 

 

   3) 기본 Camera intent로 촬영한 결과물을 App의 ImageView로 확인하기[추가사항] → 다음 글 확인

+ Recent posts