flutter开发实战-图片缩放裁剪框图片裁剪功能

news/2024/7/21 5:50:13 标签: 1024程序员节, flutter, 图像处理, extend_image

flutter开发实战-图片缩放裁剪框图片裁剪功能

在开发中,需要选择相册的图片进行裁剪出图片的一小块内容作为目标图片,如上传头像,就是在用户选择头像后,根据裁剪狂来裁剪出所需要的图片进行上传。这里记录一下使用extend_image实现的图片缩放裁剪框图片裁剪功能。

一、整体效果

图片裁剪可以缩放图片,裁剪出图片的一部分,也可以拖动裁剪框,裁剪出所需要的图片的一部分内容。

如下图所示
在这里插入图片描述

extend_image_10">二、使用extend_image来实现裁剪

这里使用的是extend_image插件

2.1 引入所需要的库

在工程的pubspec.yaml引入所需要的库

  # 路径path
  path_provider: ^2.0.15
  # image_editor
  image_editor: ^1.0.2
  # extended_image
  extended_image: ^7.0.2
    

我这里使用到了三个组件

  • path_provider
    路径path
  • image_editor
    图片编辑与裁剪
  • extended_image
    图片扩展的,可缩放

2.2 代码实现

使用extended_image来展示可缩放的裁剪框,这里需要设置mode为ExtendedImageMode.editor.
设置初始化的EditorConfig

initEditorConfigHandler: (ExtendedImageState? state) {
            return EditorConfig(
                maxScale: 4.0,
                cropRectPadding: const EdgeInsets.all(20.0),
                hitTestSize: 20.0,
                initCropRectType: InitCropRectType.imageRect,
                cropAspectRatio: CropAspectRatios.ratio4_3,
                editActionDetailsIsChanged: (EditActionDetails? details) {
                  //print(details?.totalScale);
                });
          },
    

完整代码如下


import 'dart:io';

import 'package:extended_image/extended_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_demolab/crop_editor_helper.dart';
import 'package:path_provider/path_provider.dart';

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

  @override
  State<ImageCropper> createState() => _ImageCropperState();
}

class _ImageCropperState extends State<ImageCropper> {
  final GlobalKey<ExtendedImageEditorState> editorKey =
  GlobalKey<ExtendedImageEditorState>();
  bool _cropping = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("ImageCropper测试页面"),
        ),
        body: ExtendedImage.network(
          'https://c-ssl.dtstatic.com/uploads/blog/202310/26/5zSdYLmWhOYYZxZ.thumb.1000_0.jpeg',
          fit: BoxFit.contain,
          mode: ExtendedImageMode.editor,
          enableLoadState: true,
          extendedImageEditorKey: editorKey,
          cacheRawData: true,
          //maxBytes: 1024 * 50,
          initEditorConfigHandler: (ExtendedImageState? state) {
            return EditorConfig(
                maxScale: 4.0,
                cropRectPadding: const EdgeInsets.all(20.0),
                hitTestSize: 20.0,
                initCropRectType: InitCropRectType.imageRect,
                cropAspectRatio: CropAspectRatios.ratio4_3,
                editActionDetailsIsChanged: (EditActionDetails? details) {
                  //print(details?.totalScale);
                });
          },
        ),
      floatingActionButton: FloatingActionButton(
          child: const Icon(Icons.crop),
          onPressed: () {
            cropImage();
          }),
    );
  }

  Future<void> cropImage() async {
    if (_cropping) {
      return;
    }
    _cropping = true;
    try {
      final Uint8List fileData = Uint8List.fromList((await cropImageDataWithNativeLibrary(
          state: editorKey.currentState!))!);
      // 图片保存到本地
      saveImage(fileData);
      // final String? fileFath =
      // await ImageSaver.save('extended_image_cropped_image.jpg', fileData);
      // print('save image : $fileFath');
    } finally {
      _cropping = false;
    }
  }

  void saveImage(Uint8List imageByte) async {
    var tmpDir = await getTemporaryDirectory();
    var file = await File("${tmpDir.path}/image_${DateTime.now().microsecond}.jpg").create();
    file.writeAsBytesSync(imageByte);
    print("saveImage file:${file.path}");
    int length = await file.length();
    print('saveImage file length:${length}');
    // Uint8List readImageData = await file.readAsBytesSync();
  }
}
    

使用image_editor来实现图片的裁剪功能,这里用到了Android与iOS的裁剪部分。

具体代码如下

import 'dart:ui';

// import 'package:isolate/load_balancer.dart';
// import 'package:isolate/isolate_runner.dart';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/foundation.dart';
import 'package:image_editor/image_editor.dart';

