loading

프로그래밍/안드로이드

[Android Studio] 카메라로 찍은 사진 이미지뷰에 넣기

침착곰 2021. 5. 15. 00:41
반응형

안녕하세요

안드로이드 개발을 하다보면 카메라로 찍은 사진을 바탕으로 편집을 하거나 서버에 전송하는 등 카메라 관련 기능을 구현할 때가 있습니다

이번 포스팅에서는 기본적인 카메라로 찍은 사진을 이미지뷰에 보여주는 방법에 대해서 알아보겠습니다

 

목차

카메라로 찍은 사진을 이미지뷰에 넣기
사진 원본 크기로 출력하기
사진 각도 돌리기

 


카메라로 찍은 사진을 이미지뷰에 넣기

 

activitiy_main.xml 디자인

먼저 디자인입니다

카메라 촬영을 시작할 버튼과 카메라로 찍은 사진을 보여줄 이미지뷰를 추가합니다

 

AndroidManifest.xml 수정

카메라로 촬영 후 메모리에 저장을 해야합니다

저장이 가능하도록 권한 설정을 해줍니다

아래의 코드를 추가해줍니다

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

 

AndroidManifest 전체소스

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cameraview">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

    <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.CameraView">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

MainActivity.java

메인 소스입니다

onClick에서 intent를 사용 MediaStore.ACTION_IMAGE_CAPTURE 를 이용하여 카메라 촬영창을 띄웁니다

onActivityResult로 카메라로 촬영한 사진데이터를 받아 이미지뷰에 입력합니다

package com.example.cameraview;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnCamera;
    ImageView imageView;

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

        // 디자인 정의
        btnCamera = (Button) findViewById(R.id.btnPhoto);
        imageView = (ImageView) findViewById(R.id.imageView);
        btnCamera.setOnClickListener(this);
    }

    @Override
    public void onClick(View view)    {
        switch (view.getId()) {
            // 카메라촬영 클릭 이벤트
            case R.id.btnPhoto:
                // 카메라 기능을 Intent
                Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(i, 0);
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)    {
        super.onActivityResult(requestCode, resultCode, data);

        // 카메라 촬영을 하면 이미지뷰에 사진 삽입
        if(requestCode == 0 && resultCode == RESULT_OK) {
            // Bundle로 데이터를 입력
            Bundle extras = data.getExtras();
            
            // Bitmap으로 컨버전
            Bitmap imageBitmap = (Bitmap) extras.get("data");
            
            // 이미지뷰에 Bitmap으로 이미지를 입력
            imageView.setImageBitmap(imageBitmap);
        }
    }
}

 

여기까지 작업하면 카메라로 촬영한 사진이 이미지뷰에 들어가는 것의 구현을 완료했습니다

이제 테스트해보겠습니다

 

결과 화면

이미지뷰에 촬영한 사진이 올라간 것을 볼 수 있습니다

하지만 이미지뷰에 조그맣게 표시가 됩니다

너무 작네;;

 

이제 이미지뷰를 사진의 크기에 맞춰서 키우는 방법에 대해서 알아보겠습니다

 


 

 

사진 원본 크기로 출력하기

xml 파일을 추가해줘야합니다

res 폴더에 xml 폴더와 file_paths.xml 파일을 추가해줍니다

 

file_paths.xml 수정

Main화면의 이미지뷰가 file_paths.xml를 불러올 수 있도록 수정해야합니다

이미지뷰파일 : activity_main의 ImageView Id를 적어줍니다

프로젝트패키지명 : 본인의 프로젝트패키지명을 적어줍니다

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="이미지뷰파일" path="Android/data/프로젝트패키지명/files/Pictures" />
</paths>

 

AndroidManifest.xml 수정

provider를 추가하여 file_paths.xml이 파일 권한에 접근할 권한을 추가해줍니다

위의 방식은 카메라를 촬영하여 바로 ImageView에 출력했다면,

이 방법은 스마트폰의 저장소에 저장한 이미지를 ImageView출력하는 방식이므로 권한을 추가해야합니다

        <provider android:name="androidx.core.content.FileProvider"
            android:authorities="프로젝트패키지명.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

 

AndroidManifest.xml 전체소스

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cameraview">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

    <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.CameraView">
        <activity android:name=".MainActivity">
            <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="프로젝트패키지명.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
</manifest>

 

MainActivity.java 수정

createImageFile() 메서드 선언

먼저 사진을 촬영할 때 이미지파일의 이름과 저장할 경로를 세팅하는 메서드를 만듭니다

이미지파일의 이름은 현재시간으로 세팅했습니다

이미지파일이 저장될 곳은 갤러리 폴더에 저장됩니다

// ImageFile의 경로를 가져올 메서드 선언
private File createImageFile() throws IOException {
    // 파일이름을 세팅 및 저장경로 세팅
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File StorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,
            ".jpg",
            storageDir
    );

    return image;
}

 

onClick 메서드 수정

onClick 메서드에서 이미지파일을 세팅하는 메서드를 가져와 사진이 촬영되면 이미지를 저장하고 

startActivityForResult를 호출합니다

Uri photoUri;

