Flutter 学习 之 图片的选择裁切保存

Posted 一叶飘舟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 学习 之 图片的选择裁切保存相关的知识,希望对你有一定的参考价值。

在实际任务中免不了对图片进行裁切 文件格式转换 图片的选取等操作 这里做一个记录
1. Flutter 图片选择工具 image_picker
2. 图片裁切工具 image_cropper
3. 图片保存到相册image_gallery_saver

图片选择器

介绍

这里我选择的是image_picker
优点

  • 官方出品的插件
  • 可以直接调用相册和相机无需提前申请权限
  • 可以多选和单选选择丰富
    缺点
  • 多选需要长按没有明显的提示

使用

  1. 引用组件
  2. 封装他的一个方法(以单选为例子)
enum ImageFrom
  camera,
  gallery

  ///选择一个图片
  ///[from] 是相机还是图库
  ///可选参数
  ///[maxWidth] 宽度,
  ///[maxHeight] 高度,
  ///[imageQuality] 质量
  static pickSinglePic(ImageFrom from,
      double? maxWidth, double? maxHeight, int? imageQuality) async 
    ImageSource source;
    switch (from) 
      case ImageFrom.camera:
        source = ImageSource.camera;
        break;
      case ImageFrom.gallery:
        source = ImageSource.gallery;
        break;
    
    final pickerImages = await ImagePicker().pickImage(
      source: source,
      imageQuality: imageQuality,
      maxWidth: maxWidth,
      maxHeight: maxHeight,
    );
    return pickerImages;
  

使用:

      final pickerImages = await ImageUtil.pickSinglePic(score);

图片裁切

使用

  1. 引用组件
  2. androidMainifest中增加一个View
       <activity
           android:name="com.yalantis.ucrop.UCropActivity"
           android:screenOrientation="portrait"
           android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
  1. 封装成一个方法
  ///裁切图片
  ///[image] 图片路径或文件
  ///[width] 宽度
  ///[height] 高度
  ///[aspectRatio] 比例
  ///[androidUiSettings]UI 参数
  ///[iosUiSettings] ios的ui 参数
  static cropImage(
      required image,
      required width,
      required height,
      aspectRatio,
      androidUiSettings,
      iOSUiSettings) async 
    String imagePth = "";
    if (image is String) 
      imagePth = image;
     else if (image is File) 
      imagePth = image.path;
     else 
      throw ("文件路径错误");
    
    final croppedFile = await ImageCropper().cropImage(
      sourcePath: imagePth,
      maxWidth: FormatUtil.num2int(width),
      maxHeight: FormatUtil.num2int(height),
      aspectRatio: aspectRatio ??
          CropAspectRatio(
              ratioX: FormatUtil.num2double(width),
              ratioY: FormatUtil.num2double(height)),
      uiSettings: [
        androidUiSettings ??
            AndroidUiSettings(
                toolbarTitle:
                    '图片裁切($FormatUtil.num2int(width)*$FormatUtil.num2int(height))',
                toolbarColor: Colors.blue,
                toolbarWidgetColor: Colors.white,
                initAspectRatio: CropAspectRatioPreset.original,
                hideBottomControls: false,
                lockAspectRatio: true),
        iOSUiSettings ??
            IOSUiSettings(
              title: 'Cropper',
            ),
      ],
    );
    return croppedFile;
  

  ///数字转成Int
  ///[number] 可以是String 可以是int 可以是double 出错了就返回0;
  static num2int(number) 
    try 
      if (number is String) 
        return int.parse(number);
       else if (number is int) 
        return number;
       else if (number is double) 
        return number.toInt();
       else 
        return 0;
      
     catch (e) 
      return 0;
    
  

  ///数字转成double
  ///[number] 可以是String 可以是int 可以是double 出错了就返回0;
  static num2double(number) 
    try 
      if (number is String) 
        return double.parse(number);
       else if (number is int) 
        return number.toDouble();
       else if (number is double) 
        return number;
       else 
        return 0.0;
      
     catch (e) 
      return 0.0;
    
  

使用

       File? _userImage = File(pickerImages.path);
      if (_userImage != null) 
        final croppedFile = await ImageUtil.cropImage(
            image: _userImage,
            width: 256,
            height: 512);

图片保存

  1. 引入插件
  2. 封装组件
