在 Flutter Web 中捕获 Canvas 作为图像
Capturing a Canvas as an Image in Flutter Web
我正在尝试使用 Flutter Web 中的 PictureRecorder 将 Canvas 的内容捕获为图像,但在这样做时遇到了问题
在实验过程中我画了一个简单的圆圈并尝试记录它,但我不断得到 'null' 记录的图片
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)
我将其报告为错误。似乎唯一的方法是使用 HTML5 canvas:
至少在他们修复它之前(2020 年 5 月结束,以供将来参考)
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;
}
我正在尝试使用 Flutter Web 中的 PictureRecorder 将 Canvas 的内容捕获为图像,但在这样做时遇到了问题
在实验过程中我画了一个简单的圆圈并尝试记录它,但我不断得到 'null' 记录的图片
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)
我将其报告为错误。似乎唯一的方法是使用 HTML5 canvas:
至少在他们修复它之前(2020 年 5 月结束,以供将来参考)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;
}