Save a PDF document into your iPhone/Android Photo Gallery in your Flutter app

Yuichi Fujiki
4 min readOct 14, 2023
Photo by Bank Phrom on Unsplash

Recently, I had this rather niche requirement from our client. It was mostly straightforward thanks to the well-tested libraries, with a slight caveat.

What we want to do

In my example, I display the multi-page PDF document on the screen and let users save each page as a high-resolution PNG. Final outcome looks like this :

Meet pdf_render and image_gallery_saver

We use two third-party libraries.

  1. pdf_render. This supports PDF handling in general. It offers the PDF viewer as well, but also offers other PDF manipulation like iterating through pages and converting into PNG. In this example, I am showing the preview using the library, but you can skip that part without a problem.

2. image_gallery_saver. It offers what the name suggests. It allows us to save images into iPhone/Android devices’ Photos app.

Step 1: Download a PDF file and create a PdfDocument object

In this example, we download the US tax form published on IRS website.

Future<PdfDocument> loadPdf() async {
const pdfUrl = 'https://www.irs.gov/pub/irs-pdf/fw4.pdf';

// Fetch the PDF from the URL.
final pdfResponse = await http.get(Uri.parse(pdfUrl));

// Get the temporary file path to save the PDF into.
final pdfPath = await tempPdfPath();

// Write the downloaded PDF into the file
pdfFile = File(pdfPath);
pdfFile?.writeAsBytesSync(pdfResponse.bodyBytes);

// Return PdfDocument instance
pdfDocument = await PdfDocument.openFile(pdfPath);
if (pdfDocument == null) {
throw Exception('Unable to open PDF');
}
return pdfDocument!;
}

Step 2: Iterate through pages of the PdfDocument and save each page into the photo gallery.

Each page of PdfDocument is aPdfPage . From aPdfPage , you can create a PdfPageImage and further convert it into a ui.Image format. ui.Image object is a dart generic image type and can be converted into binary.

Once we get a binary representation of each page, we can save it into the photo gallery using image_gallery_saver.

Below is the code:

void savePdfToGallery() async {
for (int i = 1; i <= pdfDocument!.pageCount; i++) {
// 1. Get PdfPage
PdfPage page = await pdfDocument!.getPage(i);

// Converting PDF points into pixels for printing.
// https://www.gdpicture.com/guides/gdpicture/About%20a%20PDF%20format.html#:~:text=In%20PDF%20documents%2C%20everything%20is,for%20DIN%20A4%20page%20size.
// 1 point = 1/72 inch
// 72 points per inch
// https://printninja.com/printing-resource-center/printninja-file-setup-checklist/offset-printing-guidelines/recommended-resolution/
// 300 dpi = 300 pixels per inch
final width = (page.width * 300 / 72).ceil();
final height = (page.height * 300 / 72).ceil();

// 2. PdfPage => PdfPageImage
PdfPageImage pagePdfImage = await page.render(
width: width, height: height, allowAntialiasingIOS: true);

// 3. PdfPageImage => ui.Image
ui.Image pageImage = await pagePdfImage.createImageDetached();

// 4. ui.Image => PNG binary representation
ByteData? imageBytes =
await pageImage.toByteData(format: ui.ImageByteFormat.png);

if (imageBytes != null) {
// 5. Save the binary into the photo gallery
final result = await ImageGallerySaver.saveImage(
imageBytes.buffer.asUint8List(),
quality: 100,
name: 'page_${i}_${DateTime.now().millisecondsSinceEpoch}');
}
}
}

The caveat is the part where we define the width/height of the PdfPageImage .

According to my reference, the PDF’s width and height are not in pixels, but in its own unit called points. And since PDF concerns being printed on physical paper, the unit is closely related to the physical length (1 point = 1/72 inches) So, when you see 611x791 as below, it means it would show up on printed media in 8.5inch x 11inch , which is approximately the US letter size.

When we convert PDF into digital image data, we need to convert these point units into our familiar pixel units. Again, according to my reference, the industry standard for high resolution is 300 ppi (pixels per inch). Then, we need to multiply 300 by the 8.5inch x 11inch to get our favorable pixels. (2546px x 3296px in this case)

So, that should explain my width/height calculation in the sample code and the rest should be quite trivial.

Conclusion

In this article, I have demonstrated how easy it is to save each page of a PDF document into an iPhone/Android Photos app using Flutter code. On the way, I gained interesting knowledge about the “size” of PDF and how it correlates with the size of raster digital images.

Hope you had fun reading this :)

As usual, the sample code is in GitHub:

--

--

Yuichi Fujiki

Technical director, Freelance developer, a Dad, a Quadriplegic, Life of Rehab