captureScreenshot method

Future<String?> captureScreenshot({
  1. ImageFormat format = ImageFormat.png,
  2. int quality = 100,
  3. 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;
  }
}