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

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 1:[1]

I spend two full days of research on this issue and read many sources :

  • According to the following long discussion by people developing Dart, Dart's waitFor is now deprecated and might well disappear someday.
  • Moreover, waitFor has never been available in Flutter due to some incompatibility because Dart has been adapted deep inside for Flutter's needs.
  • Its deprecation in Dart means that it won't be introduced in Flutter.

So here is how to deal with this in Dart/Flutter:

  • Only an async function may await for another async one.
  • All async functions must return a Future<...> (even if a Future<void>), thus forcing its caller to be async as well, and so on.
  • The only way to cut these chains of async function calls is to reach the main function or to be able to allow the asynchronous execution of a method at some point (such as a widget's build method for example).
  • Ther is another way to reduce these async chains. For example, say that you need the path of the /tmp directory at some point in your program. This is a sync operation. Now, as this path won't change, you may set a global variable at app init time. This is usually directly in main, or a function called by it.

Last but not least:

  • As for any asynchronous routine, you must take special care passing all the needed information in parameters to keep data integrity, as the execution of async functions is delayed, and those data may change in your application before the async routine get a chance to be executed. Inbound side effects should thus never be an option here.
  • Keep in mind in this respect that you should always pass copies of objects to async routines!! Indeed, in Dart/Flutter, only the reference of objects are passed by value, not the objects themselves!! This means that modifying an object potentially generates side effects, either inbound or outbound, possibly causing data corruption, for example, when saving data in a file.

I hope it helps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1