widgetToUiImage static method

Future<Image> widgetToUiImage(
  1. Widget widget, {
  2. Duration delay = const Duration(seconds: 1),
  3. double? pixelRatio,
  4. BuildContext? context,
  5. Size? targetSize,
})

Implementation

static Future<ui.Image> widgetToUiImage(
  Widget widget, {
  Duration delay: const Duration(seconds: 1),
  double? pixelRatio,
  BuildContext? context,
  Size? targetSize,
}) async {
  ///
  ///Retry counter
  ///
  int retryCounter = 3;
  bool isDirty = false;

  Widget child = widget;

  if (context != null) {
    ///
    ///Inherit Theme and MediaQuery of app
    ///
    ///
    child = InheritedTheme.captureAll(
      context,
      MediaQuery(
          data: MediaQuery.of(context),
          child: Material(
            child: child,
            color: Colors.transparent,
          )),
    );
  }

  final RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary();

  Size logicalSize = targetSize ??
      ui.window.physicalSize / ui.window.devicePixelRatio; // Adapted
  Size imageSize = targetSize ?? ui.window.physicalSize; // Adapted

  assert(logicalSize.aspectRatio.toStringAsPrecision(5) ==
      imageSize.aspectRatio
          .toStringAsPrecision(5)); // Adapted (toPrecision was not available)

  final RenderView renderView = RenderView(
    window: ui.window,
    child: RenderPositionedBox(
        alignment: Alignment.center, child: repaintBoundary),
    configuration: ViewConfiguration(
      size: logicalSize,
      devicePixelRatio: pixelRatio ?? 1.0,
    ),
  );

  final PipelineOwner pipelineOwner = PipelineOwner();
  final BuildOwner buildOwner = BuildOwner(
      focusManager: FocusManager(),
      onBuildScheduled: () {
        ///
        ///current render is dirty, mark it.
        ///
        isDirty = true;
      });

  pipelineOwner.rootNode = renderView;
  renderView.prepareInitialFrame();

  final RenderObjectToWidgetElement<RenderBox> rootElement =
      RenderObjectToWidgetAdapter<RenderBox>(
          container: repaintBoundary,
          child: Directionality(
            textDirection: TextDirection.ltr,
            child: child,
          )).attachToRenderTree(
    buildOwner,
  );
  ////
  ///Render Widget
  ///
  ///

  buildOwner.buildScope(
    rootElement,
  );
  buildOwner.finalizeTree();

  pipelineOwner.flushLayout();
  pipelineOwner.flushCompositingBits();
  pipelineOwner.flushPaint();

  ui.Image? image;

  do {
    ///
    ///Reset the dirty flag
    ///
    ///
    isDirty = false;

    image = await repaintBoundary.toImage(
        pixelRatio: pixelRatio ?? (imageSize.width / logicalSize.width));

    ///
    ///This delay sholud increas with Widget tree Size
    ///

    await Future.delayed(delay);

    ///
    ///Check does this require rebuild
    ///
    ///
    if (isDirty) {
      ///
      ///Previous capture has been updated, re-render again.
      ///
      ///
      buildOwner.buildScope(
        rootElement,
      );
      buildOwner.finalizeTree();
      pipelineOwner.flushLayout();
      pipelineOwner.flushCompositingBits();
      pipelineOwner.flushPaint();
    }
    retryCounter--;

    ///
    ///retry untill capture is successfull
    ///

  } while (isDirty && retryCounter >= 0);
  try {

    /// Dispose All widgets
    rootElement.visitChildren((Element element) {
      rootElement.deactivateChild(element);
    });
    buildOwner.finalizeTree();
  } catch (e) {}


  return image; // Adapted to directly return the image and not the Uint8List
}