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