David PHAM-VAN

Implement asynchronous printing

1 # 1.2.0 1 # 1.2.0
2 * Fix compileSdkVersion to match appcompat 2 * Fix compileSdkVersion to match appcompat
3 * Change license to Apache 2.0 3 * Change license to Apache 2.0
  4 +* Implement asynchronous printing driven by the OS
4 5
5 # 1.1.0 6 # 1.1.0
6 * Rename classes to satisfy Dart conventions 7 * Rename classes to satisfy Dart conventions
@@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
16 16
17 package net.nfet.flutter.printing; 17 package net.nfet.flutter.printing;
18 18
  19 +import static java.lang.StrictMath.max;
  20 +
19 import android.app.Activity; 21 import android.app.Activity;
20 import android.content.Context; 22 import android.content.Context;
21 import android.content.Intent; 23 import android.content.Intent;
@@ -36,6 +38,7 @@ import java.io.File; @@ -36,6 +38,7 @@ import java.io.File;
36 import java.io.FileOutputStream; 38 import java.io.FileOutputStream;
37 import java.io.IOException; 39 import java.io.IOException;
38 import java.io.OutputStream; 40 import java.io.OutputStream;
  41 +import java.util.HashMap;
39 42
40 import io.flutter.plugin.common.MethodCall; 43 import io.flutter.plugin.common.MethodCall;
41 import io.flutter.plugin.common.MethodChannel; 44 import io.flutter.plugin.common.MethodChannel;
@@ -46,12 +49,18 @@ import io.flutter.plugin.common.PluginRegistry.Registrar; @@ -46,12 +49,18 @@ import io.flutter.plugin.common.PluginRegistry.Registrar;
46 /** 49 /**
47 * PrintingPlugin 50 * PrintingPlugin
48 */ 51 */
49 -public class PrintingPlugin implements MethodCallHandler { 52 +public class PrintingPlugin extends PrintDocumentAdapter implements MethodCallHandler {
50 private static PrintManager printManager; 53 private static PrintManager printManager;
51 private final Activity activity; 54 private final Activity activity;
  55 + private final MethodChannel channel;
  56 + private PrintedPdfDocument mPdfDocument;
  57 + private byte[] documentData;
  58 + private String jobName;
  59 + private LayoutResultCallback callback;
52 60
53 - private PrintingPlugin(Activity activity) { 61 + private PrintingPlugin(Activity activity, MethodChannel channel) {
54 this.activity = activity; 62 this.activity = activity;
  63 + this.channel = channel;
55 } 64 }
56 65
57 /** 66 /**
@@ -59,35 +68,13 @@ public class PrintingPlugin implements MethodCallHandler { @@ -59,35 +68,13 @@ public class PrintingPlugin implements MethodCallHandler {
59 */ 68 */
60 public static void registerWith(Registrar registrar) { 69 public static void registerWith(Registrar registrar) {
61 final MethodChannel channel = new MethodChannel(registrar.messenger(), "printing"); 70 final MethodChannel channel = new MethodChannel(registrar.messenger(), "printing");
62 - channel.setMethodCallHandler(new PrintingPlugin(registrar.activity())); 71 + channel.setMethodCallHandler(new PrintingPlugin(registrar.activity(), channel));
63 printManager = (PrintManager) registrar.activity().getSystemService(Context.PRINT_SERVICE); 72 printManager = (PrintManager) registrar.activity().getSystemService(Context.PRINT_SERVICE);
64 } 73 }
65 74
66 @Override 75 @Override
67 - public void onMethodCall(MethodCall call, Result result) {  
68 - switch (call.method) {  
69 - case "printPdf":  
70 - printPdf((byte[]) call.argument("doc"));  
71 - result.success(0);  
72 - break;  
73 - case "sharePdf":  
74 - sharePdf((byte[]) call.argument("doc"));  
75 - result.success(0);  
76 - break;  
77 - default:  
78 - result.notImplemented();  
79 - break;  
80 - }  
81 - }  
82 -  
83 - private void printPdf(final byte[] documentData) {  
84 - PrintDocumentAdapter pda = new PrintDocumentAdapter() {  
85 - PrintedPdfDocument mPdfDocument;  
86 -  
87 - @Override  
88 public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor parcelFileDescriptor, 76 public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor parcelFileDescriptor,
89 - CancellationSignal cancellationSignal,  
90 - WriteResultCallback writeResultCallback) { 77 + CancellationSignal cancellationSignal, WriteResultCallback writeResultCallback) {
91 OutputStream output = null; 78 OutputStream output = null;
92 try { 79 try {
93 output = new FileOutputStream(parcelFileDescriptor.getFileDescriptor()); 80 output = new FileOutputStream(parcelFileDescriptor.getFileDescriptor());
@@ -108,8 +95,7 @@ public class PrintingPlugin implements MethodCallHandler { @@ -108,8 +95,7 @@ public class PrintingPlugin implements MethodCallHandler {
108 95
109 @Override 96 @Override
110 public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, 97 public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
111 - CancellationSignal cancellationSignal, LayoutResultCallback callback,  
112 - Bundle extras) { 98 + CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
113 // Create a new PdfDocument with the requested page attributes 99 // Create a new PdfDocument with the requested page attributes
114 mPdfDocument = new PrintedPdfDocument(activity, newAttributes); 100 mPdfDocument = new PrintedPdfDocument(activity, newAttributes);
115 101
@@ -119,22 +105,60 @@ public class PrintingPlugin implements MethodCallHandler { @@ -119,22 +105,60 @@ public class PrintingPlugin implements MethodCallHandler {
119 return; 105 return;
120 } 106 }
121 107
  108 + this.callback = callback;
  109 +
  110 + HashMap<String, Double> args = new HashMap<>();
  111 +
  112 + PrintAttributes.MediaSize size = newAttributes.getMediaSize();
  113 + args.put("width", size.getWidthMils() * 72.0 / 1000.0);
  114 + args.put("height", size.getHeightMils() * 72.0 / 1000.0);
  115 +
  116 + PrintAttributes.Margins margins = newAttributes.getMinMargins();
  117 + args.put("marginLeft", margins.getLeftMils() * 72.0 / 1000.0);
  118 + args.put("marginTop", margins.getTopMils() * 72.0 / 1000.0);
  119 + args.put("marginRight", margins.getRightMils() * 72.0 / 1000.0);
  120 + args.put("marginBottom", margins.getBottomMils() * 72.0 / 1000.0);
  121 +
  122 + channel.invokeMethod("onLayout", args);
  123 + }
  124 +
  125 + @Override
  126 + public void onFinish() {
  127 + // noinspection ResultOfMethodCallIgnored
  128 + }
  129 +
  130 + @Override
  131 + public void onMethodCall(MethodCall call, Result result) {
  132 + switch (call.method) {
  133 + case "printPdf":
  134 + jobName =
  135 + call.argument("name") == null ? "Document" : (String) call.argument("name");
  136 + assert jobName != null;
  137 + printManager.print(jobName, this, null);
  138 + result.success(0);
  139 + break;
  140 + case "writePdf":
  141 + documentData = (byte[]) call.argument("doc");
  142 +
122 // Return print information to print framework 143 // Return print information to print framework
123 PrintDocumentInfo info = 144 PrintDocumentInfo info =
124 - new PrintDocumentInfo.Builder("document.pdf") 145 + new PrintDocumentInfo.Builder(jobName + ".pdf")
125 .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) 146 .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
126 .build(); 147 .build();
  148 +
127 // Content layout reflow is complete 149 // Content layout reflow is complete
128 callback.onLayoutFinished(info, true); 150 callback.onLayoutFinished(info, true);
129 - }  
130 151
131 - @Override  
132 - public void onFinish() {  
133 - // noinspection ResultOfMethodCallIgnored 152 + result.success(0);
  153 + break;
  154 + case "sharePdf":
  155 + sharePdf((byte[]) call.argument("doc"));
  156 + result.success(0);
  157 + break;
  158 + default:
  159 + result.notImplemented();
  160 + break;
134 } 161 }
135 - };  
136 - String jobName = "Document";  
137 - printManager.print(jobName, pda, null);  
138 } 162 }
139 163
140 private void sharePdf(byte[] data) { 164 private void sharePdf(byte[] data) {
@@ -25,8 +25,9 @@ class MyAppState extends State<MyApp> { @@ -25,8 +25,9 @@ class MyAppState extends State<MyApp> {
25 25
26 void _printPdf() async { 26 void _printPdf() async {
27 print("Print ..."); 27 print("Print ...");
28 - final pdf = await generateDocument(PdfPageFormat.a4);  
29 - Printing.printPdf(document: pdf); 28 + await Printing.layoutPdf(
  29 + onLayout: (PdfPageFormat format) async =>
  30 + (await generateDocument(format)).save());
30 } 31 }
31 32
32 void _sharePdf() async { 33 void _sharePdf() async {
@@ -46,16 +47,17 @@ class MyAppState extends State<MyApp> { @@ -46,16 +47,17 @@ class MyAppState extends State<MyApp> {
46 } 47 }
47 48
48 Future<void> _printScreen() async { 49 Future<void> _printScreen() async {
49 - final pdf = PdfDocument(deflate: zlib.encode);  
50 - final page = PdfPage(pdf, pageFormat: PdfPageFormat.a4);  
51 - final g = page.getGraphics();  
52 -  
53 RenderRepaintBoundary boundary = 50 RenderRepaintBoundary boundary =
54 previewContainer.currentContext.findRenderObject(); 51 previewContainer.currentContext.findRenderObject();
55 final im = await boundary.toImage(); 52 final im = await boundary.toImage();
56 final bytes = await im.toByteData(format: ImageByteFormat.rawRgba); 53 final bytes = await im.toByteData(format: ImageByteFormat.rawRgba);
57 print("Print Screen ${im.width}x${im.height} ..."); 54 print("Print Screen ${im.width}x${im.height} ...");
58 55
  56 + Printing.layoutPdf(onLayout: (PdfPageFormat format) {
  57 + final pdf = PdfDocument(deflate: zlib.encode);
  58 + final page = PdfPage(pdf, pageFormat: format);
  59 + final g = page.getGraphics();
  60 +
59 // Center the image 61 // Center the image
60 final w = page.pageFormat.width - 62 final w = page.pageFormat.width -
61 page.pageFormat.marginLeft - 63 page.pageFormat.marginLeft -
@@ -73,7 +75,9 @@ class MyAppState extends State<MyApp> { @@ -73,7 +75,9 @@ class MyAppState extends State<MyApp> {
73 } 75 }
74 76
75 PdfImage image = PdfImage(pdf, 77 PdfImage image = PdfImage(pdf,
76 - image: bytes.buffer.asUint8List(), width: im.width, height: im.height); 78 + image: bytes.buffer.asUint8List(),
  79 + width: im.width,
  80 + height: im.height);
77 g.drawImage( 81 g.drawImage(
78 image, 82 image,
79 page.pageFormat.marginLeft + (w - iw) / 2.0, 83 page.pageFormat.marginLeft + (w - iw) / 2.0,
@@ -84,7 +88,8 @@ class MyAppState extends State<MyApp> { @@ -84,7 +88,8 @@ class MyAppState extends State<MyApp> {
84 iw, 88 iw,
85 ih); 89 ih);
86 90
87 - Printing.printPdf(document: pdf); 91 + return pdf.save();
  92 + });
88 } 93 }
89 94
90 @override 95 @override
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +#import <Flutter/Flutter.h>
  18 +
  19 +@interface PdfPrintPageRenderer : UIPrintPageRenderer
  20 +
  21 +- (instancetype)init:(FlutterMethodChannel*)channel;
  22 +- (void)drawPageAtIndex:(NSInteger)pageIndex inRect:(CGRect)printableRect;
  23 +
  24 +@property(nonatomic, readonly) NSInteger numberOfPages;
  25 +@property(nonatomic, readonly) NSLock* lock;
  26 +@property(nonatomic) CGPDFDocumentRef pdfDocument;
  27 +@end
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +#import "PageRenderer.h"
  18 +
  19 +@implementation PdfPrintPageRenderer {
  20 + FlutterMethodChannel* channel;
  21 +}
  22 +
  23 +@synthesize lock;
  24 +@synthesize pdfDocument;
  25 +
  26 +- (instancetype)init:(FlutterMethodChannel*)channel {
  27 + self = [super init];
  28 + self->channel = channel;
  29 + self->lock = [[NSLock alloc] init];
  30 + self->pdfDocument = nil;
  31 + return self;
  32 +}
  33 +
  34 +- (NSInteger)numberOfPages {
  35 + NSNumber* width = [[NSNumber alloc] initWithDouble:self.paperRect.size.width];
  36 + NSNumber* height =
  37 + [[NSNumber alloc] initWithDouble:self.paperRect.size.height];
  38 + NSNumber* marginLeft =
  39 + [[NSNumber alloc] initWithDouble:self.printableRect.origin.x];
  40 + NSNumber* marginTop =
  41 + [[NSNumber alloc] initWithDouble:self.printableRect.origin.y];
  42 + NSNumber* marginRight =
  43 + [[NSNumber alloc] initWithDouble:self.paperRect.size.width -
  44 + (self.printableRect.origin.x +
  45 + self.printableRect.size.width)];
  46 + NSNumber* marginBottom =
  47 + [[NSNumber alloc] initWithDouble:self.paperRect.size.height -
  48 + (self.printableRect.origin.y +
  49 + self.printableRect.size.height)];
  50 +
  51 + NSDictionary* arg = @{
  52 + @"width" : width,
  53 + @"height" : height,
  54 + @"marginLeft" : marginLeft,
  55 + @"marginTop" : marginTop,
  56 + @"marginRight" : marginRight,
  57 + @"marginBottom" : marginBottom,
  58 + };
  59 +
  60 + [lock lock];
  61 + [channel invokeMethod:@"onLayout" arguments:arg];
  62 + [lock lock];
  63 + [lock unlock];
  64 +
  65 + size_t pages = CGPDFDocumentGetNumberOfPages(pdfDocument);
  66 +
  67 + return pages;
  68 +}
  69 +
  70 +- (void)drawPageAtIndex:(NSInteger)pageIndex inRect:(CGRect)printableRect {
  71 + CGContextRef ctx = UIGraphicsGetCurrentContext();
  72 + CGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument, pageIndex + 1);
  73 + CGContextScaleCTM(ctx, 1.0, -1.0);
  74 + CGContextTranslateCTM(ctx, 0.0, -self.paperRect.size.height);
  75 + CGContextDrawPDFPage(ctx, page);
  76 +}
  77 +
  78 +@end
@@ -18,4 +18,6 @@ @@ -18,4 +18,6 @@
18 18
19 @interface PrintingPlugin 19 @interface PrintingPlugin
20 : NSObject <FlutterPlugin, UIPrintInteractionControllerDelegate> 20 : NSObject <FlutterPlugin, UIPrintInteractionControllerDelegate>
  21 +
  22 +- (instancetype)init:(FlutterMethodChannel*)channel;
21 @end 23 @end
@@ -15,19 +15,34 @@ @@ -15,19 +15,34 @@
15 */ 15 */
16 16
17 #import "PrintingPlugin.h" 17 #import "PrintingPlugin.h"
  18 +#import "PageRenderer.h"
  19 +
  20 +@implementation PrintingPlugin {
  21 + FlutterMethodChannel* channel;
  22 + PdfPrintPageRenderer* renderer;
  23 +}
18 24
19 -@implementation PrintingPlugin  
20 + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { 25 + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
21 FlutterMethodChannel* channel = 26 FlutterMethodChannel* channel =
22 [FlutterMethodChannel methodChannelWithName:@"printing" 27 [FlutterMethodChannel methodChannelWithName:@"printing"
23 binaryMessenger:[registrar messenger]]; 28 binaryMessenger:[registrar messenger]];
24 - PrintingPlugin* instance = [[PrintingPlugin alloc] init]; 29 + PrintingPlugin* instance = [[PrintingPlugin alloc] init:channel];
25 [registrar addMethodCallDelegate:instance channel:channel]; 30 [registrar addMethodCallDelegate:instance channel:channel];
26 } 31 }
27 32
  33 +- (instancetype)init:(FlutterMethodChannel*)channel {
  34 + self = [super init];
  35 + self->channel = channel;
  36 + self->renderer = [[PdfPrintPageRenderer alloc] init:channel];
  37 + return self;
  38 +}
  39 +
28 - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { 40 - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
29 if ([@"printPdf" isEqualToString:call.method]) { 41 if ([@"printPdf" isEqualToString:call.method]) {
30 - [self printPdf:[call.arguments objectForKey:@"doc"]]; 42 + [self printPdf:[call.arguments objectForKey:@"name"]];
  43 + result(@1);
  44 + } else if ([@"writePdf" isEqualToString:call.method]) {
  45 + [self writePdf:[call.arguments objectForKey:@"doc"]];
31 result(@1); 46 result(@1);
32 } else if ([@"sharePdf" isEqualToString:call.method]) { 47 } else if ([@"sharePdf" isEqualToString:call.method]) {
33 [self sharePdf:[call.arguments objectForKey:@"doc"] 48 [self sharePdf:[call.arguments objectForKey:@"doc"]
@@ -42,22 +57,22 @@ @@ -42,22 +57,22 @@
42 } 57 }
43 } 58 }
44 59
45 -- (void)printPdf:(nonnull FlutterStandardTypedData*)data { 60 +- (void)printPdf:(nonnull NSString*)name {
46 BOOL printing = [UIPrintInteractionController isPrintingAvailable]; 61 BOOL printing = [UIPrintInteractionController isPrintingAvailable];
47 if (!printing) { 62 if (!printing) {
48 NSLog(@"printing not available"); 63 NSLog(@"printing not available");
49 return; 64 return;
50 } 65 }
51 66
52 - BOOL dataOK = [UIPrintInteractionController canPrintData:[data data]];  
53 - if (!dataOK)  
54 - NSLog(@"data not ok to be printed");  
55 -  
56 UIPrintInteractionController* controller = 67 UIPrintInteractionController* controller =
57 [UIPrintInteractionController sharedPrintController]; 68 [UIPrintInteractionController sharedPrintController];
58 [controller setDelegate:self]; 69 [controller setDelegate:self];
59 - [controller setPrintingItem:[data data]];  
60 70
  71 + UIPrintInfo* printInfo = [UIPrintInfo printInfo];
  72 + printInfo.jobName = name;
  73 + printInfo.outputType = UIPrintInfoOutputGeneral;
  74 + controller.printInfo = printInfo;
  75 + [controller setPrintPageRenderer:renderer];
61 UIPrintInteractionCompletionHandler completionHandler = 76 UIPrintInteractionCompletionHandler completionHandler =
62 ^(UIPrintInteractionController* printController, BOOL completed, 77 ^(UIPrintInteractionController* printController, BOOL completed,
63 NSError* error) { 78 NSError* error) {
@@ -65,11 +80,27 @@ @@ -65,11 +80,27 @@
65 NSLog(@"FAILED! due to error in domain %@ with error code %u", 80 NSLog(@"FAILED! due to error in domain %@ with error code %u",
66 error.domain, (unsigned int)error.code); 81 error.domain, (unsigned int)error.code);
67 } 82 }
  83 + if (self->renderer.pdfDocument != nil) {
  84 + CGPDFDocumentRelease(self->renderer.pdfDocument);
  85 + self->renderer.pdfDocument = nil;
  86 + }
68 }; 87 };
69 88
70 [controller presentAnimated:YES completionHandler:completionHandler]; 89 [controller presentAnimated:YES completionHandler:completionHandler];
71 } 90 }
72 91
  92 +- (void)writePdf:(nonnull FlutterStandardTypedData*)data {
  93 + CGDataProviderRef dataProvider = CGDataProviderCreateWithData(
  94 + NULL, data.data.bytes, data.data.length, NULL);
  95 + if (renderer.pdfDocument != nil) {
  96 + CGPDFDocumentRelease(renderer.pdfDocument);
  97 + renderer.pdfDocument = nil;
  98 + }
  99 + renderer.pdfDocument = CGPDFDocumentCreateWithProvider(dataProvider);
  100 + CGDataProviderRelease(dataProvider);
  101 + [renderer.lock unlock];
  102 +}
  103 +
73 - (void)sharePdf:(nonnull FlutterStandardTypedData*)data 104 - (void)sharePdf:(nonnull FlutterStandardTypedData*)data
74 withSourceRect:(CGRect)rect { 105 withSourceRect:(CGRect)rect {
75 NSURL* tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() 106 NSURL* tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()
@@ -16,22 +16,49 @@ @@ -16,22 +16,49 @@
16 16
17 part of printing; 17 part of printing;
18 18
  19 +typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format);
  20 +
19 class Printing { 21 class Printing {
20 static const MethodChannel _channel = MethodChannel('printing'); 22 static const MethodChannel _channel = MethodChannel('printing');
  23 + static LayoutCallback _onLayout;
21 24
22 - static Future<Null> printPdf({PdfDocument document, List<int> bytes}) async {  
23 - assert(document != null || bytes != null);  
24 - assert(!(document == null && bytes == null));  
25 -  
26 - if (document != null) bytes = document.save();  
27 - 25 + static Future<dynamic> _handleMethod(MethodCall call) async {
  26 + switch (call.method) {
  27 + case "onLayout":
  28 + final bytes = await _onLayout(PdfPageFormat(
  29 + call.arguments['width'],
  30 + call.arguments['height'],
  31 + marginLeft: call.arguments['marginLeft'],
  32 + marginTop: call.arguments['marginTop'],
  33 + marginRight: call.arguments['marginRight'],
  34 + marginBottom: call.arguments['marginBottom'],
  35 + ));
28 final Map<String, dynamic> params = <String, dynamic>{ 36 final Map<String, dynamic> params = <String, dynamic>{
29 'doc': Uint8List.fromList(bytes), 37 'doc': Uint8List.fromList(bytes),
30 }; 38 };
  39 + await _channel.invokeMethod('writePdf', params);
  40 + return Future.value("");
  41 + }
  42 + }
31 43
  44 + static Future<Null> layoutPdf(
  45 + {@required LayoutCallback onLayout, String name = "Document"}) async {
  46 + _onLayout = onLayout;
  47 + _channel.setMethodCallHandler(_handleMethod);
  48 + final Map<String, dynamic> params = <String, dynamic>{'name': name};
32 await _channel.invokeMethod('printPdf', params); 49 await _channel.invokeMethod('printPdf', params);
33 } 50 }
34 51
  52 + @deprecated
  53 + static Future<Null> printPdf({PdfDocument document, List<int> bytes}) async {
  54 + assert(document != null || bytes != null);
  55 + assert(!(document == null && bytes == null));
  56 +
  57 + layoutPdf(
  58 + onLayout: (PdfPageFormat format) =>
  59 + document != null ? document.save() : bytes);
  60 + }
  61 +
35 static Future<Null> sharePdf( 62 static Future<Null> sharePdf(
36 {PdfDocument document, List<int> bytes, Rect bounds}) async { 63 {PdfDocument document, List<int> bytes, Rect bounds}) async {
37 assert(document != null || bytes != null); 64 assert(document != null || bytes != null);