Future<Uint8List?> cropImageDataWithNativeLibrary(
    {required ExtendedImageEditorState state}) async {
  print('native library start cropping');
  Rect cropRect = state.getCropRect()!;
  if (state.widget.extendedImageState.imageProvider is ExtendedResizeImage) {
    final ImmutableBuffer buffer =
        await ImmutableBuffer.fromUint8List(state.rawImageData);
    final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer);

    final double widthRatio = descriptor.width / state.image!.width;
    final double heightRatio = descriptor.height / state.image!.height;
    cropRect = Rect.fromLTRB(
      cropRect.left * widthRatio,
      cropRect.top * heightRatio,
      cropRect.right * widthRatio,
      cropRect.bottom * heightRatio,
    );
  }

  final EditActionDetails action = state.editAction!;

  final int rotateAngle = action.rotateAngle.toInt();
  final bool flipHorizontal = action.flipY;
  final bool flipVertical = action.flipX;
  final Uint8List img = state.rawImageData;

  final ImageEditorOption option = ImageEditorOption();

  if (action.needCrop) {
    option.addOption(ClipOption.fromRect(cropRect));
  }

  if (action.needFlip) {
    option.addOption(
        FlipOption(horizontal: flipHorizontal, vertical: flipVertical));
  }

  if (action.hasRotateAngle) {
    option.addOption(RotateOption(rotateAngle));
  }

  final DateTime start = DateTime.now();
  final Uint8List? result = await ImageEditor.editImage(
    image: img,
    imageEditorOption: option,
  );

  print('${DateTime.now().difference(start)} :total time');
  return result;
}
    

这里可以根据旋转,flip翻转等来进行设置编辑的imageEditorOption。

最后在我们需要将裁剪后的图片保存到本地目录,这里就需要用到了File

保存代码如下

  void saveImage(Uint8List imageByte) async {
    var tmpDir = await getTemporaryDirectory();
    var file = await File("${tmpDir.path}/image_${DateTime.now().microsecond}.jpg").create();
    file.writeAsBytesSync(imageByte);
    print("saveImage file:${file.path}");
    int length = await file.length();
    print('saveImage file length:${length}');
    // Uint8List readImageData = await file.readAsBytesSync();
  }
    

如果需要从本地读取图片,可以使用file.readAsBytesSync()。最后将Uint8List readImageData进行显示处理。

在这里插入图片描述

三、小结

flutter开发实战-图片缩放裁剪框图片裁剪功能

学习记录,每天不停进步。


http://www.niftyadmin.cn/n/5137876.html

相关文章

索引切片复习

# loc方法 data2.loc[:4,[ymd, bWendu]]# iloc方法 —— 连续取字段 data2.iloc[:4,1:3]# iloc方法 —— 非连续取字段 data2.iloc[:4,[1,4]]# 直接选取单个字段 —— Series data2[ymd]# 直接选取单个字段 —— DataFrame data2[[ymd]]# 直接选取多个字段 —— DataFrame data…

禁用swagger

springfox: documentation: auto-startup: false

Python的web自动化学习(四)Selenium的显性等待(元素定位)

引言&#xff1a; Selenium的显性等待&#xff0c;其常用的定位方法介绍&#xff0c;后面持续更细具体用法 示例如下&#xff1a; <input type"text" class"s_ipt" name"wd" id"kw" maxlength"100" autocomplete"…

最新版本QGIS 开始支持cesium 3D TILE 数据源了

最新版本QGIS 也开始支持3D TILE 数据源了!加载和运行速度也是慢&#xff0c;不过都这样&#xff0c;也不是qgis的问题!这东西对网络和性能要求比较高!据说这是cesium社区提供基金让qgis团队开发的&#xff0c;cesium社区真是很有钱啊&#x1f601;&#xff0c;不过也不奇怪&am…

【每日一题】每棵子树内缺失的最小基因值

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;DFS 写在最后 Tag 【dfs】【树】【2023-10-31】 题目来源 2003. 每棵子树内缺失的最小基因值 题目解读 找出每棵子树内缺失的最小基因值。 解题思路 方法一&#xff1a;DFS 找到基因值为 1 的节点&#xff0c;从该…

[迁移学习]UniDAformer域自适应全景分割网络

原文的标题为&#xff1a;UniDAformer: Unified Domain Adaptive Panoptic Segmentation Transformer via Hierarchical Mask Calibration&#xff0c;发表于CVPR2023。 一、概述 域自适应全景分割是指利用一个或多个相关域中的现成标注数据来缓解语义分割数据标注复杂的问题。…

优思学院|制作SPC控制图一定要用Minitab吗?

如果是使用SPC控制图作为一种控制过程变异的工具&#xff0c;无需使用Minitab&#xff0c;用Excel已经相当足够。但无论你使用哪种工具&#xff0c;你都应该要先明白SPC或者控制图工具的目的是什么&#xff0c;以及如何选择合适的控制图&#xff0c;以及如何去解读它等等。 要…

oracel处理XML时,报ORA-31011、ORA-19202。

原字段为clob&#xff0c; 查询 SELECT XMLTYPE(字段) FROM TABLE_A报错如下&#xff1a; ORA-31011: XML 语法分析失败 ORA-19202: XML 处理 LPX-00217: invalid character 12 (U000C) Error at line 1559时出错 ORA-06512: 在 "SYS.XMLTYPE", line 272 ORA-0651…