How to preview pdf in Scaffold - Flutter - flutter

I'm using the flutter pdf producer package and I'm trying to preview or display it in the scaffold but so far unable to do it
package link : https://pub.dev/packages/pdf
here is my code
class _PreviewInvoiceState extends State<PreviewInvoice> {
// pdf producer
void makePdf(){
final document = pw.Document();
document.addPage(
pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Center(child: pw.Text('hello world'));
}
)
);
}
#override
Widget build(BuildContext context) {
return Scaffold(); // trying to display it in the scaffold body property
}
}

The pdf package is for creating pdf. To view it you have to save it to storage with
// On Flutter, use the [path_provider](https://pub.dev/packages/path_provider) library:
// final output = await getTemporaryDirectory();
// final file = File("${output.path}/example.pdf");
final file = File("example.pdf");
await file.writeAsBytes(await pdf.save());
And to view you have to use package like pdf_viewer_flutter.

Related

How to load image from assets folder inside a pdf in Flutter web?

We want to show image on a pdf from assets folder in Flutter web application:
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:flutter/material.dart';
.............
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
height: 400,
width: 900,
child: PdfPreview(
build: (format) => _generatePdf(format, "SOME TITLE"),
)),
),
]));
}
Future<Uint8List> _generatePdf(PdfPageFormat format) async {
final pdf = pw.Document();
pdf.addPage(
pw.Page(
pageFormat: format,
build: (context) {
return pw.Image(AssetImage('assets/imglogo.png')); //This line gives the error
}));
return pdf.save();
}
This code gives error:
The argument type 'AssetImage' can't be assigned to the parameter type 'ImageProvider'
The documentation addresses only two cases To load an image from a file:(dart.io is not supported on the web), and To load an image from the network using the printing package:, which is not the case, so we tried the solutions provided here: 1,2, but each one gives a different exception.
Is there another approach to achieve this?
You can convert your ByteData directly to Uint8List as shown in the example code below. This can then be passed to the MemoryImage constructor:
Future<void> addPage(pw.Document pdf, String filename) async {
final imageByteData = await rootBundle.load('assets/$filename');
// Convert ByteData to Uint8List
final imageUint8List = imageByteData.buffer
.asUint8List(imageByteData.offsetInBytes, imageByteData.lengthInBytes);
final image = pw.MemoryImage(imageUint8List);
pdf.addPage(
pw.Page(
build: (pw.Context context) {
return pw.Center(
child: pw.Image(image),
); // Center
},
),
);
}
To achieve this you can get the asset image as a file, and then use this file in the PDF. If I take your code, we can add a function to get a File representation of your asset image :
Future<File> getImageFileFromAssets(String path) async {
final byteData = await rootBundle.load('assets/$path');
final file = File('${(await getTemporaryDirectory()).path}/$path');
await file.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
To make it works, you need to add path_provider to your dependencies.
Then you can use this function in your pdf generation function :
final pdf = pw.Document();
final file = await getImageFileFromAssets(yourpath);
final image = pw.MemoryImage(
file.readAsBytesSync(),
);
pdf.addPage(pw.Page(
pageFormat: format,
build: (context) {
return pw.Image(image);
}));
return pdf.save();

About PDF file opening and downloading flutter web in web hosting

I am trying to generate Pdf in flutter with pdf package in flutter Web.
while doing so I found a solution for flutter web with this code ..
Uint8List bytes = await pdf.save() ;
final blob = html.Blob([bytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
html.window.open(url, "_blank");
html.Url.revokeObjectUrl(url);
this code worked fine in local host but is not running in web hosting . please help
My first answer was deleted, so I'll repost it.
To download files look this one:
https://stackoverflow.com/a/60614367/18386517.
If you want to just open PDFs files inside your app try the pdfx package. Here is an example:
import 'dart:async';
import 'dart:typed_data';
import 'package:pdfx/pdfx.dart';
import 'package:flutter/material.dart';
class PdfLabPage extends StatefulWidget {
final String name;
final FutureOr<Uint8List> content;
const PdfLabPage({Key? key, required this.name, required this.content}) : super(key: key);
#override
State<PdfLabPage> createState() => _PdfLabPageState();
}
class _PdfLabPageState extends State<PdfLabPage> {
late PdfControllerPinch pdfController;
#override
void initState() {
pdfController = PdfControllerPinch(
document: PdfDocument.openData(widget.content)
);
super.initState();
}
#override
void dispose() {
pdfController.dispose();
super.dispose();
}
Widget pdfView() => PdfViewPinch(
controller: pdfController ,
onDocumentLoaded: (msg) {print(msg.toString());},
onDocumentError: (error) { print(error.toString());}
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.name),
),
body:
Center(
child: pdfView(),
),
);
}
}
I got the content of the PDF file from the web using:
var url = "..."
final file = await http.get(Uri.parse(url));
final content = file.bodyBytes;
But you can load from assets (Android, Ios, MacOs, Web):
final document = await PdfDocument.openAsset('assets/sample.pdf')
From file (Android, Ios, MacOs):
final document = await PdfDocument.openFile('path/to/file/on/device')
From data (Android, Ios, MacOs, Web):
final document = await PdfDocument.openData((FutureOr<Uint8List>) data)

