renderPdf function

Future<Uint8List> renderPdf(
  1. ReportTemplate template,
  2. Map<String, dynamic> data
)

Renders template with data and returns a complete PDF byte buffer.

Implementation

Future<Uint8List> renderPdf(
  ReportTemplate template,
  Map<String, dynamic> data,
) async {
  print('DEBUG: renderPdf started');
  final document = pw.Document();
  final embeddedFonts = <String, pw.Font>{};
  for (final font in template.fonts) {
    if (font.data.isEmpty || !font.isPdfCompatible) continue;
    embeddedFonts[font.family] = pw.Font.ttf(
      ByteData.sublistView(base64Decode(font.data)),
    );
  }
  final pagination = _paginateReport(template, data);
  final pageCount = pagination.pages.length;
  final renderedAt = DateTime.now();
  for (var i = 0; i < pageCount; i++) {
    print('PAGE $i staticElements keys: ${pagination.pages[i].staticElements.keys.map((e) => e.id).toList()}');
    print('PAGE $i flowedElements keys: ${pagination.pages[i].flowedElements.keys.map((e) => e.id).toList()}');
    print('PAGE $i tables keys: ${pagination.pages[i].tables.keys.map((e) => e.id).toList()}');
  }
  for (var pageIndex = 0; pageIndex < pageCount; pageIndex++) {
    final page = pagination.pages[pageIndex];
    document.addPage(
      pw.Page(
        pageFormat: template.pdfPageFormat,
        margin: pw.EdgeInsets.zero,
        build: (context) {
          final children = <pw.Widget>[];

          // 1. Process header, footer, and standard body elements
          for (final element in template.elements) {
            final isVisible = isElementVisible(
              element,
              data,
              pageNumber: pageIndex + 1,
              pageCount: pageCount,
            );
            if (!isVisible) continue;

            if (element.band == 'header' || element.band == 'footer') {
              children.add(
                pw.Positioned(
                  left: element.x,
                  top: element.y,
                  child: _pdfElement(
                    element,
                    data,
                    template: template,
                    embeddedFonts: embeddedFonts,
                    pageNumber: pageIndex + 1,
                    pageCount: pageCount,
                    now: renderedAt,
                  ),
                ),
              );
            } else if (element.band == 'body') {
              final sec = element.section.trim();
              if (sec.isEmpty || sec == 'body') {
                if (element.type == ElementType.table) {
                  final tableSlice = page.tables[element];
                  if (tableSlice != null) {
                    children.add(
                      pw.Positioned(
                        left: element.x,
                        top: tableSlice.tableY,
                        child: _pdfElement(
                          element,
                          data,
                          template: template,
                          embeddedFonts: embeddedFonts,
                          pageNumber: pageIndex + 1,
                          pageCount: pageCount,
                          now: renderedAt,
                          tableRows: tableSlice.rows,
                          tableRowOffset: tableSlice.rowOffset,
                          includeTableSummary: tableSlice.showSummary,
                        ),
                      ),
                    );
                  }
                } else if (element.flow) {
                  final flowSlice = page.flowedElements[element];
                  if (flowSlice != null) {
                    children.add(
                      pw.Positioned(
                        left: element.x,
                        top: flowSlice.elementY,
                        child: _pdfElement(
                          element,
                          data,
                          template: template,
                          embeddedFonts: embeddedFonts,
                          pageNumber: pageIndex + 1,
                          pageCount: pageCount,
                          now: renderedAt,
                          flowLines: flowSlice.lines,
                        ),
                      ),
                    );
                  }
                } else {
                  final staticY = page.staticElements[element];
                  if (staticY != null) {
                    children.add(
                      pw.Positioned(
                        left: element.x,
                        top: staticY,
                        child: _pdfElement(
                          element,
                          data,
                          template: template,
                          embeddedFonts: embeddedFonts,
                          pageNumber: pageIndex + 1,
                          pageCount: pageCount,
                          now: renderedAt,
                        ),
                      ),
                    );
                  }
                }
              }
            }
          }

          // 2. Process repeater sections
          for (final entry in page.sections.entries) {
            final secName = entry.key;
            final secPageSlice = entry.value;
            final items = resolvePath(secName, data);
            final list = items is List ? items : const [];

            for (final itemSlice in secPageSlice.items) {
              final item = list[itemSlice.itemIndex];
              final itemMap = item is Map<String, dynamic> ? item : <String, dynamic>{};
              final itemData = {...data, ...itemMap};

              for (final entryElem in itemSlice.elements.entries) {
                final element = entryElem.key;
                final elemSlice = entryElem.value;

                children.add(
                  pw.Positioned(
                    left: element.x,
                    top: elemSlice.elementY,
                    child: _pdfElement(
                      element,
                      itemData,
                      template: template,
                      embeddedFonts: embeddedFonts,
                      pageNumber: pageIndex + 1,
                      pageCount: pageCount,
                      now: renderedAt,
                      flowLines: elemSlice.lines,
                    ),
                  ),
                );
              }
            }
          }

          return pw.Stack(
            fit: pw.StackFit.expand,
            children: children,
          );
        },
      ),
    );
  }
  print('DEBUG: renderPdf finished, pages: ${pagination.pages.length}');
  return document.save();
}