Dynamically add pages with contents to PDF Document doesnt work

Hey Guys,

i want to create a PDF Document in Flutter, that has a dynamic number of pages. They all base of one template, and would be edited by me. You can see my full GitHub Repo (//TODO), but the (in my opinion) only important part right now is the following. The method initially called is writeAndOpenPDF(createPDFBytes(date), 'test.pdf'):

Future<ByteData> getTemplateBytes() async {
return await rootBundle.load('assets/template_pdf.pdf');
}
Future<List<int>> createPDFBytes(DateTime month) async {
if (!RockyRewardsManager.instance.initialized.value) {
await RockyRewardsManager.instance.initialized.stream.first;
}
var list = RockyRewardsManager.instance.rewardsList.where((reward) =>
reward.date.year == month.year && reward.date.month == month.month
).toList(growable: false);

var templateBytes = await getTemplateBytes();
var template = PdfDocument(
inputBytes: templateBytes.buffer.asUint8List(),
).pages[0].createTemplate();
var numberOfPages = (list.length / numberOfRows).ceil();
var document = PdfDocument();

for (int i = 0; i < numberOfPages; i++) {
var page = document.pages.add();
page.graphics.drawPdfTemplate(template, Offset.zero);
fillPage(
month,
'Laslo',
'Hauschild',
'Selkirk Secondary School',
i != (numberOfPages - 1)
? list.sublist(numberOfRows * i, numberOfRows * (i + 1))
: list.sublist(numberOfRows * i),
page,
);
}

List<int> resultBytes = document.save();
document.dispose();
return resultBytes;
}
PdfPage fillPage(DateTime month, String firstName, String lastName,
String school, List<RockyReward> rewards, PdfPage page) {
var font = PdfStandardFont(PdfFontFamily.helvetica, 12);
var graphics = page.graphics;
graphics.drawString(firstName, font, bounds: firstNameField);
graphics.drawString(lastName, font, bounds: lastNameField);
graphics.drawString(school, font, bounds: schoolField);
graphics.drawString(DateUtils.formatMonth(month), font, bounds: monthField);
//TODO: Fill out columns
//TODO: Fill out sums
return page;
}
Future<void> writeAndOpenPDF(List<int> bytes, String fileName) async {
//Only works on android!
final path = (await getExternalStorageDirectory())!.path;
final file = File('$path/$fileName');
await file.writeAsBytes(bytes, flush: true);
OpenFile.open(file.path);
}
It doesnt throw an error, it just displays a white screen. When i had only one page and no templates, everything worked fine. Can you help me? Thx

5 Replies 1 reply marked as answer

AP Anand Panchamoorthi Syncfusion Team September 27, 2021 02:47 PM UTC

Hi Laslo, 

Thanks for contacting Syncfusion support. 

We suspect the synchronous method call from asynchronous method may cause this issue. We suggest you to update the below method as asynchronous as below, 

Before 
Suggested 
PdfPage fillPage(DateTime month, String firstName, String lastName, String school, List<RockyReward> rewards, PdfPage page) { 
Future<PdfPage> fillPage(DateTime month, String firstName, String lastName, String school, List<RockyReward> rewards, PdfPage page) async
//Note: add 'await' before this method call 

If you are facing this issue, please provide the input PDF which you have using as template to validate further in our end. 

Please let us know if you need any further assistance in this. 

Anand Panchamoorthi 



LA Laslo September 27, 2021 10:09 PM UTC

Hello, Thanks for the detailed answer. Unfortunately, it didn't solve the problem. Here is the code, the link to the GitHub Repo (I forgot it last time, sorry about that) and the link to the pdf:

  • GitHub: https://github.com/Lasslos/rocky_rewards
  • PDF: https://github.com/Lasslos/rocky_rewards/blob/development/assets/template_pdf.pdf
  • Code:
  • import 'dart:io';
    import 'dart:ui';

    import 'package:date_utils/date_utils.dart';
    import 'package:open_file/open_file.dart';
    import 'package:path_provider/path_provider.dart';
    import 'package:rocky_rewards/pdf_creator/coordinates.dart';
    import 'package:rocky_rewards/utils/rocky_rewards.dart';
    import 'package:syncfusion_flutter_pdf/pdf.dart';
    import 'package:flutter/services.dart' show ByteData, rootBundle;

    const Rect firstNameField = Rect.fromLTWH(320, 30, 98, 14);
    const Rect lastNameField = Rect.fromLTWH(473, 30, 109, 14);
    const Rect schoolField = Rect.fromLTWH(621, 30, 44, 14);
    const Rect monthField = Rect.fromLTWH(701, 30, 49, 14);

    const RowCoordinates rowsSpan = RowCoordinates(169, 325);
    const int numberOfRows = 17;
    final List<RowCoordinates> rowList = _getRowCoordinates();
    List<RowCoordinates> _getRowCoordinates() {
    List<RowCoordinates> result = [];
    for (var i = 0; i < 17; i++) {
    var y = rowsSpan.y + (rowsSpan.height / numberOfRows * i);
    var height = rowsSpan.height / numberOfRows;
    result.add(RowCoordinates(y, height));
    }
    return result;
    }

    const ColumnCoordinates dateColumn = ColumnCoordinates(19, 72);
    const ColumnCoordinates rewardTypeColumn = ColumnCoordinates(92, 75);
    const int numberOfRewardTypeColumns = 3;
    const ColumnCoordinates groupNameColumn = ColumnCoordinates(169, 98);
    const ColumnCoordinates description = ColumnCoordinates(268, 208);
    const ColumnCoordinates attendanceTypeColumn = ColumnCoordinates(477, 44);
    const int numberOfAttendanceTypeColumns = 2;
    const hoursOfNumberOfGamesColumn = ColumnCoordinates(522, 36);
    const pointsColumn = ColumnCoordinates(559, 25);
    const signatureColumn = ColumnCoordinates(585, 92);
    const phoneColumn = ColumnCoordinates(679, 93);

    const Rect volunteerSumField = Rect.fromLTWH(92, 495, 24, 18);
    const Rect schoolSumField = Rect.fromLTWH(117, 495, 25, 18);
    const Rect communitySumField = Rect.fromLTWH(143, 495, 25, 18);

    Future<ByteData> getTemplateBytes() async {
    return await rootBundle.load('assets/template_pdf.pdf');
    }
    Future<List<int>> createPDFBytes(DateTime month) async {
    if (!RockyRewardsManager.instance.initialized.value) {
    await RockyRewardsManager.instance.initialized.stream.first;
    }
    var list = RockyRewardsManager.instance.rewardsList.where((reward) =>
    reward.date.year == month.year && reward.date.month == month.month
    ).toList(growable: false);

    var templateBytes = await getTemplateBytes();
    var template = PdfDocument(
    inputBytes: templateBytes.buffer.asUint8List(),
    ).pages[0].createTemplate();
    var numberOfPages = (list.length / numberOfRows).ceil();
    var document = PdfDocument();

    for (int i = 0; i < numberOfPages; i++) {
    var page = document.pages.add();
    page.graphics.drawPdfTemplate(template, Offset.zero);
    await fillPage(
    month,
    'Laslo',
    'Hauschild',
    'Selkirk Secondary School',
    i != (numberOfPages - 1)
    ? list.sublist(numberOfRows * i, numberOfRows * (i + 1))
    : list.sublist(numberOfRows * i),
    page,
    );
    }

    List<int> resultBytes = document.save();
    document.dispose();
    return resultBytes;
    }
    Future<PdfPage> fillPage(DateTime month, String firstName, String lastName,
    String school, List<RockyReward> rewards, PdfPage page) async {
    var font = PdfStandardFont(PdfFontFamily.helvetica, 12);
    var graphics = page.graphics;
    graphics.drawString(firstName, font, bounds: firstNameField);
    graphics.drawString(lastName, font, bounds: lastNameField);
    graphics.drawString(school, font, bounds: schoolField);
    graphics.drawString(DateUtils.formatMonth(month), font, bounds: monthField);
    //TODO: Fill out columns
    //TODO: Fill out sums
    return page;
    }
    Future<void> writeAndOpenPDF(List<int> bytes, String fileName) async {
    //Only works on android!
    final path = (await getExternalStorageDirectory())!.path;
    final file = File('$path/$fileName');
    await file.writeAsBytes(bytes, flush: true);
    OpenFile.open(file.path);
    }
  • 

Attachment: template_pdf_f50ddc34.zip


LA Laslo September 28, 2021 12:23 AM UTC

Hey,

it works now. The solution was to add the following lines:

var document = PdfDocument();
document.pageSettings.size = PdfPageSize.letter;
document.pageSettings.orientation = PdfPageOrientation.landscape;
document.pageSettings.setMargins(10);

Without that, the document just don't knows what to to with the template and handles it incorrectly.

PS: I want to say how great Flutter Syncfusion PDF works. I haven't had a singe error (except for that one which is not really an error), the usage of the api is super simple but advanced, the support is nice. Big thank you!



LA Laslo September 28, 2021 02:21 AM UTC

Hey, its me again. The solution above isn't acctually the solution. The error is that my list that I refer to when calculating how many pages the pdf will have can be empty and therefore the pdf has zero pages.


Marked as answer

AP Anand Panchamoorthi Syncfusion Team September 28, 2021 07:49 AM UTC

Hi Laslo, 

Thanks to hearing this from you.  

We are happy to assist you always. Please let us know if you need any further assistance in this. 

With Regards, 
Anand Panchamoorthi

Loader.
Up arrow icon