Showing
24 changed files
with
1028 additions
and
586 deletions
| @@ -34,11 +34,11 @@ printing/android/.gradle | @@ -34,11 +34,11 @@ printing/android/.gradle | ||
| 34 | pedantic_analyis_options_*.yaml | 34 | pedantic_analyis_options_*.yaml |
| 35 | .dartfix | 35 | .dartfix |
| 36 | node_modules | 36 | node_modules |
| 37 | -pdf/lcov.info | ||
| 38 | -pdf/coverage.json | 37 | +lcov.info |
| 38 | +coverage.json | ||
| 39 | .coverage | 39 | .coverage |
| 40 | package-lock.json | 40 | package-lock.json |
| 41 | -printing/lcov.info | 41 | +lcov.info |
| 42 | 42 | ||
| 43 | test/readme.dart | 43 | test/readme.dart |
| 44 | test/android | 44 | test/android |
| @@ -77,18 +77,18 @@ test-pdf: $(FONTS) get-pdf .coverage | @@ -77,18 +77,18 @@ test-pdf: $(FONTS) get-pdf .coverage | ||
| 77 | 77 | ||
| 78 | test-printing: $(FONTS) get-printing .coverage | 78 | test-printing: $(FONTS) get-printing .coverage |
| 79 | cd printing; flutter test --coverage --coverage-path lcov.info | 79 | cd printing; flutter test --coverage --coverage-path lcov.info |
| 80 | - cd printing/example; flutter test --coverage --coverage-path ../lcov.info | 80 | + cd printing/example; flutter test --coverage --coverage-path lcov.info |
| 81 | 81 | ||
| 82 | test-readme: $(FONTS) get-readme | 82 | test-readme: $(FONTS) get-readme |
| 83 | cd test; dart extract_readme.dart | 83 | cd test; dart extract_readme.dart |
| 84 | - cd test; dartanalyzer readme.dart | 84 | + cd test; dartanalyzer readme.dart |
| 85 | 85 | ||
| 86 | test-web: | 86 | test-web: |
| 87 | cd pdf/web_example; pub get | 87 | cd pdf/web_example; pub get |
| 88 | cd pdf/web_example; pub run webdev build | 88 | cd pdf/web_example; pub run webdev build |
| 89 | 89 | ||
| 90 | test: test-pdf test-printing node_modules test-web | 90 | test: test-pdf test-printing node_modules test-web |
| 91 | - cat pdf/lcov.info printing/lcov.info | node_modules/.bin/lcov-summary | 91 | + cat pdf/lcov.info printing/lcov.info printing/example/lcov.info | node_modules/.bin/lcov-summary |
| 92 | 92 | ||
| 93 | clean: | 93 | clean: |
| 94 | git clean -fdx -e .vscode -e ref | 94 | git clean -fdx -e .vscode -e ref |
| @@ -101,6 +101,14 @@ abstract class PdfFont extends PdfObject { | @@ -101,6 +101,14 @@ abstract class PdfFont extends PdfObject { | ||
| 101 | pdfDocument, 'ZapfDingbats', 0.820, -0.143, _zapfDingbatsWidths); | 101 | pdfDocument, 'ZapfDingbats', 0.820, -0.143, _zapfDingbatsWidths); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | + static const String _cannotDecodeMessage = | ||
| 105 | + '''--------------------------------------------- | ||
| 106 | +Cannot decode the string to Latin1. | ||
| 107 | +This font does not support Unicode characters. | ||
| 108 | +If you want to use strings other than Latin strings, use a TrueType (TTF) font instead. | ||
| 109 | +See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
| 110 | +---------------------------------------------'''; | ||
| 111 | + | ||
| 104 | /// The df type of the font, usually /Type1 | 112 | /// The df type of the font, usually /Type1 |
| 105 | final String subtype; | 113 | final String subtype; |
| 106 | 114 | ||
| @@ -141,13 +149,12 @@ abstract class PdfFont extends PdfObject { | @@ -141,13 +149,12 @@ abstract class PdfFont extends PdfObject { | ||
| 141 | final Uint8List chars = latin1.encode(s); | 149 | final Uint8List chars = latin1.encode(s); |
| 142 | final Iterable<PdfFontMetrics> metrics = chars.map(glyphMetrics); | 150 | final Iterable<PdfFontMetrics> metrics = chars.map(glyphMetrics); |
| 143 | return PdfFontMetrics.append(metrics); | 151 | return PdfFontMetrics.append(metrics); |
| 144 | - } catch (e) { | ||
| 145 | - assert(false, '''\n--------------------------------------------- | ||
| 146 | -Can not decode the string to Latin1. | ||
| 147 | -This font does not support Unicode characters. | ||
| 148 | -If you want to use strings other than Latin strings, use a TrueType (TTF) font instead. | ||
| 149 | -See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
| 150 | ----------------------------------------------'''); | 152 | + } catch (_) { |
| 153 | + assert(() { | ||
| 154 | + print(_cannotDecodeMessage); | ||
| 155 | + return true; | ||
| 156 | + }()); | ||
| 157 | + | ||
| 151 | rethrow; | 158 | rethrow; |
| 152 | } | 159 | } |
| 153 | } | 160 | } |
| @@ -169,13 +176,12 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | @@ -169,13 +176,12 @@ See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
| 169 | ..putByte(40) | 176 | ..putByte(40) |
| 170 | ..putTextBytes(latin1.encode(text)) | 177 | ..putTextBytes(latin1.encode(text)) |
| 171 | ..putByte(41); | 178 | ..putByte(41); |
| 172 | - } catch (e) { | ||
| 173 | - assert(false, '''\n--------------------------------------------- | ||
| 174 | -Can not decode the string to Latin1. | ||
| 175 | -This font does not support Unicode characters. | ||
| 176 | -If you want to use strings other than Latin strings, use a TrueType (TTF) font instead. | ||
| 177 | -See https://github.com/DavBfr/dart_pdf/wiki/Fonts-Management | ||
| 178 | ----------------------------------------------'''); | 179 | + } catch (_) { |
| 180 | + assert(() { | ||
| 181 | + print(_cannotDecodeMessage); | ||
| 182 | + return true; | ||
| 183 | + }()); | ||
| 184 | + | ||
| 179 | rethrow; | 185 | rethrow; |
| 180 | } | 186 | } |
| 181 | } | 187 | } |
| @@ -63,11 +63,17 @@ class MyAppState extends State<MyApp> { | @@ -63,11 +63,17 @@ class MyAppState extends State<MyApp> { | ||
| 63 | 63 | ||
| 64 | Future<void> _printPdf() async { | 64 | Future<void> _printPdf() async { |
| 65 | print('Print ...'); | 65 | print('Print ...'); |
| 66 | - final bool result = await Printing.layoutPdf( | ||
| 67 | - onLayout: (PdfPageFormat format) async => | ||
| 68 | - (await generateDocument(format)).save()); | ||
| 69 | - | ||
| 70 | - _showPrintedToast(result); | 66 | + try { |
| 67 | + final bool result = await Printing.layoutPdf( | ||
| 68 | + onLayout: (PdfPageFormat format) async => | ||
| 69 | + (await generateDocument(format)).save()); | ||
| 70 | + _showPrintedToast(result); | ||
| 71 | + } catch (e) { | ||
| 72 | + final ScaffoldState scaffold = Scaffold.of(shareWidget.currentContext); | ||
| 73 | + scaffold.showSnackBar(SnackBar( | ||
| 74 | + content: Text('Error: ${e.toString()}'), | ||
| 75 | + )); | ||
| 76 | + } | ||
| 71 | } | 77 | } |
| 72 | 78 | ||
| 73 | Future<void> _saveAsFile() async { | 79 | Future<void> _saveAsFile() async { |
| @@ -14,22 +14,9 @@ | @@ -14,22 +14,9 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -library printing; | ||
| 18 | - | ||
| 19 | -import 'dart:async'; | ||
| 20 | -import 'dart:typed_data'; | ||
| 21 | -import 'dart:ui' as ui; | ||
| 22 | - | ||
| 23 | -import 'package:flutter/rendering.dart'; | ||
| 24 | -import 'package:flutter/services.dart'; | ||
| 25 | -import 'package:flutter/widgets.dart'; | ||
| 26 | -import 'package:pdf/pdf.dart'; | ||
| 27 | -import 'package:pdf/widgets.dart'; | ||
| 28 | - | ||
| 29 | -part 'src/asset_utils.dart'; | ||
| 30 | -part 'src/print_job.dart'; | ||
| 31 | -part 'src/printer.dart'; | ||
| 32 | -part 'src/printing.dart'; | ||
| 33 | -part 'src/printing_info.dart'; | ||
| 34 | -part 'src/raster.dart'; | ||
| 35 | -part 'src/widgets.dart'; | 17 | +export 'src/asset_utils.dart'; |
| 18 | +export 'src/callback.dart'; | ||
| 19 | +export 'src/printer.dart'; | ||
| 20 | +export 'src/printing.dart'; | ||
| 21 | +export 'src/printing_info.dart'; | ||
| 22 | +export 'src/raster.dart'; |
printing/lib/printing_web.dart
deleted
100644 → 0
| 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 | -library printing_web; | ||
| 18 | - | ||
| 19 | -import 'dart:async'; | ||
| 20 | -import 'dart:html' as html; | ||
| 21 | -import 'dart:js' as js; | ||
| 22 | - | ||
| 23 | -import 'package:flutter/services.dart'; | ||
| 24 | -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; | ||
| 25 | - | ||
| 26 | -part 'wsrc/print_job.dart'; | ||
| 27 | - | ||
| 28 | -class PrintingPlugin { | ||
| 29 | - PrintingPlugin(this._channel); | ||
| 30 | - | ||
| 31 | - static void registerWith(Registrar registrar) { | ||
| 32 | - final MethodChannel channel = MethodChannel( | ||
| 33 | - 'net.nfet.printing', | ||
| 34 | - const StandardMethodCodec(), | ||
| 35 | - registrar.messenger, | ||
| 36 | - ); | ||
| 37 | - final PrintingPlugin instance = PrintingPlugin(channel); | ||
| 38 | - channel.setMethodCallHandler(instance.handleMethodCall); | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - final MethodChannel _channel; | ||
| 42 | - | ||
| 43 | - Future<dynamic> handleMethodCall(MethodCall call) async { | ||
| 44 | - switch (call.method) { | ||
| 45 | - case 'printPdf': | ||
| 46 | - final String name = call.arguments['name']; | ||
| 47 | - final double width = call.arguments['width']; | ||
| 48 | - final double height = call.arguments['height']; | ||
| 49 | - final double marginLeft = call.arguments['marginLeft']; | ||
| 50 | - final double marginTop = call.arguments['marginTop']; | ||
| 51 | - final double marginRight = call.arguments['marginRight']; | ||
| 52 | - final double marginBottom = call.arguments['marginBottom']; | ||
| 53 | - | ||
| 54 | - final _PrintJob printJob = _PrintJob(this, call.arguments['job']); | ||
| 55 | - return printJob.printPdf(name, width, height, marginLeft, marginTop, | ||
| 56 | - marginRight, marginBottom); | ||
| 57 | - case 'sharePdf': | ||
| 58 | - final List<int> data = call.arguments['doc']; | ||
| 59 | - final double x = call.arguments['x']; | ||
| 60 | - final double y = call.arguments['y']; | ||
| 61 | - final double width = call.arguments['w']; | ||
| 62 | - final double height = call.arguments['h']; | ||
| 63 | - final String name = call.arguments['name']; | ||
| 64 | - return _PrintJob.sharePdf(data, x, y, width, height, name); | ||
| 65 | - case 'printingInfo': | ||
| 66 | - return _PrintJob.printingInfo(); | ||
| 67 | - } | ||
| 68 | - throw UnimplementedError('Method "${call.method}" not implemented'); | ||
| 69 | - } | ||
| 70 | - | ||
| 71 | - /// Request the Pdf document from flutter | ||
| 72 | - Future<void> onLayout( | ||
| 73 | - _PrintJob printJob, | ||
| 74 | - double width, | ||
| 75 | - double height, | ||
| 76 | - double marginLeft, | ||
| 77 | - double marginTop, | ||
| 78 | - double marginRight, | ||
| 79 | - double marginBottom) async { | ||
| 80 | - final Map<String, dynamic> args = <String, dynamic>{ | ||
| 81 | - 'width': width, | ||
| 82 | - 'height': height, | ||
| 83 | - 'marginLeft': marginLeft, | ||
| 84 | - 'marginTop': marginTop, | ||
| 85 | - 'marginRight': marginRight, | ||
| 86 | - 'marginBottom': marginBottom, | ||
| 87 | - 'job': printJob.index, | ||
| 88 | - }; | ||
| 89 | - | ||
| 90 | - final dynamic result = | ||
| 91 | - await _channel.invokeMethod<dynamic>('onLayout', args); | ||
| 92 | - | ||
| 93 | - if (result is List<int>) { | ||
| 94 | - printJob.setDocument(result); | ||
| 95 | - } else { | ||
| 96 | - printJob.cancelJob(); | ||
| 97 | - } | ||
| 98 | - } | ||
| 99 | - | ||
| 100 | - /// send completion status to flutter | ||
| 101 | - Future<void> onCompleted(_PrintJob printJob, bool completed, | ||
| 102 | - [String error = '']) async { | ||
| 103 | - final Map<String, dynamic> data = <String, dynamic>{ | ||
| 104 | - 'completed': completed, | ||
| 105 | - 'error': error, | ||
| 106 | - 'job': printJob.index, | ||
| 107 | - }; | ||
| 108 | - | ||
| 109 | - await _channel.invokeMethod<dynamic>('onCompleted', data); | ||
| 110 | - } | ||
| 111 | -} |
| @@ -14,7 +14,15 @@ | @@ -14,7 +14,15 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -part of printing; | 17 | +import 'dart:async'; |
| 18 | +import 'dart:typed_data'; | ||
| 19 | +import 'dart:ui' as ui; | ||
| 20 | + | ||
| 21 | +import 'package:flutter/rendering.dart'; | ||
| 22 | +import 'package:flutter/services.dart'; | ||
| 23 | +import 'package:meta/meta.dart'; | ||
| 24 | +import 'package:pdf/pdf.dart'; | ||
| 25 | +import 'package:pdf/widgets.dart'; | ||
| 18 | 26 | ||
| 19 | /// Loads an image from a Flutter [ui.Image] | 27 | /// Loads an image from a Flutter [ui.Image] |
| 20 | /// into a [PdfImage] instance | 28 | /// into a [PdfImage] instance |
printing/lib/src/callback.dart
0 → 100644
| 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 'dart:async'; | ||
| 18 | + | ||
| 19 | +import 'package:pdf/pdf.dart'; | ||
| 20 | + | ||
| 21 | +/// Callback used to generate the Pdf document dynamically when the user | ||
| 22 | +/// changes the page settings: size and margins | ||
| 23 | +typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format); |
printing/lib/src/interface.dart
0 → 100644
| 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 'dart:async'; | ||
| 18 | + | ||
| 19 | +import 'package:flutter/rendering.dart' show Rect; | ||
| 20 | +import 'package:pdf/pdf.dart'; | ||
| 21 | +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; | ||
| 22 | + | ||
| 23 | +import 'callback.dart'; | ||
| 24 | +import 'method_channel.dart'; | ||
| 25 | +import 'printer.dart'; | ||
| 26 | +import 'printing_info.dart'; | ||
| 27 | +import 'raster.dart'; | ||
| 28 | + | ||
| 29 | +/// The interface that implementations of printing must implement. | ||
| 30 | +abstract class PrintingPlatform extends PlatformInterface { | ||
| 31 | + /// Constructs a UrlLauncherPlatform. | ||
| 32 | + PrintingPlatform() : super(token: _token); | ||
| 33 | + | ||
| 34 | + static final Object _token = Object(); | ||
| 35 | + | ||
| 36 | + static PrintingPlatform _instance = MethodChannelPrinting(); | ||
| 37 | + | ||
| 38 | + /// The default instance of [PrintingPlatform] to use. | ||
| 39 | + /// | ||
| 40 | + /// Defaults to [MethodChannelPrinting]. | ||
| 41 | + static PrintingPlatform get instance => _instance; | ||
| 42 | + | ||
| 43 | + /// Platform-specific plugins should set this with their own platform-specific | ||
| 44 | + /// class that extends [PrintingPlatform] when they register themselves. | ||
| 45 | + static set instance(PrintingPlatform instance) { | ||
| 46 | + PlatformInterface.verifyToken(instance, _token); | ||
| 47 | + _instance = instance; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + /// Returns a [PrintingInfo] object representing the capabilities | ||
| 51 | + /// supported for the current platform | ||
| 52 | + Future<PrintingInfo> info(); | ||
| 53 | + | ||
| 54 | + /// Prints a Pdf document to a local printer using the platform UI | ||
| 55 | + /// the Pdf document is re-built in a [LayoutCallback] each time the | ||
| 56 | + /// user changes a setting like the page format or orientation. | ||
| 57 | + /// | ||
| 58 | + /// returns a future with a `bool` set to true if the document is printed | ||
| 59 | + /// and false if it is canceled. | ||
| 60 | + /// throws an exception in case of error | ||
| 61 | + Future<bool> layoutPdf( | ||
| 62 | + LayoutCallback onLayout, | ||
| 63 | + String name, | ||
| 64 | + PdfPageFormat format, | ||
| 65 | + ); | ||
| 66 | + | ||
| 67 | + /// Opens the native printer picker interface, and returns the URL of the selected printer. | ||
| 68 | + Future<Printer> pickPrinter(Rect bounds); | ||
| 69 | + | ||
| 70 | + /// Prints a Pdf document to a specific local printer with no UI | ||
| 71 | + /// | ||
| 72 | + /// returns a future with a `bool` set to true if the document is printed | ||
| 73 | + /// and false if it is canceled. | ||
| 74 | + /// throws an exception in case of error | ||
| 75 | + Future<bool> directPrintPdf( | ||
| 76 | + Printer printer, | ||
| 77 | + LayoutCallback onLayout, | ||
| 78 | + String name, | ||
| 79 | + PdfPageFormat format, | ||
| 80 | + ); | ||
| 81 | + | ||
| 82 | + /// Displays a platform popup to share the Pdf document to another application | ||
| 83 | + Future<bool> sharePdf( | ||
| 84 | + List<int> bytes, | ||
| 85 | + String filename, | ||
| 86 | + Rect bounds, | ||
| 87 | + ); | ||
| 88 | + | ||
| 89 | + /// Convert an html document to a pdf data | ||
| 90 | + Future<List<int>> convertHtml( | ||
| 91 | + String html, | ||
| 92 | + String baseUrl, | ||
| 93 | + PdfPageFormat format, | ||
| 94 | + ); | ||
| 95 | + | ||
| 96 | + /// Convert a Pdf document to bitmap images | ||
| 97 | + Stream<PdfRaster> raster( | ||
| 98 | + List<int> document, | ||
| 99 | + List<int> pages, | ||
| 100 | + double dpi, | ||
| 101 | + ); | ||
| 102 | +} |
printing/lib/src/method_channel.dart
0 → 100644
| 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 'dart:async'; | ||
| 18 | +import 'dart:typed_data'; | ||
| 19 | + | ||
| 20 | +import 'package:flutter/rendering.dart' show Rect; | ||
| 21 | +import 'package:flutter/services.dart'; | ||
| 22 | +import 'package:pdf/pdf.dart'; | ||
| 23 | + | ||
| 24 | +import 'callback.dart'; | ||
| 25 | +import 'interface.dart'; | ||
| 26 | +import 'print_job.dart'; | ||
| 27 | +import 'printer.dart'; | ||
| 28 | +import 'printing_info.dart'; | ||
| 29 | +import 'raster.dart'; | ||
| 30 | + | ||
| 31 | +const MethodChannel _channel = MethodChannel('net.nfet.printing'); | ||
| 32 | + | ||
| 33 | +/// An implementation of [PrintingPlatform] that uses method channels. | ||
| 34 | +class MethodChannelPrinting extends PrintingPlatform { | ||
| 35 | + MethodChannelPrinting() : super() { | ||
| 36 | + _channel.setMethodCallHandler(_handleMethod); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + static final Map<int, PrintJob> _printJobs = <int, PrintJob>{}; | ||
| 40 | + static int _jobIndex = 0; | ||
| 41 | + | ||
| 42 | + /// Callbacks from platform plugins | ||
| 43 | + static Future<dynamic> _handleMethod(MethodCall call) async { | ||
| 44 | + switch (call.method) { | ||
| 45 | + case 'onLayout': | ||
| 46 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
| 47 | + try { | ||
| 48 | + final PdfPageFormat format = PdfPageFormat( | ||
| 49 | + call.arguments['width'], | ||
| 50 | + call.arguments['height'], | ||
| 51 | + marginLeft: call.arguments['marginLeft'], | ||
| 52 | + marginTop: call.arguments['marginTop'], | ||
| 53 | + marginRight: call.arguments['marginRight'], | ||
| 54 | + marginBottom: call.arguments['marginBottom'], | ||
| 55 | + ); | ||
| 56 | + | ||
| 57 | + final List<int> bytes = await job.onLayout(format); | ||
| 58 | + | ||
| 59 | + if (bytes == null) { | ||
| 60 | + throw 'onLayout returned null'; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + return Uint8List.fromList(bytes); | ||
| 64 | + } catch (e) { | ||
| 65 | + return e.toString(); | ||
| 66 | + } | ||
| 67 | + break; | ||
| 68 | + case 'onCompleted': | ||
| 69 | + final bool completed = call.arguments['completed']; | ||
| 70 | + final String error = call.arguments['error']; | ||
| 71 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
| 72 | + if (completed == false && error != null) { | ||
| 73 | + job.onCompleted.completeError(error); | ||
| 74 | + } else { | ||
| 75 | + job.onCompleted.complete(completed); | ||
| 76 | + } | ||
| 77 | + break; | ||
| 78 | + case 'onHtmlRendered': | ||
| 79 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
| 80 | + job.onHtmlRendered.complete(call.arguments['doc']); | ||
| 81 | + break; | ||
| 82 | + case 'onHtmlError': | ||
| 83 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
| 84 | + job.onHtmlRendered.completeError(call.arguments['error']); | ||
| 85 | + break; | ||
| 86 | + case 'onPageRasterized': | ||
| 87 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
| 88 | + final PdfRaster raster = PdfRaster( | ||
| 89 | + call.arguments['width'], | ||
| 90 | + call.arguments['height'], | ||
| 91 | + call.arguments['image'], | ||
| 92 | + ); | ||
| 93 | + job.onPageRasterized.add(raster); | ||
| 94 | + break; | ||
| 95 | + case 'onPageRasterEnd': | ||
| 96 | + final PrintJob job = _printJobs[call.arguments['job']]; | ||
| 97 | + job.onPageRasterized.close(); | ||
| 98 | + _printJobs.remove(job.index); | ||
| 99 | + break; | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + static PrintJob _newPrintJob(PrintJob job) { | ||
| 104 | + job.index = _jobIndex++; | ||
| 105 | + _printJobs[job.index] = job; | ||
| 106 | + return job; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + @override | ||
| 110 | + Future<PrintingInfo> info() async { | ||
| 111 | + _channel.setMethodCallHandler(_handleMethod); | ||
| 112 | + Map<dynamic, dynamic> result; | ||
| 113 | + | ||
| 114 | + try { | ||
| 115 | + result = await _channel.invokeMethod( | ||
| 116 | + 'printingInfo', | ||
| 117 | + <String, dynamic>{}, | ||
| 118 | + ); | ||
| 119 | + } catch (e) { | ||
| 120 | + print('Error getting printing info: $e'); | ||
| 121 | + return PrintingInfo.unavailable; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + return PrintingInfo.fromMap(result); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + @override | ||
| 128 | + Future<bool> layoutPdf( | ||
| 129 | + LayoutCallback onLayout, | ||
| 130 | + String name, | ||
| 131 | + PdfPageFormat format, | ||
| 132 | + ) async { | ||
| 133 | + final PrintJob job = _newPrintJob(PrintJob( | ||
| 134 | + onCompleted: Completer<bool>(), | ||
| 135 | + onLayout: onLayout, | ||
| 136 | + )); | ||
| 137 | + | ||
| 138 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
| 139 | + 'name': name, | ||
| 140 | + 'job': job.index, | ||
| 141 | + 'width': format.width, | ||
| 142 | + 'height': format.height, | ||
| 143 | + 'marginLeft': format.marginLeft, | ||
| 144 | + 'marginTop': format.marginTop, | ||
| 145 | + 'marginRight': format.marginRight, | ||
| 146 | + 'marginBottom': format.marginBottom, | ||
| 147 | + }; | ||
| 148 | + | ||
| 149 | + await _channel.invokeMethod<int>('printPdf', params); | ||
| 150 | + try { | ||
| 151 | + return await job.onCompleted.future; | ||
| 152 | + } finally { | ||
| 153 | + _printJobs.remove(job.index); | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + @override | ||
| 158 | + Future<Printer> pickPrinter(Rect bounds) async { | ||
| 159 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
| 160 | + 'x': bounds.left, | ||
| 161 | + 'y': bounds.top, | ||
| 162 | + 'w': bounds.width, | ||
| 163 | + 'h': bounds.height, | ||
| 164 | + }; | ||
| 165 | + final Map<dynamic, dynamic> printer = await _channel | ||
| 166 | + .invokeMethod<Map<dynamic, dynamic>>('pickPrinter', params); | ||
| 167 | + if (printer == null) { | ||
| 168 | + return null; | ||
| 169 | + } | ||
| 170 | + return Printer( | ||
| 171 | + url: printer['url'], | ||
| 172 | + name: printer['name'], | ||
| 173 | + model: printer['model'], | ||
| 174 | + location: printer['location'], | ||
| 175 | + ); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + @override | ||
| 179 | + Future<bool> directPrintPdf( | ||
| 180 | + Printer printer, | ||
| 181 | + LayoutCallback onLayout, | ||
| 182 | + String name, | ||
| 183 | + PdfPageFormat format, | ||
| 184 | + ) async { | ||
| 185 | + final PrintJob job = _newPrintJob(PrintJob( | ||
| 186 | + onCompleted: Completer<bool>(), | ||
| 187 | + )); | ||
| 188 | + | ||
| 189 | + final List<int> bytes = await onLayout(format); | ||
| 190 | + if (bytes == null) { | ||
| 191 | + return false; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
| 195 | + 'name': name, | ||
| 196 | + 'printer': printer.url, | ||
| 197 | + 'doc': Uint8List.fromList(bytes), | ||
| 198 | + 'job': job.index, | ||
| 199 | + }; | ||
| 200 | + await _channel.invokeMethod<int>('directPrintPdf', params); | ||
| 201 | + final bool result = await job.onCompleted.future; | ||
| 202 | + _printJobs.remove(job.index); | ||
| 203 | + return result; | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + @override | ||
| 207 | + Future<bool> sharePdf( | ||
| 208 | + List<int> bytes, | ||
| 209 | + String filename, | ||
| 210 | + Rect bounds, | ||
| 211 | + ) async { | ||
| 212 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
| 213 | + 'doc': Uint8List.fromList(bytes), | ||
| 214 | + 'name': filename, | ||
| 215 | + 'x': bounds.left, | ||
| 216 | + 'y': bounds.top, | ||
| 217 | + 'w': bounds.width, | ||
| 218 | + 'h': bounds.height, | ||
| 219 | + }; | ||
| 220 | + return await _channel.invokeMethod('sharePdf', params); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + @override | ||
| 224 | + Future<List<int>> convertHtml( | ||
| 225 | + String html, String baseUrl, PdfPageFormat format) async { | ||
| 226 | + final PrintJob job = _newPrintJob(PrintJob( | ||
| 227 | + onHtmlRendered: Completer<List<int>>(), | ||
| 228 | + )); | ||
| 229 | + | ||
| 230 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
| 231 | + 'html': html, | ||
| 232 | + 'baseUrl': baseUrl, | ||
| 233 | + 'width': format.width, | ||
| 234 | + 'height': format.height, | ||
| 235 | + 'marginLeft': format.marginLeft, | ||
| 236 | + 'marginTop': format.marginTop, | ||
| 237 | + 'marginRight': format.marginRight, | ||
| 238 | + 'marginBottom': format.marginBottom, | ||
| 239 | + 'job': job.index, | ||
| 240 | + }; | ||
| 241 | + | ||
| 242 | + await _channel.invokeMethod<void>('convertHtml', params); | ||
| 243 | + final List<int> result = await job.onHtmlRendered.future; | ||
| 244 | + _printJobs.remove(job.index); | ||
| 245 | + return result; | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + @override | ||
| 249 | + Stream<PdfRaster> raster( | ||
| 250 | + List<int> document, | ||
| 251 | + List<int> pages, | ||
| 252 | + double dpi, | ||
| 253 | + ) { | ||
| 254 | + final PrintJob job = _newPrintJob(PrintJob( | ||
| 255 | + onPageRasterized: StreamController<PdfRaster>(), | ||
| 256 | + )); | ||
| 257 | + | ||
| 258 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
| 259 | + 'doc': Uint8List.fromList(document), | ||
| 260 | + 'pages': pages, | ||
| 261 | + 'scale': dpi / PdfPageFormat.inch, | ||
| 262 | + 'job': job.index, | ||
| 263 | + }; | ||
| 264 | + | ||
| 265 | + _channel.invokeMethod<void>('rasterPdf', params); | ||
| 266 | + return job.onPageRasterized.stream; | ||
| 267 | + } | ||
| 268 | +} |
| @@ -14,10 +14,13 @@ | @@ -14,10 +14,13 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -part of printing; | 17 | +import 'dart:async'; |
| 18 | 18 | ||
| 19 | -class _PrintJob { | ||
| 20 | - _PrintJob({ | 19 | +import 'callback.dart'; |
| 20 | +import 'raster.dart'; | ||
| 21 | + | ||
| 22 | +class PrintJob { | ||
| 23 | + PrintJob({ | ||
| 21 | this.onLayout, | 24 | this.onLayout, |
| 22 | this.onHtmlRendered, | 25 | this.onHtmlRendered, |
| 23 | this.onCompleted, | 26 | this.onCompleted, |
| @@ -14,10 +14,12 @@ | @@ -14,10 +14,12 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -part of printing; | 17 | +import 'package:meta/meta.dart'; |
| 18 | 18 | ||
| 19 | +/// Information about a printer | ||
| 19 | @immutable | 20 | @immutable |
| 20 | class Printer { | 21 | class Printer { |
| 22 | + /// Create a printer information | ||
| 21 | const Printer({ | 23 | const Printer({ |
| 22 | @required this.url, | 24 | @required this.url, |
| 23 | this.name, | 25 | this.name, |
| @@ -25,9 +27,16 @@ class Printer { | @@ -25,9 +27,16 @@ class Printer { | ||
| 25 | this.location, | 27 | this.location, |
| 26 | }) : assert(url != null); | 28 | }) : assert(url != null); |
| 27 | 29 | ||
| 30 | + /// The platform specific printer identification | ||
| 28 | final String url; | 31 | final String url; |
| 32 | + | ||
| 33 | + /// The display name of the printer | ||
| 29 | final String name; | 34 | final String name; |
| 35 | + | ||
| 36 | + /// The printer model | ||
| 30 | final String model; | 37 | final String model; |
| 38 | + | ||
| 39 | + /// The physical location of the printer | ||
| 31 | final String location; | 40 | final String location; |
| 32 | 41 | ||
| 33 | @override | 42 | @override |
| @@ -14,83 +14,19 @@ | @@ -14,83 +14,19 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -part of printing; | 17 | +import 'dart:async'; |
| 18 | 18 | ||
| 19 | -typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format); | 19 | +import 'package:flutter/rendering.dart' show Rect, Offset; |
| 20 | +import 'package:meta/meta.dart'; | ||
| 21 | +import 'package:pdf/pdf.dart'; | ||
| 20 | 22 | ||
| 21 | -mixin Printing { | ||
| 22 | - static const MethodChannel _channel = MethodChannel('net.nfet.printing'); | ||
| 23 | - static final Map<int, _PrintJob> _printJobs = <int, _PrintJob>{}; | ||
| 24 | - static int _jobIndex = 0; | ||
| 25 | - | ||
| 26 | - /// Callbacks from platform plugins | ||
| 27 | - static Future<dynamic> _handleMethod(MethodCall call) async { | ||
| 28 | - switch (call.method) { | ||
| 29 | - case 'onLayout': | ||
| 30 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
| 31 | - try { | ||
| 32 | - final PdfPageFormat format = PdfPageFormat( | ||
| 33 | - call.arguments['width'], | ||
| 34 | - call.arguments['height'], | ||
| 35 | - marginLeft: call.arguments['marginLeft'], | ||
| 36 | - marginTop: call.arguments['marginTop'], | ||
| 37 | - marginRight: call.arguments['marginRight'], | ||
| 38 | - marginBottom: call.arguments['marginBottom'], | ||
| 39 | - ); | ||
| 40 | - | ||
| 41 | - final List<int> bytes = await job.onLayout(format); | ||
| 42 | - | ||
| 43 | - if (bytes == null) { | ||
| 44 | - return false; | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - return Uint8List.fromList(bytes); | ||
| 48 | - } catch (e) { | ||
| 49 | - print('Unable to print: $e'); | ||
| 50 | - return false; | ||
| 51 | - } | ||
| 52 | - break; | ||
| 53 | - case 'onCompleted': | ||
| 54 | - final bool completed = call.arguments['completed']; | ||
| 55 | - final String error = call.arguments['error']; | ||
| 56 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
| 57 | - if (completed == false && error != null) { | ||
| 58 | - job.onCompleted.completeError(error); | ||
| 59 | - } else { | ||
| 60 | - job.onCompleted.complete(completed); | ||
| 61 | - } | ||
| 62 | - break; | ||
| 63 | - case 'onHtmlRendered': | ||
| 64 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
| 65 | - job.onHtmlRendered.complete(call.arguments['doc']); | ||
| 66 | - break; | ||
| 67 | - case 'onHtmlError': | ||
| 68 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
| 69 | - job.onHtmlRendered.completeError(call.arguments['error']); | ||
| 70 | - break; | ||
| 71 | - case 'onPageRasterized': | ||
| 72 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
| 73 | - final PdfRaster raster = PdfRaster._( | ||
| 74 | - call.arguments['width'], | ||
| 75 | - call.arguments['height'], | ||
| 76 | - call.arguments['image'], | ||
| 77 | - ); | ||
| 78 | - job.onPageRasterized.add(raster); | ||
| 79 | - break; | ||
| 80 | - case 'onPageRasterEnd': | ||
| 81 | - final _PrintJob job = _printJobs[call.arguments['job']]; | ||
| 82 | - job.onPageRasterized.close(); | ||
| 83 | - _printJobs.remove(job.index); | ||
| 84 | - break; | ||
| 85 | - } | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - static _PrintJob _newPrintJob(_PrintJob job) { | ||
| 89 | - job.index = _jobIndex++; | ||
| 90 | - _printJobs[job.index] = job; | ||
| 91 | - return job; | ||
| 92 | - } | 23 | +import 'callback.dart'; |
| 24 | +import 'interface.dart'; | ||
| 25 | +import 'printer.dart'; | ||
| 26 | +import 'printing_info.dart'; | ||
| 27 | +import 'raster.dart'; | ||
| 93 | 28 | ||
| 29 | +mixin Printing { | ||
| 94 | /// Prints a Pdf document to a local printer using the platform UI | 30 | /// Prints a Pdf document to a local printer using the platform UI |
| 95 | /// the Pdf document is re-built in a [LayoutCallback] each time the | 31 | /// the Pdf document is re-built in a [LayoutCallback] each time the |
| 96 | /// user changes a setting like the page format or orientation. | 32 | /// user changes a setting like the page format or orientation. |
| @@ -102,61 +38,19 @@ mixin Printing { | @@ -102,61 +38,19 @@ mixin Printing { | ||
| 102 | @required LayoutCallback onLayout, | 38 | @required LayoutCallback onLayout, |
| 103 | String name = 'Document', | 39 | String name = 'Document', |
| 104 | PdfPageFormat format = PdfPageFormat.standard, | 40 | PdfPageFormat format = PdfPageFormat.standard, |
| 105 | - }) async { | ||
| 106 | - _channel.setMethodCallHandler(_handleMethod); | ||
| 107 | - | ||
| 108 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
| 109 | - onCompleted: Completer<bool>(), | ||
| 110 | - onLayout: onLayout, | ||
| 111 | - )); | ||
| 112 | - | ||
| 113 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
| 114 | - 'name': name, | ||
| 115 | - 'job': job.index, | ||
| 116 | - 'width': format.width, | ||
| 117 | - 'height': format.height, | ||
| 118 | - 'marginLeft': format.marginLeft, | ||
| 119 | - 'marginTop': format.marginTop, | ||
| 120 | - 'marginRight': format.marginRight, | ||
| 121 | - 'marginBottom': format.marginBottom, | ||
| 122 | - }; | 41 | + }) { |
| 42 | + assert(onLayout != null); | ||
| 43 | + assert(name != null); | ||
| 44 | + assert(format != null); | ||
| 123 | 45 | ||
| 124 | - await _channel.invokeMethod<int>('printPdf', params); | ||
| 125 | - try { | ||
| 126 | - return await job.onCompleted.future; | ||
| 127 | - } finally { | ||
| 128 | - _printJobs.remove(job.index); | ||
| 129 | - } | ||
| 130 | - } | ||
| 131 | - | ||
| 132 | - static Future<Map<dynamic, dynamic>> printingInfo() async { | ||
| 133 | - return await _channel.invokeMethod<Map<dynamic, dynamic>>( | ||
| 134 | - 'printingInfo', | ||
| 135 | - <String, dynamic>{}, | ||
| 136 | - ); | 46 | + return PrintingPlatform.instance.layoutPdf(onLayout, name, format); |
| 137 | } | 47 | } |
| 138 | 48 | ||
| 139 | /// Opens the native printer picker interface, and returns the URL of the selected printer. | 49 | /// Opens the native printer picker interface, and returns the URL of the selected printer. |
| 140 | - static Future<Printer> pickPrinter({Rect bounds}) async { | ||
| 141 | - _channel.setMethodCallHandler(_handleMethod); | 50 | + static Future<Printer> pickPrinter({Rect bounds}) { |
| 142 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); | 51 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); |
| 143 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
| 144 | - 'x': bounds.left, | ||
| 145 | - 'y': bounds.top, | ||
| 146 | - 'w': bounds.width, | ||
| 147 | - 'h': bounds.height, | ||
| 148 | - }; | ||
| 149 | - final Map<dynamic, dynamic> printer = await _channel | ||
| 150 | - .invokeMethod<Map<dynamic, dynamic>>('pickPrinter', params); | ||
| 151 | - if (printer == null) { | ||
| 152 | - return null; | ||
| 153 | - } | ||
| 154 | - return Printer( | ||
| 155 | - url: printer['url'], | ||
| 156 | - name: printer['name'], | ||
| 157 | - model: printer['model'], | ||
| 158 | - location: printer['location'], | ||
| 159 | - ); | 52 | + |
| 53 | + return PrintingPlatform.instance.pickPrinter(bounds); | ||
| 160 | } | 54 | } |
| 161 | 55 | ||
| 162 | /// Prints a Pdf document to a specific local printer with no UI | 56 | /// Prints a Pdf document to a specific local printer with no UI |
| @@ -164,60 +58,35 @@ mixin Printing { | @@ -164,60 +58,35 @@ mixin Printing { | ||
| 164 | /// returns a future with a `bool` set to true if the document is printed | 58 | /// returns a future with a `bool` set to true if the document is printed |
| 165 | /// and false if it is canceled. | 59 | /// and false if it is canceled. |
| 166 | /// throws an exception in case of error | 60 | /// throws an exception in case of error |
| 167 | - static Future<bool> directPrintPdf({ | 61 | + static FutureOr<bool> directPrintPdf({ |
| 168 | @required Printer printer, | 62 | @required Printer printer, |
| 169 | @required LayoutCallback onLayout, | 63 | @required LayoutCallback onLayout, |
| 170 | String name = 'Document', | 64 | String name = 'Document', |
| 171 | PdfPageFormat format = PdfPageFormat.standard, | 65 | PdfPageFormat format = PdfPageFormat.standard, |
| 172 | - }) async { | 66 | + }) { |
| 173 | if (printer == null) { | 67 | if (printer == null) { |
| 174 | return false; | 68 | return false; |
| 175 | } | 69 | } |
| 176 | 70 | ||
| 177 | - _channel.setMethodCallHandler(_handleMethod); | ||
| 178 | - | ||
| 179 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
| 180 | - onCompleted: Completer<bool>(), | ||
| 181 | - )); | ||
| 182 | - | ||
| 183 | - final List<int> bytes = await onLayout(format); | ||
| 184 | - if (bytes == null) { | ||
| 185 | - return false; | ||
| 186 | - } | ||
| 187 | - | ||
| 188 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
| 189 | - 'name': name, | ||
| 190 | - 'printer': printer.url, | ||
| 191 | - 'doc': Uint8List.fromList(bytes), | ||
| 192 | - 'job': job.index, | ||
| 193 | - }; | ||
| 194 | - await _channel.invokeMethod<int>('directPrintPdf', params); | ||
| 195 | - final bool result = await job.onCompleted.future; | ||
| 196 | - _printJobs.remove(job.index); | ||
| 197 | - return result; | ||
| 198 | - } | ||
| 199 | - | ||
| 200 | - /// Prints a [PdfDocument] or a pdf stream to a local printer using the platform UI | ||
| 201 | - @Deprecated('use Printing.layoutPdf(onLayout: (_) => document.save());') | ||
| 202 | - static Future<void> printPdf({ | ||
| 203 | - @Deprecated('use bytes with document.save()') PdfDocument document, | ||
| 204 | - List<int> bytes, | ||
| 205 | - }) async { | ||
| 206 | - assert(document != null || bytes != null); | ||
| 207 | - assert(!(document == null && bytes == null)); | 71 | + assert(onLayout != null); |
| 72 | + assert(name != null); | ||
| 73 | + assert(format != null); | ||
| 208 | 74 | ||
| 209 | - layoutPdf( | ||
| 210 | - onLayout: (PdfPageFormat format) => | ||
| 211 | - document != null ? document.save() : bytes); | 75 | + return PrintingPlatform.instance.directPrintPdf( |
| 76 | + printer, | ||
| 77 | + onLayout, | ||
| 78 | + name, | ||
| 79 | + format, | ||
| 80 | + ); | ||
| 212 | } | 81 | } |
| 213 | 82 | ||
| 214 | /// Displays a platform popup to share the Pdf document to another application | 83 | /// Displays a platform popup to share the Pdf document to another application |
| 215 | - static Future<void> sharePdf({ | 84 | + static Future<bool> sharePdf({ |
| 216 | @Deprecated('use bytes with document.save()') PdfDocument document, | 85 | @Deprecated('use bytes with document.save()') PdfDocument document, |
| 217 | List<int> bytes, | 86 | List<int> bytes, |
| 218 | String filename = 'document.pdf', | 87 | String filename = 'document.pdf', |
| 219 | Rect bounds, | 88 | Rect bounds, |
| 220 | - }) async { | 89 | + }) { |
| 221 | assert(document != null || bytes != null); | 90 | assert(document != null || bytes != null); |
| 222 | assert(!(document == null && bytes == null)); | 91 | assert(!(document == null && bytes == null)); |
| 223 | assert(filename != null); | 92 | assert(filename != null); |
| @@ -228,61 +97,40 @@ mixin Printing { | @@ -228,61 +97,40 @@ mixin Printing { | ||
| 228 | 97 | ||
| 229 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); | 98 | bounds ??= Rect.fromCircle(center: Offset.zero, radius: 10); |
| 230 | 99 | ||
| 231 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
| 232 | - 'doc': Uint8List.fromList(bytes), | ||
| 233 | - 'name': filename, | ||
| 234 | - 'x': bounds.left, | ||
| 235 | - 'y': bounds.top, | ||
| 236 | - 'w': bounds.width, | ||
| 237 | - 'h': bounds.height, | ||
| 238 | - }; | ||
| 239 | - return await _channel.invokeMethod('sharePdf', params); | 100 | + return PrintingPlatform.instance.sharePdf( |
| 101 | + bytes, | ||
| 102 | + filename, | ||
| 103 | + bounds, | ||
| 104 | + ); | ||
| 240 | } | 105 | } |
| 241 | 106 | ||
| 242 | /// Convert an html document to a pdf data | 107 | /// Convert an html document to a pdf data |
| 243 | - static Future<List<int>> convertHtml( | ||
| 244 | - {@required String html, | ||
| 245 | - String baseUrl, | ||
| 246 | - PdfPageFormat format = PdfPageFormat.a4}) async { | ||
| 247 | - _channel.setMethodCallHandler(_handleMethod); | ||
| 248 | - | ||
| 249 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
| 250 | - onHtmlRendered: Completer<List<int>>(), | ||
| 251 | - )); | ||
| 252 | - | ||
| 253 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
| 254 | - 'html': html, | ||
| 255 | - 'baseUrl': baseUrl, | ||
| 256 | - 'width': format.width, | ||
| 257 | - 'height': format.height, | ||
| 258 | - 'marginLeft': format.marginLeft, | ||
| 259 | - 'marginTop': format.marginTop, | ||
| 260 | - 'marginRight': format.marginRight, | ||
| 261 | - 'marginBottom': format.marginBottom, | ||
| 262 | - 'job': job.index, | ||
| 263 | - }; | 108 | + static Future<List<int>> convertHtml({ |
| 109 | + @required String html, | ||
| 110 | + String baseUrl, | ||
| 111 | + PdfPageFormat format = PdfPageFormat.standard, | ||
| 112 | + }) { | ||
| 113 | + assert(html != null); | ||
| 114 | + assert(format != null); | ||
| 264 | 115 | ||
| 265 | - await _channel.invokeMethod<void>('convertHtml', params); | ||
| 266 | - final List<int> result = await job.onHtmlRendered.future; | ||
| 267 | - _printJobs.remove(job.index); | ||
| 268 | - return result; | 116 | + return PrintingPlatform.instance.convertHtml( |
| 117 | + html, | ||
| 118 | + baseUrl, | ||
| 119 | + format, | ||
| 120 | + ); | ||
| 269 | } | 121 | } |
| 270 | 122 | ||
| 271 | - static Future<PrintingInfo> info() async { | ||
| 272 | - _channel.setMethodCallHandler(_handleMethod); | ||
| 273 | - Map<dynamic, dynamic> result; | ||
| 274 | - | ||
| 275 | - try { | ||
| 276 | - result = await _channel.invokeMethod( | ||
| 277 | - 'printingInfo', | ||
| 278 | - <String, dynamic>{}, | ||
| 279 | - ); | ||
| 280 | - } catch (e) { | ||
| 281 | - print('Error getting printing info: $e'); | ||
| 282 | - return PrintingInfo.unavailable; | ||
| 283 | - } | 123 | + /// Returns a [PrintingInfo] object representing the capabilities |
| 124 | + /// supported for the current platform | ||
| 125 | + static Future<PrintingInfo> info() { | ||
| 126 | + return PrintingPlatform.instance.info(); | ||
| 127 | + } | ||
| 284 | 128 | ||
| 285 | - return PrintingInfo.fromMap(result); | 129 | + /// Returns a [PrintingInfo] object representing the capabilities |
| 130 | + /// supported for the current platform as a map | ||
| 131 | + @Deprecated('Use Printing.info()') | ||
| 132 | + static Future<Map<dynamic, dynamic>> printingInfo() async { | ||
| 133 | + return (await info()).asMap(); | ||
| 286 | } | 134 | } |
| 287 | 135 | ||
| 288 | static Stream<PdfRaster> raster( | 136 | static Stream<PdfRaster> raster( |
| @@ -290,20 +138,25 @@ mixin Printing { | @@ -290,20 +138,25 @@ mixin Printing { | ||
| 290 | List<int> pages, | 138 | List<int> pages, |
| 291 | double dpi = PdfPageFormat.inch, | 139 | double dpi = PdfPageFormat.inch, |
| 292 | }) { | 140 | }) { |
| 293 | - _channel.setMethodCallHandler(_handleMethod); | 141 | + assert(document != null); |
| 142 | + assert(dpi != null); | ||
| 143 | + assert(dpi > 0); | ||
| 294 | 144 | ||
| 295 | - final _PrintJob job = _newPrintJob(_PrintJob( | ||
| 296 | - onPageRasterized: StreamController<PdfRaster>(), | ||
| 297 | - )); | 145 | + return PrintingPlatform.instance.raster(document, pages, dpi); |
| 146 | + } | ||
| 298 | 147 | ||
| 299 | - final Map<String, dynamic> params = <String, dynamic>{ | ||
| 300 | - 'doc': Uint8List.fromList(document), | ||
| 301 | - 'pages': pages, | ||
| 302 | - 'scale': dpi / PdfPageFormat.inch, | ||
| 303 | - 'job': job.index, | ||
| 304 | - }; | 148 | + /// Prints a [PdfDocument] or a pdf stream to a local printer |
| 149 | + /// using the platform UI | ||
| 150 | + @Deprecated('use Printing.layoutPdf(onLayout: (_) => document.save());') | ||
| 151 | + static Future<void> printPdf({ | ||
| 152 | + @Deprecated('use bytes with document.save()') PdfDocument document, | ||
| 153 | + List<int> bytes, | ||
| 154 | + }) async { | ||
| 155 | + assert(document != null || bytes != null); | ||
| 156 | + assert(!(document == null && bytes == null)); | ||
| 305 | 157 | ||
| 306 | - _channel.invokeMethod<void>('rasterPdf', params); | ||
| 307 | - return job.onPageRasterized.stream; | 158 | + layoutPdf( |
| 159 | + onLayout: (PdfPageFormat format) => | ||
| 160 | + document != null ? document.save() : bytes); | ||
| 308 | } | 161 | } |
| 309 | } | 162 | } |
| @@ -14,19 +14,10 @@ | @@ -14,19 +14,10 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -part of printing; | ||
| 18 | - | 17 | +/// Capabilities supported for the current platform |
| 19 | class PrintingInfo { | 18 | class PrintingInfo { |
| 20 | - factory PrintingInfo.fromMap(Map<dynamic, dynamic> map) => PrintingInfo._( | ||
| 21 | - directPrint: map['directPrint'] ?? false, | ||
| 22 | - dynamicLayout: map['dynamicLayout'] ?? false, | ||
| 23 | - canPrint: map['canPrint'], | ||
| 24 | - canConvertHtml: map['canConvertHtml'], | ||
| 25 | - canShare: map['canShare'], | ||
| 26 | - canRaster: map['canRaster'], | ||
| 27 | - ); | ||
| 28 | - | ||
| 29 | - const PrintingInfo._({ | 19 | + /// Create an information object |
| 20 | + const PrintingInfo({ | ||
| 30 | this.directPrint = false, | 21 | this.directPrint = false, |
| 31 | this.dynamicLayout = false, | 22 | this.dynamicLayout = false, |
| 32 | this.canPrint = false, | 23 | this.canPrint = false, |
| @@ -40,13 +31,38 @@ class PrintingInfo { | @@ -40,13 +31,38 @@ class PrintingInfo { | ||
| 40 | assert(canShare != null), | 31 | assert(canShare != null), |
| 41 | assert(canRaster != null); | 32 | assert(canRaster != null); |
| 42 | 33 | ||
| 43 | - static const PrintingInfo unavailable = PrintingInfo._(); | 34 | + /// Create an information object from a dictionnary |
| 35 | + factory PrintingInfo.fromMap(Map<dynamic, dynamic> map) => PrintingInfo( | ||
| 36 | + directPrint: map['directPrint'] ?? false, | ||
| 37 | + dynamicLayout: map['dynamicLayout'] ?? false, | ||
| 38 | + canPrint: map['canPrint'] ?? false, | ||
| 39 | + canConvertHtml: map['canConvertHtml'] ?? false, | ||
| 40 | + canShare: map['canShare'] ?? false, | ||
| 41 | + canRaster: map['canRaster'] ?? false, | ||
| 42 | + ); | ||
| 43 | + | ||
| 44 | + /// Default information with no feature available | ||
| 45 | + static const PrintingInfo unavailable = PrintingInfo(); | ||
| 44 | 46 | ||
| 47 | + /// The platform can print directly to a printer | ||
| 45 | final bool directPrint; | 48 | final bool directPrint; |
| 49 | + | ||
| 50 | + /// The platform can request a dynamic layout when the user change | ||
| 51 | + /// the printer or printer settings | ||
| 46 | final bool dynamicLayout; | 52 | final bool dynamicLayout; |
| 53 | + | ||
| 54 | + /// The platform implementation is able to print a Pdf document | ||
| 47 | final bool canPrint; | 55 | final bool canPrint; |
| 56 | + | ||
| 57 | + /// The platform implementation is able to convert an html document to Pdf | ||
| 48 | final bool canConvertHtml; | 58 | final bool canConvertHtml; |
| 59 | + | ||
| 60 | + /// The platform implementation is able to share a Pdf document | ||
| 61 | + /// to other applications | ||
| 49 | final bool canShare; | 62 | final bool canShare; |
| 63 | + | ||
| 64 | + /// The platform implementation is able to convert pages from a Pdf document | ||
| 65 | + /// to a stream of images | ||
| 50 | final bool canRaster; | 66 | final bool canRaster; |
| 51 | 67 | ||
| 52 | @override | 68 | @override |
printing/lib/src/printing_web.dart
0 → 100644
| 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 'dart:async'; | ||
| 18 | +import 'dart:convert'; | ||
| 19 | +import 'dart:html' as html; | ||
| 20 | +import 'dart:js' as js; | ||
| 21 | +import 'dart:typed_data'; | ||
| 22 | +import 'dart:ui'; | ||
| 23 | + | ||
| 24 | +import 'package:flutter/rendering.dart' show Rect; | ||
| 25 | +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; | ||
| 26 | +import 'package:pdf/pdf.dart'; | ||
| 27 | +import 'package:printing/src/raster.dart'; | ||
| 28 | +import 'package:printing/src/printer.dart'; | ||
| 29 | + | ||
| 30 | +import 'callback.dart'; | ||
| 31 | +import 'interface.dart'; | ||
| 32 | +import 'printing_info.dart'; | ||
| 33 | + | ||
| 34 | +class PrintingPlugin extends PrintingPlatform { | ||
| 35 | + /// Registers this class as the default instance of [PrintingPlugin]. | ||
| 36 | + static void registerWith(Registrar registrar) { | ||
| 37 | + PrintingPlatform.instance = PrintingPlugin(); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + @override | ||
| 41 | + Future<PrintingInfo> info() async { | ||
| 42 | + return const PrintingInfo( | ||
| 43 | + directPrint: false, | ||
| 44 | + dynamicLayout: false, | ||
| 45 | + canPrint: true, | ||
| 46 | + canConvertHtml: false, | ||
| 47 | + canShare: true, | ||
| 48 | + ); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @override | ||
| 52 | + Future<bool> layoutPdf( | ||
| 53 | + LayoutCallback onLayout, | ||
| 54 | + String name, | ||
| 55 | + PdfPageFormat format, | ||
| 56 | + ) async { | ||
| 57 | + final List<int> result = await onLayout(format); | ||
| 58 | + | ||
| 59 | + if (result == null || result.isEmpty) { | ||
| 60 | + return false; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + final bool isChrome = js.context['chrome'] != null; | ||
| 64 | + | ||
| 65 | + if (!isChrome) { | ||
| 66 | + final String pr = 'data:application/pdf;base64,${base64.encode(result)}'; | ||
| 67 | + final html.Window win = js.context['window']; | ||
| 68 | + win.open(pr, name); | ||
| 69 | + | ||
| 70 | + return true; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + final Completer<bool> completer = Completer<bool>(); | ||
| 74 | + final html.Blob pdfFile = html.Blob( | ||
| 75 | + <Uint8List>[Uint8List.fromList(result)], | ||
| 76 | + 'application/pdf', | ||
| 77 | + ); | ||
| 78 | + final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
| 79 | + final html.HtmlDocument doc = js.context['document']; | ||
| 80 | + final html.IFrameElement frame = doc.createElement('iframe'); | ||
| 81 | + frame.setAttribute( | ||
| 82 | + 'style', | ||
| 83 | + 'visibility: hidden; height: 0; width: 0; position: absolute;', | ||
| 84 | + // 'height: 400px; width: 600px; position: absolute; z-index: 1000', | ||
| 85 | + ); | ||
| 86 | + | ||
| 87 | + frame.setAttribute('src', pdfUrl); | ||
| 88 | + | ||
| 89 | + frame.addEventListener('load', (html.Event event) { | ||
| 90 | + final js.JsObject win = | ||
| 91 | + js.JsObject.fromBrowserObject(frame)['contentWindow']; | ||
| 92 | + | ||
| 93 | + win.callMethod('addEventListener', <dynamic>[ | ||
| 94 | + 'afterprint', | ||
| 95 | + js.allowInterop<html.EventListener>((html.Event event) { | ||
| 96 | + frame.remove(); | ||
| 97 | + completer.complete(true); | ||
| 98 | + }), | ||
| 99 | + ]); | ||
| 100 | + | ||
| 101 | + frame.focus(); | ||
| 102 | + win.callMethod('print'); | ||
| 103 | + }); | ||
| 104 | + | ||
| 105 | + doc.body.append(frame); | ||
| 106 | + | ||
| 107 | + return completer.future; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + @override | ||
| 111 | + Future<bool> sharePdf( | ||
| 112 | + List<int> bytes, | ||
| 113 | + String filename, | ||
| 114 | + Rect bounds, | ||
| 115 | + ) async { | ||
| 116 | + final html.Blob pdfFile = html.Blob( | ||
| 117 | + <Uint8List>[Uint8List.fromList(bytes)], | ||
| 118 | + 'application/pdf', | ||
| 119 | + ); | ||
| 120 | + final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
| 121 | + final html.HtmlDocument doc = js.context['document']; | ||
| 122 | + final html.AnchorElement link = doc.createElement('a'); | ||
| 123 | + link.href = pdfUrl; | ||
| 124 | + link.download = filename; | ||
| 125 | + link.click(); | ||
| 126 | + return true; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + @override | ||
| 130 | + Future<List<int>> convertHtml( | ||
| 131 | + String html, | ||
| 132 | + String baseUrl, | ||
| 133 | + PdfPageFormat format, | ||
| 134 | + ) { | ||
| 135 | + throw UnimplementedError(); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + @override | ||
| 139 | + Future<bool> directPrintPdf( | ||
| 140 | + Printer printer, | ||
| 141 | + LayoutCallback onLayout, | ||
| 142 | + String name, | ||
| 143 | + PdfPageFormat format, | ||
| 144 | + ) { | ||
| 145 | + throw UnimplementedError(); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + @override | ||
| 149 | + Future<Printer> pickPrinter( | ||
| 150 | + Rect bounds, | ||
| 151 | + ) { | ||
| 152 | + throw UnimplementedError(); | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + @override | ||
| 156 | + Stream<PdfRaster> raster( | ||
| 157 | + List<int> document, | ||
| 158 | + List<int> pages, | ||
| 159 | + double dpi, | ||
| 160 | + ) { | ||
| 161 | + throw UnimplementedError(); | ||
| 162 | + } | ||
| 163 | +} |
| @@ -14,17 +14,28 @@ | @@ -14,17 +14,28 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | -part of printing; | 17 | +import 'dart:async'; |
| 18 | +import 'dart:typed_data'; | ||
| 19 | +import 'dart:ui' as ui; | ||
| 18 | 20 | ||
| 21 | +import 'package:flutter/painting.dart'; | ||
| 22 | + | ||
| 23 | +/// Represents a bitmap image | ||
| 19 | class PdfRaster { | 24 | class PdfRaster { |
| 20 | - PdfRaster._( | 25 | + /// Create a bitmap image |
| 26 | + PdfRaster( | ||
| 21 | this.width, | 27 | this.width, |
| 22 | this.height, | 28 | this.height, |
| 23 | this.pixels, | 29 | this.pixels, |
| 24 | ); | 30 | ); |
| 25 | 31 | ||
| 32 | + /// The width of the image | ||
| 26 | final int width; | 33 | final int width; |
| 34 | + | ||
| 35 | + /// The height of the image | ||
| 27 | final int height; | 36 | final int height; |
| 37 | + | ||
| 38 | + /// The raw RGBA pixels of the image | ||
| 28 | final Uint8List pixels; | 39 | final Uint8List pixels; |
| 29 | 40 | ||
| 30 | @override | 41 | @override |
| @@ -52,9 +63,12 @@ class PdfRaster { | @@ -52,9 +63,12 @@ class PdfRaster { | ||
| 52 | } | 63 | } |
| 53 | } | 64 | } |
| 54 | 65 | ||
| 66 | +/// Image provider for a [PdfRaster] | ||
| 55 | class PdfRasterImage extends ImageProvider<PdfRaster> { | 67 | class PdfRasterImage extends ImageProvider<PdfRaster> { |
| 68 | + /// Create an ImageProvider from a [PdfRaster] | ||
| 56 | PdfRasterImage(this.raster); | 69 | PdfRasterImage(this.raster); |
| 57 | 70 | ||
| 71 | + /// The image source | ||
| 58 | final PdfRaster raster; | 72 | final PdfRaster raster; |
| 59 | 73 | ||
| 60 | Future<ImageInfo> _loadAsync() async { | 74 | Future<ImageInfo> _loadAsync() async { |
printing/lib/src/widgets.dart
deleted
100644 → 0
| 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 | -part of printing; | ||
| 18 | - | ||
| 19 | -@Deprecated('Use `Document` instead') | ||
| 20 | -class PdfDoc extends Document { | ||
| 21 | - /// Wrapper for a [Document] with zlib compression enabled by default | ||
| 22 | - PdfDoc( | ||
| 23 | - {bool compress = true, | ||
| 24 | - PdfPageMode pageMode = PdfPageMode.none, | ||
| 25 | - Theme theme, | ||
| 26 | - String title, | ||
| 27 | - String author, | ||
| 28 | - String creator, | ||
| 29 | - String subject, | ||
| 30 | - String keywords, | ||
| 31 | - String producer}) | ||
| 32 | - : super( | ||
| 33 | - compress: compress, | ||
| 34 | - pageMode: pageMode, | ||
| 35 | - theme: theme, | ||
| 36 | - title: title, | ||
| 37 | - author: author, | ||
| 38 | - creator: creator, | ||
| 39 | - subject: subject, | ||
| 40 | - keywords: keywords, | ||
| 41 | - producer: producer, | ||
| 42 | - ) { | ||
| 43 | - Document.debug = debugPaintSizeEnabled; | ||
| 44 | - } | ||
| 45 | -} |
printing/lib/wsrc/print_job.dart
deleted
100644 → 0
| 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 | -part of printing_web; | ||
| 18 | - | ||
| 19 | -class _PrintJob { | ||
| 20 | - _PrintJob(this.printing, this.index); | ||
| 21 | - | ||
| 22 | - final PrintingPlugin printing; | ||
| 23 | - final int index; | ||
| 24 | - | ||
| 25 | - String _jobName; | ||
| 26 | - | ||
| 27 | - Future<int> printPdf( | ||
| 28 | - String name, | ||
| 29 | - double width, | ||
| 30 | - double height, | ||
| 31 | - double marginLeft, | ||
| 32 | - double marginTop, | ||
| 33 | - double marginRight, | ||
| 34 | - double marginBottom) async { | ||
| 35 | - _jobName = name; | ||
| 36 | - await printing.onLayout( | ||
| 37 | - this, width, height, marginLeft, marginTop, marginRight, marginBottom); | ||
| 38 | - return 1; | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - static Future<int> sharePdf(List<int> data, double x, double y, double width, | ||
| 42 | - double height, String name) async { | ||
| 43 | - final html.Blob pdfFile = html.Blob(<dynamic>[data], 'application/pdf'); | ||
| 44 | - final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
| 45 | - final html.HtmlDocument doc = js.context['document']; | ||
| 46 | - final html.AnchorElement link = doc.createElement('a'); | ||
| 47 | - link.href = pdfUrl; | ||
| 48 | - link.download = name; | ||
| 49 | - link.click(); | ||
| 50 | - return 1; | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - static Map<String, dynamic> printingInfo() { | ||
| 54 | - return <String, dynamic>{ | ||
| 55 | - 'directPrint': false, | ||
| 56 | - 'dynamicLayout': false, | ||
| 57 | - 'canPrint': true, | ||
| 58 | - 'canConvertHtml': false, | ||
| 59 | - 'canShare': true, | ||
| 60 | - }; | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - void setDocument(List<int> result) { | ||
| 64 | - final bool isChrome = js.context['chrome'] != null; | ||
| 65 | - | ||
| 66 | - if (!isChrome) { | ||
| 67 | - sharePdf(result, 0, 0, 0, 0, _jobName + '.pdf'); | ||
| 68 | - printing.onCompleted(this, true); | ||
| 69 | - return; | ||
| 70 | - } | ||
| 71 | - | ||
| 72 | - final html.Blob pdfFile = html.Blob(<dynamic>[result], 'application/pdf'); | ||
| 73 | - final String pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
| 74 | - final html.HtmlDocument doc = js.context['document']; | ||
| 75 | - final html.IFrameElement frame = doc.createElement('iframe'); | ||
| 76 | - frame.setAttribute('style', | ||
| 77 | - 'visibility: hidden; height: 0; width: 0; position: absolute;'); | ||
| 78 | - frame.setAttribute('src', pdfUrl); | ||
| 79 | - doc.body.append(frame); | ||
| 80 | - | ||
| 81 | - frame.addEventListener('load', (html.Event event) { | ||
| 82 | - final js.JsObject win = | ||
| 83 | - js.JsObject.fromBrowserObject(frame)['contentWindow']; | ||
| 84 | - | ||
| 85 | - win.callMethod('addEventListener', <dynamic>[ | ||
| 86 | - 'afterprint', | ||
| 87 | - js.allowInterop<html.EventListener>((html.Event event) { | ||
| 88 | - frame.remove(); | ||
| 89 | - printing.onCompleted(this, true); | ||
| 90 | - }), | ||
| 91 | - ]); | ||
| 92 | - | ||
| 93 | - frame.focus(); | ||
| 94 | - win.callMethod('print'); | ||
| 95 | - printing.onCompleted(this, true); | ||
| 96 | - }); | ||
| 97 | - } | ||
| 98 | - | ||
| 99 | - Future<void> cancelJob() async {} | ||
| 100 | -} |
| @@ -4,7 +4,7 @@ description: Plugin that allows Flutter apps to generate and print documents to | @@ -4,7 +4,7 @@ description: Plugin that allows Flutter apps to generate and print documents to | ||
| 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing | 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing |
| 5 | repository: https://github.com/DavBfr/dart_pdf | 5 | repository: https://github.com/DavBfr/dart_pdf |
| 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues | 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues |
| 7 | -version: 3.1.0 | 7 | +version: 3.2.0 |
| 8 | 8 | ||
| 9 | environment: | 9 | environment: |
| 10 | sdk: ">=2.3.0 <3.0.0" | 10 | sdk: ">=2.3.0 <3.0.0" |
| @@ -15,11 +15,13 @@ dependencies: | @@ -15,11 +15,13 @@ dependencies: | ||
| 15 | sdk: flutter | 15 | sdk: flutter |
| 16 | flutter_web_plugins: | 16 | flutter_web_plugins: |
| 17 | sdk: flutter | 17 | sdk: flutter |
| 18 | - pdf: "^1.3.15" | 18 | + pdf: ^1.3.15 |
| 19 | + plugin_platform_interface: ^1.0.2 | ||
| 19 | 20 | ||
| 20 | dev_dependencies: | 21 | dev_dependencies: |
| 21 | flutter_test: | 22 | flutter_test: |
| 22 | sdk: flutter | 23 | sdk: flutter |
| 24 | + mockito: ^4.1.1 | ||
| 23 | 25 | ||
| 24 | dependency_overrides: | 26 | dependency_overrides: |
| 25 | pdf: | 27 | pdf: |
| @@ -36,5 +38,5 @@ flutter: | @@ -36,5 +38,5 @@ flutter: | ||
| 36 | macos: | 38 | macos: |
| 37 | pluginClass: PrintingPlugin | 39 | pluginClass: PrintingPlugin |
| 38 | web: | 40 | web: |
| 39 | - fileName: printing_web.dart | 41 | + fileName: src/printing_web.dart |
| 40 | pluginClass: PrintingPlugin | 42 | pluginClass: PrintingPlugin |
printing/test/document_test.dart
0 → 100644
| 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 'dart:io'; | ||
| 18 | +import 'dart:typed_data'; | ||
| 19 | + | ||
| 20 | +import 'package:flutter/services.dart'; | ||
| 21 | +import 'package:flutter/widgets.dart'; | ||
| 22 | +import 'package:flutter_test/flutter_test.dart'; | ||
| 23 | +import 'package:pdf/pdf.dart'; | ||
| 24 | +import 'package:pdf/widgets.dart' as pdf; | ||
| 25 | +import 'package:printing/printing.dart'; | ||
| 26 | + | ||
| 27 | +pdf.Document doc; | ||
| 28 | +pdf.Font ttf; | ||
| 29 | + | ||
| 30 | +void main() { | ||
| 31 | + final String path = | ||
| 32 | + Directory.current.path.split('/').last == 'test' ? '..' : '.'; | ||
| 33 | + const MethodChannel channel = MethodChannel('net.nfet.printing'); | ||
| 34 | + TestWidgetsFlutterBinding.ensureInitialized(); | ||
| 35 | + | ||
| 36 | + setUp(() { | ||
| 37 | + channel.setMockMethodCallHandler((MethodCall methodCall) async { | ||
| 38 | + print(methodCall); | ||
| 39 | + return '1'; | ||
| 40 | + }); | ||
| 41 | + }); | ||
| 42 | + | ||
| 43 | + tearDown(() { | ||
| 44 | + channel.setMockMethodCallHandler(null); | ||
| 45 | + }); | ||
| 46 | + | ||
| 47 | + test('convertHtml', () async { | ||
| 48 | + // expect(await Printing.platformVersion, '42'); | ||
| 49 | + }); | ||
| 50 | + | ||
| 51 | + test('pdfImageFromImageProvider(FileImage)', () async { | ||
| 52 | + final PdfImage image = await pdfImageFromImageProvider( | ||
| 53 | + pdf: doc.document, image: FileImage(File('$path/example.png'))); | ||
| 54 | + | ||
| 55 | + doc.addPage( | ||
| 56 | + pdf.Page( | ||
| 57 | + build: (pdf.Context context) => pdf.Center( | ||
| 58 | + child: pdf.Container( | ||
| 59 | + child: pdf.Image(image), | ||
| 60 | + ), | ||
| 61 | + ), | ||
| 62 | + ), | ||
| 63 | + ); | ||
| 64 | + }); | ||
| 65 | + | ||
| 66 | + setUpAll(() { | ||
| 67 | + pdf.Document.debug = true; | ||
| 68 | + pdf.RichText.debug = true; | ||
| 69 | + final Uint8List fontData = | ||
| 70 | + File('$path/../pdf/open-sans.ttf').readAsBytesSync(); | ||
| 71 | + ttf = pdf.Font.ttf(fontData.buffer.asByteData()); | ||
| 72 | + doc = pdf.Document(); | ||
| 73 | + }); | ||
| 74 | + | ||
| 75 | + tearDownAll(() { | ||
| 76 | + final File file = File('printing.pdf'); | ||
| 77 | + file.writeAsBytesSync(doc.save()); | ||
| 78 | + }); | ||
| 79 | +} |
printing/test/info_test.dart
0 → 100644
| 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 'package:flutter_test/flutter_test.dart'; | ||
| 18 | +import 'package:printing/printing.dart'; | ||
| 19 | + | ||
| 20 | +void main() { | ||
| 21 | + setUp(() { | ||
| 22 | + TestWidgetsFlutterBinding.ensureInitialized(); | ||
| 23 | + }); | ||
| 24 | + | ||
| 25 | + test('PrintingInfo', () async { | ||
| 26 | + final PrintingInfo info = PrintingInfo.unavailable; | ||
| 27 | + expect(info.canConvertHtml, false); | ||
| 28 | + expect(info.directPrint, false); | ||
| 29 | + expect(info.dynamicLayout, false); | ||
| 30 | + expect(info.canPrint, false); | ||
| 31 | + expect(info.canConvertHtml, false); | ||
| 32 | + expect(info.canShare, false); | ||
| 33 | + expect(info.canRaster, false); | ||
| 34 | + | ||
| 35 | + expect(info.toString(), isA<String>()); | ||
| 36 | + }); | ||
| 37 | + | ||
| 38 | + test('PrintingInfo.fromMap', () async { | ||
| 39 | + final PrintingInfo info = PrintingInfo.fromMap( | ||
| 40 | + <dynamic, dynamic>{ | ||
| 41 | + 'canPrint': true, | ||
| 42 | + }, | ||
| 43 | + ); | ||
| 44 | + | ||
| 45 | + expect(info.canConvertHtml, false); | ||
| 46 | + expect(info.directPrint, false); | ||
| 47 | + expect(info.dynamicLayout, false); | ||
| 48 | + expect(info.canPrint, true); | ||
| 49 | + expect(info.canConvertHtml, false); | ||
| 50 | + expect(info.canShare, false); | ||
| 51 | + expect(info.canRaster, false); | ||
| 52 | + }); | ||
| 53 | +} |
| 1 | -import 'dart:io'; | ||
| 2 | -import 'dart:typed_data'; | 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 | + */ | ||
| 3 | 16 | ||
| 4 | -import 'package:flutter/services.dart'; | ||
| 5 | -import 'package:flutter/widgets.dart'; | ||
| 6 | import 'package:flutter_test/flutter_test.dart'; | 17 | import 'package:flutter_test/flutter_test.dart'; |
| 18 | +import 'package:mockito/mockito.dart'; | ||
| 7 | import 'package:pdf/pdf.dart'; | 19 | import 'package:pdf/pdf.dart'; |
| 8 | -import 'package:pdf/widgets.dart' as pdf; | 20 | +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; |
| 9 | import 'package:printing/printing.dart'; | 21 | import 'package:printing/printing.dart'; |
| 10 | - | ||
| 11 | -pdf.Document doc; | ||
| 12 | -pdf.Font ttf; | 22 | +import 'package:printing/src/interface.dart'; |
| 13 | 23 | ||
| 14 | void main() { | 24 | void main() { |
| 15 | - final String path = | ||
| 16 | - Directory.current.path.split('/').last == 'test' ? '..' : '.'; | ||
| 17 | - const MethodChannel channel = MethodChannel('net.nfet.printing'); | ||
| 18 | - TestWidgetsFlutterBinding.ensureInitialized(); | ||
| 19 | - | ||
| 20 | setUp(() { | 25 | setUp(() { |
| 21 | - channel.setMockMethodCallHandler((MethodCall methodCall) async { | ||
| 22 | - print(methodCall); | ||
| 23 | - return '1'; | ||
| 24 | - }); | 26 | + TestWidgetsFlutterBinding.ensureInitialized(); |
| 27 | + final MockPrinting mock = MockPrinting(); | ||
| 28 | + PrintingPlatform.instance = mock; | ||
| 25 | }); | 29 | }); |
| 26 | 30 | ||
| 27 | - tearDown(() { | ||
| 28 | - channel.setMockMethodCallHandler(null); | 31 | + test('info', () async { |
| 32 | + final PrintingInfo info = await Printing.info(); | ||
| 33 | + expect(info, null); | ||
| 29 | }); | 34 | }); |
| 30 | 35 | ||
| 31 | - test('convertHtml', () async { | ||
| 32 | - // expect(await Printing.platformVersion, '42'); | 36 | + test('layoutPdf', () async { |
| 37 | + expect( | ||
| 38 | + () async => await Printing.layoutPdf(onLayout: null), | ||
| 39 | + throwsAssertionError, | ||
| 40 | + ); | ||
| 41 | + | ||
| 42 | + expect( | ||
| 43 | + await Printing.layoutPdf( | ||
| 44 | + onLayout: (_) => null, | ||
| 45 | + name: 'doc', | ||
| 46 | + format: PdfPageFormat.letter, | ||
| 47 | + ), | ||
| 48 | + null); | ||
| 33 | }); | 49 | }); |
| 34 | 50 | ||
| 35 | - test('pdfImageFromImageProvider(FileImage)', () async { | ||
| 36 | - final PdfImage image = await pdfImageFromImageProvider( | ||
| 37 | - pdf: doc.document, image: FileImage(File('$path/example.png'))); | 51 | + test('sharePdf', () async { |
| 52 | + expect( | ||
| 53 | + () async => await Printing.sharePdf(bytes: null), | ||
| 54 | + throwsAssertionError, | ||
| 55 | + ); | ||
| 38 | 56 | ||
| 39 | - doc.addPage( | ||
| 40 | - pdf.Page( | ||
| 41 | - build: (pdf.Context context) => pdf.Center( | ||
| 42 | - child: pdf.Container( | ||
| 43 | - child: pdf.Image(image), | ||
| 44 | - ), | ||
| 45 | - ), | 57 | + expect( |
| 58 | + await Printing.sharePdf( | ||
| 59 | + bytes: <int>[], | ||
| 60 | + ), | ||
| 61 | + null, | ||
| 62 | + ); | ||
| 63 | + }); | ||
| 64 | + | ||
| 65 | + test('pickPrinter', () async { | ||
| 66 | + expect( | ||
| 67 | + await Printing.pickPrinter(), | ||
| 68 | + null, | ||
| 69 | + ); | ||
| 70 | + }); | ||
| 71 | + | ||
| 72 | + test('directPrintPdf', () async { | ||
| 73 | + expect( | ||
| 74 | + await Printing.directPrintPdf(onLayout: null, printer: null), | ||
| 75 | + false, | ||
| 76 | + ); | ||
| 77 | + | ||
| 78 | + expect( | ||
| 79 | + () async => await Printing.directPrintPdf( | ||
| 80 | + onLayout: null, | ||
| 81 | + printer: const Printer(url: 'test'), | ||
| 82 | + ), | ||
| 83 | + throwsAssertionError, | ||
| 84 | + ); | ||
| 85 | + | ||
| 86 | + expect( | ||
| 87 | + await Printing.directPrintPdf( | ||
| 88 | + onLayout: (_) => null, | ||
| 89 | + printer: const Printer(url: 'test'), | ||
| 46 | ), | 90 | ), |
| 91 | + null, | ||
| 47 | ); | 92 | ); |
| 48 | }); | 93 | }); |
| 49 | 94 | ||
| 50 | - setUpAll(() { | ||
| 51 | - pdf.Document.debug = true; | ||
| 52 | - pdf.RichText.debug = true; | ||
| 53 | - final Uint8List fontData = | ||
| 54 | - File('$path/../pdf/open-sans.ttf').readAsBytesSync(); | ||
| 55 | - ttf = pdf.Font.ttf(fontData.buffer.asByteData()); | ||
| 56 | - doc = pdf.Document(); | 95 | + test('convertHtml', () async { |
| 96 | + expect( | ||
| 97 | + await Printing.convertHtml(html: '<html></html>'), | ||
| 98 | + null, | ||
| 99 | + ); | ||
| 57 | }); | 100 | }); |
| 58 | 101 | ||
| 59 | - tearDownAll(() { | ||
| 60 | - final File file = File('printing.pdf'); | ||
| 61 | - file.writeAsBytesSync(doc.save()); | 102 | + test('raster', () async { |
| 103 | + expect( | ||
| 104 | + () => Printing.raster(null), | ||
| 105 | + throwsAssertionError, | ||
| 106 | + ); | ||
| 107 | + | ||
| 108 | + expect( | ||
| 109 | + Printing.raster(<int>[]), | ||
| 110 | + null, | ||
| 111 | + ); | ||
| 62 | }); | 112 | }); |
| 63 | } | 113 | } |
| 114 | + | ||
| 115 | +class MockPrinting extends Mock | ||
| 116 | + with MockPlatformInterfaceMixin | ||
| 117 | + implements PrintingPlatform {} |
printing/test/raster_test.dart
0 → 100644
| 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 'dart:typed_data'; | ||
| 18 | +import 'dart:ui' as ui; | ||
| 19 | + | ||
| 20 | +import 'package:flutter/widgets.dart'; | ||
| 21 | +import 'package:flutter_test/flutter_test.dart'; | ||
| 22 | +import 'package:printing/printing.dart'; | ||
| 23 | + | ||
| 24 | +void main() { | ||
| 25 | + setUp(() { | ||
| 26 | + TestWidgetsFlutterBinding.ensureInitialized(); | ||
| 27 | + }); | ||
| 28 | + | ||
| 29 | + test('PdfRaster', () async { | ||
| 30 | + final PdfRaster raster = | ||
| 31 | + PdfRaster(10, 10, Uint8List.fromList(List<int>.filled(10 * 10 * 4, 0))); | ||
| 32 | + expect(raster.toString(), 'Image 10x10 400 bytes'); | ||
| 33 | + expect(await raster.toImage(), isA<ui.Image>()); | ||
| 34 | + expect(await raster.toPng(), isA<Uint8List>()); | ||
| 35 | + }); | ||
| 36 | + | ||
| 37 | + testWidgets('PdfRasterImage', (WidgetTester tester) async { | ||
| 38 | + final PdfRaster raster = | ||
| 39 | + PdfRaster(10, 10, Uint8List.fromList(List<int>.filled(10 * 10 * 4, 0))); | ||
| 40 | + | ||
| 41 | + await tester.pumpWidget(Image(image: PdfRasterImage(raster))); | ||
| 42 | + await tester.pumpAndSettle(); | ||
| 43 | + }); | ||
| 44 | +} |
-
Please register or login to post a comment