2

I have a RawImage widget but I actually need an image provider (like AssetImage or MemoryImage) so that I can build a DecorationImage from it. Is that possible? I've tried a lot of things, including trying to construct a MemoryImage from the raw byte-values but nothing worked so far...

Any help woud be appreciated!

travisjayday
  • 784
  • 6
  • 16

2 Answers2

2

The simplest way is by going via PNG, which encodes the pixels and geometry of the original image. For example:

Future<MemoryImage> convert(RawImage rawImage) async {
  var byteData = await rawImage.image.toByteData(
    format: ui.ImageByteFormat.png,
  );
  return MemoryImage(byteData.buffer.asUint8List());
}

This has the disadvantage of an unnecessary compress/decompress, but won't be noticeable for small images. To avoid that, use ui.ImageByteFormat.rawRgba and prepend a BMP file header. (The file header serves to pass the geometry to the memory image decoder.)

Richard Heap
  • 48,344
  • 9
  • 130
  • 112
  • The new `bitmap` package handles the BMP header bit for you, but uses experimental ffi: https://github.com/renancaraujo/bitmap/ Also see this answer: https://stackoverflow.com/questions/54030340/convert-a-uint8list-to-image-in-flutter-dart-ui/54030817#54030817 – Richard Heap Oct 12 '19 at 03:20
0

Here is a solution that doesn't require an unnecessary copy or compress/decompress. This works because an ImageProvider ultimately needs to return a ui.Image. If you already have it, you can skip all the fancy caching and async loading logic of ImageProvider. I used implements rather than extends to throw away the base implementation and return a custom ImageStreamCompleter that simply forwards the ui.Image to the widget.

import 'dart:ui' as ui;

class RawImageProvider implements ImageProvider {
  final ui.Image image;

  RawImageProvider(this.image);

  @override
  ImageStreamCompleter load(key, decode) => throw UnimplementedError();

  @override
  Future obtainKey(ImageConfiguration cfg) => throw UnimplementedError();

  @override
  Future<bool> evict({
    ImageCache cache,
    ImageConfiguration configuration = ImageConfiguration.empty,
  }) {
    return SynchronousFuture(true);
  }

  @override
  ImageStream resolve(ImageConfiguration configuration) {
    return ImageStream()..setCompleter(RawImageStreamCompleter(image));
  }

  void dispose() => image?.dispose();
}

class RawImageStreamCompleter extends ImageStreamCompleter {
  RawImageStreamCompleter(ui.Image image) {
    setImage(ImageInfo(image: image));
  }
}
maff
  • 855
  • 1
  • 9
  • 10
  • Nice, but I get on `RawImageProvider`: `Missing concrete implementations of 'ImageProvider.createStream', 'ImageProvider.loadBuffer', 'ImageProvider.loadImage', 'ImageProvider.obtainCacheStatus', and 1 more` – Luke Hutchison Sep 01 '23 at 22:43
  • Also `'RawImageProvider.obtainKey' ('Future Function(ImageConfiguration)') isn't a valid override of 'ImageProvider.obtainKey' ('Future Function(ImageConfiguration)').` and `'RawImageProvider.evict' ('Future Function({ImageCache cache, ImageConfiguration configuration})') isn't a valid override of 'ImageProvider.evict' ('Future Function({ImageCache? cache, ImageConfiguration configuration})').` – Luke Hutchison Sep 01 '23 at 22:45