screenshot method
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,
);
}