flutterdartpdfflutter-dependenciesdart-pub

Issue Sharing Images from Multi-Page PDF in Flutter


I'm developing a Flutter app where I need to convert a multi-page PDF into images and then share these images. I'm using the pdf_image_renderer package for rendering the PDF pages to images and share_plus for sharing. However, I'm encountering an issue where, despite having multiple pages in the PDF, only the first page's image is shared twice.

convertPdfToImages: This function should convert each page of a PDF into an image, but it's currently sharing images of only the first page.

import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf_image_renderer/pdf_image_renderer.dart' as pdf_renderer;
import 'package:share_plus/share_plus.dart';

Future<List<XFile>> convertPdfToImages(Uint8List pdfBytes, String title) async {
  final pdfFile = File('${(await getTemporaryDirectory()).path}/temp.pdf');
  await pdfFile.writeAsBytes(pdfBytes);

  final pdfDocument = pdf_renderer.PdfImageRendererPdf(path: pdfFile.path);
  await pdfDocument.open();

  final pageCount = await pdfDocument.getPageCount();
  final List<XFile> imageFiles = [];

  for (int i = 0; i < pageCount; i++) {
    try {
      final size = await pdfDocument.getPageSize(pageIndex: i);
      final pdfImage = await pdfDocument.renderPage(
        x: 0,
        y: 0,
        width: size.width.toInt(),
        height: size.height.toInt(),
        scale: 1.0,
        background: Colors.transparent,
      );

      if (pdfImage != null) {
        final imageFile = File('${(await getTemporaryDirectory()).path}/${title}_page_${i + 1}.png');
        await imageFile.writeAsBytes(pdfImage);

        imageFiles.add(XFile(imageFile.path));
      } else {
        print('Failed to render page $i');
      }
    } catch (e) {
      print('Error processing page $i: $e');
    }
  }

  await pdfDocument.close();
  pdfFile.delete();

  return imageFiles;
}

shareAsImages: This function calls convertPdfToImages and then shares the images.

Future<void> shareAsImages(Map<String, dynamic> data) async {
  final pdfBytes = await _generatePdf(data);
  final imageFiles = await convertPdfToImages(pdfBytes, data['title']);

  await Share.shareXFiles(
    imageFiles,
    text: 'Created using: ${constants.CommonUrls.appPlaystoreUrl}',
  );
}

_generatePdf: This function generates a multi-page PDF. Here's a simplified version:

import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;

Future<Uint8List> _generatePdf(Map<String, dynamic> data) async {
  final pdf = pw.Document();

  pdf.addPage(
    pw.MultiPage(
      build: (pw.Context context) {
        return [
          pw.Text('${data['title']}', style: pw.TextStyle(fontSize: 24, fontWeight: pw.FontWeight.bold)),
          pw.SizedBox(height: 16),
          pw.Text('Course: ${data['course']}'),
          pw.Text('Category: ${data['category']}'),
          pw.Text('Serving Size: ${data['serveSize']}'),
          pw.Text('Preparation Time: ${data['prepTime']}'),
          pw.Text('Cooking Time: ${data['cookingTime']}'),
          if (data['rating'] != null && double.tryParse(data['rating'].toString()) != 0.0) ...[
            pw.Text('Rating: ${data['rating']}'),
          ],
          pw.Text('Source: ${data['source']}'),
          pw.SizedBox(height: 16),
          pw.Text('Ingredients:', style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)),
          pw.Text(data['ingredients'] ?? ''),
          pw.SizedBox(height: 16),
          pw.Text('Instructions:', style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)),
          pw.Text(data['instructions'] ?? ''),
          if (data['notes'] != null && data['notes'].isNotEmpty) ...[
            pw.SizedBox(height: 16),
            pw.Text('Notes:', style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)),
            pw.Text(data['notes'] ?? ''),
          ],
          if (data['nutrition']['show'] == true && data['nutrition'].entries.any((e) => e.value != null && e.value.isNotEmpty)) ...[
            pw.SizedBox(height: 16),
            pw.Text('Nutrition Info:', style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)),
            pw.Text('Per Serve Size: ${data['nutrition']['serveSize'] ?? ''}'),
            pw.Text('Calories: ${data['nutrition']['calories'] ?? ''}'),
            pw.Text('Total Fat: ${data['nutrition']['totalFat'] ?? ''}'),
            pw.Text('Saturated Fat: ${data['nutrition']['saturatedFat'] ?? ''}'),
            pw.Text('Cholesterol: ${data['nutrition']['cholesterol'] ?? ''}'),
            pw.Text('Sodium: ${data['nutrition']['sodium'] ?? ''}'),
            pw.Text('Total Carbohydrate: ${data['nutrition']['totalCarbohydrate'] ?? ''}'),
            pw.Text('Dietary Fiber: ${data['nutrition']['dietaryFiber'] ?? ''}'),
            pw.Text('Sugars: ${data['nutrition']['sugars'] ?? ''}'),
            pw.Text('Protein: ${data['nutrition']['protein'] ?? ''}'),
          ],
        ];
      },
    ),
  );

  return pdf.save();
}

Issue: Despite having multiple pages in the PDF, the convertPdfToImages function is currently sharing only the first page's image twice and missing the second page.

enter image description here


Solution

  • Actually I was missing pageIndex: i,

    final pdfImage = await pdfDocument.renderPage(
            pageIndex: i, // This Line
            x: 0,
            y: 0,
            width: size.width.toInt(),
            height: size.height.toInt(),
            scale: 1.0,
            background: Colors.transparent,
          );