toImage method

Future<Image> toImage({
  1. required int size,
  2. PrettyQrDecoration decoration = const PrettyQrDecoration(),
  3. ImageConfiguration configuration = ImageConfiguration.empty,
})

Returns the QR code as image.

Notes: Does not work with nested images on the Web until the stable Flutter 3.7.0 version. See: https://github.com/flutter/flutter/issues/103803.

Implementation

Future<ui.Image> toImage({
  required final int size,
  final PrettyQrDecoration decoration = const PrettyQrDecoration(),
  final ImageConfiguration configuration = ImageConfiguration.empty,
}) {
  PrettyQrDecoration safeDecoration = decoration;
  if (decoration.image != null && !_isNestedImagesSupported) {
    safeDecoration = PrettyQrDecoration(shape: decoration.shape);
  }

  final imageSize = Size.square(size.toDouble());
  final imageCompleter = Completer<ui.Image>();
  final pictureRecorder = ui.PictureRecorder();
  final imageConfiguration = configuration.copyWith(size: imageSize);

  final context = PrettyQrPaintingContext(
    Canvas(pictureRecorder),
    Offset.zero & imageSize,
    matrix: PrettyQrMatrix.fromQrImage(this),
    textDirection: configuration.textDirection,
  );

  late PrettyQrPainter decorationPainter;
  try {
    decorationPainter = safeDecoration.createPainter(() {
      decorationPainter.paint(context, imageConfiguration);
      final picture = pictureRecorder.endRecording();
      imageCompleter.complete(picture.toImage(size, size));
    });
    decorationPainter.paint(context, imageConfiguration);

    final decorationImageStream = safeDecoration.image?.image.resolve(
      configuration,
    );

    if (decorationImageStream == null) {
      final picture = pictureRecorder.endRecording();
      imageCompleter.complete(picture.toImage(size, size));
    } else {
      late ImageStreamListener imageStreamListener;
      imageStreamListener = ImageStreamListener(
        (imageInfo, synchronous) {
          decorationImageStream.removeListener(imageStreamListener);
          imageInfo.dispose();
          if (synchronous) {
            final picture = pictureRecorder.endRecording();
            imageCompleter.complete(picture.toImage(size, size));
          }
        },
        onError: (error, stackTrace) {
          decorationImageStream.removeListener(imageStreamListener);
          imageCompleter.completeError(error, stackTrace);
        },
      );
      decorationImageStream.addListener(imageStreamListener);
    }
  } catch (error, stackTrace) {
    imageCompleter.completeError(error, stackTrace);
  }

  return imageCompleter.future.whenComplete(() {
    decorationPainter.dispose();
  });
}