Flutter: converting an Image object to a base64 string without using a File

Issue

I grabbed somewhere the following code to convert a picture to a base64 string without accessing a file :

String ImageToString(Image image) {
    String result;
    var stream = image.image.resolve(const ImageConfiguration());
    stream.addListener(ImageStreamListener((imageInfo, _) async {
      var byteData =
          await imageInfo.image.toByteData(format: ImageByteFormat.png);
      var data = byteData!.buffer
          .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes);
      result = base64Encode(data);
    }));

    // Need to wait for completion here

    return result;
  }

The problem is that I need to wait for the asynchronous task completion.

  1. How can I wait for the completion in this case?
  2. Or else, is there a synchronous wait to perform this?

Solution

Among the many other sources of my two full days’ research, according to the following long discussion by people developing Dart, Dart’s waitFor is now deprecated and then at risk of disappearing. This is even without taking into account that waitFor has never been available in Flutter due to Dart having been adapted for Flutter deep inside. Its deprecation in Dart makes it virtually impossible to be introduced in Flutter in the foreseeable future.

So waiting for the completion of asynchronous tasks in synchronous code is simply impossible in Flutter. Until otherwise proven, or things change in years from now. Conclusion: if your project can’t live without this functionality, you’d better choose another language and framework.

Everything you will try, that falls short of using await (which may only be used in async code), like then etc; will only register a task for later execution, not wait for it. In short, you throw a bottle in the ocean and hope that it will land somewhere sometimes, and you can’t wait for it.

The other way to work with Flutter; is to make almost everything asynchronous; because what you can do is to synchronize things in asynchronous code. But this is a "bit" cumbersome IMHO. You need indeed to make each routine async in the calling chain (i.e. the routines in the stack) upwards up to main! This needs extra effort, that you may not need with other languages.

Moreover, as for any asynchronous routine, you must take special care passing all the needed information in parameters to keep data integrity, as the execution is delayed, and those data may change in your application before the async routine is executed. For this, you need to keep in mind to pass copies of objects to async routines! Indeed, in Dart/Flutter, only the references of the object are passed by value. This means that modifying an object generates side effects, from the main code to the async routine (causing data corruption, if you want to save data in a file, for example), or reverse (causing data corruption, if you progressively fill in an object the results of a long calculation, for example).

Answered By – Jacques

Answer Checked By – Cary Denson (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.