35

My end goal is to be able to share a dynamic image by either passing the raw image data or saving the image to disk for a native android/ios service to share. How would I convert a Widget or Canvas in flutter to raw image data (like byte[])?

ripple182
  • 801
  • 1
  • 8
  • 13

3 Answers3

44

There is support for this now. You can either use RenderRepaintBoundry or OffsetLayer or Scene. They all have a toImage. Here is the link to RenderRepaintBoundry.toImage()

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

  @override
  PngHomeState createState() => PngHomeState();
}

class PngHomeState extends State<PngHome> {
  GlobalKey globalKey = GlobalKey();

  Future<void> _capturePng() async {
    RenderRepaintBoundary boundary = globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
    ui.Image image = await boundary.toImage();
    ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    Uint8List pngBytes = byteData!.buffer.asUint8List();
    print(pngBytes);
  }

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      key: globalKey,
      child: Center(
        child: TextButton(
          onPressed: _capturePng,
          child: const Text('Take screenshot', textDirection: TextDirection.ltr),
        ),
      ),
    );
  }
}

This is copied from the docs and adapted to latest null safety and dart language features. The values for globalKey.currentContext and byteData can be null, so your production code should ideally check them.

Andrei Tudor Diaconu
  • 2,157
  • 21
  • 26
  • Great solution ! I'm wondering if it is possible to capture only parts of the Widgets ? Because only a portion of the widget is what I needed. – colin Aug 17 '18 at 10:05
  • 2
    @colin If possible, try to wrap the part that you want to capture in one of the mentioned widgets. Also, [Scene.toImage()](https://master-docs-flutter-io.firebaseapp.com/flutter/dart-ui/Scene/toImage.html) receives a width and height, which you might be able to leverage differently (I'm not sure if it crops or distorts the original image): – Andrei Tudor Diaconu Aug 22 '18 at 08:33
  • 2
    > Gone through the paint phase Does that mean the widget has to be on scree? – lawonga Apr 10 '19 at 16:42
  • 1
    @lawonga I don't think the widget needs to be on the screen since you can also specify a pixel density to draw it at (not dependent on the actual device density) – Andrei Tudor Diaconu Apr 11 '19 at 12:18
  • I figured it out yesterday!! Thanks – lawonga Apr 11 '19 at 15:05
  • is it possible to save canvas as jpg? – aiki93 Jun 25 '19 at 20:20
  • @aiki93 Not out of the box with this method. According to https://api.flutter.dev/flutter/dart-ui/ImageByteFormat-class.html I see you have a choice between png and raw format (which I imagine is something like .bmp). If you really need jpeg you could consider converting to it later. – Andrei Tudor Diaconu Jun 30 '19 at 09:55
  • @AndreiTudorDiaconu - Capturing offscreen parts of the widget is important, I've opened a question about it here if you don't mind contributing: https://stackoverflow.com/questions/57583965/flutter-dart-capture-entire-partially-offscreen-widget-as-image – A. L. Strine Aug 21 '19 at 03:16
  • I cannot assign the result of findRenderObject to RenderRepaintBoundary as the type differs. "A value of type 'RenderObject?' can't be assigned to a variable of type 'RenderRepaintBoundary'." – JPLauber May 03 '22 at 13:12
  • @JPLauber Updated the answer to address your comment. I hope providing a broader context for the `_capturePng` method makes it clearer how it can be used. Also, the answer now uses null safety. – Andrei Tudor Diaconu Jun 09 '22 at 08:53
5

This is not currently possible from Dart code running in a FlutterView today, however we have a bug on file tracking implementing such: https://github.com/flutter/flutter/issues/6774

It is possible to render Flutter widgets as part of a FlutterView and then use Java or Objective-C interfaces onto the FlutterView to capture a picture, such as the standard android.View.getBitmap which FlutterView implements: https://docs.flutter.io/javadoc/io/flutter/view/FlutterView.html#getBitmap--

If this important to your application needs and would like to be able to capture Bitmaps of Widget trees from inside Dart code we'd love to hear about it. Please feel encouraged to provide further context on the above referenced issue!

Eric Seidel
  • 3,282
  • 1
  • 15
  • 22
5

You can use the Screenshot package to get an image of the widget you want.

https://pub.dev/packages/screenshot

Bensal
  • 3,316
  • 1
  • 23
  • 35