반응형
Overview
이번 포스팅에서는...
- image_picker 라이브러리를 사용하여
- 카메라로 촬영된 사진과
- 갤러리에서 선택한 사진을
- 보다 쉽게 화면에 출력
하는 것을 다룹니다.
- 카메라 촬영 후 앱에 보여주기
- 갤러리에서 사진 선택후 앱에 보여주기
image_picker 라이브러리 선택 이유
카메라 사용을 위해 현재 pub.dev 에서 가장 좋아요 수가 많은(most likes) 카메라 관련 라이브러리로 선택하여 포스팅을 작성하였습니다.
image_picker
- 이미지 라이브러리에서 이미지를 선택하기 위한 iOS 및 Android용 Flutter 플러그인
- 카메라로 새로운 사진을 찍거나 갤러리의 사진을 이용할 수 있음
라이브러리(종속성) 추가
(터미널에서) flutter pub add image_picker
flutter pub add image_picker
카메라를 사용하기 위한 플랫폼 설정
iOS
- (프로젝트 디렉토리 내에서) ios - Runner - Info.plist
- Info.plist 파일에 아래의 내용을 추가
- 비디오 녹화가 필요하지 않은 경우 NSMicrophoneUsageDescription 은 제외해도 상관 없음
<key>NSPhotoLibraryUsageDescription</key>
<string>갤러리를 사용하기 위한 권한</string>
<key>NSCameraUsageDescription</key>
<string>카메라를 사용하기 위한 권한</string>
<key>NSMicrophoneUsageDescription</key>
<string>카메라에서 비디오 녹화 시 마이크를 사용하기 위한 권한</string>
Android
기존에는 AndroidManifest.xml에 권한을 추가해주어야 했지만 지금은 따로 추가하지 않아도 됩니다.
Windows, macOS, Linux
image_picker 라이브러리는 데스크톱 플랫폼에서는 제한적으로 지원합니다.
포스팅에서는 모바일을 기준으로 작성하였기 때문에 제한적 지원되는 기능에 대해서는 설명하지 않습니다.
skip~ XD
예제
아래의 예제는 flutter image_picker 공식 문서에서 발췌한 내용입니다.
final ImagePicker picker = ImagePicker();
// Pick an image.
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
// Capture a photo.
final XFile? photo = await picker.pickImage(source: ImageSource.camera);
// Pick a video.
final XFile? galleryVideo =
await picker.pickVideo(source: ImageSource.gallery);
// Capture a video.
final XFile? cameraVideo = await picker.pickVideo(source: ImageSource.camera);
// Pick multiple images.
final List<XFile> images = await picker.pickMultiImage();
// Pick singe image or video.
final XFile? media = await picker.pickMedia();
// Pick multiple images and videos.
final List<XFile> medias = await picker.pickMultipleMedia();
코딩
아래의 코드 테스트는 안드로이드를 기준으로 테스팅되었습니다.
파일 생성 및 기본 설정
- 카메라 기능을 구현할 파일을 생성해줍니다.
- cameraView.dart
- image_picker 사용을 위해 최상단에 라이브러리를 호출합니다.
import 'package:image_picker/image_picker.dart';
- 이미지를 불러올 수 있도록 위젯의 상태를 변경 가능하도록 StatefulWidget을 상속합니다.
class CameraView extends StatefulWidget {
const CameraView({super.key});
@override
State<CameraView> createState() => _CameraViewState();
}
class _CameraViewState extends State<CameraView> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
UI 디자인
- 카메라와 앨범의 기능을 테스트하기 위하여 위와 같은 화면을 구성합니다.
- 버튼 클릭 이벤트의 'getImage'
- 새로 정의할 함수명이며 갤러리나 카메라를 통해 이미지를 호출하는 기능을 합니다.
- Column - SizedBox의 속해있는 _buildPhotoArea
- 불러온 이미지를 출력하는 영역입니다.
- 다른 위젯을 정의하여 상황에 따라 이미지가 있고 없고를 보여주기 위함입니다.
- 버튼 클릭 이벤트의 'getImage'
@override
Widget build(BuildContext context) {
return SafeArea(
child: Container(
color: Colors.white,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 300,
height: 300,
child: _buildPhotoArea(),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 카메라 선택 버튼
ElevatedButton(
onPressed: () {
getImage(ImageSource.camera);
},
child: const Text("카메라"),
),
const Padding(padding: EdgeInsets.all(10)),
// 앨범 선택 버튼
ElevatedButton(
onPressed: () {
getImage(ImageSource.gallery);
},
child: const Text("앨범"),
),
],
)
],
),
),
),
);
}
- 이미지를 보여주기 위한 위젯 정의
Widget _buildPhotoArea() {
// 불러온 이미지가 있는지 없는지 확인
return _imageFile != null
// 불러온 이미지가 있으면 출력
? Center(
child: Image.file(
File(_imageFile!.path),
),
)
// 불러온 이미지가 없으면 텍스트 출력
: const Center(
child: Text("불러온 이미지가 없습니다."),
);
}
기능 구현
주석에 모두 적어놓았지만 기본적인 절차를 서술하자면,
'카메라' 혹은 '앨범' 버튼을 클릭하면 상황에 맞는 imageSource 객체가 getImage 파라미터로 사용됩니다.
imageSource 객체는 위의 UI 설계에서 정의해놓은 ElevatedButton에서 입력되는 파라미터를 의미합니다.
- 버튼에서의 파라미터
- 카메라 버튼 : image_picker의 ImageSource.camera 속성을 사용하여 카메라를 보여줍니다.
- 앨범 버튼 : image_picker의 ImageSource.gallery 속성을 사용하여 갤러리(앨범)을 보여줍니다.
- getImage 함수에서의 파라미터
- 카메라일 경우 : 카메라로 촬영한 사진을 imageSource로 사용합니다.
- 앨범일 경우 : 앨범에서 선택한 사진을 imageSource로 사용합니다.
// Image Picker 인스턴스 생성
final ImagePicker picker = ImagePicker();
// 카메라 또는 갤러리의 이미지를 저장할 변수
XFile? _imageFile;
// 이미지를 가져오는 함수
Future<void> getImage(ImageSource imageSource) async {
try {
// 카메라 또는 갤러리의 이미지
final XFile? imageFile = await picker.pickImage(
source: imageSource, maxHeight: 300, maxWidth: 300);
if (imageFile != null) {
// 이미지를 화면에 출력하기 위해 앱의 상태 변경
setState(() {
_imageFile = imageFile;
});
}
} catch (e) {
print("디버깅용 이미지 호출 에러 : $e");
}
}
메인 함수와 연결
- import 부분은 각자의 프로젝트에 맞게 이름을 넣어주세요.
import 'package:flutter/material.dart';
import 'package:flutter_zzicsu/cameraView.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(
const MaterialApp(
home: cameraView(),
),
);
}
카메라 기능 구현 전체 소스 코드
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class CameraView extends StatefulWidget {
const CameraView({super.key});
@override
State<CameraView> createState() => _CameraViewState();
}
class _CameraViewState extends State<CameraView> {
// Image Picker 인스턴스 생성
final ImagePicker picker = ImagePicker();
// 카메라 또는 갤러리의 이미지를 저장할 변수
XFile? _imageFile;
// 이미지를 가져오는 함수
Future<void> getImage(ImageSource imageSource) async {
try {
// 카메라 또는 갤러리의 이미지
final XFile? imageFile = await picker.pickImage(
source: imageSource, maxHeight: 300, maxWidth: 300);
if (imageFile != null) {
// 이미지를 화면에 출력하기 위해 앱의 상태 변경
setState(() {
_imageFile = imageFile;
});
}
} catch (e) {
print("디버깅용 이미지 호출 에러 : $e");
}
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Container(
color: Colors.white,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 300,
height: 300,
child: _buildPhotoArea(),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 카메라 선택 버튼
ElevatedButton(
onPressed: () {
getImage(ImageSource.camera);
},
child: const Text("카메라"),
),
const Padding(padding: EdgeInsets.all(10)),
// 앨범 선택 버튼
ElevatedButton(
onPressed: () {
getImage(ImageSource.gallery);
},
child: const Text("앨범"),
),
],
)
],
),
),
),
);
}
Widget _buildPhotoArea() {
// 불러온 이미지가 있는지 없는지 확인
return _imageFile != null
// 불러온 이미지가 있으면 출력
? Center(
child: Image.file(
File(_imageFile!.path),
),
)
// 불러온 이미지가 없으면 텍스트 출력
: const Center(
child: Text("불러온 이미지가 없습니다."),
);
}
}
다음 포스팅
다음 포스팅에서는 불러온 이미지를 자르거나 확대/축소, 회전하는 것을 다룹니다.
아래의 파란 글씨를 누르면 다음 포스팅으로 이동합니다.
참고
- pub.dev - Flutter Package - image_picker
- 이 글은 티스토리 블로그 '영주머니의 개발주머니' 님의 글을 많이 참고하여 포스팅되었습니다.
반응형