[Flutter]image_picker로 이미지 가져오기

한상욱·2023년 11월 22일
0

Flutter

목록 보기
6/26
post-thumbnail

들어가며

앱에서 이미지를 가져오려는 경우 갤러리로 접근하여 이미지를 가져와야합니다. Flutter는 ImagePicker라이브러리를 이용해서 간단하게 갤러리에 접근 및 이미지를 가져올 수 있습니다. 이번에는 image_picker에 대해서 알아보겠습니다.

ImagePicker

image_picker는 정말 간단하게 갤러리에 접근하고 이미지를 가져올 수 있도록 하는 라이브러리입니다. 정말 많은 기능이 있으나, 우리는 Android, IOS, Web에서 사용하는 방법에 대해서 그 중에서도 갤러리에 접근하여 이미지를 가져오는 예제를 알아보겠습니다.

Android 권한 설정

안드로이드에서는 AndroidManifest.xml 파일안에 android:requestLegacyExternalStorage="true" 을 추가해주어야 합니다.

이미 앱을 실행했었다면, 위의 코드를 추가한 후 flutter clean을 수행해줍니다.

IOS 권한 설정

IOS는 info.plist 파일안에 갤러리와 이미지에 대한 권한을 선언해주어야 합니다. 해당 내용은 나중에 앱스토어 심사에서 사용되므로 해당 권한이 필요한 이유는 자세하게 적는것이 좋습니다.

예제 앱 생성

가장 간단한 형식의 앱을 만들겠습니다. 앱바 상단에 있는 액션버튼을 통해 갤러리에 접근 후 이미지를 불러오는 앱입니다.

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_image_picker/src/app.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: App(),
    );
  }
}

기본적인 main.dart 파일의 구성은 위와 같습니다. 이제 앱의 기능은 app.dart파일을 통해 구현해보겠습니다.

갤러리에 접근해서 이미지 불러오기

기본적으로 이미지를 불러오면 앱에 불러온 이미지의 썸네일을 보여주어야 하기 때문에 stateful 위젯을 사용하겠습니다. 맨 처음에는 불러온 이미지를 담는 변수 file을 선언합니다.

class App extends StatefulWidget {
  const App({super.key});

  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  // file 선언
  XFile? file;
  ...

결과로 불러오는 데이터는 모두 XFile이라는 타입을 가집니다. 기본적으로 처음에는 해당 데이터가 존재할 수 없기 때문에 Nullable 표기를 붙여줍니다. 이제 이미지를 불러오는 메소드를 작성해보겠습니다.

  Future<void> _pickImage() async {
    ImagePicker().pickImage(source: ImageSource.gallery).then((image) {
      if (image != null) {
        setState(() {
          file = image;
        });
      }
    });
  }

이미지를 불러오는 것은 굉장히 간단합니다. 위 표현은 함수형 프로그래밍을 이용하여 함축적으로 표현하였으나, 꼭 정해진 답은 아닙니다.

가장 먼저, 권한 설정에 대한 코드가 필요하나 image_picker는 권한에 관련한 설정을 완료하였다면 해당 기능을 이용할 때 권한을 사용자에게 요청합니다. 하지만 실제로는 Permission Handler를 이용해서 초기에 설정하는 것이 좋습니다.

그 후에는 이미지의 소스에 대한 정보를 기입해주어야 됩니다. 만약 ImageSource.camera로 선언하게 되면 카메라 기능을 이용해서 이미지를 생성하게 됩니다.

이런 방식으로 이미지를 불러왔다면, setState 메소드를 이용해서 해당 파일을 file 변수에 전달하고 리빌드 해줍니다. 아래는 나머지 UI에 대한 코드입니다.

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

class App extends StatefulWidget {
  const App({super.key});

  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  XFile? file;

  Future<void> _pickImage() async {
    ImagePicker().pickImage(source: ImageSource.gallery).then((image) {
      if (image != null) {
        setState(() {
          file = image;
        });
      }
    });
  }

  
  Widget build(BuildContext context) {
    final length = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: const Text("Image Picker"),
        actions: [
          IconButton(onPressed: _pickImage, icon: const Icon(Icons.image))
        ],
      ),
      body: Center(
          child: Container(
        color: Colors.grey,
        height: length,
        width: length,
        child: (file != null)
            ? Image.file(
                File(file!.path),
                fit: BoxFit.cover,
              )
            : const Icon(
                Icons.image,
                size: 50,
                color: Colors.white,
              ),
      )),
    );
  }
}

이로써, image_picker라이브러리를 이용하여 이미지를 불러올 수 있습니다.

데스크톱 환경

만약 web 환경에서 image_picker를 사용하게 되는 경우에는 image.file 메소드를 지원하지 않습니다. 이러한 경우 해당 파일을 byte로 변환하여 image.memory를 이용하여 사용자에게 전달할 수 있습니다.

import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

...

class _AppState extends State<App> {
  Uint8List? file; // Uint8List 타입으로 데이터 반환

  Future<void> _pickImage() async {
    ImagePicker().pickImage(source: ImageSource.gallery).then((image) {
      if (image != null) {
      // readAsBytes 메소드를 이용해서 데이터 변환
        image.readAsBytes().then((f) => setState(() => file = f));
      }
    });
  }
]

	...
      body: Center(
          child: Container(
        color: Colors.grey,
        height: length,
        width: length,
        child: (file != null)
            ? Image.memory(
                file!,
                fit: BoxFit.cover,
              )
            : const Icon(
                Icons.image,
                size: 50,
                color: Colors.white,
              ),
      )),
    );
  }
}

이렇게 되는 경우에는 데이터는 Uint8List 타입으로 반환됩니다. image는 readAsBytes()메소드를 이용하여 Uint8List 타입으로 변환할 수 있습니다.

profile
자기주도적, 지속 성장하는 모바일앱 개발자가 되기 위해

0개의 댓글