David PHAM-VAN

Automatic pdf.js library loading

@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 - Fix parsing TTF fonts with zero-length glyphs 6 - Fix parsing TTF fonts with zero-length glyphs
7 - Fix PdfPreview page format and orientation updates 7 - Fix PdfPreview page format and orientation updates
8 - Update Pdfium version to 4929 8 - Update Pdfium version to 4929
  9 +- Automatic pdf.js library loading
9 10
10 ## 5.7.2 11 ## 5.7.2
11 12
@@ -36,8 +36,9 @@ for documentation. @@ -36,8 +36,9 @@ for documentation.
36 ``` 36 ```
37 4. For MacOS add printing capability by opening macos directory in XCode 37 4. For MacOS add printing capability by opening macos directory in XCode
38 38
39 -5. For the web, a javascript library and a small script has to be added to  
40 - your `web/index.html` file, just before `</head>`: 39 +5. If you want to manually set the PdfJs library version for the web, a javascript
  40 + library and a small script has to be added to your `web/index.html` file, just
  41 + before `</head>`. Otherwise it is loaded automatically:
41 42
42 ```html 43 ```html
43 <script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.8.335/pdf.min.js"></script> 44 <script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.8.335/pdf.min.js"></script>
@@ -8,8 +8,6 @@ analyzer: @@ -8,8 +8,6 @@ analyzer:
8 missing_return: warning 8 missing_return: warning
9 public_member_api_docs: ignore 9 public_member_api_docs: ignore
10 todo: ignore 10 todo: ignore
11 - constant_identifier_names: ignore  
12 - avoid_print: ignore  
13 11
14 linter: 12 linter:
15 rules: 13 rules:
@@ -29,12 +29,13 @@ import 'package:pdf/pdf.dart'; @@ -29,12 +29,13 @@ import 'package:pdf/pdf.dart';
29 29
30 import 'src/callback.dart'; 30 import 'src/callback.dart';
31 import 'src/interface.dart'; 31 import 'src/interface.dart';
  32 +import 'src/mutex.dart';
