getPNGScreenShotWithMetadata method

Future<Map<String, dynamic>?> getPNGScreenShotWithMetadata({
  1. GlobalKey<State<StatefulWidget>>? customKey,
})

Capturar screenshot del widget actual con metadatos de dispositivo (similar a getPNGScreenShot del JS SDK)

Implementation

Future<Map<String, dynamic>?> getPNGScreenShotWithMetadata(
    {GlobalKey? customKey}) async {
  try {
    final key = customKey ?? _appRootKey;
    if (key?.currentContext == null) {
      ObslyLogger.warn('Cannot capture screenshot: No valid context found');
      return null;
    }

    final renderObject = key!.currentContext!.findRenderObject();
    if (renderObject is! RenderRepaintBoundary) {
      ObslyLogger.warn(
          'Cannot capture screenshot: RenderObject is not a RenderRepaintBoundary, found: ${renderObject.runtimeType}');
      return null;
    }
    final RenderRepaintBoundary boundary = renderObject;

    // Obtener información del dispositivo y contexto
    final context = key.currentContext!;
    final mediaQuery = MediaQuery.of(context);
    final deviceInfo = DeviceInfoCollector.instance.getDeviceInfo();

    // Calcular pixel ratio dinámico para conseguir ~6KB
    final view = View.of(context);
    final screenSize = mediaQuery.size;

    // Target: ~400x300px para mejor calidad visual
    final targetWidth = 400.0;
    final targetHeight = 300.0;

    // Calcular pixelRatio necesario
    final ratioX = targetWidth / screenSize.width;
    final ratioY = targetHeight / screenSize.height;
    final double pixelRatio = math.min(ratioX, ratioY);

    final ui.Image image = await boundary.toImage(pixelRatio: pixelRatio);

    // Usar compresión más agresiva para conseguir ~2-3KB (JPEG-like)
    final ByteData? byteData =
        await image.toByteData(format: ui.ImageByteFormat.png);

    if (byteData == null) {
      ObslyLogger.error('Failed to convert image to byte data');
      return null;
    }

    final Uint8List imageBytes = byteData.buffer.asUint8List();

    // Apply anonymization if enabled
    Uint8List finalBytes = imageBytes;
    if (_enableAnonymization) {
      final anonymizedBytes =
          await ObslyScreenshotAnonymizer.instance.anonymizeScreenshot(
        imageBytes: imageBytes,
        context: context,
        devicePixelRatio: pixelRatio,
      );
      finalBytes = anonymizedBytes ?? imageBytes;
    }

    // Aplicar compresión simple (reducir colores para simular JPEG)
    final Uint8List compressedBytes =
        await _compressForUIEvents(finalBytes, image.width, image.height);

    // Log del tamaño para verificar target de ~2-3KB
    final sizeKB = (compressedBytes.length / 1024).toStringAsFixed(1);
    ObslyLogger.debug(
        'DEBUGTIMING: 📸 Screenshot size: ${sizeKB}KB (${image.width}x${image.height}px, ratio: ${pixelRatio.toStringAsFixed(2)})');

    // Para UI events, usar imagen comprimida
    final String base64Image = base64Encode(compressedBytes);
    final String fullBase64 = 'data:image/png;base64,$base64Image';

    // Crear metadatos del dispositivo para el preview (similar al JS SDK)
    final deviceMetadata = {
      'devicePixelRatio': view.devicePixelRatio,
      'logicalSize': {
        'width': mediaQuery.size.width,
        'height': mediaQuery.size.height,
      },
      'physicalSize': {
        'width': view.physicalSize.width,
        'height': view.physicalSize.height,
      },
      'deviceInfo': {
        'name': deviceInfo.name,
        'manufacturer': deviceInfo.manufacturer,
        'model': deviceInfo.model,
        'osName': deviceInfo.osName,
        'osVersion': deviceInfo.osVersion,
        'formFactor': deviceInfo.formFactor,
        'resolution': deviceInfo.resolution,
        'orientation': deviceInfo.orientation,
      },
      'captureInfo': {
        'originalSize': {
          'width': image.width,
          'height': image.height,
        },
        'compressedSize': compressedBytes.length,
        'compressionRatio': imageBytes.isNotEmpty
            ? (compressedBytes.length / imageBytes.length)
            : 1.0,
        'timestamp': DateTime.now().millisecondsSinceEpoch,
      }
    };

    // Validar que el screenshot se generó correctamente
    if (base64Image.isNotEmpty) {
      ObslyLogger.debug(
          'Screenshot with metadata captured successfully: ${imageBytes.length} → ${compressedBytes.length} bytes');
      return {
        'image': fullBase64,
        'metadata': deviceMetadata,
      };
    } else {
      ObslyLogger.error('Failed to capture screenshot');
      return null;
    }
  } catch (e) {
    ObslyLogger.error('Error capturing PNG screenshot with metadata: $e');
    return null;
  }
}