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