///保存Uint8List 到相册
  ///[image]Uint8List 数组
  ///[quality] 质量
  ///[name] 保存的名字
  static saveImage2Album(image, quality = 100, name = "photo") async 
    final result =
        await ImageGallerySaver.saveImage(image, quality: quality, name: name);
    return result;
  

他还有一个保存文件的方法

_saveVideo() async 
    var appDocDir = await getTemporaryDirectory();
    String savePath = appDocDir.path + "/temp.mp4";
    await Dio().download("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4", savePath);
    final result = await ImageGallerySaver.saveFile(savePath);
    print(result);
 

使用
保存前注意先申请一下存储权限

    PermissionUtil.checkPermission(
        permissionList: [Permission.photos, Permission.storage],
        onFailed: () => ToastUtil().showCenterToast("图片处理错误"),
        onSuccess: () async 
          final result = await FileUtil.saveImage2Album(finalImgBuffer!,
              quality: 100, name: "photo");
          if (result != null) 
            ToastUtil().showCenterToast("保存成功~~~");
           else 
            ToastUtil().showCenterToast("保存失败~~~");
          
        );

Flutter 中对 图片文件的操作

图片间格式的转换等操作

图片文件转换成Base64

转换思路 File=>Uint8List =>Base64
使用场景:有些接口需要多图片上传使用base64进行多组图片上传操作

  ///文件转 Uint8List
  static file2Uint8List(File file) async 
    Uint8List imageBytes = await file.readAsBytes();
    return imageBytes;
  
  /// unit8List 转base64
  static uint8List2Base64(Uint8List uint8list) 
    String base64 = base64Encode(uint8list);
    return base64;
  

Base64转dart.ui中的Image

使用场景:从接口获取的base64要画在Canvas上需要转换的格式

import 'dart:ui' as ui;
  ///base64 转成需要的Image文件 这个Image是UI 下面的Image和Image widget不同 !!!
  ///[asset] base64 无头字符串
  ///[width]宽度
  ///[height] 高度
  static Future<ui.Image> base64ToImage(String asset, width, height) async 
    Uint8List bytes = base64Decode(asset);
    ui.Codec codec = await ui.instantiateImageCodec(bytes,
        targetWidth: width, targetHeight: height);
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  

用Canvas绘画

用 recorder 记录绘画的结果保存Picture

    ///canvas的记录工具 用来保存canvas的
    final recorder = ui.PictureRecorder();

    ///canvas 绘图工具
    Canvas canvas = Canvas(recorder);

    ///画笔 颜色为传入颜色 状态是填充
    Paint paint = Paint();
    paint.color = bgColor;
    paint.style = PaintingStyle.fill;

    ///底下跟我画个背景
    canvas.drawRect(Rect.fromLTWH(0, 0, width, height), paint);

    ///顶上再画个人
    paint.color = Colors.black;
    paint.style = PaintingStyle.stroke;
    paint.strokeWidth = 10;
    ui.Image image = await base64ToImage(imageFile,
        width: width.toInt(), height: height.toInt());
    canvas.drawImage(image, Offset.zero, paint);
    // 转换成图片
    ///记录画的canvas
    Picture picture = recorder.endRecording();

将Picture 转换成ByteData

最终转换成 Uint8List 显示在屏幕上

  ///获取到的picture 转换成 ByteData
  ///[picture] canvas画然后记录的文件
  ///[width] 宽度
  ///[height] 高度
  static Future<ByteData?> picture2ByteData(
      ui.Picture picture, double width, double height) async 
    ui.Image img = await picture.toImage(width.toInt(), height.toInt());

    debugPrint('img的尺寸: $img');

    ByteData? byteData = await img.toByteData(format: ui.ImageByteFormat.png);

    return byteData;
  

将ByteData 转成 Uint8List

作用是可以显示在ImageWidget上 或者后续转成Base64 或者直接保存到本地

/// 将ByteData 转成 Uint8List
  /// [data] ByteData数据
  /// return [Uint8List] Uint8List
  static byteData2Uint8List(ByteData data) 
    return data.buffer.asUint8List();
  

以上是关于Flutter 学习 之 图片的选择裁切保存的主要内容,如果未能解决你的问题,请参考以下文章

node.js(express)中使用Jcrop进行图片裁切上传

node.js(express)中使用Jcrop进行图片裁切上传

ps中裁切的快捷键

前端裁切图片插件之cropper介绍

ipcloud上传裁切图片,保存为base64再压缩传给后台

新修正的 Ajax PHP 图片裁切-来自www.srcfans.com开源代码