screenshot method

  1. @protected
Future<Image?> screenshot(
  1. Object? object,
  2. {required double width,
  3. required double height,
  4. double margin = 0.0,
  5. double maxPixelRatio = 1.0,
  6. bool debugPaint = false}
)

Captures an image of the current state of an object that is a RenderObject or Element.

The returned ui.Image has uncompressed raw RGBA bytes and will be scaled to be at most width pixels wide and height pixels tall. The returned image will never have a scale between logical pixels and the size of the output image larger than maxPixelRatio. margin indicates the number of pixels relative to the un-scaled size of the object to include as a margin to include around the bounds of the object in the screenshot. Including a margin can be useful to capture areas that are slightly outside of the normal bounds of an object such as some debug paint information.

Implementation

@protected
Future<ui.Image?> screenshot(
  Object? object, {
  required double width,
  required double height,
  double margin = 0.0,
  double maxPixelRatio = 1.0,
  bool debugPaint = false,
}) async {
  if (object is! Element && object is! RenderObject) {
    return null;
  }
  final RenderObject? renderObject = object is Element ? object.renderObject : (object as RenderObject?);
  if (renderObject == null || !renderObject.attached) {
    return null;
  }

  if (renderObject.debugNeedsLayout) {
    final PipelineOwner owner = renderObject.owner!;
    assert(!owner.debugDoingLayout);
    owner
      ..flushLayout()
      ..flushCompositingBits()
      ..flushPaint();

    // If we still need layout, then that means that renderObject was skipped
    // in the layout phase and therefore can't be painted. It is clearer to
    // return null indicating that a screenshot is unavailable than to return
    // an empty image.
    if (renderObject.debugNeedsLayout) {
      return null;
    }
  }

  Rect renderBounds = _calculateSubtreeBounds(renderObject);
  if (margin != 0.0) {
    renderBounds = renderBounds.inflate(margin);
  }
  if (renderBounds.isEmpty) {
    return null;
  }

  final double pixelRatio = math.min(
    maxPixelRatio,
    math.min(
      width / renderBounds.width,
      height / renderBounds.height,
    ),
  );

  return _ScreenshotPaintingContext.toImage(
    renderObject,
    renderBounds,
    pixelRatio: pixelRatio,
    debugPaint: debugPaint,
  );
}