greenzebra
greenzebra

Reputation: 577

How do I combine Text and an Image File into one Image File in Flutter?

Below is a snippet of code from a function that uploads a generated QR code (using the qr_flutter package) to firebase storage; then gets the firebase storage url to save in a custom model that is uploaded to firebase firestore (not shown).

This works fine, however I want to upload a file that consists of the QR code bounded by title text above and address text below. (Essentially a Column with children [title, qrFile, address]).

My question is: How do I combine Text and my qrFile into a single image file that I can upload to firebase storage?

String qrString = 'qr_data_here';
        final qrValidationResult = QrValidator.validate(
          data: qrString,
          version: QrVersions.auto,
          errorCorrectionLevel: QrErrorCorrectLevel.L,
        );
        if (qrValidationResult.status == QrValidationStatus.valid) {
          final qrCode = qrValidationResult.qrCode;
          const String title = 'title_name_here';
          final String address = 'address_here';
          final painter = QrPainter.withQr(
            qr: qrCode!,
            color: const Color(0xFF000000),
            gapless: true,
            embeddedImageStyle: null,
            embeddedImage: null,
          );
          Directory tempDir = await getTemporaryDirectory();
          String tempPath = tempDir.path;
          final ts = DateTime.now().millisecondsSinceEpoch.toString();
          String path = '$tempPath/$ts.png';
                                                // ui is from import 'dart:ui' as ui;
          final picData =
              await painter.toImageData(2048, format: ui.ImageByteFormat.png);
          // writeToFile is seen in code snippet below
          await writeToFile(
            picData!,
            path,
          );
        } else {
          genericErrorDialog(context);
        }
        // qrStorage is a reference to a folder in firebase storage
        await qrStorage.child('name_here').putFile(qrFile);
        var url =
            await qrStorage.child('name_here').getDownloadURL();
  late File qrFile;

  Future<void> writeToFile(ByteData data, String path) async {
    final buffer = data.buffer;
    qrFile = await File(path).writeAsBytes(
        buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
  }

Upvotes: 1

Views: 1184

Answers (1)

greenzebra
greenzebra

Reputation: 577

One solution is to use the screenshot package (https://pub.dev/packages/screenshot). This package has a function to save a widget as an image (without displaying it on screen) as shown below.

ScreenshotController screenshotController = ScreenshotController();


await screenshotController
              .captureFromWidget(CustomWidget())
              .then((capturedImage) async {
            await do_something_with_capturedImage_here();
          });

As it relates to my question specifically; Below is the code to generate a qr code, place it in a widget (needs some more formatting) with text, and then save the widget as an image file and upload to firebase.

String qrString = 'qr_data_here';
        final qrValidationResult = QrValidator.validate(
          data: qrString,
          version: QrVersions.auto,
          errorCorrectionLevel: QrErrorCorrectLevel.L,
        );
        if (qrValidationResult.status == QrValidationStatus.valid) {
          final qrCode = qrValidationResult.qrCode;
          const String title = 'title_name_here';
          final String address = 'address_here';
          final painter = QrPainter.withQr(
            qr: qrCode!,
            color: const Color(0xFF000000),
            gapless: true,
            embeddedImageStyle: null,
            embeddedImage: null,
          );
          Directory tempDir = await getTemporaryDirectory();
          String tempPath = tempDir.path;
          final ts = DateTime.now().millisecondsSinceEpoch.toString();
          String path = '$tempPath/$ts.png';
                                                // ui is from import 'dart:ui' as ui;
          final picData =
              await painter.toImageData(2048, format: ui.ImageByteFormat.png);
          // writeToFile is seen in code snippet below
          await writeToFile(
            picData!,
            path,
          );
          await screenshotController
              .captureFromWidget(Column(
            children: [
              Text(title),
              Image.file(qrFile),
              Text(address),
            ],
          ))
              .then((capturedImage) async {
            await widgetToImageFile(capturedImage);
          });
        } else {
          genericErrorDialog(context);
        }
        // qrStorage is a reference to a folder in firebase storage
        await qrStorage.child('name_here').putFile(fullQrFile);
        var url =
            await qrStorage.child('name_here').getDownloadURL();
ScreenshotController screenshotController = ScreenshotController();
  late File qrFile;
  late File fullQrFile;


  Future<void> writeToFile(ByteData data, String path) async {
    final buffer = data.buffer;
    qrFile = await File(path).writeAsBytes(
        buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
  }

  Future<void> widgetToImageFile(
    Uint8List capturedImage,
  ) async {
    Directory newTempDir = await getTemporaryDirectory();
    String newTempPath = newTempDir.path;
    final newTs = DateTime.now().millisecondsSinceEpoch.toString();
    String path = '$newTempPath/$newTs.png';
    fullQrFile = await File(path).writeAsBytes(capturedImage);
  }

Upvotes: 1

Related Questions