0

I want to take a screenshot of a widget in a different isolate. Firstly, I tried to take a screenshot in the main thread, and it worked fine but since it's considered a heavy process, I need to do it in a different thread, creating a new isolate. When I tried to take the screenshot via compute I am getting the following error:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'dart:ui/window.dart': Failed assertion: line 298 pos 12: '<optimized out>': is not true.
E/flutter (20904): #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
E/flutter (20904): #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
E/flutter (20904): #2      FlutterWindow.viewConfiguration (dart:ui/window.dart:298:12)
E/flutter (20904): #3      FlutterView.physicalSize (dart:ui/window.dart:136:28)
E/flutter (20904): #4      ScreenshotController.captureFromWidget (package:screenshot/screenshot.dart:123:34)
E/flutter (20904): #5      capture (package:multithreading/components/receipt.dart:12:44)
E/flutter (20904): #6      _IsolateConfiguration.applyAndTime.<anonymous closure> (package:flutter/src/foundation/_isolates_io.dart:108:21)
E/flutter (20904): #7      Timeline.timeSync (dart:developer/timeline.dart:160:22)
E/flutter (20904): #8      _IsolateConfiguration.applyAndTime (package:flutter/src/foundation/_isolates_io.dart:106:21)
E/flutter (20904): #9      _spawn (package:flutter/src/foundation/_isolates_io.dart:127:67)
E/flutter (20904): #10     _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:300:17)
E/flutter (20904): #11     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)

receipt.dart

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:screenshot/screenshot.dart';

final screenshotController = ScreenshotController();

Future<Uint8List> capture(double pixel) async{
  final bytes = await screenshotController.captureFromWidget(
    Padding(
      padding: const EdgeInsets.all(12.0),
      child: Container(
        height: 500,
        width: 300,
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
        decoration: ShapeDecoration(
          color: CupertinoColors.systemGreen,
          shadows: [
            BoxShadow(
              color: Colors.grey.withOpacity(0.5),
              blurRadius: 6,
            ),
          ],
        ),
      ),
    ),
    delay: Duration.zero,
    pixelRatio: pixel,
  );
  return bytes;
}

computePage.dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'components/receipt.dart';

class ComputePage extends StatefulWidget {
  const ComputePage({Key? key}) : super(key: key);

  @override
  State<ComputePage> createState() => _ComputePageState();
}

class _ComputePageState extends State<ComputePage> {
  Uint8List? widgetImage;

  Future captureWidget() async {
    if (widgetImage == null) {
      widgetImage = await compute(capture, 10.0);
      // widgetImage = await capture(10.0); // Uncomment this line, it works fine
    } else {
      widgetImage = null;
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              height: 500,
              width: 300,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: widgetImage == null
                    ? const Color(0xFF2AA65C)
                    : Colors.white,
                borderRadius: BorderRadius.circular(30.0),
                border: Border.all(color: Colors.red, width: 6),
              ),
              child: widgetImage == null
                  ? const Text(
                'Image',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                ),
              )
                  : Image.memory(widgetImage!),
            ),
            const SizedBox(height: 50),
            ElevatedButton(
              onPressed: () {
                captureWidget();
              },
              style: ElevatedButton.styleFrom(
                backgroundColor: const Color(0xFFEAF6EF),
                fixedSize: const Size(double.infinity, 50),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12.0),
                ),
              ),
              child: const Text(
                'Capture',
                style: TextStyle(
                  color: Color(0xFF2AA65C),
                  fontSize: 16,
                  fontWeight: FontWeight.w700,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Please copy the code above to reproduce the error

Any help or advice is appreciated....

Sardonic777
  • 63
  • 1
  • 6
  • "but since it's considered a heavy process, I need to do it in a different thread" - who said that? it it not true, you don't need any special stuff to call [toImage](https://api.flutter.dev/flutter/rendering/RenderRepaintBoundary/toImage.html) – pskink Dec 04 '22 at 08:52
  • If you've payed attention I'm giving 10 pixelRatio to capture the widget, and processing this feature in our main thread the app is freezing, the circularprogressIndicator is pausing while the operation is being performed. That's why I said it is something that takes much time and makes our app work heavy – Sardonic777 Dec 04 '22 at 10:07
  • and what is `10 pixelRatio` supposed to do? – pskink Dec 04 '22 at 10:12
  • By default the ratio is 1, I'm giving to it 10 because we need a clean image. In short, the higher the value of pixelRatio higher the quality of screenshot is – Sardonic777 Dec 04 '22 at 10:31
  • so I think the culprit is a 3rd party package you are using, tried "normal" `RepaintBoundary`? – pskink Dec 04 '22 at 10:40
  • I need to take screenshot of a widget, which is not rendered. I mean I have a widget, it's just a shape, and it's not rendered in UI. And RepaintBoundary works only with the rendered widgets.... – Sardonic777 Dec 04 '22 at 10:43
  • any `Widget` or just a `Decoration`? if the latter then use https://api.flutter.dev/flutter/painting/BoxPainter/paint.html - basically you cannot use any UI related staff in flutter `Isolate` so what you are trying to do with `compute` function will not work – pskink Dec 04 '22 at 10:52

0 Answers0