Reputation: 415
I did some research and find out that you can create PDF with images or texts or by exporting the screenshot, but I want to create much more like in the image below:
So what I want to achieve is to have a good resolution for PDF to print the PDF as a book after this. The physical book has a lot of pages and my client wants to create the virtual one.
So, I have the design (as you can see in the image), but I still need to create some text fields, signature and some logic in the widget. How can I export after that to a one page PDF for every widget? Screenshot won't be enough because I think it doesn't have a good quality and ofc the text and everything else won't be suited in the phone screen.
I am thinking to use the basic design and to add manually by code the texts, but I don't know how to export this to a PDF after that.
Upvotes: 3
Views: 10414
Reputation: 683
I had problem in Flutter to generate pdf
from a widget
If anyone wants to
generate pdf
, image on pdf
, custom font
, download pdf
and display pdf
.
I share my work here to help someone.
First install these 3 packages
pdf: ^3.10.7
path_provider: ^2.1.2
open_file: ^3.3.2
You may add some below permissions
ios (info.plist)
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
android (AndroidManifest.xml)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
You must import below in your Class
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:flutter/services.dart' show rootBundle;
Below is my download function
void _printScreen(statement) async {
final Directory? directory;
final ByteData fontData =
await rootBundle.load('assets/fonts/Outfit/static/Outfit-Regular.ttf');
final ttf = pw.Font.ttf(fontData.buffer.asByteData());
final image = pw.MemoryImage(
(await rootBundle.load('assets/images/logo_text.png'))
.buffer
.asUint8List(),
);
try {
final doc = pw.Document();
doc.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.ListView(
children: [
pw.Container(
padding: pw.EdgeInsets.fromLTRB(10, 0, 10, 0),
child: pw.Column(
mainAxisAlignment: pw.MainAxisAlignment.start,
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Image(
image,
width: 120,
fit: pw.BoxFit.contain,
),
pw.SizedBox(height: 50),
pw.Text(
"${widget.statement.name}",
style: pw.TextStyle(font: ttf),
),
pw.Text(
"${widget.statement.phone}",
style: pw.TextStyle(font: ttf),
),
pw.Text(
"${widget.statement.email}",
style: pw.TextStyle(font: ttf),
),
pw.SizedBox(height: 50),
pw.Row(
children: [
pw.Text(
"${widget.statement.month}",
style: pw.TextStyle(
fontWeight: pw.FontWeight.bold,
font: ttf,
fontSize: 20),
),
pw.SizedBox(width: 10),
pw.Text(
"${widget.statement.year}",
style: pw.TextStyle(
fontWeight: pw.FontWeight.bold,
font: ttf,
fontSize: 20),
),
],
),
pw.Text(
"Monthly statement",
style: pw.TextStyle(
font: ttf,
color: PdfColor.fromInt(Colors.grey.value),
),
),
pw.SizedBox(height: 30),
pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
children: [
pw.Text(
"TOTAL EARNINGS",
style: pw.TextStyle(
font: ttf,
color: PdfColor.fromInt(Colors.grey.value),
fontSize: 30,
fontWeight: pw.FontWeight.bold),
),
pw.Text(
"\$${widget.statement.totalEarning}",
style: pw.TextStyle(
font: ttf,
fontSize: 30,
fontWeight: pw.FontWeight.bold),
),
],
),
pw.SizedBox(height: 50),
pw.Text(
"Earnings breakdown",
style: pw.TextStyle(
font: ttf,
fontSize: 22,
fontWeight: pw.FontWeight.bold,
decoration: pw.TextDecoration.underline,
),
),
pw.SizedBox(height: 30),
pw.Row(
children: [
pw.SizedBox(
width: 120,
child: pw.Text(
"Moving cost",
style: pw.TextStyle(font: ttf),
)),
pw.Text("\$${widget.statement.movingCost}"),
],
),
pw.Row(
children: [
pw.SizedBox(
width: 120,
child: pw.Text(
"Travel cost",
style: pw.TextStyle(font: ttf),
)),
pw.Text("\$${widget.statement.travelCost}"),
],
),
pw.Row(
children: [
pw.SizedBox(
width: 120,
child: pw.Text(
"Service fee",
style: pw.TextStyle(font: ttf),
)),
pw.Text("\$${widget.statement.serviceFee}"),
],
),
pw.Row(
children: [
pw.SizedBox(
width: 120,
child: pw.Text(
"GST",
style: pw.TextStyle(font: ttf),
)),
pw.Text("\$${widget.statement.gst}"),
],
),
pw.Row(
children: [
pw.SizedBox(
width: 120,
child: pw.Text(
"Tips",
style: pw.TextStyle(font: ttf),
)),
pw.Text("\$${widget.statement.tips}"),
],
),
pw.Row(
children: [
pw.SizedBox(
width: 120,
child: pw.Text(
"Refunds",
style: pw.TextStyle(font: ttf),
)),
pw.Text("\$${widget.statement.refund}"),
],
),
pw.SizedBox(height: 50),
pw.Text(
"Total number of jobs completed for the month ${widget.statement.numberOfJobs}",
style: pw.TextStyle(font: ttf),
),
pw.SizedBox(height: 80),
pw.Text(
"THIS IS NOT AN OFFICIAL INVOICE OR TAX DOCUMENT",
style: pw.TextStyle(
font: ttf,
fontSize: 20,
color: PdfColor.fromInt(Colors.grey.value),
),
),
],
),
),
],
);
}));
if (Platform.isIOS) {
directory = await getApplicationDocumentsDirectory();
} else {
directory = await getDownloadsDirectory();
}
if (directory == null) {
CustomSnackbar.showBottom(context, "Document directory not available");
return;
}
String path = directory.path;
String myFile =
'${path}/Tingsapp-statement-${statement.month}-${statement.year}.pdf';
final file = File(myFile);
await file.writeAsBytes(await doc.save());
OpenFile.open(myFile);
} catch (e) {
debugPrint("$e");
CustomSnackbar.showBottom(context, "$e");
}
}
I hope this help someone.
Upvotes: 1