DavBfr / dart_pdf

Pdf creation module for dart/flutter
https://pub.dev/packages/pdf
Apache License 2.0
1.38k stars 612 forks source link

Is there a way to make pdf.save non blocking on web? #1528

Open c-seeger opened 9 months ago

c-seeger commented 9 months ago

I'm currently building a large pdf with this library but when saving and downloading, it blocks the main thread.

On mobile I can use Isolates but this will not work on web. Any suggestions here or someone that solved this already?

here is some example code:

import 'package:pdf/pdf.dart';
import 'package:printing/printing.dart';
import 'pdfdata.dart';
...

Future<void> generatePDF(
    BuildContext context, List<PDFData> dataList) async {
  final pw.Document pdf = pw.Document();
  try {
    for (final PDFData data in dataList) {
      await generatePDFPages(context, data, pdf);
    }
    await Printing.sharePdf(bytes: await pdf.save(), filename: 'qr-code.pdf');
  } catch (e) {
    throw Exception('pdf generation error');
  }
}

Future<void> generatedPDFPages(BuildContext context, PDFData data) async {
  pdf.addPage(....)
}
c-seeger commented 9 months ago

@DavBfr any ideas?

DavBfr commented 9 months ago

There is no isolates on web, so I have no solution. This code is 100% Dart so it runs on the main thread.

bambinoua commented 9 months ago

@DavBfr any ideas?

Try to read this. Maybe it will helps.

c-seeger commented 9 months ago

yeah there is a still open issue for this. If i find some time I will try to use web workers + dart2js to simulate isolation on web.

c-seeger commented 9 months ago

maybe WASM support could also work (at least for newer browsers)

DavBfr commented 9 months ago

Or maybe https://pub.dev/packages/isolated_worker

c-seeger commented 8 months ago

The main issue here is not the isolation itself since web worker can do this. The critical part is the pdf library is written in dart but web worker needs js/wasm code to run so we need to do either dart2js so web worker can use the pdf library or dart2wasm to run wasm code in web worker instead. Will check once I find some time for this issue.

savs90 commented 8 months ago

Is it possible to create a stream to which to subscribe that returns the pdf data the moment you manipulate the pdf (add page, text images, etc...) ?

jpohhhh commented 7 months ago

I can't recommend Squadron highly enough, and it should be ~perfect for this --

only issue you can run into is if you import Flutter UI code, and thus can't dart2js it, but as we see above on Nov 20th, code is 100% Dart.

(I'm actually here because syncfusion_pdf touches Flutter UI code so I can't dart2js it, and I'm trolling through the repo to triple check if there's PDF -> text parsing code. Don't use the attached examples directly because they use SyncFusion, but it's enough for you to see what I've arrived at for best practice.)

Squadron: https://pub.dev/packages/squadron generate_js_script.txt pdf_parser_service.dart.txt

james-majormap commented 2 months ago

How about add pagePostProcessDoneCallback option to document.save()? ('package:pdf/widgets.dart')

It still block main thread, but has chance to make UI feedback (e.g. page processed progress)

I have extended Document class, and it seems below.

@override
Future<Uint8List> save({Function? pagePostProcessDoneCallback}) async {
  if (!_paint) {
    for (final page in _pages) {
      page.postProcess(this);
      if (pagePostProcessDoneCallback != null) {
        await Future.delayed(const Duration(milliseconds: 5));
        pagePostProcessDoneCallback.call();
      }
    }
    _paint = true;
  }
  return await document.save();
}