Home 카메라로 사진 찍어 저장하기
Post
Cancel

카메라로 사진 찍어 저장하기

카메라로 사진 찍어 저장하기

카메라로 사진을 찍기 위해 사용되는 방법은 크게 두가지로 나눌 수 있다.

  • 인텐트로 단말의 카메라 앱을 실행한 후 결과 사진을 받아 처리하기
  • 앱 화면에 카메라 미리보기를 보여주고 직접 사진을 찍어 처리하기

스마트폰 단말에는 카메라 앱이 미리 설치되어 있는데 이 앱을 사용하면 가장 간단하게 다른 기능의 앱을 구현할 수 있다.

단말의 카메라 앱은 다른 개발자가 미리 만들어 설치해둔 것이므로 우리가 만들려는 앱에서 카메라 앱의 화면을 띄우려면 인텐트를 만들어 시스템에 요청하면 된다.


인텐트를 사용해 단말의 카메라 앱을 실행한 후 결과 사진 처리하기

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class MainActivity extends AppCompatActivity {  
    ImageView imageView;  
  
    File file;  
    Uri uri;  
  
    @Override  
  protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
  
        imageView = findViewById(R.id.imageView);  
  
        Button button = findViewById(R.id.button);  
        button.setOnClickListener(new View.OnClickListener() {  
            @Override  
			 public void onClick(View v) {  
                takePicture();  
            }  
        });  
  
    }  
  
    public void takePicture() {  
        try {  
            file = createFile();  
            if (file.exists()) {  
                file.delete();  
            }  
  
            file.createNewFile();  
        } catch(Exception e) {  
            e.printStackTrace();  
        }  
  
        if(Build.VERSION.SDK_INT >= 24) {  
            uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, file);  
        } else {  
            uri = Uri.fromFile(file);  
        }  
  
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);  
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);  
  
        startActivityForResult(intent, 101);  
    }  
  
    private File createFile() {  
        String filename = "capture.jpg";  
        File outFile = new File(getFilesDir(), filename);  
        Log.d("Main", "File path : " + outFile.getAbsolutePath());  
  
        return outFile;  
    }  
  
    @Override  
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {  
        super.onActivityResult(requestCode, resultCode, data);  
  
        if (requestCode == 101 && resultCode == RESULT_OK) {  
            try {  
                Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));  
                imageView.setImageBitmap(bitmap);  
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
  
}

버튼을 클릭하면 takePicture 메서드를 호출한다.

이 메서드가 호출되면 먼저 파일을 만드는데 이 파일은 카메라 앱에서 사진을 찍은 후에 그 결과물을 저장할 파일이다.

FileProvider.getUriForFile 메서드를 사용하면 카메라 앱에서 공유하며 사용할 수 있는 파일의 정보를 Uri 객체로 만들 수 있다.

putExtra 메서드는 다른 액티비티에 부가 데이터를 전달할 때 사용하는데 <키,value>로 전달한다.

Uri 객체는 MediaStore.EXTRA_OUTPUT 키를 사용해서 인텐트에 부가 데이터를 추가한다.

인텐트 객체를 만들었으므로 startActivityForResult 메서드를 이용해서 시스템으로 인텐트 객체를 전달한다.

단말의 카메라 앱을 띄워달라는 액션 정보는 MediaStore.ACTION_IMAGE_CAPTURE이다.

인텐트 객체를 만들어 카메라 앱을 실행한 후 사진을 찍고 나면 카메라 앱의 액티비티를 닫게 되는데 그때 응답을 받는 부분은 onActicityResult 메서드이다.

onActicityResult 호출되면 카메라 앱에서 찍은 사진을 파일에서 확인할 수 있다.

일반적으로 카메라 해상도가 높은 경우 비트맵 객체의 크기도 커지므로 적당한 비율로 축소하여 만들게된다. 여기에서는 1/8 크기로 축소했으며 bitmap 객체로 만들때는 BitmapFactory 클래스의 decodeFile 메서드를 호출하면 된다.


external.xml

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>  
<paths xmlns:android="http://schemas.android.com/apk/res/android">  
    <cache-path name="cache" path="/" />  
    <files-path name="files" path="/" />  
    <external-files-path name="external_files" path="." />  
</paths>

external.xml 파일 안에 있는 <path> 태그는 <cache-path>, <files-path>, <\external-files-path> 태그를 포함하고 있으며 이는 앱의 cache 폴더, files 폴더, externalFiles 폴더를 접근할 수 있도록 허용한다.


AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  package="org.techtown.capture.intent">  
  
    <application  
  android:allowBackup="true"  
  android:icon="@mipmap/ic_launcher"  
  android:label="@string/app_name"  
  android:roundIcon="@mipmap/ic_launcher_round"  
  android:supportsRtl="true"  
  android:theme="@style/Theme.SampleCaptureIntent">  
        <activity android:name=".MainActivity" android:exported="true">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
  
        <provider  
			  android:name="androidx.core.content.FileProvider"  
			  android:authorities="${applicationId}"  
			  android:exported="false"  
			  android:grantUriPermissions="true">  
            <meta-data  
				  android:name="android.support.FILE_PROVIDER_PATHS"  
				  android:resource="@xml/external" />  
        </provider>  
  
    </application>  
  
</manifest>

AndroidManifest.xml 파일을 열고 <provider> 태그로 내용 제공자를 추가한다.

내용 제공자는 androidx 패키지 안에 들어 있는 FileProvider를 사용한다.

<provider> 태그 안에는 name 속성이 들어 있고 android.core.content.FileProvider 클래스를 지정하고 있다.

FileProvider 특정 폴더를 공유하는데 사용하는 내용 제공자이다.

<authorities> 속성에 설정한 값은 이 앱의 패키지 이름이다.

<meta-data> 태그 안에는 name과 resource 속성이 들어가며 resource 속성으로 /app/res/xml 폴더 안에 만들었던 external.xml 파일을 지정한다.

이때 파일 확장자는 제외하므로 @xml/external 값으로 설정된다.


결과

ezgif com-gif-maker

This post is licensed under CC BY 4.0 by the author.