32 import 'src/pdfjs.dart'; 33 import 'src/pdfjs.dart';
33 import 'src/printer.dart'; 34 import 'src/printer.dart';
34 import 'src/printing_info.dart'; 35 import 'src/printing_info.dart';
35 import 'src/raster.dart'; 36 import 'src/raster.dart';
36 37
37 -/// Print plugin targetting Flutter on the Web 38 +/// Print plugin targeting Flutter on the Web
38 class PrintingPlugin extends PrintingPlatform { 39 class PrintingPlugin extends PrintingPlatform {
39 /// Registers this class as the default instance of [PrintingPlugin]. 40 /// Registers this class as the default instance of [PrintingPlugin].
40 static void registerWith(Registrar registrar) { 41 static void registerWith(Registrar registrar) {
@@ -45,16 +46,67 @@ class PrintingPlugin extends PrintingPlatform { @@ -45,16 +46,67 @@ class PrintingPlugin extends PrintingPlatform {
45 46
46 static const String _frameId = '__net_nfet_printing__'; 47 static const String _frameId = '__net_nfet_printing__';
47 48
  49 + static const _pdfJsVersion =
  50 + 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.13.216';
  51 +
  52 + final _loading = Mutex();
  53 +
  54 + bool get _hasPdfJsLib => js.context.callMethod('eval', <String>[
  55 + 'typeof pdfjsLib !== "undefined" && pdfjsLib.GlobalWorkerOptions.workerSrc!="";'
  56 + ]);
  57 +
  58 + Future<void> _initPlugin() async {
  59 + await _loading.acquire();
  60 +
  61 + if (!_hasPdfJsLib) {
  62 + final script = ScriptElement()
  63 + ..type = 'text/javascript'
  64 + ..async = true
  65 + ..src = '$_pdfJsVersion/pdf.min.js';
  66 + assert(document.head != null);
  67 + document.head!.append(script);
  68 + await script.onLoad.first;
  69 +
  70 + if (js.context['pdfjsLib'] == null) {
  71 + // In dev, requireJs is loaded in
  72 + final require = js.JsObject.fromBrowserObject(js.context['require']);
  73 + require.callMethod('config', <dynamic>[
  74 + js.JsObject.jsify({
  75 + 'paths': {
  76 + 'pdfjs-dist/build/pdf': '$_pdfJsVersion/pdf.min',
  77 + 'pdfjs-dist/build/pdf.worker': '$_pdfJsVersion/pdf.worker.min',
  78 + }
  79 + })
  80 + ]);
  81 +
  82 + final completer = Completer<void>();
  83 +
  84 + js.context.callMethod('require', <dynamic>[
  85 + js.JsObject.jsify(
  86 + ['pdfjs-dist/build/pdf', 'pdfjs-dist/build/pdf.worker']),
  87 + (dynamic app) {
  88 + js.context['pdfjsLib'] = app;
  89 + completer.complete();
  90 + }
  91 + ]);
  92 +
  93 + await completer.future;
  94 + }
  95 +
  96 + js.context['pdfjsLib']['GlobalWorkerOptions']['workerSrc'] =
  97 + '$_pdfJsVersion/pdf.worker.min.js';
  98 + }
  99 +
  100 + _loading.release();
  101 + }
  102 +
48 @override 103 @override
49 Future<PrintingInfo> info() async { 104 Future<PrintingInfo> info() async {
50 - final dynamic workerSrc = js.context.callMethod('eval', <String>[  
51 - 'typeof pdfjsLib !== "undefined" && pdfjsLib.GlobalWorkerOptions.workerSrc!="";'  
52 - ]);  
53 - 105 + await _initPlugin();
54 return PrintingInfo( 106 return PrintingInfo(
55 canPrint: true, 107 canPrint: true,
56 canShare: true, 108 canShare: true,
57 - canRaster: workerSrc, 109 + canRaster: _hasPdfJsLib,
58 ); 110 );
59 } 111 }
60 112
@@ -235,6 +287,8 @@ class PrintingPlugin extends PrintingPlatform { @@ -235,6 +287,8 @@ class PrintingPlugin extends PrintingPlatform {
235 List<int>? pages, 287 List<int>? pages,
236 double dpi, 288 double dpi,
237 ) async* { 289 ) async* {
  290 + await _initPlugin();
  291 +
238 final t = PdfJs.getDocument(Settings()..data = document); 292 final t = PdfJs.getDocument(Settings()..data = document);
239 293
240 final d = await promiseToFuture<PdfJsDoc>(t.promise); 294 final d = await promiseToFuture<PdfJsDoc>(t.promise);
@@ -19,6 +19,8 @@ import 'dart:convert'; @@ -19,6 +19,8 @@ import 'dart:convert';
19 19
20 import 'package:flutter/services.dart'; 20 import 'package:flutter/services.dart';
21 21
  22 +import '../mutex.dart';
  23 +
22 /// Application asset manifest. 24 /// Application asset manifest.
23 mixin AssetManifest { 25 mixin AssetManifest {
24 static final _assets = <String>[]; 26 static final _assets = <String>[];
@@ -63,29 +65,3 @@ mixin AssetManifest { @@ -63,29 +65,3 @@ mixin AssetManifest {
63 return _assets.contains(key); 65 return _assets.contains(key);
64 } 66 }
65 } 67 }
66 -  
67 -/// Simple Mutex  
68 -class Mutex {  
69 - final _waiting = <Completer>[];  
70 -  
71 - bool _locked = false;  
72 -  
73 - /// Lock the mutex  
74 - Future<void> acquire() async {  
75 - if (_locked) {  
76 - final c = Completer<void>();  
77 - _waiting.add(c);  
78 - await c.future;  
79 - }  
80 - _locked = true;  
81 - }  
82 -  
83 - /// Release the mutex  
84 - void release() {  
85 - _locked = false;  
86 - for (final e in _waiting) {  
87 - e.complete();  
88 - }  
89 - _waiting.clear();  
90 - }  
91 -}  
  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 +/// Simple Mutex
  20 +class Mutex {
  21 + final _waiting = <Completer>[];
  22 +
  23 + bool _locked = false;
  24 +
  25 + bool get locked => _locked;
  26 +
  27 + /// Wait for the mutex to be available
  28 + Future<void> wait() async {
  29 + await acquire();
  30 + release();
  31 + }
  32 +
  33 + /// Lock the mutex
  34 + Future<void> acquire() async {
  35 + if (_locked) {
  36 + final c = Completer<void>();
  37 + _waiting.add(c);
  38 + await c.future;
  39 + }
  40 + _locked = true;
  41 + }
  42 +
  43 + /// Release the mutex
  44 + void release() {
  45 + _locked = false;
  46 + for (final e in _waiting) {
  47 + e.complete();
  48 + }
  49 + _waiting.clear();
  50 + }
  51 +}