@Override
public void onClick(View view)    {
    switch (view.getId()) {
        // 카메라촬영 클릭 이벤트
        case R.id.btnPhoto:
            // 카메라 기능을 Intent
            Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

            // 사진파일 변수 선언 및 경로세팅
            File photoFile = null;
            try { photoFile = createImageFile(); } catch (IOException ex) { }

            // 사진을 저장하고 이미지뷰에 출력
            if(photoFile != null) {
                photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
                i.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);

                startActivityForResult(i, 0);
        }

            break;
    }
}

 

onActivityResult 수정

imageView.setImageURI 메서드를 사용 해당경로의 이미지를 가져와 ImageView에 출력합니다

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)    {
    super.onActivityResult(requestCode, resultCode, data);

    // 카메라 촬영을 하면 이미지뷰에 사진 삽입
    if(requestCode == 0 && resultCode == RESULT_OK) {
            // 이미지뷰에 파일경로의 사진을 가져와 출력
            imageView.setImageURI(photoUri);
    }
}

 

MainActivity의 전체 소스

package com.example.cameraview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.ImageDecoder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnCamera;
    ImageView imageView;

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

        // 디자인 정의
        btnCamera = (Button) findViewById(R.id.btnPhoto);
        imageView = (ImageView) findViewById(R.id.imageView);
        btnCamera.setOnClickListener(this);
    }

    Uri photoUri;

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            // 카메라촬영 클릭 이벤트
            case R.id.btnPhoto:
                // 카메라 기능을 Intent
                Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

                // 사진파일 변수 선언 및 경로세팅
                File photoFile = null;
                try {
                    photoFile = createImageFile();
                } catch (IOException ex) {
                }

                // 사진을 저장하고 이미지뷰에 출력
                if (photoFile != null) {
                    photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
                    i.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);

                    startActivityForResult(i, 0);
                }

                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // 카메라 촬영을 하면 이미지뷰에 사진 삽입
        if (requestCode == 0 && resultCode == RESULT_OK) {
            // 이미지뷰에 파일경로의 사진을 가져와 출력
            imageView.setImageURI(photoUri);
        }
    }

    // ImageFile의 경로를 가져올 메서드 선언
    private File createImageFile() throws IOException {
        // 파일이름을 세팅 및 저장경로 세팅
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File StorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,
                ".jpg",
                storageDir
        );

        return image;
    }
}

 

여기까지 작은 화면으로 보이는 이미지뷰를 원본이미지크기로 출력하는 것에 대해서 알아봤습니다

이제 테스트를 해보겠습니다!!

 

결과 화면

 

위의 사진을 보면 알겠지만 사진은 원래크기로 보이지만

사진이 돌아가있습니다...

다음 단계에서는 돌아간 사진을 정상적으로 보이는 방법에 대해서 설명하겠습니다

 


사진 각도 돌리기

MainActivity.java 수정

MainActivity에 두 개의 메서드를 추가합니다

사진의 돌아간 각도를 계산하는 메서드인 exifOrientationToDegrees()와

사진을 회전시키는 메서드인 rotate()입니다

// 사진의 돌아간 각도를 계산하는 메서드 선언
private int exifOrientationToDegrees(int exifOrientation) {
    if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
        return 90;
    } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
        return 180;
    } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
        return 270;
    }
    return 0;
}

// 이미지를 회전시키는 메서드 선언
private Bitmap rotate(Bitmap bitmap, float degree) {
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

 

createImageFile 수정

사진파일의 경로를 저장할 전역변수를 선언합니다

String imageFilePath;

 

아래와 같이 사진파일의 경로를 저장합니다

imageFilePath = image.getAbsolutePath();

 

createImageFile() 메서드 전체소스입니다

// ImageFile의 경로를 가져올 메서드 선언
private File createImageFile() throws IOException {
    // 파일이름을 세팅 및 저장경로 세팅
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File StorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,
            ".jpg",
            storageDir
    );

    imageFilePath = image.getAbsolutePath();

    return image;
}

 

onActivityResult() 수정

onActivityResult()에 위에서 추가한 메서드로 exifOrientationToDegrees()로 사진파일의 회전각도를 확인하고, rotate() 메서드를 사용하여 이미지파일을 회전시킵니다

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    // 카메라 촬영을 하면 이미지뷰에 사진 삽입
    if (requestCode == 0 && resultCode == RESULT_OK) {
        // 이미지파일을 bitmap 변수에 초기화
        Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);
        ExifInterface exif = null;

        try {
            exif = new ExifInterface(imageFilePath);
        }
        catch(IOException e){
            e.printStackTrace();
        }

        // 이미지를 회전각도를 구한다
        int exifOrientation;
        int exifDegree;

        if (exif != null) {
            exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            exifDegree = exifOrientationToDegrees(exifOrientation);
        } else {
            exifDegree = 0;
        }

        // 이미지를 출력
        imageView.setImageBitmap(rotate(bitmap, exifDegree));
    }
}

 

여기까지 안드로이드에서 사진을 촬영하여 이미지를 출력하는 기능에 대한 설명을 모두 마쳤습니다!!

마지막으로 결과 화면입니다!

이미지가 정상적으로 출력됩니다

 

이 글을 보신 분들이 안드로이드 개발에 도움이 되었으면 좋겠습니다

설명 마치겠습니다!!

반응형
그리드형