在 Flutter Web 中将画布捕获为图像

Posted

技术标签:

【中文标题】在 Flutter Web 中将画布捕获为图像【英文标题】:Capturing a Canvas as an Image in Flutter Web 【发布时间】:2019-09-26 20:27:08 【问题描述】:

我正在尝试使用 Flutter Web 中的 PictureRecorder 将 Canvas 的内容捕获为图像,但这样做有困难

在试验过程中,我画了一个简单的圆圈并尝试记录它,但记录的图片一直为“空”

import 'package:flutter_web/material.dart';
import 'package:flutter_web_ui/ui.dart' as ui;

import 'dart:typed_data';

void main() => runApp(App());

class App extends StatelessWidget 
  void generateImage() async 
    final ui.Paint paint = ui.Paint()
      ..style = ui.PaintingStyle.stroke
      ..strokeWidth = 1.0;
    final ui.PictureRecorder recorder = ui.PictureRecorder();
    final ui.Canvas pictureCanvas = ui.Canvas(recorder);
    pictureCanvas.drawCircle(Offset.zero, 20.0, paint);
    final ui.Picture picture = recorder.endRecording();
    ui.Image referenceImage = picture.toImage(50, 50);
    ByteData img =
        await referenceImage.toByteData(format: ui.ImageByteFormat.png);
  

  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(12.0),
              child: RaisedButton(
                child: Text('Generate image'),
                onPressed: generateImage,
              ),
            ),
          ],
        ),
      ),
    );
  

这是我在 chrome 控制台中遇到的错误,

main.dart:24 Uncaught (in promise) TypeError: Cannot read property 'toByteData' of null
    at generateImage (main.dart:24)
    at generateImage.next (<anonymous>)
    at runBody (dart_sdk.js:22330)
    at Object.async.async (dart_sdk.js:22358)
    at main.App.new.generateImage (main.dart:15)
    at src__material__ink_well.InkWell.new.<anonymous> (main.dart:38)
    at _InkResponseState.new.[_handleTap] (ink_well.dart:511)
    at ink_well.dart:565
    at src__gestures__tap.TapGestureRecognizer.new.invokeCallback (recognizer.dart:169)
    at src__gestures__tap.TapGestureRecognizer.new.[_checkUp] (tap.dart:251)
    at src__gestures__tap.TapGestureRecognizer.new.handlePrimaryPointer (tap.dart:176)
    at src__gestures__tap.TapGestureRecognizer.new.handleEvent (recognizer.dart:439)
    at src__gestures__pointer_router.PointerRouter.new.[_dispatch] (pointer_router.dart:73)
    at src__gestures__pointer_router.PointerRouter.new.route (pointer_router.dart:100)
    at src__widgets__binding.WidgetsFlutterBinding.new.handleEvent (binding.dart:223)
    at src__widgets__binding.WidgetsFlutterBinding.new.dispatchEvent (binding.dart:201)
    at src__widgets__binding.WidgetsFlutterBinding.new.[_handlePointerEvent] (binding.dart:156)
    at src__widgets__binding.WidgetsFlutterBinding.new.[_flushPointerEventQueue] (binding.dart:103)
    at src__widgets__binding.WidgetsFlutterBinding.new.[_handlePointerDataPacket] (binding.dart:87)
    at src__engine.PointerBinding.new.[_onPointerData] (pointer_binding.dart:80)
    at pointer_binding.dart:194
    at htmlElement.<anonymous> (pointer_binding.dart:135)

【问题讨论】:

【参考方案1】:

我将其报告为错误。至少在他们修复它之前(2020 年 5 月结束,以供将来参考)似乎唯一的方法是使用 HTML5 画布:

import 'dart:html' as html;

final canvas = html.CanvasElement(width: width, height: height);
var context = canvas.context2D;
context.draw...(); // do whatever drawing you need
final blob = await canvas.toBlob('image/jpeg', 0.8);

从 blob 到字节数组的转换可以通过以下方式完成:

Future<Uint8List> _getBlobData(html.Blob blob) 
  final completer = Completer<Uint8List>();
  final reader = html.FileReader();
  reader.readAsArrayBuffer(blob);
  reader.onLoad.listen((_) => completer.complete(reader.result));
  return completer.future;

【讨论】:

只有你的回答对我有帮助。 context.draw...(); 附近出现错误,请您更正一下? 不,抱歉,我不能也不会。至少有十几个不同的drawXXX() 函数,我不知道你真正需要哪一个。该代码向您展示了如何在原理中执行此操作,但您必须使其适应您的实际绘图需求。 @Gábor,谢谢,我明白你的意思了,请问你知道context.drawImage(source, destX, destY); 里面有什么价值吗? 我的问题是HTML5画布支持哪些操作,好吧,访问developer.mozilla.org/en-US/docs/Web/API/Canvas_API

以上是关于在 Flutter Web 中将画布捕获为图像的主要内容,如果未能解决你的问题,请参考以下文章

Javascript:将画布另存为图像 ==>“未捕获的类型错误:未定义不是函数”

如何在 Flutter 中将图像转换为文件?

在 Flutter 错误中将 base64 转换为图像

无法在javascript中将图像绘制到画布

捕获完整的画布图像

使用响应式布局从画布中捕获分段图像