본문 바로가기
ETC/Flutter

[flutter] 서버로 이미지 업로드 하기(Dio, image_picker)

by 안주형 2021. 11. 30.

유저 프로필 사진을 변경하거나 리뷰에 올릴 사진을 업로드하기 위해 서버에 사진을 업로드하는 경우가 필요하다. 오늘은 서버로 이미지 파일을 업로드하는 경우를 알아보려고 한다.

그전에 설치해야 할 패키지가 두 가지가 있다.

첫 번째는 Http 통신을 위한 dio 패키지이다.

 Http 패키지를 이용해 통신하던 사람들에게도 이미지를 업로드할 때는 dio 패키지를 추천한다. 이미지를 서버에 업로드하기 위해서는 Content-Type를 multipart/form-data로 전송해야 하는데 dio를 사용하면 손쉽게 이용할 수 있고, 따로 http통신처럼 decode를 해주지 않아도 자동으로 decode 된 상태로 response가 내려오기 때문이다.

 

dio | Dart Package

A powerful Http client for Dart, which supports Interceptors, FormData, Request Cancellation, File Downloading, Timeout etc.

pub.dev

 

두 번째는 휴대폰에서 이미지를 손쉽게 선택할 수 있게 해주는 image_picker 패키지이다.

image_picker 패키지를 통해 단일 이미지(동영상) 선택, 또는 다중 이미지 선택을 손쉽게 할 수 있다.

 

image_picker | Flutter Package

Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera.

pub.dev

image_picker 설치 후 접근 권한을 주기 위해서 ios > Runner > Info.plist 파일에 아래의 코드를 넣어준다.

<key>NSPhotoLibraryUsageDescription</key>
<string></string>
<key>NSCameraUsageDescription</key>
<string></string>
<key>NSMicrophoneUsageDescription</key>
<string></string>

 

이미지를 불러오는 함수의 예시는 아래와 같다.(단일 이미지를 선택하는 함수이다.)

다중 이미지https://pub.dev/packages/image_picker 의 ReadeMe 제일 아래 부분을 살펴보면 자세히 나와있다.

 

먼저 아래와 같이 생성자를 선언해준다.

final ImagePicker _picker = ImagePicker();

 

그다음 이미지를 불러와 XFile 타입의 변수에 담아준다. source부분에 ImageSource.gallery는 갤러리에서 불러온다는 의미이고, 카메라로 바로 촬영을 하기 위해서는 ImageSource.camera로 변경해주면 된다. 그리고 순서대로 maxHeight와 maxWidth는 사진의 최대 크기를 자동으로 조절해주는 것이고, imageQuality는 이미지의 용량이 크기 때문에 압축을 위해 퀄리티를 낮춰주는 부분이다.  후에 서버와 통신할 때 알게 되겠지만, 만약 전송 시 이미지의 데이터 크기가 서버에서 제한한 요량을 넘어서면 http 413 Error를 뱉어낸다. 때문에 압축을 통해 사전에 그럴 경우를 줄여준다.

    XFile? selectImage = await _picker.pickImage(
      //이미지를 선택
      source: ImageSource.gallery, //위치는 갤러리
      maxHeight: 75,
      maxWidth: 75,
      imageQuality: 30, // 이미지 크기 압축을 위해 퀄리티를 30으로 낮춤.
    );

 

이제 이미지를 선택하여 값이 있을 경우에, 서버와 통신을 시도하면 되는데, 그전에 이미지의 값을 이미지의 경로로 바꿔준다. 아래와 같이. path를 붙여주면 된다.

if (selectImage != null) {
    dynamic sendData = selectImage.path;
 }

 

이미지 데이터를 서버로 전송하기 위해서는 formData의 형식으로 아래와 같이 변경시켜줘야 한다. 'image'는 서버에서 요구하는 key 값이기에 본인의 서버 key에 맞게 변경시켜주면 된다.

var formData = FormData.fromMap({'image': await MultipartFile.fromFile(sendData)});

 

아래는 이제 dio를 활용해 서버와 통신하는 함수이다. contentType를 잘 설정해주고  headers부분에 값을 보내야 한다면 아래와 같이 dio.options.headers 에 값을 넣어주면 된다. formData는 아래 data: 부분에 넣어주면 된다.

http와 다르게 전송받은 데이터는 response.data 와같이 .data를 붙여주면 된다.

Future<dynamic> patchUserProfileImage(dynamic input) async {
    print("프로필 사진을 서버에 업로드 합니다.");
    var dio = new Dio();
    try {
      dio.options.contentType = 'multipart/form-data';
      dio.options.maxRedirects.isFinite;

      dio.options.headers = {'token': token};
      var response = await dio.patch(
        baseUri + '/users/profileimage',
        data: input,
      );
      print('성공적으로 업로드했습니다');
      return response.data;
    } catch (e) {
      print(e);
    }
  }

 

이제 내려받은 response.data를 통해 알맞게 가공하여 사용하면 된다..

 

 

댓글