Flutter Image 여러장 Upload + Resizing 하기.

Whatamelon!·2020년 11월 24일
1

요 5개 라이브러리와 함께 이미지를 리사이징하고 올려보겠습니당

1. 변수 선언

List<dynamic> images = List<dynamic>();
List<Uint8List> byteArrayList;
List _resizeImages = new List();

2. 이미지 가져오는 위젯 선언

 		AbsorbPointer(
                      absorbing: !_once,
                      child: InkWell(
                        onTap:() => _pickAsset(PickType.onlyImage),
                        child: DottedBorder(
                          padding: EdgeInsets.all(1),
                          dashPattern: [8,3],
                          color: Du.darkGrey(),
                          strokeWidth: 3,
                          strokeCap: StrokeCap.butt,
                          radius: Radius.circular(5),
                          borderType: BorderType.RRect,
                          child: ClipRRect(
                            borderRadius: BorderRadius.all(Radius.circular(5)),
                            child: Container(
                              width: mw(332),
                              height: mw(90),
                              color: Du.lightGrey(),
                              child: Center(child: Text('사진 첨부하기', style: Ts.bd1dgm(),),),
                            ),
                          ),
                        ),
                      ),
                    ),



  void _pickAsset(PickType type) async {
    List imgList = await PhotoPicker.pickAsset(
      context: context,
      themeColor: Colors.black,
      textColor: Colors.white,
      padding: 1.0,
      dividerColor: Colors.grey,
      disableColor: Colors.grey.shade300,
      itemRadio: 1,
      maxSelected: 5,
      provider: I18nProvider.chinese,
      rowCount: 4,
      thumbSize: 150,
      sortDelegate: SortDelegate.common,
      checkBoxBuilderDelegate: DefaultCheckBoxBuilderDelegate(
        activeColor: Colors.white,
        unselectedColor: Colors.white,
        checkColor: Colors.black,
      ),
      badgeDelegate: const DurationBadgeDelegate(),
      pickType: type,
    );

    if (imgList == null || imgList.isEmpty) {
      print('no images');
      return;
    } else {
      List<String> r = [];
      for (var e in imgList) {
        var file = await e.file;
        r.add(file.absolute.path);
      }
      currentSelected = r.join("\n\n");

      List preview = [];
      preview.addAll(imgList);
      
      if (!mounted) return;
      setState(() {
        print('');
        images = preview;
        _resizeImages.clear();
      });

    }
  } 
  
  
  Widget buildGridView() {
    if (images != null)
      return GridView.count(
        physics: NeverScrollableScrollPhysics(),
        mainAxisSpacing: mw(4),
        crossAxisSpacing: mw(4),
        crossAxisCount: 4,
        shrinkWrap: true,
        childAspectRatio: 1,
        children: images
            .map((item) => Stack(
            children : [
              AssetImageWidget(
                assetEntity: item,
                width: mw(77),
                height: mw(77),
                boxFit: BoxFit.cover,
              ),
              Positioned(
                  child: Container(
                    width: mw(77),
                    height: mw(77),
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.all(Radius.circular(5)),
                        color: Colors.black.withOpacity(0.5)
                    ),
                  )
              ),
              Positioned(
                  right: 6,
                  top: 2,
                  child: GestureDetector(
                    onTap: () {
                      print(item.id);
                      int j = 0;
                      for(var h = 0; h < images.length; h ++) {
                        print(images[h].id);
                        if(item.id == images[h].id) {
                          j = h;
                        }
                      }
                      setState(() {
                        images.removeAt(j);
                      });
                    },
                    child: Icon(Icons.clear, size: 14, color: Colors.white,),
                  )
              )
            ]
        )).toList(),
      );
    else
      return Container(color: Colors.white);
  }
                

3. 이미지 리사이징을 해줍니당

