Flutter图像绘制插件draw_on_image_plugin的使用

Flutter图像绘制插件draw_on_image_plugin的使用

获取开始

首先,创建插件实例:

DrawOnImagePlugin _plugin = DrawOnImagePlugin();

然后,创建一个数据类来保存绘制参数,例如字体大小、内边距、颜色等:

var writeData = WriteImageData(
  text, 
  imageBytes,
  left: left,
  right: right,
  top: top,
  bottom: bottom,
  color: color.value,
  fontSize: size
);

其中,textimageBytes 是必需的参数,其余参数是可选的。

接下来,将这些数据传递给插件:

String path = await _plugin.writeTextOnImage(writeData);

这样你就会得到一个新的带有文本的图片路径。你需要自己管理(移动、重命名、删除)新生成的文件。

更多详细信息可以在 示例 中查看。

完整示例

下面是完整的示例代码:

import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';

import 'package:draw_on_image_plugin/draw_on_image_plugin.dart';
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';

void main() {
  runApp(MaterialApp(
    home: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  DrawOnImagePlugin _plugin = DrawOnImagePlugin(); 
  String? _pathToNewFile; 

  Future<void> _sendPluginRequest(BasicDrawParameters params) async {    
    ByteData imageBytes = await rootBundle.load("assets/images/test_image.png");    
    String fileName = await _plugin.writeTextOnImage(
      WriteImageData(
        params.text, 
        imageBytes,
        left: params.left,
        right: params.right,
        top: params.top,
        bottom: params.bottom,
        color: params.color.value,
        fontSize: params.size
      ));

    setState(() {
      _pathToNewFile = fileName;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    var dimensions = ScreenDimensions(context);
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Column(
          children: [
            Container(
              width: dimensions.width,
              height: dimensions.withoutSafeAreaHeight * 0.75,              
              child: _pathToNewFile == null
                ? _buildInitialScreen()
                : _buildMainScreen(),
            ),
            _buildButton()
          ]
        )
      ),
    );
  }

  Widget _buildButton() {    
    return ElevatedButton(
      onPressed: () async {
        _pathToNewFile = null;
        BasicDrawParameters params = await Navigator.of(context).push(
          MaterialPageRoute(
            builder: (context) => DrawOptionsDialog()
          )
        );
        _sendPluginRequest(params);
      }, 
      child: Container(
        color: Colors.blue,
        padding: const EdgeInsets.all(10.0),
        child: const Text("Draw"),
      )
    );
  }
  
  Widget _buildInitialScreen() {
    return Image.asset(
      "assets/images/test_image.png",
      fit: BoxFit.contain
    );
  }

  Widget _buildMainScreen() {
    return Image.file(
      File(_pathToNewFile ?? ""),
      fit: BoxFit.contain
    );
  }
}

class DrawOptionsDialog extends StatefulWidget {
  const DrawOptionsDialog({ Key? key }) : super(key: key);

  [@override](/user/override)
  _DrawOptionsDialogState createState() => _DrawOptionsDialogState();
}

class _DrawOptionsDialogState extends State<DrawOptionsDialog> {
  final TextEditingController _drawTextController = new TextEditingController();
  final TextEditingController _fontSizeController = new TextEditingController();
  final TextEditingController _leftController = new TextEditingController();
  final TextEditingController _rightController = new TextEditingController();
  final TextEditingController _topController = new TextEditingController();
  final TextEditingController _bottomController = new TextEditingController();
  Color _selectedColor = Colors.red;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          child: Column(
            children: [
              _buildTextInputField(),
              _buildTextSizeField(),
              _buildPaddingsRow(),
              _buildColorPicker(),
              _buildButton()  
            ]
          )
        ),
      ),
    );
  }

  Widget _buildTextInputField() {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: TextField(
        controller: _drawTextController,
        keyboardType: TextInputType.multiline,
        maxLines: null,              
        decoration: InputDecoration(
          border: OutlineInputBorder(),
          labelText: 'Text to draw',
        )
      )
    );
  }

  Widget _buildTextSizeField() {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: TextField(
        controller: _fontSizeController,
        keyboardType: TextInputType.number,        
        decoration: InputDecoration(
          border: OutlineInputBorder(),
          labelText: 'Font Size',
        )
      )
    );
  }

  Widget _buildColorPicker() {
    return ColorPicker(
      pickerColor: _selectedColor,
      onColorChanged: _onColorChange,
      showLabel: true,
      pickerAreaHeightPercent: 0.8,
    );
  }

  Widget _buildButton() {
    return ElevatedButton(
      onPressed: _doneButtonTap,
      child: Container(
        color: Colors.blue,
        padding: const EdgeInsets.all(10.0),
        child: const Text("Done"),
      )
    );
  }

  Widget _buildPaddingsRow() {
    return Row(      
      children: [
        Expanded(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _leftController,
              keyboardType: TextInputType.number,        
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Left',
              )
            ),
          ),
        ),
        Expanded(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _rightController,
              keyboardType: TextInputType.number,        
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Right',
              )
            ),
          ),
        ),
        Expanded(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _topController,
              keyboardType: TextInputType.number,        
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Top',
              )
            ),
          ),
        ),
        Expanded(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _bottomController,
              keyboardType: TextInputType.number,        
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Bottom',
              )
            ),
          ),
        )
      ]
    );
  }

  void _onColorChange(Color newColor) {
    _selectedColor = newColor;
  }

  void _doneButtonTap() {
    FocusScope.of(context).unfocus();    
    BasicDrawParameters? parameters = _buildDrawParameters(); 
    if (parameters == null) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text("Error!"),
            content: Text("Error during creating parameters."),
            actions: [
              ElevatedButton(
                child: Text("OK"),
                onPressed: () => Navigator.of(context).pop()
              )
            ]
          );
        }
      );
    } else {
      Navigator.pop(context, parameters);
    }
  }

  BasicDrawParameters? _buildDrawParameters() {
    BasicDrawParameters? parameters; 

    try {
      int left = int.parse(_leftController.text);
      int right = int.parse(_rightController.text);
      int top = int.parse(_topController.text);
      int bottom = int.parse(_bottomController.text);
      int size = int.parse(_fontSizeController.text);

      parameters = BasicDrawParameters(
        _drawTextController.text, 
        _selectedColor, 
        size, 
        left, 
        right, 
        top, 
        bottom
      );
    } catch(error) {
      print("Error during building parameters : $error");
    } 
    return parameters;
  }
}

