I know how to save visible widgets to an image using RepaintBoundary
What I want is a way to save a widget
that is not visible to the user as an image
.
I know how to save visible widgets to an image using RepaintBoundary
What I want is a way to save a widget
that is not visible to the user as an image
.
/// Creates an image from the given widget by first spinning up a element and render tree,
/// then waiting for the given [wait] amount of time and then creating an image via a [RepaintBoundary].
///
/// The final image will be of size [imageSize] and the the widget will be layout, ... with the given [logicalSize].
Future<Uint8List> createImageFromWidget(Widget widget, {Duration wait, Size logicalSize, Size imageSize}) async {
final RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary();
logicalSize ??= ui.window.physicalSize / ui.window.devicePixelRatio;
imageSize ??= ui.window.physicalSize;
assert(logicalSize.aspectRatio == imageSize.aspectRatio);
final RenderView renderView = RenderView(
window: null,
child: RenderPositionedBox(alignment: Alignment.center, child: repaintBoundary),
configuration: ViewConfiguration(
size: logicalSize,
devicePixelRatio: 1.0,
),
);
final PipelineOwner pipelineOwner = PipelineOwner();
final BuildOwner buildOwner = BuildOwner();
pipelineOwner.rootNode = renderView;
renderView.prepareInitialFrame();
final RenderObjectToWidgetElement<RenderBox> rootElement = RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary,
child: widget,
).attachToRenderTree(buildOwner);
buildOwner.buildScope(rootElement);
if (wait != null) {
await Future.delayed(wait);
}
buildOwner.buildScope(rootElement);
buildOwner.finalizeTree();
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
final ui.Image image = await repaintBoundary.toImage(pixelRatio: imageSize.width / logicalSize.width);
final ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData.buffer.asUint8List();
}
You can use this code to create image of the widget which is not visible. `
static Future<Uint8List?> createImageFromWidget(
BuildContext context, Widget widget,
{Duration? wait, Size? logicalSize, Size? imageSize}) async {
final repaintBoundary = RenderRepaintBoundary();
logicalSize ??=
View.of(context).physicalSize / View.of(context).devicePixelRatio;
imageSize ??= View.of(context).physicalSize;
assert(logicalSize.aspectRatio == imageSize.aspectRatio,
'logicalSize and imageSize must not be the same');
final renderView = RenderView(
child: RenderPositionedBox(
alignment: Alignment.center, child: repaintBoundary),
configuration: ViewConfiguration(
size: logicalSize,
devicePixelRatio: 1,
),
view: View.of(context) //PlatformDispatcher.instance.views.first,
);
final pipelineOwner = PipelineOwner();
final buildOwner = BuildOwner(focusManager: FocusManager());
pipelineOwner.rootNode = renderView;
renderView.prepareInitialFrame();
final rootElement = RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary,
child: Directionality(
textDirection: TextDirection.ltr,
child: widget,
)).attachToRenderTree(buildOwner);
buildOwner.buildScope(rootElement);
if (wait != null) {
await Future.delayed(wait);
}
buildOwner
..buildScope(rootElement)
..finalizeTree();
pipelineOwner
..flushLayout()
..flushCompositingBits()
..flushPaint();
final image = await repaintBoundary.toImage(
pixelRatio: imageSize.width / logicalSize.width);
final byteData = await image.toByteData(format: ImageByteFormat.png);
return byteData?.buffer.asUint8List();
}`
For more reference you can visit this link
It works for me but the code has been changed a little for later versions of Dart >= 3.0.0
static Future<Uint8List?> createImageFromWidget(BuildContext context,Widget widget,{Duration? wait, Size? logicalSize, Size? imageSize}) async {
final repaintBoundary = RenderRepaintBoundary();
logicalSize ??=
View.of(context).physicalSize / View.of(context).devicePixelRatio;
imageSize ??= View.of(context).physicalSize;
assert(logicalSize.aspectRatio == imageSize.aspectRatio,
'logicalSize and imageSize must not be the same');
final renderView = RenderView(
child: RenderPositionedBox(
alignment: Alignment.center, child: repaintBoundary),
configuration: ViewConfiguration(
logicalConstraints: BoxConstraints.tight(logicalSize),
devicePixelRatio: View.of(context).devicePixelRatio,
),
view: View.of(context));
final pipelineOwner = PipelineOwner();
final buildOwner = BuildOwner(focusManager: FocusManager());
pipelineOwner.rootNode = renderView;
renderView.prepareInitialFrame();
final rootElement = RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary,
child: Directionality(
textDirection: ui.TextDirection.ltr,
child: widget,
)).attachToRenderTree(buildOwner);
buildOwner.buildScope(rootElement);
if (wait != null) {
await Future.delayed(wait);
}
buildOwner
..buildScope(rootElement)
..finalizeTree();
pipelineOwner
..flushLayout()
..flushCompositingBits()
..flushPaint();
final image = await repaintBoundary.toImage(
pixelRatio: imageSize.width / logicalSize.width);
final byteData = await image.toByteData(format: ImageByteFormat.png);
return byteData?.buffer.asUint8List();
}
With this you will able to Capture the widget, and if you want share it. In my case with share_plus
Future<void> _captureAndShare() async {
try {
Widget qrScreen = QrScreen();// Your Widget
Size logicalSize = const Size(800, 1280);
Size imageSize = const Size(800, 1280);
// Needs a Size
qrScreen = MediaQuery(
data: MediaQueryData(size: logicalSize),
child: qrScreen,
);
Uint8List? imageUint = await createImageFromWidget(
context,
qrScreen,
wait: const Duration(milliseconds: 20),
imageSize: imageSize,
logicalSize: logicalSize,
);
if (imageUint == null) {
print('Failed to capture: the image is null.');
return;
}
// Save the image in a temp file
Directory tempDir = await getTemporaryDirectory();
File file = await File('${tempDir.path}/shared_image.png').create();
await file.writeAsBytes(imageUint);
// Share the image
XFile xFile = XFile(file.path);
await Share.shareXFiles([xFile], text: "Hello world");
} catch (e) {
print('Failed to capture and share the image: $e');
}
}
MediaQuery.of(context).size.height/width
in logicalSize
and imageSize
–
Amandie © 2022 - 2025 — McMap. All rights reserved.
RepaintBoundary
behind all other widgets so that it's not visible to user. – Upholster