기준 크기를 500px로 잡아줍니다.
만약 이미지사이즈가 1000X1500이라면, 500X750 이 되도록 만들어줍니다.


  Future<bool> resizeImage1() async{
      for(var i = 0; i < images.length; i ++) {

        AssetEntity entity = images[i];
        File file = await entity.file;
        var path2 = file.path;
        var width;
        var height;

        var decodedImage = await decodeImageFromList(file.readAsBytesSync());

        if(Platform.isAndroid) {
           width = decodedImage.width;
           height = decodedImage.height;
        } else {
           width = entity.width;
           height = entity.height;
        }

        if(width < 500 || height < 500) {
          _resizeImages.add(await resizeImage2(path2, width, height, i));
        }
        else if(width < height) {

          var ratio2 = (height/width).toStringAsFixed(3);
          var newValue2 = 500*double.parse(ratio2);

          _resizeImages.add(await resizeImage2(path2, 500, newValue2, i));

        } else if(height < width) {

          var ratio2 = (width/height).toStringAsFixed(3);
          var newValue2 = 500*double.parse(ratio2);
          _resizeImages.add(await resizeImage2(path2, newValue2, 500,i));

        } else {
          _resizeImages.add(await resizeImage2(path2, 500, 500,i));
        }
    }
    return true;
  }


  resizeImage2(String path, width, height, index) async {
    Uint8List data = await File(path).readAsBytes();
    var roundWidth = width.round();
    var roundHeight = height.round();
    File imagePath = File(path);

    var isHEIC = '${imagePath.path.substring(imagePath.path.length-4,imagePath.path.length)}';
    
    if(isHEIC == 'HEIC'||isHEIC == 'heic') {
      String jpegPath = await HeicToJpg.convert(imagePath.path);
      imagePath = File(jpegPath);
    }

    var realExt = p.extension('$imagePath');

    Im.Image image = Im.decodeImage(imagePath.readAsBytesSync());
    Im.Image smallerImage = Im.copyResize(image, width:roundWidth, height: roundHeight);


    var directory;
    var appPath;
    var realPath;
    if (Platform.isIOS) {
      directory = await getApplicationDocumentsDirectory();
      appPath = directory.path;
      realPath = "$appPath/userPhotos";
    } else {
      directory = await getExternalStorageDirectory();
      appPath = directory.path;
      realPath = "$appPath/userPhotos";
    }


    Directory(realPath).create().then((Directory directory) {});
    var pos = realExt.lastIndexOf("'");
    realExt = (pos != -1)? realExt.substring(0, pos): realExt;

    File writeImage = new File('$realPath/$index$realExt')..writeAsBytes(await Im.encodeNamedImage(smallerImage, realExt));
    return writeImage;
  }

4. RESTAPI로 올려보겠습니다.



  Future<bool> writeReview() async {
  try {
    Uri uri = Uri.parse('https://rest.pickling.kr/nitems/130/reviewparam');
    var request = new http.MultipartRequest('POST', uri);

    if(_resizeImages.length != 0) {
      for(var ex = 0; ex < _resizeImages.length; ex++) {
        File imagePath = _resizeImages[ex];
        print('path : $imagePath');
        String fileType = imagePath.path.substring(imagePath.path.lastIndexOf('.')+1,imagePath.path.length);
        request.files.add(await http.MultipartFile.fromPath(
          'imgFiles',
          imagePath.path,
          contentType: new MediaType('image', '${fileType.toLowerCase()}', {'charset': 'utf-8'}),
        ));
      }
    } else {
      request.fields['imgFiles'] = '';
    }

    var response = await request.send();
    print('response code: ${response.statusCode}');

    if(response.statusCode == 200) {
      return true;
    } else {
      return false;
    }
  } catch(e) {
    print('error $e');
    return false;
  }
  }
  

번외 커스터마이징한 AssetImageWidget

import 'dart:typed_data';

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

class AssetImageWidget extends StatelessWidget {
  final AssetEntity assetEntity;
  final double width;
  final double height;
  final BoxFit boxFit;

  const AssetImageWidget({
    Key key,
    @required this.assetEntity,
    this.width,
    this.height,
    this.boxFit,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (assetEntity == null) {
      return _buildContainer();
    }

    print("assetEntity.width = ${assetEntity.width} , assetEntity.height = ${assetEntity.height}");

    return FutureBuilder<Uint8List>(
      builder: (BuildContext context, snapshot) {
        if (snapshot.hasData) {
          return _buildContainer(
            child: ClipRRect(
              borderRadius: BorderRadius.all(Radius.circular(5)),
              child: Image.memory(
                snapshot.data,
                width: width,
                height: height,
                fit: boxFit,
              ),
            ),
          );
        } else {
          return _buildContainer();
        }
      },
      future: assetEntity.thumbDataWithSize(
        width.toInt(),
        height.toInt(),
      ),
    );
  }

  Widget _buildContainer({Widget child}) {
    child ??= Container();
    return Container(
        width: width,
        height: height,
        child: child,
    );
  }
}

👋 👋 👋

profile
플러터도 하구 자바스크립트두 하구 이것저것 해요 :D

0개의 댓글