class ScreenDimensions {
  double width = 0;
  double fullHeight = 0;
  double withoutSafeAreaHeight = 0;

  ScreenDimensions(BuildContext context) {
    width = MediaQuery.of(context).size.width;
    fullHeight = MediaQuery.of(context).size.height;

    var padding = MediaQuery.of(context).padding;
    withoutSafeAreaHeight = fullHeight - padding.top - padding.bottom;
  }
}

class BasicDrawParameters {
  final Color color;
  final String text;
  final int size;
  final int left;
  final int right;
  final int top;
  final int bottom;

  const BasicDrawParameters(
    this.text,
    this.color,
    this.size,
    this.left,
    this.right,
    this.top,
    this.bottom,
  );
}

更多关于Flutter图像绘制插件draw_on_image_plugin的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图像绘制插件draw_on_image_plugin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 draw_on_image_plugin 的示例代码。这个插件允许你在图像上进行绘制操作,比如添加文字、线条、形状等。首先,确保你已经在 pubspec.yaml 文件中添加了该插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  draw_on_image: ^x.y.z  # 请替换为最新的版本号

然后,运行 flutter pub get 来获取依赖。

以下是一个完整的示例代码,展示如何使用 draw_on_image_plugin 在图像上绘制:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Draw on Image Example'),
        ),
        body: DrawOnImageExample(),
      ),
    );
  }
}

class DrawOnImageExample extends StatefulWidget {
  @override
  _DrawOnImageExampleState createState() => _DrawOnImageExampleState();
}

class _DrawOnImageExampleState extends State<DrawOnImageExample> {
  final GlobalKey _drawImageKey = GlobalKey();
  late List<OverlayEntry> _overlayEntries;

  @override
  void initState() {
    super.initState();
    _overlayEntries = [];
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        DrawOnImage(
          key: _drawImageKey,
          image: NetworkImage('https://via.placeholder.com/600x400'),
          initialDrawCommands: [
            DrawCommand(
              type: DrawCommandType.text,
              points: [Offset(50, 50)],
              data: TextStyleData(
                text: 'Hello Flutter!',
                style: TextStyle(color: Colors.black, fontSize: 24),
              ),
            ),
            DrawCommand(
              type: DrawCommandType.line,
              points: [Offset(50, 100), Offset(200, 100)],
              data: PaintData(
                color: Colors.red,
                strokeWidth: 4.0,
              ),
            ),
          ],
          onLoad: (BuildContext context, ImageProvider imageProvider) async {
            // 在图像加载完成后可以执行的操作
          },
          onCommandAdded: (DrawCommand command) {
            // 当新命令被添加时执行的操作
            setState(() {
              _overlayEntries.add(command.toOverlayEntry());
            });
          },
        ),
        // 显示所有 OverlayEntry
        if (_overlayEntries.isNotEmpty)
          Positioned.fill(
            child: Stack(
              children: List.generate(
                _overlayEntries.length,
                (index) => _overlayEntries[index],
              ),
            ),
          ),
      ],
    );
  }

  @override
  void dispose() {
    _overlayEntries.forEach((entry) => entry.remove());
    super.dispose();
  }
}

在这个示例中,我们做了以下事情:

  1. 导入必要的包:我们导入了 flutter/material.dartdraw_on_image/draw_on_image.dart
  2. 定义主应用MyApp 是我们的主应用,它包含一个 Scaffold 和一个 DrawOnImageExample 组件。
  3. 创建绘制图像的组件DrawOnImageExample 是一个有状态的组件,它包含了 DrawOnImage 小部件。
  4. 初始化绘制命令:在 DrawOnImage 小部件中,我们定义了初始的绘制命令,包括一个文本命令和一条线命令。
  5. 处理命令添加:当新的绘制命令被添加时,我们将它们转换为 OverlayEntry 并显示在图像上。
  6. 清理资源:在 dispose 方法中,我们移除所有的 OverlayEntry 以避免内存泄漏。

请注意,这个示例假设 draw_on_image 插件提供了 DrawOnImageDrawCommandDrawCommandTypeTextStyleDataPaintData 等类和方法。实际使用时,你可能需要根据插件的具体 API 文档进行调整。如果插件的 API 有变化,请参考最新的官方文档。

回到顶部