Showing
18 changed files
with
307 additions
and
73 deletions
@@ -91,7 +91,7 @@ class Invoice { | @@ -91,7 +91,7 @@ class Invoice { | ||
91 | 91 | ||
92 | double get _grandTotal => _total * (1 + tax); | 92 | double get _grandTotal => _total * (1 + tax); |
93 | 93 | ||
94 | - PdfImage _logo; | 94 | + pw.MemoryImage _logo; |
95 | 95 | ||
96 | Future<Uint8List> buildPdf(PdfPageFormat pageFormat) async { | 96 | Future<Uint8List> buildPdf(PdfPageFormat pageFormat) async { |
97 | // Create a PDF document. | 97 | // Create a PDF document. |
@@ -101,9 +101,8 @@ class Invoice { | @@ -101,9 +101,8 @@ class Invoice { | ||
101 | final font2 = await rootBundle.load('assets/roboto2.ttf'); | 101 | final font2 = await rootBundle.load('assets/roboto2.ttf'); |
102 | final font3 = await rootBundle.load('assets/roboto3.ttf'); | 102 | final font3 = await rootBundle.load('assets/roboto3.ttf'); |
103 | 103 | ||
104 | - _logo = PdfImage.file( | ||
105 | - doc.document, | ||
106 | - bytes: (await rootBundle.load('assets/logo.png')).buffer.asUint8List(), | 104 | + _logo = pw.MemoryImage( |
105 | + (await rootBundle.load('assets/logo.png')).buffer.asUint8List(), | ||
107 | ); | 106 | ); |
108 | 107 | ||
109 | // Add page to the PDF | 108 | // Add page to the PDF |
@@ -191,7 +190,8 @@ class Invoice { | @@ -191,7 +190,8 @@ class Invoice { | ||
191 | alignment: pw.Alignment.topRight, | 190 | alignment: pw.Alignment.topRight, |
192 | padding: const pw.EdgeInsets.only(bottom: 8, left: 30), | 191 | padding: const pw.EdgeInsets.only(bottom: 8, left: 30), |
193 | height: 72, | 192 | height: 72, |
194 | - child: _logo != null ? pw.Image(_logo) : pw.PdfLogo(), | 193 | + child: |
194 | + _logo != null ? pw.Image.provider(_logo) : pw.PdfLogo(), | ||
195 | ), | 195 | ), |
196 | // pw.Container( | 196 | // pw.Container( |
197 | // color: baseColor, | 197 | // color: baseColor, |
@@ -29,9 +29,8 @@ const sep = 120.0; | @@ -29,9 +29,8 @@ const sep = 120.0; | ||
29 | Future<Uint8List> generateResume(PdfPageFormat format) async { | 29 | Future<Uint8List> generateResume(PdfPageFormat format) async { |
30 | final doc = pw.Document(title: 'My Résumé', author: 'David PHAM-VAN'); | 30 | final doc = pw.Document(title: 'My Résumé', author: 'David PHAM-VAN'); |
31 | 31 | ||
32 | - final profileImage = PdfImage.file( | ||
33 | - doc.document, | ||
34 | - bytes: (await rootBundle.load('assets/profile.jpg')).buffer.asUint8List(), | 32 | + final profileImage = pw.MemoryImage( |
33 | + (await rootBundle.load('assets/profile.jpg')).buffer.asUint8List(), | ||
35 | ); | 34 | ); |
36 | 35 | ||
37 | final pageTheme = await _myPageTheme(format); | 36 | final pageTheme = await _myPageTheme(format); |
@@ -121,7 +120,7 @@ Future<Uint8List> generateResume(PdfPageFormat format) async { | @@ -121,7 +120,7 @@ Future<Uint8List> generateResume(PdfPageFormat format) async { | ||
121 | width: 100, | 120 | width: 100, |
122 | height: 100, | 121 | height: 100, |
123 | color: lightGreen, | 122 | color: lightGreen, |
124 | - child: pw.Image(profileImage), | 123 | + child: pw.Image.provider(profileImage), |
125 | ), | 124 | ), |
126 | ), | 125 | ), |
127 | pw.Column(children: <pw.Widget>[ | 126 | pw.Column(children: <pw.Widget>[ |
@@ -79,6 +79,7 @@ | @@ -79,6 +79,7 @@ | ||
79 | - Add Chart Widget [Marco Papula] | 79 | - Add Chart Widget [Marco Papula] |
80 | - Add Divider and VerticalDivider Widget | 80 | - Add Divider and VerticalDivider Widget |
81 | - Replace Theme with ThemeData | 81 | - Replace Theme with ThemeData |
82 | +- Implement ImageProvider | ||
82 | 83 | ||
83 | ## 1.6.2 | 84 | ## 1.6.2 |
84 | 85 |
@@ -56,17 +56,15 @@ pdf.addPage(pw.Page( | @@ -56,17 +56,15 @@ pdf.addPage(pw.Page( | ||
56 | To load an image from a file: | 56 | To load an image from a file: |
57 | 57 | ||
58 | ```dart | 58 | ```dart |
59 | -final image = PdfImage.file( | ||
60 | - pdf.document, | ||
61 | - bytes: File('test.webp').readAsBytesSync(), | 59 | +final image = pw.MemoryImage( |
60 | + File('test.webp').readAsBytesSync(), | ||
62 | ); | 61 | ); |
63 | 62 | ||
64 | -pdf.addPage(pw.Page( | ||
65 | - build: (pw.Context context) { | 63 | +pdf.addPage(pw.Page(build: (pw.Context context) { |
66 | return pw.Center( | 64 | return pw.Center( |
67 | - child: pw.Image(image), | 65 | + child: pw.Image.provider(image), |
68 | ); // Center | 66 | ); // Center |
69 | - })); // Page | 67 | +})); // Page |
70 | ``` | 68 | ``` |
71 | 69 | ||
72 | To use a TrueType font: | 70 | To use a TrueType font: |
@@ -50,6 +50,7 @@ part 'widgets/geometry.dart'; | @@ -50,6 +50,7 @@ part 'widgets/geometry.dart'; | ||
50 | part 'widgets/grid_view.dart'; | 50 | part 'widgets/grid_view.dart'; |
51 | part 'widgets/icon.dart'; | 51 | part 'widgets/icon.dart'; |
52 | part 'widgets/image.dart'; | 52 | part 'widgets/image.dart'; |
53 | +part 'widgets/image_provider.dart'; | ||
53 | part 'widgets/multi_page.dart'; | 54 | part 'widgets/multi_page.dart'; |
54 | part 'widgets/page.dart'; | 55 | part 'widgets/page.dart'; |
55 | part 'widgets/page_theme.dart'; | 56 | part 'widgets/page_theme.dart'; |
@@ -144,20 +144,36 @@ class BoxBorder { | @@ -144,20 +144,36 @@ class BoxBorder { | ||
144 | 144 | ||
145 | @immutable | 145 | @immutable |
146 | class DecorationImage { | 146 | class DecorationImage { |
147 | - const DecorationImage( | ||
148 | - {@required this.image, | 147 | + @Deprecated('Use DecorationImage.provider()') |
148 | + DecorationImage({ | ||
149 | + @required PdfImage image, | ||
149 | this.fit = BoxFit.cover, | 150 | this.fit = BoxFit.cover, |
150 | - this.alignment = Alignment.center}) | ||
151 | - : assert(image != null), | 151 | + this.alignment = Alignment.center, |
152 | + }) : assert(image != null), | ||
153 | + assert(fit != null), | ||
154 | + assert(alignment != null), | ||
155 | + image = ImageProxy(image), | ||
156 | + dpi = null; | ||
157 | + | ||
158 | + const DecorationImage.provider({ | ||
159 | + @required this.image, | ||
160 | + this.fit = BoxFit.cover, | ||
161 | + this.alignment = Alignment.center, | ||
162 | + this.dpi, | ||
163 | + }) : assert(image != null), | ||
152 | assert(fit != null), | 164 | assert(fit != null), |
153 | assert(alignment != null); | 165 | assert(alignment != null); |
154 | 166 | ||
155 | - final PdfImage image; | 167 | + final ImageProvider image; |
156 | final BoxFit fit; | 168 | final BoxFit fit; |
157 | final Alignment alignment; | 169 | final Alignment alignment; |
170 | + final double dpi; | ||
158 | 171 | ||
159 | void paint(Context context, PdfRect box) { | 172 | void paint(Context context, PdfRect box) { |
160 | - final imageSize = PdfPoint(image.width.toDouble(), image.height.toDouble()); | 173 | + final _image = image.resolve(context, box.size, dpi: dpi); |
174 | + | ||
175 | + final imageSize = | ||
176 | + PdfPoint(_image.width.toDouble(), _image.height.toDouble()); | ||
161 | final sizes = applyBoxFit(fit, imageSize, box.size); | 177 | final sizes = applyBoxFit(fit, imageSize, box.size); |
162 | final scaleX = sizes.destination.x / sizes.source.x; | 178 | final scaleX = sizes.destination.x / sizes.source.x; |
163 | final scaleY = sizes.destination.y / sizes.source.y; | 179 | final scaleY = sizes.destination.y / sizes.source.y; |
@@ -174,7 +190,7 @@ class DecorationImage { | @@ -174,7 +190,7 @@ class DecorationImage { | ||
174 | ..drawRect(box.x, box.y, box.width, box.height) | 190 | ..drawRect(box.x, box.y, box.width, box.height) |
175 | ..clipPath() | 191 | ..clipPath() |
176 | ..setTransform(mat) | 192 | ..setTransform(mat) |
177 | - ..drawImage(image, 0, 0, imageSize.x, imageSize.y) | 193 | + ..drawImage(_image, 0, 0, imageSize.x, imageSize.y) |
178 | ..restoreContext(); | 194 | ..restoreContext(); |
179 | } | 195 | } |
180 | } | 196 | } |
@@ -75,18 +75,27 @@ void _drawImageRect(PdfGraphics canvas, PdfImage image, PdfRect sourceRect, | @@ -75,18 +75,27 @@ void _drawImageRect(PdfGraphics canvas, PdfImage image, PdfRect sourceRect, | ||
75 | } | 75 | } |
76 | 76 | ||
77 | class Image extends Widget { | 77 | class Image extends Widget { |
78 | + @Deprecated('Use Image.provider instead') | ||
78 | Image( | 79 | Image( |
79 | - this.image, { | 80 | + PdfImage image, { |
80 | this.fit = BoxFit.contain, | 81 | this.fit = BoxFit.contain, |
81 | this.alignment = Alignment.center, | 82 | this.alignment = Alignment.center, |
82 | this.width, | 83 | this.width, |
83 | this.height, | 84 | this.height, |
84 | }) : assert(image != null), | 85 | }) : assert(image != null), |
85 | - aspectRatio = image.height.toDouble() / image.width.toDouble(); | 86 | + image = ImageProxy(image), |
87 | + dpi = null; | ||
86 | 88 | ||
87 | - final PdfImage image; | 89 | + Image.provider( |
90 | + this.image, { | ||
91 | + this.fit = BoxFit.contain, | ||
92 | + this.alignment = Alignment.center, | ||
93 | + this.width, | ||
94 | + this.height, | ||
95 | + this.dpi, | ||
96 | + }) : assert(image != null); | ||
88 | 97 | ||
89 | - final double aspectRatio; | 98 | + final ImageProvider image; |
90 | 99 | ||
91 | final BoxFit fit; | 100 | final BoxFit fit; |
92 | 101 | ||
@@ -96,6 +105,8 @@ class Image extends Widget { | @@ -96,6 +105,8 @@ class Image extends Widget { | ||
96 | 105 | ||
97 | final double height; | 106 | final double height; |
98 | 107 | ||
108 | + final double dpi; | ||
109 | + | ||
99 | @override | 110 | @override |
100 | void layout(Context context, BoxConstraints constraints, | 111 | void layout(Context context, BoxConstraints constraints, |
101 | {bool parentUsesSize = false}) { | 112 | {bool parentUsesSize = false}) { |
@@ -119,9 +130,11 @@ class Image extends Widget { | @@ -119,9 +130,11 @@ class Image extends Widget { | ||
119 | void paint(Context context) { | 130 | void paint(Context context) { |
120 | super.paint(context); | 131 | super.paint(context); |
121 | 132 | ||
133 | + final rect = context.localToGlobal(box); | ||
134 | + | ||
122 | _paintImage( | 135 | _paintImage( |
123 | canvas: context.canvas, | 136 | canvas: context.canvas, |
124 | - image: image, | 137 | + image: image.resolve(context, rect.size, dpi: dpi), |
125 | rect: box, | 138 | rect: box, |
126 | alignment: alignment, | 139 | alignment: alignment, |
127 | fit: fit, | 140 | fit: fit, |
pdf/lib/widgets/image_provider.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 | +part of widget; | ||
18 | + | ||
19 | +/// Identifies an image without committing to the precise final asset | ||
20 | +abstract class ImageProvider { | ||
21 | + ImageProvider( | ||
22 | + this._width, | ||
23 | + this._height, | ||
24 | + this.orientation, | ||
25 | + this.dpi, | ||
26 | + ); | ||
27 | + | ||
28 | + final double dpi; | ||
29 | + | ||
30 | + final int _width; | ||
31 | + | ||
32 | + /// Image width | ||
33 | + int get width => orientation.index >= 4 ? _height : _width; | ||
34 | + | ||
35 | + final int _height; | ||
36 | + | ||
37 | + /// Image height | ||
38 | + int get height => orientation.index < 4 ? _height : _width; | ||
39 | + | ||
40 | + /// The internal orientation of the image | ||
41 | + final PdfImageOrientation orientation; | ||
42 | + | ||
43 | + final _cache = <int, PdfImage>{}; | ||
44 | + | ||
45 | + PdfImage buildImage(Context context, {int width, int height}); | ||
46 | + | ||
47 | + /// Resolves this image provider using the given context, returning a PdfImage | ||
48 | + /// The image is automatically added to the document | ||
49 | + PdfImage resolve(Context context, PdfPoint size, {double dpi}) { | ||
50 | + assert(size != null); | ||
51 | + final effectiveDpi = dpi ?? this.dpi; | ||
52 | + | ||
53 | + if (effectiveDpi == null || _cache[0] != null) { | ||
54 | + _cache[0] ??= buildImage(context); | ||
55 | + | ||
56 | + assert(_cache[0].pdfDocument == context.document, | ||
57 | + 'Do not reuse an ImageProvider object across multiple documents'); | ||
58 | + return _cache[0]; | ||
59 | + } | ||
60 | + | ||
61 | + final width = (size.x / PdfPageFormat.inch * effectiveDpi).toInt(); | ||
62 | + final height = (size.y / PdfPageFormat.inch * effectiveDpi).toInt(); | ||
63 | + | ||
64 | + if (!_cache.containsKey(width)) { | ||
65 | + _cache[width] ??= buildImage(context, width: width, height: height); | ||
66 | + } | ||
67 | + | ||
68 | + assert(_cache[width].pdfDocument == context.document, | ||
69 | + 'Do not reuse an ImageProvider object across multiple documents'); | ||
70 | + return _cache[width]; | ||
71 | + } | ||
72 | +} | ||
73 | + | ||
74 | +class ImageProxy extends ImageProvider { | ||
75 | + ImageProxy( | ||
76 | + this._image, { | ||
77 | + double dpi, | ||
78 | + }) : super(_image.width, _image.height, _image.orientation, dpi); | ||
79 | + | ||
80 | + /// The proxy image | ||
81 | + final PdfImage _image; | ||
82 | + | ||
83 | + @override | ||
84 | + PdfImage buildImage(Context context, {int width, int height}) => _image; | ||
85 | +} | ||
86 | + | ||
87 | +class MemoryImage extends ImageProvider { | ||
88 | + factory MemoryImage( | ||
89 | + Uint8List bytes, { | ||
90 | + PdfImageOrientation orientation, | ||
91 | + double dpi, | ||
92 | + }) { | ||
93 | + final decoder = im.findDecoderForData(bytes); | ||
94 | + if (decoder is im.JpegDecoder) { | ||
95 | + final info = PdfJpegInfo(bytes); | ||
96 | + | ||
97 | + return MemoryImage._( | ||
98 | + bytes, | ||
99 | + info.width, | ||
100 | + info.height, | ||
101 | + orientation ?? info.orientation, | ||
102 | + dpi, | ||
103 | + ); | ||
104 | + } | ||
105 | + | ||
106 | + final info = decoder.startDecode(bytes); | ||
107 | + return MemoryImage._( | ||
108 | + bytes, | ||
109 | + info.width, | ||
110 | + info.height, | ||
111 | + orientation ?? PdfImageOrientation.topLeft, | ||
112 | + dpi, | ||
113 | + ); | ||
114 | + } | ||
115 | + | ||
116 | + MemoryImage._( | ||
117 | + this.bytes, | ||
118 | + int width, | ||
119 | + int height, | ||
120 | + PdfImageOrientation orientation, | ||
121 | + double dpi, | ||
122 | + ) : super(width, height, orientation, dpi); | ||
123 | + | ||
124 | + /// The image data | ||
125 | + final Uint8List bytes; | ||
126 | + | ||
127 | + @override | ||
128 | + PdfImage buildImage(Context context, {int width, int height}) { | ||
129 | + if (width == null) { | ||
130 | + return PdfImage.file(context.document, bytes: bytes); | ||
131 | + } | ||
132 | + | ||
133 | + final image = im.decodeImage(bytes); | ||
134 | + print(width); | ||
135 | + final resized = im.copyResize(image, width: width); | ||
136 | + return PdfImage.fromImage(context.document, image: resized); | ||
137 | + } | ||
138 | +} | ||
139 | + | ||
140 | +class ImageImage extends ImageProvider { | ||
141 | + ImageImage( | ||
142 | + this._image, { | ||
143 | + double dpi, | ||
144 | + PdfImageOrientation orientation, | ||
145 | + }) : super(_image.width, _image.height, | ||
146 | + orientation ?? PdfImageOrientation.topLeft, dpi); | ||
147 | + | ||
148 | + /// The image data | ||
149 | + final im.Image _image; | ||
150 | + | ||
151 | + @override | ||
152 | + PdfImage buildImage(Context context, {int width, int height}) { | ||
153 | + if (width == null) { | ||
154 | + return PdfImage.fromImage(context.document, image: _image); | ||
155 | + } | ||
156 | + | ||
157 | + final resized = im.copyResize(_image, width: width); | ||
158 | + return PdfImage.fromImage(context.document, image: resized); | ||
159 | + } | ||
160 | +} | ||
161 | + | ||
162 | +class RawImage extends ImageImage { | ||
163 | + RawImage({ | ||
164 | + @required Uint8List bytes, | ||
165 | + @required int width, | ||
166 | + @required int height, | ||
167 | + PdfImageOrientation orientation, | ||
168 | + double dpi, | ||
169 | + }) : super(im.Image.fromBytes(width, height, bytes), | ||
170 | + orientation: orientation, dpi: dpi); | ||
171 | +} |
@@ -19,7 +19,6 @@ import 'dart:io'; | @@ -19,7 +19,6 @@ import 'dart:io'; | ||
19 | import 'dart:isolate'; | 19 | import 'dart:isolate'; |
20 | import 'dart:typed_data'; | 20 | import 'dart:typed_data'; |
21 | 21 | ||
22 | -import 'package:pdf/pdf.dart'; | ||
23 | import 'package:pdf/widgets.dart'; | 22 | import 'package:pdf/widgets.dart'; |
24 | import 'package:test/test.dart'; | 23 | import 'package:test/test.dart'; |
25 | 24 | ||
@@ -35,12 +34,12 @@ class Message { | @@ -35,12 +34,12 @@ class Message { | ||
35 | void compute(Message message) { | 34 | void compute(Message message) { |
36 | final pdf = Document(); | 35 | final pdf = Document(); |
37 | 36 | ||
38 | - final image = PdfImage.jpeg( | ||
39 | - pdf.document, | ||
40 | - image: message.image, | 37 | + final image = MemoryImage( |
38 | + message.image, | ||
41 | ); | 39 | ); |
42 | 40 | ||
43 | - pdf.addPage(Page(build: (Context context) => Center(child: Image(image)))); | 41 | + pdf.addPage( |
42 | + Page(build: (Context context) => Center(child: Image.provider(image)))); | ||
44 | 43 | ||
45 | message.sendPort.send(pdf.save()); | 44 | message.sendPort.send(pdf.save()); |
46 | } | 45 | } |
@@ -17,29 +17,27 @@ | @@ -17,29 +17,27 @@ | ||
17 | import 'dart:convert'; | 17 | import 'dart:convert'; |
18 | import 'dart:io'; | 18 | import 'dart:io'; |
19 | 19 | ||
20 | -import 'package:pdf/pdf.dart'; | ||
21 | import 'package:pdf/widgets.dart'; | 20 | import 'package:pdf/widgets.dart'; |
22 | import 'package:test/test.dart'; | 21 | import 'package:test/test.dart'; |
23 | 22 | ||
24 | import 'utils.dart'; | 23 | import 'utils.dart'; |
25 | 24 | ||
26 | Document pdf; | 25 | Document pdf; |
27 | -PdfImage image; | 26 | +MemoryImage image; |
28 | 27 | ||
29 | void main() { | 28 | void main() { |
30 | setUpAll(() async { | 29 | setUpAll(() async { |
31 | Document.debug = true; | 30 | Document.debug = true; |
32 | pdf = Document(); | 31 | pdf = Document(); |
33 | 32 | ||
34 | - image = PdfImage.jpeg( | ||
35 | - pdf.document, | ||
36 | - image: await download('https://www.nfet.net/nfet.jpg'), | 33 | + image = MemoryImage( |
34 | + await download('https://www.nfet.net/nfet.jpg'), | ||
37 | ); | 35 | ); |
38 | }); | 36 | }); |
39 | 37 | ||
40 | test('Pdf Jpeg Download', () async { | 38 | test('Pdf Jpeg Download', () async { |
41 | pdf.addPage(Page( | 39 | pdf.addPage(Page( |
42 | - build: (Context context) => Center(child: Image(image)), | 40 | + build: (Context context) => Center(child: Image.provider(image)), |
43 | )); | 41 | )); |
44 | }); | 42 | }); |
45 | 43 | ||
@@ -51,10 +49,9 @@ void main() { | @@ -51,10 +49,9 @@ void main() { | ||
51 | crossAxisSpacing: 10, | 49 | crossAxisSpacing: 10, |
52 | children: List<Widget>.generate( | 50 | children: List<Widget>.generate( |
53 | images.length, | 51 | images.length, |
54 | - (int index) => Image( | ||
55 | - PdfImage.jpeg( | ||
56 | - pdf.document, | ||
57 | - image: base64.decode(images[index]), | 52 | + (int index) => Image.provider( |
53 | + MemoryImage( | ||
54 | + base64.decode(images[index]), | ||
58 | ), | 55 | ), |
59 | ), | 56 | ), |
60 | ), | 57 | ), |
@@ -72,7 +69,7 @@ void main() { | @@ -72,7 +69,7 @@ void main() { | ||
72 | return SizedBox( | 69 | return SizedBox( |
73 | width: 200, | 70 | width: 200, |
74 | height: 100, | 71 | height: 100, |
75 | - child: Image( | 72 | + child: Image.provider( |
76 | image, | 73 | image, |
77 | fit: fit, | 74 | fit: fit, |
78 | ), | 75 | ), |
@@ -85,10 +82,9 @@ void main() { | @@ -85,10 +82,9 @@ void main() { | ||
85 | test('Pdf Image decode', () { | 82 | test('Pdf Image decode', () { |
86 | final imageWidgets = imageFiles.map<Widget>( | 83 | final imageWidgets = imageFiles.map<Widget>( |
87 | (String image) => SizedBox( | 84 | (String image) => SizedBox( |
88 | - child: Image( | ||
89 | - PdfImage.file( | ||
90 | - pdf.document, | ||
91 | - bytes: gzip.decode(base64.decode(image)), | 85 | + child: Image.provider( |
86 | + MemoryImage( | ||
87 | + gzip.decode(base64.decode(image)), | ||
92 | ), | 88 | ), |
93 | ), | 89 | ), |
94 | width: 200, | 90 | width: 200, |
@@ -19,7 +19,6 @@ import 'dart:io'; | @@ -19,7 +19,6 @@ import 'dart:io'; | ||
19 | import 'dart:math' as math; | 19 | import 'dart:math' as math; |
20 | import 'dart:typed_data'; | 20 | import 'dart:typed_data'; |
21 | 21 | ||
22 | -import 'package:pdf/pdf.dart'; | ||
23 | import 'package:pdf/widgets.dart'; | 22 | import 'package:pdf/widgets.dart'; |
24 | 23 | ||
25 | Future<Uint8List> download( | 24 | Future<Uint8List> download( |
@@ -56,7 +55,7 @@ Future<Uint8List> download( | @@ -56,7 +55,7 @@ Future<Uint8List> download( | ||
56 | return Uint8List.fromList(data); | 55 | return Uint8List.fromList(data); |
57 | } | 56 | } |
58 | 57 | ||
59 | -PdfImage generateBitmap(PdfDocument pdf, int w, int h) { | 58 | +ImageProvider generateBitmap(int w, int h) { |
60 | final bm = Uint32List(w * h); | 59 | final bm = Uint32List(w * h); |
61 | final dw = w.toDouble(); | 60 | final dw = w.toDouble(); |
62 | final dh = h.toDouble(); | 61 | final dh = h.toDouble(); |
@@ -69,9 +68,8 @@ PdfImage generateBitmap(PdfDocument pdf, int w, int h) { | @@ -69,9 +68,8 @@ PdfImage generateBitmap(PdfDocument pdf, int w, int h) { | ||
69 | } | 68 | } |
70 | } | 69 | } |
71 | 70 | ||
72 | - return PdfImage( | ||
73 | - pdf, | ||
74 | - image: bm.buffer.asUint8List(), | 71 | + return RawImage( |
72 | + bytes: bm.buffer.asUint8List(), | ||
75 | width: w, | 73 | width: w, |
76 | height: h, | 74 | height: h, |
77 | ); | 75 | ); |
@@ -55,7 +55,7 @@ void main() { | @@ -55,7 +55,7 @@ void main() { | ||
55 | }); | 55 | }); |
56 | 56 | ||
57 | test('Container Widgets Image', () { | 57 | test('Container Widgets Image', () { |
58 | - final image = generateBitmap(pdf.document, 100, 200); | 58 | + final image = generateBitmap(100, 200); |
59 | 59 | ||
60 | final widgets = <Widget>[]; | 60 | final widgets = <Widget>[]; |
61 | for (var shape in BoxShape.values) { | 61 | for (var shape in BoxShape.values) { |
@@ -66,7 +66,7 @@ void main() { | @@ -66,7 +66,7 @@ void main() { | ||
66 | decoration: BoxDecoration( | 66 | decoration: BoxDecoration( |
67 | shape: shape, | 67 | shape: shape, |
68 | borderRadiusEx: const BorderRadius.all(Radius.circular(10)), | 68 | borderRadiusEx: const BorderRadius.all(Radius.circular(10)), |
69 | - image: DecorationImage(image: image, fit: fit), | 69 | + image: DecorationImage.provider(image: image, fit: fit), |
70 | ), | 70 | ), |
71 | width: 100, | 71 | width: 100, |
72 | height: 100, | 72 | height: 100, |
@@ -37,7 +37,7 @@ void main() { | @@ -37,7 +37,7 @@ void main() { | ||
37 | MultiPage( | 37 | MultiPage( |
38 | theme: ThemeData.withFont(icons: icons), | 38 | theme: ThemeData.withFont(icons: icons), |
39 | build: (Context context) { | 39 | build: (Context context) { |
40 | - final iconList = List<IconData>(); | 40 | + final iconList = <IconData>[]; |
41 | final pdfFont = icons.getFont(context); | 41 | final pdfFont = icons.getFont(context); |
42 | if (pdfFont is PdfTtfFont) { | 42 | if (pdfFont is PdfTtfFont) { |
43 | iconList.addAll( | 43 | iconList.addAll( |
@@ -24,7 +24,7 @@ import 'package:test/test.dart'; | @@ -24,7 +24,7 @@ import 'package:test/test.dart'; | ||
24 | void main() { | 24 | void main() { |
25 | Document pdf; | 25 | Document pdf; |
26 | TextStyle symbol; | 26 | TextStyle symbol; |
27 | - PdfImage im; | 27 | + ImageProvider im; |
28 | 28 | ||
29 | setUpAll(() { | 29 | setUpAll(() { |
30 | Document.debug = true; | 30 | Document.debug = true; |
@@ -43,7 +43,7 @@ void main() { | @@ -43,7 +43,7 @@ void main() { | ||
43 | 43 | ||
44 | final imData = zlib.decode(base64.decode( | 44 | final imData = zlib.decode(base64.decode( |
45 | 'eJz7//8/w388uOTCT6a4Ez96Q47++I+OI479mEVALyNU7z9seuNP/mAm196Ekz8YR+0dWHtBmJC9S+7/Zog89iMIKLYaHQPVJGLTD7MXpDfq+I9goNhPdPPDjv3YlnH6Jye6+2H21l/6yeB/4HsSDr1bQXrRwq8HqHcGyF6QXp9933N0tn/7Y7vn+/9gLPaih0PDlV9MIAzVm6ez7dsfzW3f/oMwzAx0e7FhoJutdbcj9MKw9frnL2J2POfBpxeEg478YLba/X0Wsl6lBXf+s0bP/s8ePXeWePJCvPEJNYMRZIYWSO/cq/9Z/Nv+M4bO+M8YDjFDJGkhzvSE7A6jRTdnsQR2wfXCMLHuMC5byyidvGgWE5JeZDOIcYdR+TpmkBno+mFmAAC+DGhl')); | 45 | 'eJz7//8/w388uOTCT6a4Ez96Q47++I+OI479mEVALyNU7z9seuNP/mAm196Ekz8YR+0dWHtBmJC9S+7/Zog89iMIKLYaHQPVJGLTD7MXpDfq+I9goNhPdPPDjv3YlnH6Jye6+2H21l/6yeB/4HsSDr1bQXrRwq8HqHcGyF6QXp9933N0tn/7Y7vn+/9gLPaih0PDlV9MIAzVm6ez7dsfzW3f/oMwzAx0e7FhoJutdbcj9MKw9frnL2J2POfBpxeEg478YLba/X0Wsl6lBXf+s0bP/s8ePXeWePJCvPEJNYMRZIYWSO/cq/9Z/Nv+M4bO+M8YDjFDJGkhzvSE7A6jRTdnsQR2wfXCMLHuMC5byyidvGgWE5JeZDOIcYdR+TpmkBno+mFmAAC+DGhl')); |
46 | - im = PdfImage(pdf.document, image: imData, width: 16, height: 20); | 46 | + im = RawImage(bytes: imData, width: 16, height: 20); |
47 | }); | 47 | }); |
48 | 48 | ||
49 | test('Pdf Widgets page 1', () { | 49 | test('Pdf Widgets page 1', () { |
@@ -85,7 +85,7 @@ void main() { | @@ -85,7 +85,7 @@ void main() { | ||
85 | Row( | 85 | Row( |
86 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, | 86 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
87 | children: <Widget>[ | 87 | children: <Widget>[ |
88 | - Image(im), | 88 | + Image.provider(im), |
89 | PdfLogo(), | 89 | PdfLogo(), |
90 | Column( | 90 | Column( |
91 | children: <Widget>[ | 91 | children: <Widget>[ |
@@ -55,12 +55,12 @@ To load an image from an ImageProvider: | @@ -55,12 +55,12 @@ To load an image from an ImageProvider: | ||
55 | 55 | ||
56 | ```dart | 56 | ```dart |
57 | const imageProvider = const AssetImage('assets/image.png'); | 57 | const imageProvider = const AssetImage('assets/image.png'); |
58 | -final PdfImage image = await pdfImageFromImageProvider(pdf: doc.document, image: imageProvider); | 58 | +final image = await flutterImageProvider(imageProvider); |
59 | 59 | ||
60 | doc.addPage(pw.Page( | 60 | doc.addPage(pw.Page( |
61 | build: (pw.Context context) { | 61 | build: (pw.Context context) { |
62 | return pw.Center( | 62 | return pw.Center( |
63 | - child: pw.Image(image), | 63 | + child: pw.Image.provider(image), |
64 | ); // Center | 64 | ); // Center |
65 | })); // Page | 65 | })); // Page |
66 | ``` | 66 | ``` |
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | import 'dart:async'; | 17 | import 'dart:async'; |
18 | import 'dart:ui' as ui; | 18 | import 'dart:ui' as ui; |
19 | 19 | ||
20 | -import 'package:flutter/rendering.dart'; | 20 | +import 'package:flutter/rendering.dart' as rdr; |
21 | import 'package:flutter/services.dart'; | 21 | import 'package:flutter/services.dart'; |
22 | import 'package:meta/meta.dart'; | 22 | import 'package:meta/meta.dart'; |
23 | import 'package:pdf/pdf.dart'; | 23 | import 'package:pdf/pdf.dart'; |
@@ -25,6 +25,7 @@ import 'package:pdf/widgets.dart'; | @@ -25,6 +25,7 @@ import 'package:pdf/widgets.dart'; | ||
25 | 25 | ||
26 | /// Loads an image from a Flutter [ui.Image] | 26 | /// Loads an image from a Flutter [ui.Image] |
27 | /// into a [PdfImage] instance | 27 | /// into a [PdfImage] instance |
28 | +@Deprecated('Use flutterImageProvider') | ||
28 | Future<PdfImage> pdfImageFromImage( | 29 | Future<PdfImage> pdfImageFromImage( |
29 | {@required PdfDocument pdf, @required ui.Image image}) async { | 30 | {@required PdfDocument pdf, @required ui.Image image}) async { |
30 | final bytes = await image.toByteData(format: ui.ImageByteFormat.rawRgba); | 31 | final bytes = await image.toByteData(format: ui.ImageByteFormat.rawRgba); |
@@ -37,16 +38,17 @@ Future<PdfImage> pdfImageFromImage( | @@ -37,16 +38,17 @@ Future<PdfImage> pdfImageFromImage( | ||
37 | 38 | ||
38 | /// Loads an image from a Flutter [ImageProvider] | 39 | /// Loads an image from a Flutter [ImageProvider] |
39 | /// into a [PdfImage] instance | 40 | /// into a [PdfImage] instance |
41 | +@Deprecated('Use flutterImageProvider') | ||
40 | Future<PdfImage> pdfImageFromImageProvider( | 42 | Future<PdfImage> pdfImageFromImageProvider( |
41 | {@required PdfDocument pdf, | 43 | {@required PdfDocument pdf, |
42 | - @required ImageProvider image, | ||
43 | - ImageConfiguration configuration, | ||
44 | - ImageErrorListener onError}) async { | 44 | + @required rdr.ImageProvider image, |
45 | + rdr.ImageConfiguration configuration, | ||
46 | + rdr.ImageErrorListener onError}) async { | ||
45 | final completer = Completer<PdfImage>(); | 47 | final completer = Completer<PdfImage>(); |
46 | - final stream = image.resolve(configuration ?? ImageConfiguration.empty); | 48 | + final stream = image.resolve(configuration ?? rdr.ImageConfiguration.empty); |
47 | 49 | ||
48 | - ImageStreamListener listener; | ||
49 | - listener = ImageStreamListener((ImageInfo image, bool sync) async { | 50 | + rdr.ImageStreamListener listener; |
51 | + listener = rdr.ImageStreamListener((rdr.ImageInfo image, bool sync) async { | ||
50 | final result = await pdfImageFromImage(pdf: pdf, image: image.image); | 52 | final result = await pdfImageFromImage(pdf: pdf, image: image.image); |
51 | if (!completer.isCompleted) { | 53 | if (!completer.isCompleted) { |
52 | completer.complete(result); | 54 | completer.complete(result); |
@@ -68,6 +70,46 @@ Future<PdfImage> pdfImageFromImageProvider( | @@ -68,6 +70,46 @@ Future<PdfImage> pdfImageFromImageProvider( | ||
68 | return completer.future; | 70 | return completer.future; |
69 | } | 71 | } |
70 | 72 | ||
73 | +/// Loads an image from a Flutter [ImageProvider] | ||
74 | +/// into an [ImageProvider] instance | ||
75 | +Future<ImageProvider> flutterImageProvider( | ||
76 | + rdr.ImageProvider image, { | ||
77 | + rdr.ImageConfiguration configuration, | ||
78 | + rdr.ImageErrorListener onError, | ||
79 | +}) async { | ||
80 | + final completer = Completer<ImageProvider>(); | ||
81 | + final stream = image.resolve(configuration ?? rdr.ImageConfiguration.empty); | ||
82 | + | ||
83 | + rdr.ImageStreamListener listener; | ||
84 | + listener = rdr.ImageStreamListener((rdr.ImageInfo image, bool sync) async { | ||
85 | + final bytes = | ||
86 | + await image.image.toByteData(format: ui.ImageByteFormat.rawRgba); | ||
87 | + | ||
88 | + final result = RawImage( | ||
89 | + bytes: bytes.buffer.asUint8List(), | ||
90 | + width: image.image.width, | ||
91 | + height: image.image.height); | ||
92 | + | ||
93 | + if (!completer.isCompleted) { | ||
94 | + completer.complete(result); | ||
95 | + } | ||
96 | + stream.removeListener(listener); | ||
97 | + }, onError: (dynamic exception, StackTrace stackTrace) { | ||
98 | + if (!completer.isCompleted) { | ||
99 | + completer.complete(null); | ||
100 | + } | ||
101 | + if (onError != null) { | ||
102 | + onError(exception, stackTrace); | ||
103 | + } else { | ||
104 | + // https://groups.google.com/forum/#!topic/flutter-announce/hp1RNIgej38 | ||
105 | + assert(false, 'image failed to load'); | ||
106 | + } | ||
107 | + }); | ||
108 | + | ||
109 | + stream.addListener(listener); | ||
110 | + return completer.future; | ||
111 | +} | ||
112 | + | ||
71 | /// Loads a font from an asset bundle key. If used multiple times with the same font name, | 113 | /// Loads a font from an asset bundle key. If used multiple times with the same font name, |
72 | /// it will be included multiple times in the pdf file | 114 | /// it will be included multiple times in the pdf file |
73 | Future<TtfFont> fontFromAssetBundle(String key, AssetBundle bundle) async { | 115 | Future<TtfFont> fontFromAssetBundle(String key, AssetBundle bundle) async { |
@@ -18,7 +18,7 @@ dependencies: | @@ -18,7 +18,7 @@ dependencies: | ||
18 | image: ^2.1.4 | 18 | image: ^2.1.4 |
19 | js: ^0.6.1 | 19 | js: ^0.6.1 |
20 | meta: ^1.1.5 | 20 | meta: ^1.1.5 |
21 | - pdf: ^1.11.1 | 21 | + pdf: ^1.13.0 |
22 | plugin_platform_interface: ^1.0.2 | 22 | plugin_platform_interface: ^1.0.2 |
23 | 23 | ||
24 | dev_dependencies: | 24 | dev_dependencies: |
@@ -45,15 +45,15 @@ void main() { | @@ -45,15 +45,15 @@ void main() { | ||
45 | // expect(await Printing.platformVersion, '42'); | 45 | // expect(await Printing.platformVersion, '42'); |
46 | }); | 46 | }); |
47 | 47 | ||
48 | - test('pdfImageFromImageProvider(FileImage)', () async { | ||
49 | - final image = await pdfImageFromImageProvider( | ||
50 | - pdf: doc.document, image: FileImage(File('$path/example.png'))); | 48 | + test('flutterImageProvider(FileImage)', () async { |
49 | + final image = | ||
50 | + await flutterImageProvider(FileImage(File('$path/example.png'))); | ||
51 | 51 | ||
52 | doc.addPage( | 52 | doc.addPage( |
53 | pw.Page( | 53 | pw.Page( |
54 | build: (pw.Context context) => pw.Center( | 54 | build: (pw.Context context) => pw.Center( |
55 | child: pw.Container( | 55 | child: pw.Container( |
56 | - child: pw.Image(image), | 56 | + child: pw.Image.provider(image), |
57 | ), | 57 | ), |
58 | ), | 58 | ), |
59 | ), | 59 | ), |
-
Please register or login to post a comment