layoutPdf method
Future<bool>
layoutPdf(
- Printer? printer,
- LayoutCallback onLayout,
- String name,
- PdfPageFormat format,
- bool dynamicLayout,
- bool usePrinterSettings,
- OutputType outputType,
- bool forceCustomPrintPaper,
Prints a Pdf document to a local printer using the platform UI the Pdf document is re-built in a LayoutCallback each time the user changes a setting like the page format or orientation.
returns a future with a bool
set to true if the document is printed
and false if it is canceled.
throws an exception in case of error
Implementation
@override
Future<bool> layoutPdf(
Printer? printer,
LayoutCallback onLayout,
String name,
PdfPageFormat format,
bool dynamicLayout,
bool usePrinterSettings,
OutputType outputType,
bool forceCustomPrintPaper,
) async {
late Uint8List result;
try {
result = await onLayout(format);
} catch (e, s) {
InformationCollector? collector;
assert(() {
collector = () sync* {
yield StringProperty('PageFormat', format.toString());
};
return true;
}());
FlutterError.reportError(
FlutterErrorDetails(
exception: e,
stack: s,
stackFilter: (input) => input,
library: 'printing',
context: ErrorDescription('while generating a PDF'),
informationCollector: collector,
),
);
rethrow;
}
if (result.isEmpty) {
return false;
}
// UserAgent can contain both Chrome and Safari for Chrome browser.
// UserAgent contains only Safari for Safari browser.
final userAgent = web.window.navigator.userAgent;
final isChrome = userAgent.contains('Chrome');
final isSafari = userAgent.contains('Safari') && !isChrome;
final isFirefox = userAgent.contains('Firefox');
final isMobile = userAgent.contains('Mobile');
// Chrome, Safari, and Firefox on a desktop computer
if ((isChrome || isSafari || isFirefox) && !isMobile) {
final completer = Completer<bool>();
final pdfFile = web.Blob(
[result.toJS].toJS,
web.BlobPropertyBag(type: 'application/pdf'),
);
final pdfUrl = web.URL.createObjectURL(pdfFile);
final doc = web.window.document;
final script =
doc.getElementById(_scriptId) ?? doc.createElement('script');
script.setAttribute('id', _scriptId);
script.setAttribute('type', 'text/javascript');
script.innerHTML =
'''function ${_frameId}_print(){var f=document.getElementById('$_frameId');f.focus();f.contentWindow.print();}'''
.toJS;
doc.body!.append(script);
final frame = doc.getElementById(_frameId) ?? doc.createElement('iframe');
if (isFirefox) {
// Set the iframe to be is visible on the page (guaranteed by fixed position) but hidden using opacity 0, because
// this works in Firefox. The height needs to be sufficient for some part of the document other than the PDF
// viewer's toolbar to be visible in the page
frame.setAttribute(
'style',
'width: 1px; height: 100px; position: fixed; left: 0; top: 0; opacity: 0; border-width: 0; margin: 0; padding: 0',
);
} else {
// Hide the iframe in other browsers
frame.setAttribute(
'style',
'visibility: hidden; height: 0; width: 0; position: absolute;',
// 'height: 400px; width: 600px; position: absolute; z-index: 1000',
);
}
frame.setAttribute('id', _frameId);
frame.setAttribute('src', pdfUrl);
final stopWatch = Stopwatch();
web.EventListener? load;
load = (web.Event event) {
frame.removeEventListener('load', load);
Timer(Duration(milliseconds: isSafari ? 500 : 0), () {
try {
stopWatch.start();
web.window.callMethod('${_frameId}_print'.toJS);
stopWatch.stop();
completer.complete(true);
} catch (e) {
assert(() {
// ignore: avoid_print
print('Error: $e');
return true;
}());
completer.complete(_getPdf(result));
}
});
}.toJS;
frame.addEventListener('load', load);
doc.body!.append(frame);
final res = await completer.future;
// If print() is synchronous
if (stopWatch.elapsedMilliseconds > 1000) {
frame.remove();
script.remove();
}
return res;
}
return _getPdf(result);
}