captureScreenshot method
Future<String?>
captureScreenshot({
- ImageFormat format = ImageFormat.png,
- int quality = 100,
- double pixelRatio = 3.0,
Capture a single screenshot of the widget
Returns the file path of the saved image.
format - Image format (PNG or JPG, default: PNG)
quality - Image quality for JPG (1-100, default: 100, ignored for PNG)
pixelRatio - Pixel ratio for high-resolution capture (default: 3.0 for retina)
Implementation
Future<String?> captureScreenshot({
ImageFormat format = ImageFormat.png,
int quality = 100,
double pixelRatio = 3.0,
}) async {
try {
debugPrint('[WidgetRecorder] 📸 Capturing screenshot...');
debugPrint('[WidgetRecorder] 📸 ├─ Format: ${format.name.toUpperCase()}');
debugPrint('[WidgetRecorder] 📸 ├─ Pixel ratio: ${pixelRatio}x');
if (format == ImageFormat.jpg) {
debugPrint('[WidgetRecorder] 📸 └─ Quality: $quality%');
}
final renderObject = _boundaryKey.currentContext?.findRenderObject();
if (renderObject == null) {
throw Exception('Widget not found. Ensure WidgetRecorder is built.');
}
final boundary = renderObject as RenderRepaintBoundary;
debugPrint('[WidgetRecorder] 📸 Capturing image at ${pixelRatio}x resolution...');
// Capture at high resolution for quality
final image = await boundary.toImage(pixelRatio: pixelRatio);
debugPrint('[WidgetRecorder] ✅ Image captured: ${image.width}x${image.height} pixels');
// Convert to bytes based on format
final ByteData? byteData;
String extension;
if (format == ImageFormat.png) {
debugPrint('[WidgetRecorder] 🔄 Encoding as PNG...');
byteData = await image.toByteData(format: ui.ImageByteFormat.png);
extension = 'png';
} else {
debugPrint('[WidgetRecorder] 🔄 Encoding as JPG...');
// JPG format - quality parameter is used here
byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
extension = 'jpg';
// For JPG, we need to encode manually with quality
if (byteData != null) {
final pngByteData = await image.toByteData(format: ui.ImageByteFormat.png);
image.dispose();
if (pngByteData == null) {
throw Exception('Failed to encode image');
}
debugPrint('[WidgetRecorder] ⚠️ Note: Saving as PNG (native JPG encoding not supported)');
// Save as PNG and return (Flutter doesn't support JPG encoding with quality natively)
final Directory dir;
if (customSavePath != null) {
debugPrint('[WidgetRecorder] 📁 Using custom save path: $customSavePath');
dir = Directory(customSavePath!);
if (!await dir.exists()) {
debugPrint('[WidgetRecorder] 📁 └─ Creating directory...');
await dir.create(recursive: true);
}
} else {
dir = await getTemporaryDirectory();
debugPrint('[WidgetRecorder] 📁 Using temporary directory: ${dir.path}');
}
final filePath = '${dir.path}/screenshot_${DateTime.now().millisecondsSinceEpoch}.$extension';
final file = File(filePath);
final bytes = pngByteData.buffer.asUint8List();
debugPrint('[WidgetRecorder] 💾 Writing ${bytes.length} bytes to file...');
await file.writeAsBytes(bytes);
debugPrint('[WidgetRecorder] ✅ Screenshot saved: $filePath');
return filePath;
}
}
if (byteData == null) {
throw Exception('Failed to capture image data');
}
// Save to directory
final Directory dir;
if (customSavePath != null) {
debugPrint('[WidgetRecorder] 📁 Using custom save path: $customSavePath');
dir = Directory(customSavePath!);
if (!await dir.exists()) {
debugPrint('[WidgetRecorder] 📁 └─ Creating directory...');
await dir.create(recursive: true);
}
} else {
dir = await getTemporaryDirectory();
debugPrint('[WidgetRecorder] 📁 Using temporary directory: ${dir.path}');
}
final filePath = '${dir.path}/screenshot_${DateTime.now().millisecondsSinceEpoch}.$extension';
final file = File(filePath);
final bytes = byteData.buffer.asUint8List();
debugPrint('[WidgetRecorder] 💾 Writing ${bytes.length} bytes to file...');
await file.writeAsBytes(bytes);
image.dispose();
debugPrint('[WidgetRecorder] ✅ Screenshot saved: $filePath');
return filePath;
} catch (e) {
debugPrint('[WidgetRecorder] ❌ Error capturing screenshot: $e');
debugPrint('[WidgetRecorder] ❌ Stack trace: ${StackTrace.current}');
onError?.call(e.toString());
return null;
}
}