How to create multi pages pdf in flutter with images?

I have a list of file image paths. I need to create pdf from these images. How can I do it? I already know how to create pdf from a single image using pdf package.
Replace Page widget with MultiPage widget, default max pages is 20.
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart';
final pdf = Document();
pdf.addPage(
MultiPage(
pageFormat: PdfPageFormat.a4,
build: (Context context) => <Widget>[*/your widgets here*/],
)
)
Check out pdf library. The documentation contains example codes which will let you create a pdf file with multiple pages with images inside.
final image = PdfImage.file(
pdf.document,
bytes: File('test.webp').readAsBytesSync(),
);
final pdf = pw.Document();
final image = PdfImage.file(
pdf.document,
bytes: File('test.webp').readAsBytesSync(),
);
pdf.addPage(pw.Page(
build: (pw.Context context) {
return pw.Center(
child: pw.Image(image),
); // Center
})); // Page
final file = File("example.pdf");
await file.writeAsBytes(pdf.save());

PDF File generation with Flutter web

I'm in the process of Web'ifing a Flutter mobile application and attempting to get around the lack for support for Path Provider in Web.
I'm using the PDF (pdf: ^1.9.0) package to generate a PDF document and upload it to Google Drive and I'm trying to find out if I can generate and store the PDF In memory to make it web compatible.
Example current code using Path Provider.
createFile() async {
final downloads = await getApplicationSupportDirectory();
final file = File("${downloads.path}/$filename.pdf");
await file.writeAsBytes(pdf.save());
await GoogleDriveController.uploadFileToGoogleDrive(file.path);
}
Question: Is there a way to generate and store Fies in memory for web using Flutter web?
I managed to find a work around to generate the PDF and trigger a download via the browser instead and thought I should post incase anyone stumbles across this.
//Create PDF in Bytes
Uint8List pdfInBytes = pdf.save();
//Create blob and link from bytes
final blob = html.Blob([pdfInBytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
final anchor = html.document.createElement('a') as html.AnchorElement
..href = url
..style.display = 'none'
..download = 'pdf.pdf';
html.document.body.children.add(anchor);
//Trigger the download of this PDF in the browser.
RaisedButton(
child: Text('Press'),
onPressed: () {
anchor.click();
Navigator.pop(context);
},
)
My answer is a variant on Yonkee above specifically for flutter web. In this answer, I have added the imports required (dart:html and dart:typed_data) and added formatting of text as I needed that feature.
import 'package:flutter/material.dart';
import 'package:pdf/widgets.dart' as pw;
import 'dart:typed_data';
import 'dart:html' as html;
class PDFSave extends StatefulWidget {
#override
_PDFSaveState createState() => _PDFSaveState();
}
class _PDFSaveState extends State<PDFSave> {
final pdf = pw.Document();
var anchor;
savePDF() async {
Uint8List pdfInBytes = await pdf.save();
final blob = html.Blob([pdfInBytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
anchor = html.document.createElement('a') as html.AnchorElement
..href = url
..style.display = 'none'
..download = 'pdf.pdf';
html.document.body.children.add(anchor);
}
createPDF() async {
pdf.addPage(
pw.Page(
build: (pw.Context context) => pw.Column(
children: [
pw.Text('Hello World', style: pw.TextStyle(fontSize: 40)),
],
),
),
);
savePDF();
}
#override
void initState() {
super.initState();
createPDF();
}
#override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('PDF Creator'),
),
body: Center(
child:RaisedButton(
child: Text('Press'),
onPressed: () {
anchor.click();
Navigator.pop(context);
},
)
));
}
}

Is there a way to detect touch in pdf using flutter?

I'm using dart pdf library and I want to detect touch on screen while the pdf is being viewed. Is there a way to do that? For viewing the pdf file I'm using a PDFViewerScaffold with the created file's path. I tried wrapping the PDFViewerScaffold with Listener and GestureDetector, but no luck.
My code so far:
Viewing the pdf file:
class PdfViewerPage extends StatelessWidget {
final String path;
const PdfViewerPage({Key key, this.path}) : super(key: key);
#override
Widget build(BuildContext context) {
return PDFViewerScaffold(
path: path,
);
}
}
Making the pdf file:
final Document pdf = Document();
...
pdf.addPage(MultiPage(
pageFormat:
...
footer: (Context context) {
...
},
build: (Context context) => <Widget>[
...
...
Any help would be appreciated!
I had the same problem a while back, FlutterFullPdfViewer uses native component and encapsulate it in a FrameLayout(in android) that can only be manipulated through native code.
What I did is that I forked the project, and added my own implementation.
In the android part you have a method called in FlutterFullPdfViewerManager.java :
void openPDF(String path) {
File file = new File(path);
pdfView.fromFile(file)
.enableSwipe(true)
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
.load();
}
You can change this to:
void openPDF(String path) {
File file = new File(path);
pdfView.fromFile(file)
.enableSwipe(true)
.swipeHorizontal(false)
.enableDoubletap(true)
.onTap(e-> {
if (e.getRawX() > 300) {//put your value here
//send rebuild instruction to flutter
}
.defaultPage(0)
.load();
}
Or something along these lines, you will also find that there is a lot of extra stuff that you can do on pdfView that could be helpful to you.