The Dart Knight rises! | Convert excel data into a custom-designed PDF

What if I tell you that you can paint a PDF the Flutter way, wouldn’t that be awesome!

Waleed Arshad
CodeChai

--

Hey guys, I am writing this article simply because I just discovered a cool dart package 📦 which can be used to create PDFs just like we paint a normal UI in Flutter using a widget hierarchy!

The package, along with some more, can be used to create some valid business use cases so here is what this article is going to include:

  • Writing all the code as a test
  • Reading an excel file in dart
  • Converting an image URL to a file (to embed in the PDF)
  • Creating a PDF file through dart
  • Writing basic Flutter-kind widgets inside PDF

The list of packages you will need:

Let’s code

Create a new Flutter application and add a new dart file in the test folder.

Add a main function and a test function inside the main

import 'package:flutter_test/flutter_test.dart';void main() {
test('PDF writing test', () async {
// your code goes here
});
}

We need to read an excel file and for that, the excel file should exist. Create an excel file with some values, I created something like this:

Save this excel in the root of your Flutter project in order to simplify the access of this file in your code.

Let’s read this excel in our code

var bytes = File.fromUri(Uri.parse('excelBook.xlsx')).readAsBytesSync();
var decoder = SpreadsheetDecoder.decodeBytes(bytes);
var table = decoder.tables['Sheet1'];
var values = table.rows[0];

The values variable now stores a list of the all the values in the first row. You can access it using indexes.

Before we jump to creating PDF, let us see how we are going to parse this image link into something that can be written to a pdf file.

Write this function outside the test body:

Future<Uint8List> _networkImageToByte(String url) async {
Uint8List byteImage = await networkImageToByte(url);
return byteImage;
}

The function networkImageToByte is from this library which returns a Uint8List.

Now, add this to the previous code:

var fileName = 'sample.png';
var outFile = File.fromUri(Uri.parse(fileName));
outFile.createSync();
outFile.writeAsBytesSync(await _networkImageToByte(values[3]));
final img = imageDecode.decodeImage(File(fileName).readAsBytesSync());

This piece of code will pick up the 4th value from the list of values and decode it in a form that is readable by the pdf widget hierarchy.

Let’s begin creating PDF widgets.

The PDF widgets are just like widgets we use in Flutter with some changes and limitations.

First, let’s add the converted image into a pdf image widget.

final image = PdfImage(
pdf.document,
image: img.data.buffer.asUint8List(),
width: img.width,
height: img.height,
);

Now we create a pdf document file and add a pdf page into it.

final Document pdf = Document();
pdf.addPage(Page(
pageFormat: PdfPageFormat(600, 400),
build: (Context context) {
return Column(children: [
Text('Hello World'),
Center(
child: SizedBox(
height: 100.0,
width: 100.0,
child: Image(image),
),
)
]); // Center
}));

Save the file in the project root directory.

final File file = File('example.pdf');
file.writeAsBytesSync(pdf.save());

The complete file will look something like this:

import 'dart:io';
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:image/image.dart' as imageDecode;
import 'package:spreadsheet_decoder/spreadsheet_decoder.dart';
import 'package:pdf/pdf.dart';
import 'package:network_image_to_byte/network_image_to_byte.dart';
import 'package:pdf/widgets.dart';

void main() {

Future<Uint8List> _networkImageToByte(String url) async {
Uint8List byteImage = await networkImageToByte(url);
return byteImage;
}

test('PDF writing test', () async {

var bytes = File.fromUri(Uri.parse('excelBook.xlsx')).readAsBytesSync();
var decoder = SpreadsheetDecoder.decodeBytes(bytes);
var table = decoder.tables['Sheet1'];
var values = table.rows[0];

var fileName = 'sample.png';
var outFile = File.fromUri(Uri.parse(fileName));
outFile.createSync();
outFile.writeAsBytesSync(await _networkImageToByte(values[3]));
final img = imageDecode.decodeImage(File(fileName).readAsBytesSync());

final Document pdf = Document();
final image = PdfImage(
pdf.document,
image: img.data.buffer.asUint8List(),
width: img.width,
height: img.height,
);

pdf.addPage(Page(
pageFormat: PdfPageFormat(600, 400),
build: (Context context) {
return Column(children: [
Text('Hello World'),
Center(
child: SizedBox(
height: 100.0,
width: 100.0,
child: Image(image),
),
)
]); // Center
}));

final File file = File('example.pdf');
file.writeAsBytesSync(pdf.save());
});
}

The pdf package might not have exact widgets like we have in Flutter, eg. I was unable to paint a ListTile for pdf. But you can create a lot of stuff using the widgets available and for the pdf the use cases won’t be so complex so it’s a good start to create PDFs right from your dart code.

Happy coding!

--

--

Waleed Arshad
CodeChai
Writer for

Writer || Tech philosophy || Senior Flutter Engineer || Google Developer Expert