Difficulty adding Images to PDF Export

Custom Code

Hi all, I have had good success with a Custom Action using the pdf and printing pubspec packages following Dimitar Klaturov excellent tutorials. However, I am having no luck modifying it to also include images stored in Firebase.

What have you tried so far?

My original code (working).

// Automatic FlutterFlow imports
import '/backend/backend.dart';
import '/backend/schema/structs/index.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import 'package:flutter/services.dart' show rootBundle;

import '../../auth/firebase_auth/auth_util.dart';
import '../../backend/firebase_storage/storage.dart';

Future pdfBookDownload(
  BuildContext context,
  String? bookTitle,
  List<ChaptersRecord>? chapters,
  List<SectionsRecord>? sections,
) async {
  // Null safety checks
  bookTitle = bookTitle ?? '';
  chapters = chapters ?? [];
  sections = sections ?? [];

  // Initialize the PDF document
  final pdf = pw.Document();

  // Add title page for the book
  pdf.addPage(
    pw.Page(
      build: (pw.Context context) {
        return pw.Center(
          child: pw.Text(
            bookTitle ?? '',
            style: pw.TextStyle(fontSize: 36, fontWeight: pw.FontWeight.bold),
          ),
        );
      },
    ),
  );

  // Iterate through chapters
  for (final chapter in chapters) {
    final chapterTitle = chapter.chapterTitle ?? '';
    final chapterSections = sections.where(
      (section) => section.chapterId == chapter.reference,
    );

    // Add chapter page
    pdf.addPage(
      pw.MultiPage(
        pageFormat: PdfPageFormat.a4,
        build: (context) {
          final List<pw.Widget> pageContents = [];

          // Add chapter title
          pageContents.add(
            pw.Center(
              child: pw.Text(
                chapterTitle ?? '',
                style: pw.TextStyle(fontSize: 24),
              ),
            ),
          );
          pageContents.add(pw.SizedBox(height: 20));

          // Add section_title and section_body from chapter's sections
          for (final section in chapterSections) {
            final sectionTitle = section.sectionTitle ?? '';
            final sectionBody = section.sectionBody ?? '';
            if (sectionTitle.isNotEmpty) {
              pageContents.add(pw.Header(
                level: 1,
                child: pw.Text(sectionTitle),
              ));
            }
            if (sectionBody.isNotEmpty) {
              pageContents.add(pw.Paragraph(text: sectionBody));
            }
          }

          return pageContents;
        },
      ),
    );
  }

  // Generate and download the PDF document
  await Printing.layoutPdf(
    onLayout: (format) async => pdf.save(),
  );

  // Show a snackbar to indicate that the download is complete
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text('PDF Downloaded'),
    ),
  );
}

I realize I need to asynchronously load all the images (which have a URL stored on the 'section' document) before I call the build function. But I cannot seem to use the networkImage function correctly.

// Automatic FlutterFlow imports
import '/backend/backend.dart';
import '/backend/schema/structs/index.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import 'package:flutter/services.dart' show rootBundle;

import '../../auth/firebase_auth/auth_util.dart';
import '../../backend/firebase_storage/storage.dart';

Future pdfBookDownloadImage4(
  BuildContext context,
  String? bookTitle,
  List<ChaptersRecord>? chapters,
  List<SectionsRecord>? sections,
) async {
  // Null safety checks
  bookTitle = bookTitle ?? '';
  chapters = chapters ?? [];
  sections = sections ?? [];

  // Initialize the PDF document
  final pdf = pw.Document();

  // List to store ImageProvider objects
  List<Image> images = [];

  try {
    // Fetch all image URLs
    final List<String> imageUrls = sections
        .where((section) => section.image != null && section.image!.isNotEmpty)
        .map((section) => section.image!)
        .toList();

    // Load all images asynchronously
    await Future.forEach(imageUrls, (imageUrl) async {
      Image image = await networkImage(imageUrl);
      images.add(image);
    });

    // Add title page for the book
    pdf.addPage(
      pw.Page(
        build: (pw.Context context) {
          return pw.Center(
            child: pw.Text(
              bookTitle ?? '',
              style: pw.TextStyle(fontSize: 36, fontWeight: pw.FontWeight.bold),
            ),
          );
        },
      ),
    );

    // Iterate through chapters
    for (final chapter in chapters) {
      final chapterTitle = chapter.chapterTitle ?? '';
      final chapterSections =
          sections.where((section) => section.chapterId == chapter.reference);

      // Add chapter page
      pdf.addPage(
        pw.MultiPage(
          pageFormat: PdfPageFormat.a4,
          build: (context) {
            final List<pw.Widget> pageContents = [];

            // Add chapter title
            pageContents.add(
              pw.Center(
                child: pw.Text(
                  chapterTitle,
                  style: pw.TextStyle(fontSize: 24),
                ),
              ),
            );
            pageContents.add(pw.SizedBox(height: 20));

            // Add section_title, section_body, and image with caption from chapter's sections
            for (final section in chapterSections) {
              final sectionTitle = section.sectionTitle ?? '';
              final sectionBody = section.sectionBody ?? '';
              final imageUrl = section.image ?? '';
              final imageCaption = section.imageCaption ?? '';

              if (sectionTitle.isNotEmpty) {
                pageContents.add(pw.Header(
                  level: 1,
                  child: pw.Text(sectionTitle),
                ));
              }
              if (sectionBody.isNotEmpty) {
                pageContents.add(pw.Paragraph(text: sectionBody));
              }

              // Add preloaded image with caption
              if (imageUrl.isNotEmpty) {
                final imageIndex = imageUrls.indexOf(imageUrl);
                if (imageIndex != -1) {
                  pageContents.add(pw.Container(
                    alignment: pw.Alignment.center,
                    child: pw.Column(
                      children: [
                        pw.Image(images[imageIndex]),
                        pw.Text(
                          imageCaption,
                          style: pw.TextStyle(
                              fontStyle: pw.FontStyle.italic, fontSize: 12),
                        ),
                      ],
                    ),
                  ));
                }
              }
            }

            return pageContents;
          },
        ),
      );
    }

    // Generate and download the PDF document
    await Printing.layoutPdf(
      onLayout: (format) async => pdf.save(),
    );

    // Show a snackbar to indicate that the download is complete
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('PDF Downloaded'),
      ),
    );
  } catch (e) {
    // Handle errors
    print('Error: $e');
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Failed to download PDF'),
      ),
    );
  }
}

Did you check FlutterFlow's Documentation for this topic?
No
1 reply