I'm using CustomPainter
to draw something to a canvas
.
Later I want to display that drawing in an Image
widget (which takes an image parameter of type ImageProvider<Object>
).
After some research I have found out a way to get there in basically two steps:
ui.Image
object from the canvas drawingui.Image
to an ImageProvider
that can be passed to an Image
widgetimport 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:bitmap/bitmap.dart';
class MyCustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
//drawing some stuff here
//canvas.drawRect(...);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
Future<ui.Image> getImage() {
final ui.PictureRecorder recorder = ui.PictureRecorder();
try {
//500 x 500 pixels
paint(Canvas(recorder), const Size(500, 500));
} catch (e) {
debugPrint(e.toString());
}
final ui.Picture picture = recorder.endRecording();
final img = picture.toImage(500, 500);
return img;
}
static Future<ImageProvider> getProviderFromImage(ui.Image image) async {
final ByteData? bytedata = await image.toByteData();
if (bytedata == null) {
return Future.error("some error msg");
}
final Bitmap bitmap = Bitmap.fromHeadless(
image.width, image.height, bytedata.buffer.asUint8List());
final Uint8List headedIntList = bitmap.buildHeaded();
return MemoryImage(headedIntList);
}
}
The problem here is that this won't work for Flutter Web because the bitmap package does not have web support.
I already tried converting the ByteData
to Uint8List
without the bitmap package:
static Future<ImageProvider> getProviderFromImage(ui.Image image) async {
final ByteData? bytedata = await image.toByteData();
if (bytedata == null) {
return Future.error("some error msg");
}
final Uint8List headedIntList =
Uint8List.view(bytedata.buffer);
return MemoryImage(headedIntList);
}
But the resulting ImageProvider
won't be accepted by the Image
widget:
════════ Exception caught by image resource service ════════════════════════════ The following ImageCodecException was thrown resolving an image codec: Failed to decode image data. Image source: encoded image bytes
My approach actually works if the format
parameter of toByteData()
is passed:
static Future<ImageProvider> getProviderFromImage(ui.Image image) async {
final ByteData? bytedata = await image.toByteData(format: ui.ImageByteFormat.png);
if (bytedata == null) {
return Future.error("some error msg");
}
final Uint8List headedIntList =
Uint8List.view(bytedata.buffer);
return MemoryImage(headedIntList);
}