takeOverlayCapture method

Future<File?> takeOverlayCapture()

Implementation

Future<File?> takeOverlayCapture() async {
  final overlayBox =
      _overlayKey.currentContext?.findRenderObject() as RenderBox?;
  if (overlayBox == null) {
    widget.onError?.call('Error Capturing overlay: Overlay box not found');
    return null;
  }

  final cameraBoundary = _cameraPreviewKey.currentContext?.findRenderObject()
      as RenderRepaintBoundary?;
  if (cameraBoundary == null) {
    widget.onError
        ?.call('Error Capturing overlay: Camera boundary not found');
    return null;
  }

  // Capture the image using camera controller
  final xFile = await widget._controller.cameraController!.takePicture();
  final imageBytes = await xFile.readAsBytes();

  // Calculate overlay position relative to camera preview
  final cameraOffset = cameraBoundary.localToGlobal(Offset.zero);
  final overlayOffset = overlayBox.localToGlobal(Offset.zero);
  final previewBox = cameraBoundary as RenderBox;

  // Create crop data map with all required parameters
  final cropData = {
    'imageBytes': imageBytes,
    'left': overlayOffset.dx - cameraOffset.dx,
    'top': overlayOffset.dy - cameraOffset.dy,
    'width': overlayBox.size.width,
    'height': overlayBox.size.height,
    'previewWidth': previewBox.size.width,
    'previewHeight': previewBox.size.height,
  };

  final timestamp = DateTime.now().millisecondsSinceEpoch;
  final filename = 'overlay_image_$timestamp.png';

  // Process differently based on platform
  if (kIsWeb) {
    try {
      // Convert image bytes to a Blob with explicit MIME type
      final blob = web.Blob([cropData['imageBytes']], 'image/png');
      final url = web.Url.createObjectUrlFromBlob(blob);

      // Create a complete crop data object
      final Map<String, dynamic> safeCropData = {
        'imageUrl': url.toString(),
        'left': cropData['left'] ?? 0,
        'top': cropData['top'] ?? 0,
        'width': cropData['width'] ?? 0,
        'height': cropData['height'] ?? 0,
        'previewWidth': cropData['previewWidth'] ?? 0,
        'previewHeight': cropData['previewHeight'] ?? 0,
      };

      // Web worker processing
      final croppedPng = await _processWithWebWorker(safeCropData);

      // Create file with processed image
      final processedBlob = web.Blob([croppedPng], 'image/png');
      final path = web.Url.createObjectUrlFromBlob(processedBlob);

      return File(filename, 'png', null, path, croppedPng);
    } catch (e) {
      print('Error in image processing: $e');
      widget.onError?.call('Error processing image: $e');
      return null;
    }
  } else {
    // Non-web platform processing
    try {
      final img.Image? decodedImage = img.decodeImage(imageBytes);
      if (decodedImage == null) {
        widget.onError?.call('Error Capturing overlay: Failed to decode image bytes');
        return null;
      }

      final croppedPng = _cropImageForNonWeb(
          decodedImage,
          cropData['left'] as double,
          cropData['top'] as double,
          cropData['width'] as double,
          cropData['height'] as double,
          cropData['previewWidth'] as double,
          cropData['previewHeight'] as double
      );

      // Save to temp file
      final tempDir = await getTemporaryDirectory();
      final tempFile = io.File('${tempDir.path}/$filename');
      await tempFile.writeAsBytes(croppedPng);

      return File(filename, 'png', null, tempFile.path, croppedPng);
    } catch (e) {
      widget.onError?.call('Error processing image: $e');
      return null;
    }
  }
}