美文网首页
flutter 实战 之 生成证件照/免冠照

flutter 实战 之 生成证件照/免冠照

作者: 半城半离人 | 来源:发表于2022-05-31 00:05 被阅读0次

在网上翻了一圈发现并没有人贡献这方面的代码可能是技术含量太低了,我这里记录以下
用到的工具
1.权限管理https://www.jianshu.com/p/35b37c012351

2.dio 网络 https://www.jianshu.com/p/fdd12bb921c2

3. 图片的操作 https://www.jianshu.com/p/bf97573eb69e https://www.jianshu.com/p/c276b27520c0

实现原理

通过拍照/选取图片 (image_picker)
裁切尺寸大小图片(image_cropper)
将文件转成Base64 上传百度AI进行轮廓裁剪(百度AI)
通过Canvas绘画合成
将文件保存到本地并显示在widget上

选取图片

  ///选择一个图片
  ///[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;
  }

裁切图片大小

  ///裁切图片
  ///[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;
  }

将获取到的图片转成Base64 上传

  ///图片转base64 无头
  ///[file] 文件
  ///[base64] String 类型的base64
  static file2Base64(File file) async {
    Uint8List imageBytes = await file2Uint8List(file);
    String base64 = base64Encode(imageBytes);
    return base64;
  }
  ///文件转 Uint8List
  static file2Uint8List(File file) async {
    Uint8List imageBytes = await file.readAsBytes();
    return imageBytes;
  }

上传百度AI

  static Future<String> getToken() async {
    /// 第一个必穿参数 第二个第三个自己去百度Ai官网申请 免费额度一万次
    Map<String, dynamic> param = {
      "grant_type": "client_credentials",
      "client_id": clientId,
      "client_secret": clientSecret
    };
    Response<dynamic> response =
        await DioClient().doPost(Api.getToken, queryParameters: param);
    return response.data["access_token"];
  }

  /// 获取文件Base64的前景照 这里用的fromData传输
  static Future<String> getBase64(Map<String, dynamic> param) async {
    Response<dynamic> response = await DioClient().doPost(Api.uploadURL,
        data: FormData.fromMap(param),
        options: Options(contentType: "application/x-www-form-urlencoded"));
    return response.data["foreground"];
  }

获取到的Base64画到Cnvas上

 ///创建一个图片的 ByteData
  ///[width] 图片宽度
  ///[height] 图片高度
  ///[bgColor] 背景颜色
  ///[imageFile] base64的图片路径(无头)
  static generateImageData(
      {required double width,
      required double height,
      bgColor = Colors.white,
      imageFile}) async {
    ///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();

    return await picture2ByteData(picture, width, height);
  }

将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
  /// [data] ByteData数据
  /// return [Uint8List] Uint8List
  static byteData2Uint8List(ByteData data) {
    return data.buffer.asUint8List();
  }

保存图片

///保存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;
 }

完整demo 在 https://gitee.com/half_city/flutter_identification_photo

相关文章

网友评论

      本文标题:flutter 实战 之 生成证件照/免冠照

      本文链接:https://www.haomeiwen.com/subject/yionurtx.html