dart_pdf icon indicating copy to clipboard operation
dart_pdf copied to clipboard

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

Open c-seeger opened this issue 2 years ago • 11 comments
trafficstars

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 avatar Nov 19 '23 12:11 c-seeger

@DavBfr any ideas?

c-seeger avatar Nov 20 '23 09:11 c-seeger

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

DavBfr avatar Nov 20 '23 10:11 DavBfr

@DavBfr any ideas?

Try to read this. Maybe it will helps.

bambinoua avatar Nov 21 '23 08:11 bambinoua

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 avatar Nov 21 '23 08:11 c-seeger

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

c-seeger avatar Nov 21 '23 08:11 c-seeger

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

DavBfr avatar Nov 21 '23 11:11 DavBfr

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.

c-seeger avatar Nov 29 '23 08:11 c-seeger

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...) ?

savs90 avatar Dec 13 '23 15:12 savs90

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

jpohhhh avatar Jan 04 '24 18:01 jpohhhh

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();
}

james-majormap avatar Jun 14 '24 01:06 james-majormap