Showing
10 changed files
with
379 additions
and
3 deletions
| @@ -28,6 +28,7 @@ printing/android/local.properties | @@ -28,6 +28,7 @@ printing/android/local.properties | ||
| 28 | printing/*.log | 28 | printing/*.log |
| 29 | printing/ios/Flutter | 29 | printing/ios/Flutter |
| 30 | printing/ios/Runner | 30 | printing/ios/Runner |
| 31 | +printing/android/.gradle | ||
| 31 | 32 | ||
| 32 | .pana | 33 | .pana |
| 33 | pedantic_analyis_options_*.yaml | 34 | pedantic_analyis_options_*.yaml |
| 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 | +package android.print; | ||
| 18 | + | ||
| 19 | +import android.app.Activity; | ||
| 20 | +import android.os.CancellationSignal; | ||
| 21 | +import android.os.ParcelFileDescriptor; | ||
| 22 | + | ||
| 23 | +import java.io.File; | ||
| 24 | +import java.io.FileInputStream; | ||
| 25 | +import java.io.FileNotFoundException; | ||
| 26 | +import java.io.IOException; | ||
| 27 | +import java.io.InputStream; | ||
| 28 | + | ||
| 29 | +public class PdfConvert { | ||
| 30 | + public static void print(final Activity activity, final PrintDocumentAdapter adapter, | ||
| 31 | + final PrintAttributes attributes, final Result result) { | ||
| 32 | + adapter.onLayout(null, attributes, null, new PrintDocumentAdapter.LayoutResultCallback() { | ||
| 33 | + @Override | ||
| 34 | + public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { | ||
| 35 | + File outputDir = activity.getCacheDir(); | ||
| 36 | + File outputFile = null; | ||
| 37 | + try { | ||
| 38 | + outputFile = File.createTempFile("printing", "pdf", outputDir); | ||
| 39 | + } catch (IOException e) { | ||
| 40 | + outputFile.delete(); | ||
| 41 | + result.onError(e.getMessage()); | ||
| 42 | + return; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + try { | ||
| 46 | + final File finalOutputFile = outputFile; | ||
| 47 | + adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, | ||
| 48 | + ParcelFileDescriptor.open( | ||
| 49 | + outputFile, ParcelFileDescriptor.MODE_READ_WRITE), | ||
| 50 | + new CancellationSignal(), | ||
| 51 | + new PrintDocumentAdapter.WriteResultCallback() { | ||
| 52 | + @Override | ||
| 53 | + public void onWriteFinished(PageRange[] pages) { | ||
| 54 | + super.onWriteFinished(pages); | ||
| 55 | + | ||
| 56 | + if (pages.length == 0) { | ||
| 57 | + finalOutputFile.delete(); | ||
| 58 | + result.onError("No page created"); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + result.onSuccess(finalOutputFile); | ||
| 62 | + finalOutputFile.delete(); | ||
| 63 | + } | ||
| 64 | + }); | ||
| 65 | + } catch (FileNotFoundException e) { | ||
| 66 | + outputFile.delete(); | ||
| 67 | + result.onError(e.getMessage()); | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + }, null); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public static byte[] readFile(File file) throws IOException { | ||
| 74 | + byte[] buffer = new byte[(int) file.length()]; | ||
| 75 | + InputStream ios = null; | ||
| 76 | + try { | ||
| 77 | + ios = new FileInputStream(file); | ||
| 78 | + if (ios.read(buffer) == -1) { | ||
| 79 | + throw new IOException("EOF reached while trying to read the whole file"); | ||
| 80 | + } | ||
| 81 | + } finally { | ||
| 82 | + try { | ||
| 83 | + if (ios != null) ios.close(); | ||
| 84 | + } catch (IOException e) { | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + return buffer; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + public interface Result { | ||
| 91 | + void onSuccess(File file); | ||
| 92 | + | ||
| 93 | + void onError(String message); | ||
| 94 | + } | ||
| 95 | +} |
| @@ -16,22 +16,24 @@ | @@ -16,22 +16,24 @@ | ||
| 16 | 16 | ||
| 17 | package net.nfet.flutter.printing; | 17 | package net.nfet.flutter.printing; |
| 18 | 18 | ||
| 19 | -import static java.lang.StrictMath.max; | ||
| 20 | - | ||
| 21 | import android.app.Activity; | 19 | import android.app.Activity; |
| 22 | import android.content.Context; | 20 | import android.content.Context; |
| 23 | import android.content.Intent; | 21 | import android.content.Intent; |
| 24 | import android.net.Uri; | 22 | import android.net.Uri; |
| 23 | +import android.os.Build; | ||
| 25 | import android.os.Bundle; | 24 | import android.os.Bundle; |
| 26 | import android.os.CancellationSignal; | 25 | import android.os.CancellationSignal; |
| 27 | import android.os.Environment; | 26 | import android.os.Environment; |
| 28 | import android.os.ParcelFileDescriptor; | 27 | import android.os.ParcelFileDescriptor; |
| 29 | import android.print.PageRange; | 28 | import android.print.PageRange; |
| 29 | +import android.print.PdfConvert; | ||
| 30 | import android.print.PrintAttributes; | 30 | import android.print.PrintAttributes; |
| 31 | import android.print.PrintDocumentAdapter; | 31 | import android.print.PrintDocumentAdapter; |
| 32 | import android.print.PrintDocumentInfo; | 32 | import android.print.PrintDocumentInfo; |
| 33 | import android.print.PrintManager; | 33 | import android.print.PrintManager; |
| 34 | import android.print.pdf.PrintedPdfDocument; | 34 | import android.print.pdf.PrintedPdfDocument; |
| 35 | +import android.webkit.WebView; | ||
| 36 | +import android.webkit.WebViewClient; | ||
| 35 | import androidx.core.content.FileProvider; | 37 | import androidx.core.content.FileProvider; |
| 36 | 38 | ||
| 37 | import java.io.File; | 39 | import java.io.File; |
| @@ -155,6 +157,28 @@ public class PrintingPlugin extends PrintDocumentAdapter implements MethodCallHa | @@ -155,6 +157,28 @@ public class PrintingPlugin extends PrintDocumentAdapter implements MethodCallHa | ||
| 155 | sharePdf((byte[]) call.argument("doc"), (String) call.argument("name")); | 157 | sharePdf((byte[]) call.argument("doc"), (String) call.argument("name")); |
| 156 | result.success(0); | 158 | result.success(0); |
| 157 | break; | 159 | break; |
| 160 | + case "convertHtml": | ||
| 161 | + double width = (double) call.argument("width"); | ||
| 162 | + double height = (double) call.argument("height"); | ||
| 163 | + double marginLeft = (double) call.argument("marginLeft"); | ||
| 164 | + double marginTop = (double) call.argument("marginTop"); | ||
| 165 | + double marginRight = (double) call.argument("marginRight"); | ||
| 166 | + double marginBottom = (double) call.argument("marginBottom"); | ||
| 167 | + | ||
| 168 | + PrintAttributes.Margins margins = | ||
| 169 | + new PrintAttributes.Margins(Double.valueOf(marginLeft * 1000.0).intValue(), | ||
| 170 | + Double.valueOf(marginTop * 1000.0 / 72.0).intValue(), | ||
| 171 | + Double.valueOf(marginRight * 1000.0 / 72.0).intValue(), | ||
| 172 | + Double.valueOf(marginBottom * 1000.0 / 72.0).intValue()); | ||
| 173 | + | ||
| 174 | + PrintAttributes.MediaSize size = new PrintAttributes.MediaSize("flutter_printing", | ||
| 175 | + "Provided size", Double.valueOf(width * 1000.0 / 72.0).intValue(), | ||
| 176 | + Double.valueOf(height * 1000.0 / 72.0).intValue()); | ||
| 177 | + | ||
| 178 | + convertHtml((String) call.argument("html"), size, margins, | ||
| 179 | + (String) call.argument("baseUrl")); | ||
| 180 | + result.success(0); | ||
| 181 | + break; | ||
| 158 | default: | 182 | default: |
| 159 | result.notImplemented(); | 183 | result.notImplemented(); |
| 160 | break; | 184 | break; |
| @@ -192,4 +216,49 @@ public class PrintingPlugin extends PrintDocumentAdapter implements MethodCallHa | @@ -192,4 +216,49 @@ public class PrintingPlugin extends PrintDocumentAdapter implements MethodCallHa | ||
| 192 | e.printStackTrace(); | 216 | e.printStackTrace(); |
| 193 | } | 217 | } |
| 194 | } | 218 | } |
| 219 | + | ||
| 220 | + private void convertHtml(String data, final PrintAttributes.MediaSize size, | ||
| 221 | + final PrintAttributes.Margins margins, String baseUrl) { | ||
| 222 | + final WebView webView = new WebView(activity.getApplicationContext()); | ||
| 223 | + | ||
| 224 | + webView.loadDataWithBaseURL(baseUrl, data, "text/HTML", "UTF-8", null); | ||
| 225 | + | ||
| 226 | + webView.setWebViewClient(new WebViewClient() { | ||
| 227 | + @Override | ||
| 228 | + public void onPageFinished(WebView view, String url) { | ||
| 229 | + super.onPageFinished(view, url); | ||
| 230 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | ||
| 231 | + PrintAttributes attributes = | ||
| 232 | + new PrintAttributes.Builder() | ||
| 233 | + .setMediaSize(size) | ||
| 234 | + .setResolution( | ||
| 235 | + new PrintAttributes.Resolution("pdf", "pdf", 600, 600)) | ||
| 236 | + .setMinMargins(margins) | ||
| 237 | + .build(); | ||
| 238 | + | ||
| 239 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | ||
| 240 | + final PrintDocumentAdapter adapter = | ||
| 241 | + webView.createPrintDocumentAdapter("printing"); | ||
| 242 | + | ||
| 243 | + PdfConvert.print(activity, adapter, attributes, new PdfConvert.Result() { | ||
| 244 | + @Override | ||
| 245 | + public void onSuccess(File file) { | ||
| 246 | + try { | ||
| 247 | + byte[] fileContent = PdfConvert.readFile(file); | ||
| 248 | + channel.invokeMethod("onHtmlRendered", fileContent); | ||
| 249 | + } catch (IOException e) { | ||
| 250 | + onError(e.getMessage()); | ||
| 251 | + } | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + @Override | ||
| 255 | + public void onError(String message) { | ||
| 256 | + channel.invokeMethod("onHtmlError", message); | ||
| 257 | + } | ||
| 258 | + }); | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + } | ||
| 262 | + }); | ||
| 263 | + } | ||
| 195 | } | 264 | } |
printing/example/assets/example.html
0 → 100644
| 1 | +<!DOCTYPE html> | ||
| 2 | +<html> | ||
| 3 | + | ||
| 4 | +<head> | ||
| 5 | + <style> | ||
| 6 | + * { | ||
| 7 | + font-family: Arial, Helvetica, sans-serif; | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + table, | ||
| 11 | + th, | ||
| 12 | + td { | ||
| 13 | + border: 1px solid black; | ||
| 14 | + border-collapse: collapse; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + th, | ||
| 18 | + td { | ||
| 19 | + padding: 5px; | ||
| 20 | + } | ||
| 21 | + </style> | ||
| 22 | +</head> | ||
| 23 | + | ||
| 24 | +<body> | ||
| 25 | + <h2>Html conversion</h2> | ||
| 26 | + | ||
| 27 | + <caption>Sample HTML Table</caption> | ||
| 28 | + <table> | ||
| 29 | + <tr> | ||
| 30 | + <th>Company</th> | ||
| 31 | + <th>Contact</th> | ||
| 32 | + <th>Country</th> | ||
| 33 | + </tr> | ||
| 34 | + <tr> | ||
| 35 | + <td>Alfreds Futterkiste</td> | ||
| 36 | + <td>Maria Anders</td> | ||
| 37 | + <td>Germany</td> | ||
| 38 | + </tr> | ||
| 39 | + <tr> | ||
| 40 | + <td>Centro comercial Moctezuma</td> | ||
| 41 | + <td>Francisco Chang</td> | ||
| 42 | + <td>Mexico</td> | ||
| 43 | + </tr> | ||
| 44 | + <tr> | ||
| 45 | + <td>Ernst Handel</td> | ||
| 46 | + <td>Roland Mendel</td> | ||
| 47 | + <td>Austria</td> | ||
| 48 | + </tr> | ||
| 49 | + <tr> | ||
| 50 | + <td>Island Trading</td> | ||
| 51 | + <td>Helen Bennett</td> | ||
| 52 | + <td>UK</td> | ||
| 53 | + </tr> | ||
| 54 | + <tr> | ||
| 55 | + <td>Laughing Bacchus Winecellars</td> | ||
| 56 | + <td>Yoshi Tannamuri</td> | ||
| 57 | + <td>Canada</td> | ||
| 58 | + </tr> | ||
| 59 | + <tr> | ||
| 60 | + <td>Magazzini Alimentari Riuniti</td> | ||
| 61 | + <td>Giovanni Rovelli</td> | ||
| 62 | + <td>Italy</td> | ||
| 63 | + </tr> | ||
| 64 | + </table> | ||
| 65 | + | ||
| 66 | + <p>HTML links are defined with the a tag:</p> | ||
| 67 | + | ||
| 68 | + <a href="https://github.com/DavBfr/dart_pdf">This is a link</a> | ||
| 69 | + | ||
| 70 | + <h2>An Unordered HTML List</h2> | ||
| 71 | + | ||
| 72 | + <ul> | ||
| 73 | + <li>Coffee</li> | ||
| 74 | + <li>Tea</li> | ||
| 75 | + <li>Milk</li> | ||
| 76 | + </ul> | ||
| 77 | + | ||
| 78 | + <h2>An Ordered HTML List</h2> | ||
| 79 | + | ||
| 80 | + <ol> | ||
| 81 | + <li>Coffee</li> | ||
| 82 | + <li>Tea</li> | ||
| 83 | + <li>Milk</li> | ||
| 84 | + </ol> | ||
| 85 | + | ||
| 86 | +</body> | ||
| 87 | + | ||
| 88 | +</html> |
| @@ -5,6 +5,7 @@ import 'dart:ui' as ui; | @@ -5,6 +5,7 @@ import 'dart:ui' as ui; | ||
| 5 | 5 | ||
| 6 | import 'package:flutter/material.dart'; | 6 | import 'package:flutter/material.dart'; |
| 7 | import 'package:flutter/rendering.dart'; | 7 | import 'package:flutter/rendering.dart'; |
| 8 | +import 'package:flutter/services.dart'; | ||
| 8 | import 'package:path_provider/path_provider.dart'; | 9 | import 'package:path_provider/path_provider.dart'; |
| 9 | 10 | ||
| 10 | import 'package:pdf/pdf.dart'; | 11 | import 'package:pdf/pdf.dart'; |
| @@ -94,6 +95,14 @@ class MyAppState extends State<MyApp> { | @@ -94,6 +95,14 @@ class MyAppState extends State<MyApp> { | ||
| 94 | }); | 95 | }); |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 98 | + Future<void> _printHtml() async { | ||
| 99 | + print('Print html ...'); | ||
| 100 | + await Printing.layoutPdf(onLayout: (PdfPageFormat format) async { | ||
| 101 | + final String html = await rootBundle.loadString('assets/example.html'); | ||
| 102 | + return await Printing.convertHtml(format: format, html: html); | ||
| 103 | + }); | ||
| 104 | + } | ||
| 105 | + | ||
| 97 | @override | 106 | @override |
| 98 | Widget build(BuildContext context) { | 107 | Widget build(BuildContext context) { |
| 99 | return RepaintBoundary( | 108 | return RepaintBoundary( |
| @@ -117,6 +126,8 @@ class MyAppState extends State<MyApp> { | @@ -117,6 +126,8 @@ class MyAppState extends State<MyApp> { | ||
| 117 | onPressed: _printScreen), | 126 | onPressed: _printScreen), |
| 118 | RaisedButton( | 127 | RaisedButton( |
| 119 | child: const Text('Save to file'), onPressed: _saveAsFile), | 128 | child: const Text('Save to file'), onPressed: _saveAsFile), |
| 129 | + RaisedButton( | ||
| 130 | + child: const Text('Print Html'), onPressed: _printHtml), | ||
| 120 | ], | 131 | ], |
| 121 | ), | 132 | ), |
| 122 | ), | 133 | ), |
| @@ -16,10 +16,12 @@ | @@ -16,10 +16,12 @@ | ||
| 16 | 16 | ||
| 17 | import Flutter | 17 | import Flutter |
| 18 | import UIKit | 18 | import UIKit |
| 19 | +import WebKit | ||
| 19 | 20 | ||
| 20 | public class SwiftPrintingPlugin: NSObject, FlutterPlugin, UIPrintInteractionControllerDelegate { | 21 | public class SwiftPrintingPlugin: NSObject, FlutterPlugin, UIPrintInteractionControllerDelegate { |
| 21 | private var channel: FlutterMethodChannel? | 22 | private var channel: FlutterMethodChannel? |
| 22 | private var renderer: PdfPrintPageRenderer? | 23 | private var renderer: PdfPrintPageRenderer? |
| 24 | + private var urlObservation: NSKeyValueObservation? | ||
| 23 | 25 | ||
| 24 | init(_ channel: FlutterMethodChannel?) { | 26 | init(_ channel: FlutterMethodChannel?) { |
| 25 | super.init() | 27 | super.init() |
| @@ -52,6 +54,30 @@ public class SwiftPrintingPlugin: NSObject, FlutterPlugin, UIPrintInteractionCon | @@ -52,6 +54,30 @@ public class SwiftPrintingPlugin: NSObject, FlutterPlugin, UIPrintInteractionCon | ||
| 52 | ) | 54 | ) |
| 53 | } | 55 | } |
| 54 | result(NSNumber(value: 1)) | 56 | result(NSNumber(value: 1)) |
| 57 | + } else if call.method == "convertHtml" { | ||
| 58 | + let width = CGFloat((args["width"] as? NSNumber)?.floatValue ?? 0.0) | ||
| 59 | + let height = CGFloat((args["height"] as? NSNumber)?.floatValue ?? 0.0) | ||
| 60 | + let marginLeft = CGFloat((args["marginLeft"] as? NSNumber)?.floatValue ?? 0.0) | ||
| 61 | + let marginTop = CGFloat((args["marginTop"] as? NSNumber)?.floatValue ?? 0.0) | ||
| 62 | + let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0) | ||
| 63 | + let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0) | ||
| 64 | + convertHtml( | ||
| 65 | + (args["html"] as? String)!, | ||
| 66 | + withPageSize: CGRect( | ||
| 67 | + x: 0.0, | ||
| 68 | + y: 0.0, | ||
| 69 | + width: width, | ||
| 70 | + height: height | ||
| 71 | + ), | ||
| 72 | + andMargin: CGRect( | ||
| 73 | + x: marginLeft, | ||
| 74 | + y: marginTop, | ||
| 75 | + width: width - marginRight - marginLeft, | ||
| 76 | + height: height - marginBottom - marginTop | ||
| 77 | + ), | ||
| 78 | + andBaseUrl: args["baseUrl"] as? String == nil ? nil : URL(string: (args["baseUrl"] as? String)!) | ||
| 79 | + ) | ||
| 80 | + result(NSNumber(value: 1)) | ||
| 55 | } else { | 81 | } else { |
| 56 | result(FlutterMethodNotImplemented) | 82 | result(FlutterMethodNotImplemented) |
| 57 | } | 83 | } |
| @@ -118,4 +144,56 @@ public class SwiftPrintingPlugin: NSObject, FlutterPlugin, UIPrintInteractionCon | @@ -118,4 +144,56 @@ public class SwiftPrintingPlugin: NSObject, FlutterPlugin, UIPrintInteractionCon | ||
| 118 | } | 144 | } |
| 119 | UIApplication.shared.keyWindow?.rootViewController?.present(activityViewController, animated: true) | 145 | UIApplication.shared.keyWindow?.rootViewController?.present(activityViewController, animated: true) |
| 120 | } | 146 | } |
| 147 | + | ||
| 148 | + func convertHtml(_ data: String, withPageSize rect: CGRect, andMargin margin: CGRect, andBaseUrl baseUrl: URL?) { | ||
| 149 | + let viewController = UIApplication.shared.delegate?.window?!.rootViewController | ||
| 150 | + let wkWebView = WKWebView(frame: viewController!.view.bounds) | ||
| 151 | + wkWebView.isHidden = true | ||
| 152 | + wkWebView.tag = 100 | ||
| 153 | + viewController?.view.addSubview(wkWebView) | ||
| 154 | + wkWebView.loadHTMLString(data, baseURL: baseUrl ?? Bundle.main.bundleURL) | ||
| 155 | + | ||
| 156 | + urlObservation = wkWebView.observe(\.isLoading, changeHandler: { _, _ in | ||
| 157 | + // this is workaround for issue with loading local images | ||
| 158 | + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { | ||
| 159 | + // assign the print formatter to the print page renderer | ||
| 160 | + let renderer = UIPrintPageRenderer() | ||
| 161 | + renderer.addPrintFormatter(wkWebView.viewPrintFormatter(), startingAtPageAt: 0) | ||
| 162 | + | ||
| 163 | + // assign paperRect and printableRect values | ||
| 164 | + renderer.setValue(rect, forKey: "paperRect") | ||
| 165 | + renderer.setValue(margin, forKey: "printableRect") | ||
| 166 | + | ||
| 167 | + // create pdf context and draw each page | ||
| 168 | + let pdfData = NSMutableData() | ||
| 169 | + UIGraphicsBeginPDFContextToData(pdfData, .zero, nil) | ||
| 170 | + | ||
| 171 | + for i in 0 ..< renderer.numberOfPages { | ||
| 172 | + UIGraphicsBeginPDFPage() | ||
| 173 | + renderer.drawPage(at: i, in: UIGraphicsGetPDFContextBounds()) | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + UIGraphicsEndPDFContext() | ||
| 177 | + | ||
| 178 | + if let viewWithTag = viewController?.view.viewWithTag(wkWebView.tag) { | ||
| 179 | + viewWithTag.removeFromSuperview() // remove hidden webview when pdf is generated | ||
| 180 | + | ||
| 181 | + // clear WKWebView cache | ||
| 182 | + if #available(iOS 9.0, *) { | ||
| 183 | + WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in | ||
| 184 | + records.forEach { record in | ||
| 185 | + WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {}) | ||
| 186 | + } | ||
| 187 | + } | ||
| 188 | + } | ||
| 189 | + } | ||
| 190 | + | ||
| 191 | + // dispose urlObservation | ||
| 192 | + self.urlObservation = nil | ||
| 193 | + | ||
| 194 | + let data = FlutterStandardTypedData(bytes: pdfData as Data) | ||
| 195 | + self.channel?.invokeMethod("onHtmlRendered", arguments: data) | ||
| 196 | + } | ||
| 197 | + }) | ||
| 198 | + } | ||
| 121 | } | 199 | } |
| @@ -21,6 +21,7 @@ typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format); | @@ -21,6 +21,7 @@ typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format); | ||
| 21 | mixin Printing { | 21 | mixin Printing { |
| 22 | static const MethodChannel _channel = MethodChannel('printing'); | 22 | static const MethodChannel _channel = MethodChannel('printing'); |
| 23 | static LayoutCallback _onLayout; | 23 | static LayoutCallback _onLayout; |
| 24 | + static Completer<List<int>> _onHtmlRendered; | ||
| 24 | 25 | ||
| 25 | static Future<void> _handleMethod(MethodCall call) async { | 26 | static Future<void> _handleMethod(MethodCall call) async { |
| 26 | switch (call.method) { | 27 | switch (call.method) { |
| @@ -37,6 +38,12 @@ mixin Printing { | @@ -37,6 +38,12 @@ mixin Printing { | ||
| 37 | 'doc': Uint8List.fromList(bytes), | 38 | 'doc': Uint8List.fromList(bytes), |
| 38 | }; | 39 | }; |
| 39 | return await _channel.invokeMethod('writePdf', params); | 40 | return await _channel.invokeMethod('writePdf', params); |
| 41 | + case 'onHtmlRendered': | ||
| 42 | + _onHtmlRendered.complete(call.arguments); | ||
| 43 | + break; | ||
| 44 | + case 'onHtmlError': | ||
| 45 | + _onHtmlRendered.completeError(call.arguments); | ||
| 46 | + break; | ||
| 40 | } | 47 | } |
| 41 | } | 48 | } |
| 42 | 49 | ||
| @@ -89,4 +96,25 @@ mixin Printing { | @@ -89,4 +96,25 @@ mixin Printing { | ||
| 89 | }; | 96 | }; |
| 90 | return await _channel.invokeMethod('sharePdf', params); | 97 | return await _channel.invokeMethod('sharePdf', params); |
| 91 | } | 98 | } |
| 99 | + | ||
| 100 | + static Future<List<int>> convertHtml( | ||
| 101 | + {@required String html, | ||
| 102 | + String baseUrl, | ||
| 103 | + PdfPageFormat format = PdfPageFormat.a4}) async { | ||
| 104 | + final Map<String, dynamic> params = <String, dynamic>{ | ||
| 105 | + 'html': html, | ||
| 106 | + 'baseUrl': baseUrl, | ||
| 107 | + 'width': format.width, | ||
| 108 | + 'height': format.height, | ||
| 109 | + 'marginLeft': format.marginLeft, | ||
| 110 | + 'marginTop': format.marginTop, | ||
| 111 | + 'marginRight': format.marginRight, | ||
| 112 | + 'marginBottom': format.marginBottom, | ||
| 113 | + }; | ||
| 114 | + | ||
| 115 | + _channel.setMethodCallHandler(_handleMethod); | ||
| 116 | + _onHtmlRendered = Completer<List<int>>(); | ||
| 117 | + await _channel.invokeMethod<void>('convertHtml', params); | ||
| 118 | + return _onHtmlRendered.future; | ||
| 119 | + } | ||
| 92 | } | 120 | } |
| @@ -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: 2.0.4 | 7 | +version: 2.1.0 |
| 8 | 8 | ||
| 9 | environment: | 9 | environment: |
| 10 | sdk: ">=2.1.0 <3.0.0" | 10 | sdk: ">=2.1.0 <3.0.0" |
-
Please register or login to post a comment