Showing
6 changed files
with
167 additions
and
5 deletions
| @@ -26,6 +26,10 @@ | @@ -26,6 +26,10 @@ | ||
| 26 | }); | 26 | }); |
| 27 | } | 27 | } |
| 28 | </script> | 28 | </script> |
| 29 | + <script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.min.js"></script> | ||
| 30 | + <script type="text/javascript"> | ||
| 31 | + pdfjsLib.GlobalWorkerOptions.workerSrc = "//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.worker.min.js"; | ||
| 32 | + </script> | ||
| 29 | <script src="main.dart.js" type="application/javascript"></script> | 33 | <script src="main.dart.js" type="application/javascript"></script> |
| 30 | </body> | 34 | </body> |
| 31 | </html> | 35 | </html> |
printing/lib/src/pdfjs.dart
0 → 100644
| 1 | +@JS() | ||
| 2 | +library pdf.js; | ||
| 3 | + | ||
| 4 | +import 'dart:html'; | ||
| 5 | +import 'dart:typed_data'; | ||
| 6 | + | ||
| 7 | +import 'package:js/js.dart'; | ||
| 8 | + | ||
| 9 | +@JS('pdfjsLib') | ||
| 10 | +class PdfJs { | ||
| 11 | + external static PdfJsDocLoader getDocument(Settings data); | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +@anonymous | ||
| 15 | +@JS() | ||
| 16 | +class Settings { | ||
| 17 | + external set data(Uint8List value); | ||
| 18 | + external set scale(double value); | ||
| 19 | + external set canvasContext(CanvasRenderingContext2D value); | ||
| 20 | + external set viewport(PdfJsViewport value); | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +@anonymous | ||
| 24 | +@JS() | ||
| 25 | +class PdfJsDocLoader { | ||
| 26 | + external Future<PdfJsDoc> get promise; | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +@anonymous | ||
| 30 | +@JS() | ||
| 31 | +class PdfJsDoc { | ||
| 32 | + external Future<PdfJsPage> getPage(int num); | ||
| 33 | + external int get numPages; | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +@anonymous | ||
| 37 | +@JS() | ||
| 38 | +class PdfJsPage { | ||
| 39 | + external PdfJsViewport getViewport(Settings data); | ||
| 40 | + external PdfJsRender render(Settings data); | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +@anonymous | ||
| 44 | +@JS() | ||
| 45 | +class PdfJsViewport { | ||
| 46 | + external num get width; | ||
| 47 | + external num get height; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +@anonymous | ||
| 51 | +@JS() | ||
| 52 | +class PdfJsRender { | ||
| 53 | + external Future<void> get promise; | ||
| 54 | +} |
| @@ -17,13 +17,18 @@ | @@ -17,13 +17,18 @@ | ||
| 17 | import 'dart:async'; | 17 | import 'dart:async'; |
| 18 | import 'dart:convert'; | 18 | import 'dart:convert'; |
| 19 | import 'dart:html' as html; | 19 | import 'dart:html' as html; |
| 20 | +import 'dart:html'; | ||
| 21 | +import 'dart:io'; | ||
| 20 | import 'dart:js' as js; | 22 | import 'dart:js' as js; |
| 23 | +import 'dart:js_util'; | ||
| 21 | import 'dart:typed_data'; | 24 | import 'dart:typed_data'; |
| 22 | import 'dart:ui'; | 25 | import 'dart:ui'; |
| 23 | 26 | ||
| 24 | import 'package:flutter/rendering.dart' show Rect; | 27 | import 'package:flutter/rendering.dart' show Rect; |
| 25 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; | 28 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; |
| 29 | +import 'package:image/image.dart' as im; | ||
| 26 | import 'package:pdf/pdf.dart'; | 30 | import 'package:pdf/pdf.dart'; |
| 31 | +import 'package:printing/src/pdfjs.dart'; | ||
| 27 | import 'package:printing/src/printer.dart'; | 32 | import 'package:printing/src/printer.dart'; |
| 28 | import 'package:printing/src/raster.dart'; | 33 | import 'package:printing/src/raster.dart'; |
| 29 | 34 | ||
| @@ -41,12 +46,17 @@ class PrintingPlugin extends PrintingPlatform { | @@ -41,12 +46,17 @@ class PrintingPlugin extends PrintingPlatform { | ||
| 41 | 46 | ||
| 42 | @override | 47 | @override |
| 43 | Future<PrintingInfo> info() async { | 48 | Future<PrintingInfo> info() async { |
| 44 | - return const PrintingInfo( | 49 | + final dynamic workerSrc = js.context.callMethod('eval', <String>[ |
| 50 | + 'typeof pdfjsLib !== "undefined" && pdfjsLib.GlobalWorkerOptions.workerSrc!="";' | ||
| 51 | + ]); | ||
| 52 | + | ||
| 53 | + return PrintingInfo( | ||
| 45 | directPrint: false, | 54 | directPrint: false, |
| 46 | dynamicLayout: false, | 55 | dynamicLayout: false, |
| 47 | canPrint: true, | 56 | canPrint: true, |
| 48 | canConvertHtml: false, | 57 | canConvertHtml: false, |
| 49 | canShare: true, | 58 | canShare: true, |
| 59 | + canRaster: workerSrc, | ||
| 50 | ); | 60 | ); |
| 51 | } | 61 | } |
| 52 | 62 | ||
| @@ -160,7 +170,99 @@ class PrintingPlugin extends PrintingPlatform { | @@ -160,7 +170,99 @@ class PrintingPlugin extends PrintingPlatform { | ||
| 160 | Uint8List document, | 170 | Uint8List document, |
| 161 | List<int> pages, | 171 | List<int> pages, |
| 162 | double dpi, | 172 | double dpi, |
| 163 | - ) { | ||
| 164 | - throw UnimplementedError(); | 173 | + ) async* { |
| 174 | + final PdfJsDocLoader t = PdfJs.getDocument(Settings()..data = document); | ||
| 175 | + | ||
| 176 | + final PdfJsDoc d = await promiseToFuture(t.promise); | ||
| 177 | + final int numPages = d.numPages; | ||
| 178 | + | ||
| 179 | + final html.CanvasElement canvas = | ||
| 180 | + js.context['document'].createElement('canvas'); | ||
| 181 | + final html.CanvasRenderingContext2D context = canvas.getContext('2d'); | ||
| 182 | + | ||
| 183 | + for (int i = 0; i < numPages; i++) { | ||
| 184 | + final PdfJsPage page = await promiseToFuture(d.getPage(i + 1)); | ||
| 185 | + final PdfJsViewport viewport = page.getViewport(Settings()..scale = 1.5); | ||
| 186 | + | ||
| 187 | + canvas.height = viewport.height.toInt(); | ||
| 188 | + canvas.width = viewport.width.toInt(); | ||
| 189 | + | ||
| 190 | + final Settings renderContext = Settings() | ||
| 191 | + ..canvasContext = context | ||
| 192 | + ..viewport = viewport; | ||
| 193 | + | ||
| 194 | + await promiseToFuture<void>(page.render(renderContext).promise); | ||
| 195 | + | ||
| 196 | + // final Uint8ClampedList data = | ||
| 197 | + // context.getImageData(0, 0, canvas.width, canvas.height).data; | ||
| 198 | + | ||
| 199 | + // Convert the image to PNG | ||
| 200 | + final Completer<void> completer = Completer<void>(); | ||
| 201 | + final html.Blob blob = await canvas.toBlob(); | ||
| 202 | + final BytesBuilder data = BytesBuilder(); | ||
| 203 | + final html.FileReader r = FileReader(); | ||
| 204 | + r.readAsArrayBuffer(blob); | ||
| 205 | + r.onLoadEnd.listen( | ||
| 206 | + (ProgressEvent e) { | ||
| 207 | + data.add(r.result); | ||
| 208 | + completer.complete(); | ||
| 209 | + }, | ||
| 210 | + ); | ||
| 211 | + await completer.future; | ||
| 212 | + | ||
| 213 | + yield _WebPdfRaster( | ||
| 214 | + canvas.width, | ||
| 215 | + canvas.height, | ||
| 216 | + data.toBytes(), | ||
| 217 | + ); | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +class _WebPdfRaster extends PdfRaster { | ||
| 223 | + _WebPdfRaster( | ||
| 224 | + int width, | ||
| 225 | + int height, | ||
| 226 | + this.png, | ||
| 227 | + ) : super(width, height, null); | ||
| 228 | + | ||
| 229 | + final Uint8List png; | ||
| 230 | + | ||
| 231 | + Uint8List _pixels; | ||
| 232 | + | ||
| 233 | + @override | ||
| 234 | + Uint8List get pixels { | ||
| 235 | + if (_pixels == null) { | ||
| 236 | + final im.Image img = asImage(); | ||
| 237 | + _pixels = img.data.buffer.asUint8List(); | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + return _pixels; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + @override | ||
| 244 | + Future<Image> toImage() { | ||
| 245 | + final Completer<Image> comp = Completer<Image>(); | ||
| 246 | + decodeImageFromPixels( | ||
| 247 | + png, | ||
| 248 | + width, | ||
| 249 | + height, | ||
| 250 | + PixelFormat.rgba8888, | ||
| 251 | + (Image image) => comp.complete(image), | ||
| 252 | + ); | ||
| 253 | + return comp.future; | ||
| 254 | + } | ||
| 255 | + | ||
| 256 | + @override | ||
| 257 | + Future<Uint8List> toPng() async { | ||
| 258 | + return png; | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + @override | ||
| 262 | + im.Image asImage() { | ||
| 263 | + if (_pixels != null) { | ||
| 264 | + return super.asImage(); | ||
| 265 | + } | ||
| 266 | + return im.PngDecoder().decodeImage(png); | ||
| 165 | } | 267 | } |
| 166 | } | 268 | } |
| @@ -24,7 +24,7 @@ import 'package:image/image.dart' as im; | @@ -24,7 +24,7 @@ import 'package:image/image.dart' as im; | ||
| 24 | /// Represents a bitmap image | 24 | /// Represents a bitmap image |
| 25 | class PdfRaster { | 25 | class PdfRaster { |
| 26 | /// Create a bitmap image | 26 | /// Create a bitmap image |
| 27 | - PdfRaster( | 27 | + const PdfRaster( |
| 28 | this.width, | 28 | this.width, |
| 29 | this.height, | 29 | this.height, |
| 30 | this.pixels, | 30 | this.pixels, |
| @@ -40,7 +40,7 @@ class PdfRaster { | @@ -40,7 +40,7 @@ class PdfRaster { | ||
| 40 | final Uint8List pixels; | 40 | final Uint8List pixels; |
| 41 | 41 | ||
| 42 | @override | 42 | @override |
| 43 | - String toString() => 'Image ${width}x$height ${pixels.lengthInBytes} bytes'; | 43 | + String toString() => 'Image ${width}x$height ${width * height * 4} bytes'; |
| 44 | 44 | ||
| 45 | /// Decode RGBA raw image to dart:ui Image | 45 | /// Decode RGBA raw image to dart:ui Image |
| 46 | Future<ui.Image> toImage() { | 46 | Future<ui.Image> toImage() { |
| @@ -19,6 +19,7 @@ dependencies: | @@ -19,6 +19,7 @@ dependencies: | ||
| 19 | plugin_platform_interface: ^1.0.2 | 19 | plugin_platform_interface: ^1.0.2 |
| 20 | meta: ^1.1.5 | 20 | meta: ^1.1.5 |
| 21 | image: ^2.1.4 | 21 | image: ^2.1.4 |
| 22 | + js: ^0.6.1 | ||
| 22 | 23 | ||
| 23 | dev_dependencies: | 24 | dev_dependencies: |
| 24 | flutter_test: | 25 | flutter_test: |
-
Please register or login to post a comment