Reputation: 2814
I have a game a bit like Wordle, and I want to add a share capability much like Wordle does. I have a flag on my game grid widget which allows me to render the normal displayed version, or a special version for sharing. I'd like to use the widget to get a PNG file (or PNG byte data). I'd prefer to not actually draw this to the screen, just render it to some framebuffer and convert to PNG, although rendering to the screen is okay if the alternative is not possible. Looking through the docs, its not obvious whether what I am trying to do is possible or even makes sense (it seems I probably have to get the widget instantiated as an element and then get a render object, which seems to imply having to put it in my layout and draw it to the display), but maybe I am missing something. Is there a way to do this?
Upvotes: 4
Views: 1915
Reputation: 492
Here is the complete implementation, don't need any package
import 'package:path_provider/path_provider.dart';
import 'dart:io';
class WidgetScreenshotExample extends StatefulWidget {
const WidgetScreenshotExample({super.key});
@override
State<WidgetScreenshotExample> createState() =>
_WidgetScreenshotExampleState();
}
class _WidgetScreenshotExampleState extends State<WidgetScreenshotExample> {
final globalKey = GlobalKey();
Future<Uint8List> takeScreenshot() async {
//Get the render object from context.
final boundary =
globalKey.currentContext?.findRenderObject() as RenderRepaintBoundary;
//Convert to the image
final image = await boundary.toImage();
final bytes = await image.toByteData(format: ImageByteFormat.png);
Uint8List memoryImageData = bytes!.buffer.asUint8List();
return memoryImageData;
}
Future<String> saveImage(Uint8List bytes) async {
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
String path = "";
try {
Directory root = await getTemporaryDirectory();
String directoryPath = '${root.path}/appName';
// Create the directory if it doesn't exist
await Directory(directoryPath).create(recursive: true);
String filePath = '$directoryPath/$timestamp.jpg';
final file = await File(filePath).writeAsBytes(bytes);
path = file.path;
} catch (e) {
debugPrint(e.toString());
}
return path;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: RepaintBoundary(
key: globalKey,
child: Container(
color: Colors.red,
padding: const EdgeInsets.all(20),
child: const Text('Your Widget'),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.save),
onPressed: () async {
final imageData = await takeScreenshot();
await saveImage(imageData);
},
),
);
}
}
Upvotes: 0
Reputation: 25110
screenshot
package.A simple package to capture widgets as Images. Now you can also capture the widgets that are not rendered on the screen!
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
Uint8List _imageFile;
//Create an instance of ScreenshotController
ScreenshotController screenshotController = ScreenshotController();
@override
void initState() {
// TODO: implement initState
super.initState();
}
...
}
Screenshot(
controller: screenshotController,
child: Text("This text will be captured as image"),
),
screenshotController.capture().then((Uint8List image) {
//Capture Done
setState(() {
_imageFile = image;
});
}).catchError((onError) {
print(onError);
});
final directory = (await getApplicationDocumentsDirectory ()).path; //from path_provide package
String fileName = DateTime.now().microsecondsSinceEpoch;
path = '$directory';
screenshotController.captureAndSave(
path //set path where screenshot will be saved
fileName:fileName
);
Upvotes: 3
Reputation: 1187
I was once working on an app in which I needed something similar. After searching for a while I found a package named 'screenshot'
This package lets you convert both visible or invisible widgets to an image.
Here is the sample code from their document
ScreenshotController screenshotController = ScreenshotController();
function createScreenshot(){
screenshotController
.captureFromWidget(Container(
padding: const EdgeInsets.all(30.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent, width: 5.0),
color: Colors.redAccent,
),
child: Text("This is an invisible widget"),
),
).then((capturedImage) {
// Here you will get image object
});
}
Upvotes: 0