Showing
3 changed files
with
129 additions
and
2 deletions
1 | # Changelog | 1 | # Changelog |
2 | 2 | ||
3 | -## 5.5.1 | 3 | +## 5.6.0 |
4 | 4 | ||
5 | - Update Google fonts | 5 | - Update Google fonts |
6 | - Fix typo in README | 6 | - Fix typo in README |
@@ -9,6 +9,7 @@ | @@ -9,6 +9,7 @@ | ||
9 | - Fix error while loading shared libraries on Linux | 9 | - Fix error while loading shared libraries on Linux |
10 | - Update pdfium library to 4627 | 10 | - Update pdfium library to 4627 |
11 | - Apply Flutter 2.5 coding style | 11 | - Apply Flutter 2.5 coding style |
12 | +- Add WidgetWraper.fromWidget() | ||
12 | 13 | ||
13 | ## 5.5.0 | 14 | ## 5.5.0 |
14 | 15 |
@@ -20,6 +20,7 @@ import 'dart:ui' as ui; | @@ -20,6 +20,7 @@ import 'dart:ui' as ui; | ||
20 | 20 | ||
21 | import 'package:flutter/material.dart'; | 21 | import 'package:flutter/material.dart'; |
22 | import 'package:flutter/rendering.dart'; | 22 | import 'package:flutter/rendering.dart'; |
23 | +import 'package:flutter/widgets.dart'; | ||
23 | import 'package:pdf/pdf.dart'; | 24 | import 'package:pdf/pdf.dart'; |
24 | import 'package:pdf/widgets.dart' as pw; | 25 | import 'package:pdf/widgets.dart' as pw; |
25 | 26 | ||
@@ -100,6 +101,118 @@ class WidgetWraper extends pw.ImageProvider { | @@ -100,6 +101,118 @@ class WidgetWraper extends pw.ImageProvider { | ||
100 | ); | 101 | ); |
101 | } | 102 | } |
102 | 103 | ||
104 | + /// Wrap a Flutter Widget to an ImageProvider. | ||
105 | + /// | ||
106 | + /// ``` | ||
107 | + /// final wrapped = await WidgetWraper.fromWidget( | ||
108 | + /// widget: Container( | ||
109 | + /// color: Colors.white, | ||
110 | + /// child: Text( | ||
111 | + /// 'Hello world !', | ||
112 | + /// style: TextStyle(color: Colors.amber), | ||
113 | + /// ), | ||
114 | + /// ), | ||
115 | + /// constraints: BoxConstraints(maxWidth: 100, maxHeight: 400), | ||
116 | + /// pixelRatio: 3, | ||
117 | + /// ); | ||
118 | + /// | ||
119 | + /// pdf.addPage( | ||
120 | + /// pw.Page( | ||
121 | + /// pageFormat: format, | ||
122 | + /// build: (context) { | ||
123 | + /// return pw.Image(wrapped, width: 100); | ||
124 | + /// }, | ||
125 | + /// ), | ||
126 | + /// ); | ||
127 | + /// ``` | ||
128 | + static Future<WidgetWraper> fromWidget({ | ||
129 | + required Widget widget, | ||
130 | + required BoxConstraints constraints, | ||
131 | + double pixelRatio = 1.0, | ||
132 | + PdfImageOrientation? orientation, | ||
133 | + double? dpi, | ||
134 | + }) async { | ||
135 | + assert(pixelRatio > 0); | ||
136 | + | ||
137 | + if (!constraints.hasBoundedHeight || !constraints.hasBoundedHeight) { | ||
138 | + throw Exception( | ||
139 | + 'Unable to convert an unbounded widget. Add maxWidth and maxHeight to the constraints.'); | ||
140 | + } | ||
141 | + | ||
142 | + widget = ConstrainedBox( | ||
143 | + constraints: constraints, | ||
144 | + child: widget, | ||
145 | + ); | ||
146 | + | ||
147 | + final _properties = DiagnosticPropertiesBuilder(); | ||
148 | + widget.debugFillProperties(_properties); | ||
149 | + | ||
150 | + if (_properties.properties.isEmpty) { | ||
151 | + throw ErrorDescription('Unable to get the widget properties'); | ||
152 | + } | ||
153 | + | ||
154 | + final _constraints = _properties.properties | ||
155 | + .whereType<DiagnosticsProperty<BoxConstraints>>() | ||
156 | + .first | ||
157 | + .value; | ||
158 | + | ||
159 | + if (_constraints == null || | ||
160 | + !_constraints.hasBoundedWidth || | ||
161 | + !_constraints.hasBoundedWidth) { | ||
162 | + throw Exception('Unable to convert an unbounded widget.'); | ||
163 | + } | ||
164 | + | ||
165 | + final _repaintBoundary = RenderRepaintBoundary(); | ||
166 | + | ||
167 | + final renderView = RenderView( | ||
168 | + child: RenderPositionedBox( | ||
169 | + alignment: Alignment.center, child: _repaintBoundary), | ||
170 | + configuration: ViewConfiguration( | ||
171 | + size: Size(_constraints.maxWidth, _constraints.maxHeight), | ||
172 | + devicePixelRatio: ui.window.devicePixelRatio), | ||
173 | + window: _FlutterView( | ||
174 | + configuration: ui.ViewConfiguration( | ||
175 | + devicePixelRatio: ui.window.devicePixelRatio, | ||
176 | + ), | ||
177 | + ), | ||
178 | + ); | ||
179 | + | ||
180 | + final pipelineOwner = PipelineOwner()..rootNode = renderView; | ||
181 | + renderView.prepareInitialFrame(); | ||
182 | + | ||
183 | + final buildOwner = BuildOwner(focusManager: FocusManager()); | ||
184 | + final _rootElement = RenderObjectToWidgetAdapter<RenderBox>( | ||
185 | + container: _repaintBoundary, | ||
186 | + child: Directionality( | ||
187 | + textDirection: TextDirection.ltr, | ||
188 | + child: IntrinsicHeight(child: IntrinsicWidth(child: widget)), | ||
189 | + ), | ||
190 | + ).attachToRenderTree(buildOwner); | ||
191 | + | ||
192 | + buildOwner | ||
193 | + ..buildScope(_rootElement) | ||
194 | + ..finalizeTree(); | ||
195 | + | ||
196 | + pipelineOwner | ||
197 | + ..flushLayout() | ||
198 | + ..flushCompositingBits() | ||
199 | + ..flushPaint(); | ||
200 | + | ||
201 | + final image = await _repaintBoundary.toImage(pixelRatio: pixelRatio); | ||
202 | + final bytes = await image.toByteData(format: ui.ImageByteFormat.rawRgba); | ||
203 | + if (bytes == null) { | ||
204 | + throw Exception('Unable to read image data'); | ||
205 | + } | ||
206 | + | ||
207 | + return WidgetWraper._( | ||
208 | + bytes.buffer.asUint8List(), | ||
209 | + image.width, | ||
210 | + image.height, | ||
211 | + orientation ?? PdfImageOrientation.topLeft, | ||
212 | + dpi, | ||
213 | + ); | ||
214 | + } | ||
215 | + | ||
103 | /// The image data | 216 | /// The image data |
104 | final Uint8List bytes; | 217 | final Uint8List bytes; |
105 | 218 | ||
@@ -114,3 +227,16 @@ class WidgetWraper extends pw.ImageProvider { | @@ -114,3 +227,16 @@ class WidgetWraper extends pw.ImageProvider { | ||
114 | ); | 227 | ); |
115 | } | 228 | } |
116 | } | 229 | } |
230 | + | ||
231 | +class _FlutterView extends ui.FlutterView { | ||
232 | + _FlutterView({required this.configuration}); | ||
233 | + | ||
234 | + final ui.ViewConfiguration configuration; | ||
235 | + | ||
236 | + @override | ||
237 | + ui.PlatformDispatcher get platformDispatcher => | ||
238 | + ui.PlatformDispatcher.instance; | ||
239 | + | ||
240 | + @override | ||
241 | + ui.ViewConfiguration get viewConfiguration => configuration; | ||
242 | +} |
@@ -6,7 +6,7 @@ description: > | @@ -6,7 +6,7 @@ description: > | ||
6 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing | 6 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing |
7 | repository: https://github.com/DavBfr/dart_pdf | 7 | repository: https://github.com/DavBfr/dart_pdf |
8 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues | 8 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues |
9 | -version: 5.5.1 | 9 | +version: 5.6.0 |
10 | 10 | ||
11 | environment: | 11 | environment: |
12 | sdk: ">=2.12.0 <3.0.0" | 12 | sdk: ">=2.12.0 <3.0.0" |
-
Please register or login to post a comment