Showing
12 changed files
with
346 additions
and
84 deletions
@@ -22,7 +22,7 @@ import 'package:pdf/pdf.dart'; | @@ -22,7 +22,7 @@ import 'package:pdf/pdf.dart'; | ||
22 | import 'package:pdf/widgets.dart' as pw; | 22 | import 'package:pdf/widgets.dart' as pw; |
23 | 23 | ||
24 | Future<Uint8List> generateDocument(PdfPageFormat format) async { | 24 | Future<Uint8List> generateDocument(PdfPageFormat format) async { |
25 | - final pw.Document doc = pw.Document(); | 25 | + final pw.Document doc = pw.Document(pageMode: PdfPageMode.outlines); |
26 | 26 | ||
27 | doc.addPage(pw.MultiPage( | 27 | doc.addPage(pw.MultiPage( |
28 | pageFormat: | 28 | pageFormat: |
@@ -57,6 +57,7 @@ Future<Uint8List> generateDocument(PdfPageFormat format) async { | @@ -57,6 +57,7 @@ Future<Uint8List> generateDocument(PdfPageFormat format) async { | ||
57 | build: (pw.Context context) => <pw.Widget>[ | 57 | build: (pw.Context context) => <pw.Widget>[ |
58 | pw.Header( | 58 | pw.Header( |
59 | level: 0, | 59 | level: 0, |
60 | + title: 'Portable Document Format', | ||
60 | child: pw.Row( | 61 | child: pw.Row( |
61 | mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, | 62 | mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, |
62 | children: <pw.Widget>[ | 63 | children: <pw.Widget>[ |
@@ -207,20 +207,27 @@ class PdfSecString extends PdfString { | @@ -207,20 +207,27 @@ class PdfSecString extends PdfString { | ||
207 | [PdfStringFormat format = PdfStringFormat.binary]) | 207 | [PdfStringFormat format = PdfStringFormat.binary]) |
208 | : super(value, format); | 208 | : super(value, format); |
209 | 209 | ||
210 | - factory PdfSecString.fromString(PdfObject object, String value) { | 210 | + factory PdfSecString.fromString( |
211 | + PdfObject object, | ||
212 | + String value, [ | ||
213 | + PdfStringFormat format = PdfStringFormat.litteral, | ||
214 | + ]) { | ||
211 | return PdfSecString( | 215 | return PdfSecString( |
212 | object, | 216 | object, |
213 | PdfString._string(value), | 217 | PdfString._string(value), |
214 | - PdfStringFormat.litteral, | 218 | + format, |
215 | ); | 219 | ); |
216 | } | 220 | } |
217 | 221 | ||
218 | - factory PdfSecString.fromStream(PdfObject object, PdfStream value, | ||
219 | - [PdfStringFormat format = PdfStringFormat.litteral]) { | 222 | + factory PdfSecString.fromStream( |
223 | + PdfObject object, | ||
224 | + PdfStream value, [ | ||
225 | + PdfStringFormat format = PdfStringFormat.litteral, | ||
226 | + ]) { | ||
220 | return PdfSecString( | 227 | return PdfSecString( |
221 | object, | 228 | object, |
222 | value.output(), | 229 | value.output(), |
223 | - PdfStringFormat.litteral, | 230 | + format, |
224 | ); | 231 | ); |
225 | } | 232 | } |
226 | 233 |
@@ -14,13 +14,15 @@ | @@ -14,13 +14,15 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | +// ignore_for_file: omit_local_variable_types | ||
18 | + | ||
17 | part of pdf; | 19 | part of pdf; |
18 | 20 | ||
19 | class PdfNames extends PdfObject { | 21 | class PdfNames extends PdfObject { |
20 | /// This constructs a Pdf Name object | 22 | /// This constructs a Pdf Name object |
21 | PdfNames(PdfDocument pdfDocument) : super(pdfDocument); | 23 | PdfNames(PdfDocument pdfDocument) : super(pdfDocument); |
22 | 24 | ||
23 | - final PdfArray _dests = PdfArray(); | 25 | + final Map<String, PdfDataType> _dests = <String, PdfDataType>{}; |
24 | 26 | ||
25 | void addDest( | 27 | void addDest( |
26 | String name, | 28 | String name, |
@@ -32,8 +34,7 @@ class PdfNames extends PdfObject { | @@ -32,8 +34,7 @@ class PdfNames extends PdfObject { | ||
32 | assert(page.pdfDocument == pdfDocument); | 34 | assert(page.pdfDocument == pdfDocument); |
33 | assert(name != null); | 35 | assert(name != null); |
34 | 36 | ||
35 | - _dests.add(PdfSecString.fromString(this, name)); | ||
36 | - _dests.add(PdfDict(<String, PdfDataType>{ | 37 | + _dests[name] = PdfDict(<String, PdfDataType>{ |
37 | '/D': PdfArray(<PdfDataType>[ | 38 | '/D': PdfArray(<PdfDataType>[ |
38 | page.ref(), | 39 | page.ref(), |
39 | const PdfName('/XYZ'), | 40 | const PdfName('/XYZ'), |
@@ -41,13 +42,32 @@ class PdfNames extends PdfObject { | @@ -41,13 +42,32 @@ class PdfNames extends PdfObject { | ||
41 | if (posY == null) const PdfNull() else PdfNum(posY), | 42 | if (posY == null) const PdfNull() else PdfNum(posY), |
42 | if (posZ == null) const PdfNull() else PdfNum(posZ), | 43 | if (posZ == null) const PdfNull() else PdfNum(posZ), |
43 | ]), | 44 | ]), |
44 | - })); | 45 | + }); |
45 | } | 46 | } |
46 | 47 | ||
47 | @override | 48 | @override |
48 | void _prepare() { | 49 | void _prepare() { |
49 | super._prepare(); | 50 | super._prepare(); |
50 | 51 | ||
51 | - params['/Dests'] = PdfDict(<String, PdfDataType>{'/Names': _dests}); | 52 | + if (_dests.isEmpty) { |
53 | + return; | ||
54 | + } | ||
55 | + | ||
56 | + final PdfArray dests = PdfArray(); | ||
57 | + | ||
58 | + final List<String> keys = _dests.keys.toList()..sort(); | ||
59 | + | ||
60 | + for (String name in keys) { | ||
61 | + dests.add(PdfSecString.fromString(this, name)); | ||
62 | + dests.add(_dests[name]); | ||
63 | + } | ||
64 | + | ||
65 | + params['/Dests'] = PdfDict(<String, PdfDataType>{ | ||
66 | + '/Names': dests, | ||
67 | + '/Limits': PdfArray(<PdfDataType>[ | ||
68 | + PdfSecString.fromString(this, keys.first), | ||
69 | + PdfSecString.fromString(this, keys.last), | ||
70 | + ]) | ||
71 | + }); | ||
52 | } | 72 | } |
53 | } | 73 | } |
@@ -26,15 +26,36 @@ enum PdfOutlineMode { | @@ -26,15 +26,36 @@ enum PdfOutlineMode { | ||
26 | fitrect | 26 | fitrect |
27 | } | 27 | } |
28 | 28 | ||
29 | +enum PdfOutlineStyle { | ||
30 | + /// Normal | ||
31 | + normal, | ||
32 | + | ||
33 | + /// Italic | ||
34 | + italic, | ||
35 | + | ||
36 | + // Bold | ||
37 | + bold, | ||
38 | + | ||
39 | + /// Italic and Bold | ||
40 | + italicBold, | ||
41 | +} | ||
42 | + | ||
29 | class PdfOutline extends PdfObject { | 43 | class PdfOutline extends PdfObject { |
30 | /// Constructs a Pdf Outline object. When selected, the specified region | 44 | /// Constructs a Pdf Outline object. When selected, the specified region |
31 | /// is displayed. | 45 | /// is displayed. |
32 | - /// | ||
33 | - /// @param title Title of the outline | ||
34 | - /// @param dest The destination page | ||
35 | - /// @param rect coordinate | ||
36 | - PdfOutline(PdfDocument pdfDocument, {this.title, this.dest, this.rect}) | ||
37 | - : super(pdfDocument, '/Outlines'); | 46 | + PdfOutline( |
47 | + PdfDocument pdfDocument, { | ||
48 | + this.title, | ||
49 | + this.dest, | ||
50 | + this.rect, | ||
51 | + this.anchor, | ||
52 | + this.color, | ||
53 | + this.destMode = PdfOutlineMode.fitpage, | ||
54 | + this.style = PdfOutlineStyle.normal, | ||
55 | + }) : assert(anchor == null || (dest == null && rect == null)), | ||
56 | + assert(destMode != null), | ||
57 | + assert(style != null), | ||
58 | + super(pdfDocument); | ||
38 | 59 | ||
39 | /// This holds any outlines below us | 60 | /// This holds any outlines below us |
40 | List<PdfOutline> outlines = <PdfOutline>[]; | 61 | List<PdfOutline> outlines = <PdfOutline>[]; |
@@ -51,33 +72,25 @@ class PdfOutline extends PdfObject { | @@ -51,33 +72,25 @@ class PdfOutline extends PdfObject { | ||
51 | /// The region on the destination page | 72 | /// The region on the destination page |
52 | final PdfRect rect; | 73 | final PdfRect rect; |
53 | 74 | ||
75 | + /// Named destination | ||
76 | + final String anchor; | ||
77 | + | ||
78 | + /// Color of the outline text | ||
79 | + final PdfColor color; | ||
80 | + | ||
54 | /// How the destination is handled | 81 | /// How the destination is handled |
55 | - PdfOutlineMode destMode = PdfOutlineMode.fitpage; | 82 | + final PdfOutlineMode destMode; |
83 | + | ||
84 | + /// How to display the outline text | ||
85 | + final PdfOutlineStyle style; | ||
86 | + | ||
87 | + int effectiveLevel; | ||
56 | 88 | ||
57 | /// This method creates an outline, and attaches it to this one. | 89 | /// This method creates an outline, and attaches it to this one. |
58 | /// When the outline is selected, the supplied region is displayed. | 90 | /// When the outline is selected, the supplied region is displayed. |
59 | - /// | ||
60 | - /// Note: the coordinates are in User space. They are converted to User | ||
61 | - /// space. | ||
62 | - /// | ||
63 | - /// This allows you to have an outline for say a Chapter, | ||
64 | - /// then under the chapter, one for each section. You are not really | ||
65 | - /// limited on how deep you go, but it's best not to go below say 6 levels, | ||
66 | - /// for the reader's sake. | ||
67 | - /// | ||
68 | - /// @param title Title of the outline | ||
69 | - /// @param dest The destination page | ||
70 | - /// @param x coordinate of region in User space | ||
71 | - /// @param y coordinate of region in User space | ||
72 | - /// @param w width of region in User space | ||
73 | - /// @param h height of region in User space | ||
74 | - /// @return [PdfOutline] object created, for creating sub-outlines | ||
75 | - PdfOutline add({String title, PdfPage dest, PdfRect rect}) { | ||
76 | - final PdfOutline outline = | ||
77 | - PdfOutline(pdfDocument, title: title, dest: dest, rect: rect); | ||
78 | - // Tell the outline of ourselves | 91 | + void add(PdfOutline outline) { |
79 | outline.parent = this; | 92 | outline.parent = this; |
80 | - return outline; | 93 | + outlines.add(outline); |
81 | } | 94 | } |
82 | 95 | ||
83 | /// @param os OutputStream to send the object to | 96 | /// @param os OutputStream to send the object to |
@@ -88,20 +101,33 @@ class PdfOutline extends PdfObject { | @@ -88,20 +101,33 @@ class PdfOutline extends PdfObject { | ||
88 | // These are for kids only | 101 | // These are for kids only |
89 | if (parent != null) { | 102 | if (parent != null) { |
90 | params['/Title'] = PdfSecString.fromString(this, title); | 103 | params['/Title'] = PdfSecString.fromString(this, title); |
91 | - final PdfArray dests = PdfArray(); | ||
92 | - dests.add(dest.ref()); | ||
93 | 104 | ||
94 | - if (destMode == PdfOutlineMode.fitpage) { | ||
95 | - dests.add(const PdfName('/Fit')); | 105 | + if (color != null) { |
106 | + params['/C'] = PdfColorType(color); | ||
107 | + } | ||
108 | + | ||
109 | + if (style != PdfOutlineStyle.normal) { | ||
110 | + params['/F'] = PdfNum(style.index); | ||
111 | + } | ||
112 | + | ||
113 | + if (anchor != null) { | ||
114 | + params['/Dest'] = PdfSecString.fromString(this, anchor); | ||
96 | } else { | 115 | } else { |
97 | - dests.add(const PdfName('/FitR')); | ||
98 | - dests.add(PdfNum(rect.left)); | ||
99 | - dests.add(PdfNum(rect.bottom)); | ||
100 | - dests.add(PdfNum(rect.right)); | ||
101 | - dests.add(PdfNum(rect.top)); | 116 | + final PdfArray dests = PdfArray(); |
117 | + dests.add(dest.ref()); | ||
118 | + | ||
119 | + if (destMode == PdfOutlineMode.fitpage) { | ||
120 | + dests.add(const PdfName('/Fit')); | ||
121 | + } else { | ||
122 | + dests.add(const PdfName('/FitR')); | ||
123 | + dests.add(PdfNum(rect.left)); | ||
124 | + dests.add(PdfNum(rect.bottom)); | ||
125 | + dests.add(PdfNum(rect.right)); | ||
126 | + dests.add(PdfNum(rect.top)); | ||
127 | + } | ||
128 | + params['/Dest'] = dests; | ||
102 | } | 129 | } |
103 | params['/Parent'] = parent.ref(); | 130 | params['/Parent'] = parent.ref(); |
104 | - params['/Dest'] = dests; | ||
105 | 131 | ||
106 | // were a descendent, so by default we are closed. Find out how many | 132 | // were a descendent, so by default we are closed. Find out how many |
107 | // entries are below us | 133 | // entries are below us |
@@ -19,22 +19,38 @@ | @@ -19,22 +19,38 @@ | ||
19 | part of widget; | 19 | part of widget; |
20 | 20 | ||
21 | class Anchor extends SingleChildWidget { | 21 | class Anchor extends SingleChildWidget { |
22 | - Anchor({Widget child, @required this.name, this.description}) | ||
23 | - : assert(name != null), | 22 | + Anchor({ |
23 | + Widget child, | ||
24 | + @required this.name, | ||
25 | + this.description, | ||
26 | + this.zoom, | ||
27 | + this.setX = false, | ||
28 | + }) : assert(name != null), | ||
29 | + assert(setX != null), | ||
24 | super(child: child); | 30 | super(child: child); |
25 | 31 | ||
26 | final String name; | 32 | final String name; |
27 | 33 | ||
28 | final String description; | 34 | final String description; |
29 | 35 | ||
36 | + final double zoom; | ||
37 | + | ||
38 | + final bool setX; | ||
39 | + | ||
30 | @override | 40 | @override |
31 | void paint(Context context) { | 41 | void paint(Context context) { |
32 | super.paint(context); | 42 | super.paint(context); |
33 | paintChild(context); | 43 | paintChild(context); |
34 | 44 | ||
35 | final Matrix4 mat = context.canvas.getTransform(); | 45 | final Matrix4 mat = context.canvas.getTransform(); |
36 | - final Vector3 lt = mat.transform3(Vector3(box.left, box.bottom, 0)); | ||
37 | - context.document.pdfNames.addDest(name, context.page, posY: lt.y); | 46 | + final Vector3 lt = mat.transform3(Vector3(box.left, box.top, 0)); |
47 | + context.document.pdfNames.addDest( | ||
48 | + name, | ||
49 | + context.page, | ||
50 | + posX: setX ? lt.x : null, | ||
51 | + posY: lt.y, | ||
52 | + posZ: zoom, | ||
53 | + ); | ||
38 | 54 | ||
39 | if (description != null) { | 55 | if (description != null) { |
40 | final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0)); | 56 | final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0)); |
@@ -307,3 +323,74 @@ class TextField extends Annotation { | @@ -307,3 +323,74 @@ class TextField extends Annotation { | ||
307 | textStyle: textStyle, | 323 | textStyle: textStyle, |
308 | )); | 324 | )); |
309 | } | 325 | } |
326 | + | ||
327 | +class Outline extends Anchor { | ||
328 | + Outline({ | ||
329 | + Widget child, | ||
330 | + @required String name, | ||
331 | + @required this.title, | ||
332 | + this.level = 0, | ||
333 | + this.color, | ||
334 | + this.style = PdfOutlineStyle.normal, | ||
335 | + }) : assert(title != null), | ||
336 | + assert(level != null && level >= 0), | ||
337 | + assert(style != null), | ||
338 | + super(child: child, name: name, setX: true); | ||
339 | + | ||
340 | + final String title; | ||
341 | + | ||
342 | + final int level; | ||
343 | + | ||
344 | + final PdfColor color; | ||
345 | + | ||
346 | + final PdfOutlineStyle style; | ||
347 | + | ||
348 | + PdfOutline _outline; | ||
349 | + | ||
350 | + @override | ||
351 | + void layout(Context context, BoxConstraints constraints, | ||
352 | + {bool parentUsesSize = false}) { | ||
353 | + super.layout(context, constraints, parentUsesSize: parentUsesSize); | ||
354 | + _buildOutline(context); | ||
355 | + } | ||
356 | + | ||
357 | + @override | ||
358 | + void debugPaint(Context context) { | ||
359 | + context.canvas | ||
360 | + ..setFillColor(PdfColors.pink100) | ||
361 | + ..drawRect(box.x, box.y, box.width, box.height) | ||
362 | + ..fillPath(); | ||
363 | + } | ||
364 | + | ||
365 | + void _buildOutline(Context context) { | ||
366 | + if (_outline != null) { | ||
367 | + return; | ||
368 | + } | ||
369 | + | ||
370 | + _outline = PdfOutline( | ||
371 | + context.document, | ||
372 | + title: title, | ||
373 | + anchor: name, | ||
374 | + color: color, | ||
375 | + style: style, | ||
376 | + ); | ||
377 | + | ||
378 | + PdfOutline parent = context.document.outline; | ||
379 | + int l = level; | ||
380 | + | ||
381 | + while (l > 0) { | ||
382 | + if (parent.effectiveLevel == l) { | ||
383 | + break; | ||
384 | + } | ||
385 | + | ||
386 | + if (parent.outlines.isEmpty) { | ||
387 | + parent.effectiveLevel = level; | ||
388 | + break; | ||
389 | + } | ||
390 | + parent = parent.outlines.last; | ||
391 | + l--; | ||
392 | + } | ||
393 | + | ||
394 | + parent.add(_outline); | ||
395 | + } | ||
396 | +} |
@@ -19,15 +19,23 @@ | @@ -19,15 +19,23 @@ | ||
19 | part of widget; | 19 | part of widget; |
20 | 20 | ||
21 | class Header extends StatelessWidget { | 21 | class Header extends StatelessWidget { |
22 | - Header( | ||
23 | - {this.level = 1, | ||
24 | - this.text, | ||
25 | - this.child, | ||
26 | - this.decoration, | ||
27 | - this.margin, | ||
28 | - this.padding, | ||
29 | - this.textStyle}) | ||
30 | - : assert(level >= 0 && level <= 5); | 22 | + Header({ |
23 | + this.level = 1, | ||
24 | + this.text, | ||
25 | + this.child, | ||
26 | + this.decoration, | ||
27 | + this.margin, | ||
28 | + this.padding, | ||
29 | + this.textStyle, | ||
30 | + String title, | ||
31 | + this.outlineColor, | ||
32 | + this.outlineStyle = PdfOutlineStyle.normal, | ||
33 | + }) : assert(level != null, level >= 0 && level <= 5), | ||
34 | + assert(text != null || child != null), | ||
35 | + assert(outlineStyle != null), | ||
36 | + title = title ?? text; | ||
37 | + | ||
38 | + final String title; | ||
31 | 39 | ||
32 | final String text; | 40 | final String text; |
33 | 41 | ||
@@ -43,6 +51,10 @@ class Header extends StatelessWidget { | @@ -43,6 +51,10 @@ class Header extends StatelessWidget { | ||
43 | 51 | ||
44 | final TextStyle textStyle; | 52 | final TextStyle textStyle; |
45 | 53 | ||
54 | + final PdfColor outlineColor; | ||
55 | + | ||
56 | + final PdfOutlineStyle outlineStyle; | ||
57 | + | ||
46 | @override | 58 | @override |
47 | Widget build(Context context) { | 59 | Widget build(Context context) { |
48 | BoxDecoration _decoration = decoration; | 60 | BoxDecoration _decoration = decoration; |
@@ -85,13 +97,27 @@ class Header extends StatelessWidget { | @@ -85,13 +97,27 @@ class Header extends StatelessWidget { | ||
85 | _textStyle ??= Theme.of(context).header5; | 97 | _textStyle ??= Theme.of(context).header5; |
86 | break; | 98 | break; |
87 | } | 99 | } |
88 | - return Container( | 100 | + |
101 | + final Widget container = Container( | ||
89 | alignment: Alignment.topLeft, | 102 | alignment: Alignment.topLeft, |
90 | margin: _margin, | 103 | margin: _margin, |
91 | padding: _padding, | 104 | padding: _padding, |
92 | decoration: _decoration, | 105 | decoration: _decoration, |
93 | child: child ?? Text(text, style: _textStyle), | 106 | child: child ?? Text(text, style: _textStyle), |
94 | ); | 107 | ); |
108 | + | ||
109 | + if (title == null) { | ||
110 | + return container; | ||
111 | + } | ||
112 | + | ||
113 | + return Outline( | ||
114 | + name: text.hashCode.toString(), | ||
115 | + title: title, | ||
116 | + child: container, | ||
117 | + level: level, | ||
118 | + color: outlineColor, | ||
119 | + style: outlineStyle, | ||
120 | + ); | ||
95 | } | 121 | } |
96 | } | 122 | } |
97 | 123 |
@@ -40,6 +40,7 @@ import 'widget_form_test.dart' as widget_form; | @@ -40,6 +40,7 @@ import 'widget_form_test.dart' as widget_form; | ||
40 | import 'widget_grid_view_test.dart' as widget_grid_view; | 40 | import 'widget_grid_view_test.dart' as widget_grid_view; |
41 | import 'widget_multipage_test.dart' as widget_multipage; | 41 | import 'widget_multipage_test.dart' as widget_multipage; |
42 | import 'widget_opacity_test.dart' as widget_opacity; | 42 | import 'widget_opacity_test.dart' as widget_opacity; |
43 | +import 'widget_outline_test.dart' as widget_outline; | ||
43 | import 'widget_partitions_test.dart' as widget_partitions; | 44 | import 'widget_partitions_test.dart' as widget_partitions; |
44 | import 'widget_table_test.dart' as widget_table; | 45 | import 'widget_table_test.dart' as widget_table; |
45 | import 'widget_test.dart' as widget; | 46 | import 'widget_test.dart' as widget; |
@@ -73,6 +74,7 @@ void main() { | @@ -73,6 +74,7 @@ void main() { | ||
73 | widget_grid_view.main(); | 74 | widget_grid_view.main(); |
74 | widget_multipage.main(); | 75 | widget_multipage.main(); |
75 | widget_opacity.main(); | 76 | widget_opacity.main(); |
77 | + widget_outline.main(); | ||
76 | widget_partitions.main(); | 78 | widget_partitions.main(); |
77 | widget_table.main(); | 79 | widget_table.main(); |
78 | widget_text.main(); | 80 | widget_text.main(); |
@@ -175,14 +175,14 @@ Document pdf; | @@ -175,14 +175,14 @@ Document pdf; | ||
175 | void main() { | 175 | void main() { |
176 | setUpAll(() { | 176 | setUpAll(() { |
177 | Document.debug = true; | 177 | Document.debug = true; |
178 | - pdf = Document(); | 178 | + pdf = Document(pageMode: PdfPageMode.outlines); |
179 | }); | 179 | }); |
180 | 180 | ||
181 | test('Pdf Colors', () { | 181 | test('Pdf Colors', () { |
182 | pdf.addPage(MultiPage( | 182 | pdf.addPage(MultiPage( |
183 | pageFormat: PdfPageFormat.standard, | 183 | pageFormat: PdfPageFormat.standard, |
184 | build: (Context context) => <Widget>[ | 184 | build: (Context context) => <Widget>[ |
185 | - Header(text: 'Red'), | 185 | + Header(text: 'Red', outlineColor: PdfColors.red), |
186 | GridView( | 186 | GridView( |
187 | crossAxisCount: 4, | 187 | crossAxisCount: 4, |
188 | direction: Axis.vertical, | 188 | direction: Axis.vertical, |
@@ -207,7 +207,7 @@ void main() { | @@ -207,7 +207,7 @@ void main() { | ||
207 | Color(PdfColors.redAccent700, 'Red', 'Accent 700'), | 207 | Color(PdfColors.redAccent700, 'Red', 'Accent 700'), |
208 | ]), | 208 | ]), |
209 | NewPage(), | 209 | NewPage(), |
210 | - Header(text: 'Pink'), | 210 | + Header(text: 'Pink', outlineColor: PdfColors.pink), |
211 | GridView( | 211 | GridView( |
212 | crossAxisCount: 4, | 212 | crossAxisCount: 4, |
213 | direction: Axis.vertical, | 213 | direction: Axis.vertical, |
@@ -232,7 +232,7 @@ void main() { | @@ -232,7 +232,7 @@ void main() { | ||
232 | Color(PdfColors.pinkAccent700, 'Pink', 'Accent 700'), | 232 | Color(PdfColors.pinkAccent700, 'Pink', 'Accent 700'), |
233 | ]), | 233 | ]), |
234 | NewPage(), | 234 | NewPage(), |
235 | - Header(text: 'Purple'), | 235 | + Header(text: 'Purple', outlineColor: PdfColors.purple), |
236 | GridView( | 236 | GridView( |
237 | crossAxisCount: 4, | 237 | crossAxisCount: 4, |
238 | direction: Axis.vertical, | 238 | direction: Axis.vertical, |
@@ -257,7 +257,7 @@ void main() { | @@ -257,7 +257,7 @@ void main() { | ||
257 | Color(PdfColors.purpleAccent700, 'Purple', 'Accent 700'), | 257 | Color(PdfColors.purpleAccent700, 'Purple', 'Accent 700'), |
258 | ]), | 258 | ]), |
259 | NewPage(), | 259 | NewPage(), |
260 | - Header(text: 'Deep Purple'), | 260 | + Header(text: 'Deep Purple', outlineColor: PdfColors.deepPurple), |
261 | GridView( | 261 | GridView( |
262 | crossAxisCount: 4, | 262 | crossAxisCount: 4, |
263 | direction: Axis.vertical, | 263 | direction: Axis.vertical, |
@@ -286,7 +286,7 @@ void main() { | @@ -286,7 +286,7 @@ void main() { | ||
286 | 'Accent 700'), | 286 | 'Accent 700'), |
287 | ]), | 287 | ]), |
288 | NewPage(), | 288 | NewPage(), |
289 | - Header(text: 'Indigo'), | 289 | + Header(text: 'Indigo', outlineColor: PdfColors.indigo), |
290 | GridView( | 290 | GridView( |
291 | crossAxisCount: 4, | 291 | crossAxisCount: 4, |
292 | direction: Axis.vertical, | 292 | direction: Axis.vertical, |
@@ -311,7 +311,7 @@ void main() { | @@ -311,7 +311,7 @@ void main() { | ||
311 | Color(PdfColors.indigoAccent700, 'Indigo', 'Accent 700'), | 311 | Color(PdfColors.indigoAccent700, 'Indigo', 'Accent 700'), |
312 | ]), | 312 | ]), |
313 | NewPage(), | 313 | NewPage(), |
314 | - Header(text: 'Blue'), | 314 | + Header(text: 'Blue', outlineColor: PdfColors.blue), |
315 | GridView( | 315 | GridView( |
316 | crossAxisCount: 4, | 316 | crossAxisCount: 4, |
317 | direction: Axis.vertical, | 317 | direction: Axis.vertical, |
@@ -336,7 +336,7 @@ void main() { | @@ -336,7 +336,7 @@ void main() { | ||
336 | Color(PdfColors.blueAccent700, 'Blue', 'Accent 700'), | 336 | Color(PdfColors.blueAccent700, 'Blue', 'Accent 700'), |
337 | ]), | 337 | ]), |
338 | NewPage(), | 338 | NewPage(), |
339 | - Header(text: 'Light Blue'), | 339 | + Header(text: 'Light Blue', outlineColor: PdfColors.lightBlue), |
340 | GridView( | 340 | GridView( |
341 | crossAxisCount: 4, | 341 | crossAxisCount: 4, |
342 | direction: Axis.vertical, | 342 | direction: Axis.vertical, |
@@ -365,7 +365,7 @@ void main() { | @@ -365,7 +365,7 @@ void main() { | ||
365 | 'Accent 700'), | 365 | 'Accent 700'), |
366 | ]), | 366 | ]), |
367 | NewPage(), | 367 | NewPage(), |
368 | - Header(text: 'Cyan'), | 368 | + Header(text: 'Cyan', outlineColor: PdfColors.cyan), |
369 | GridView( | 369 | GridView( |
370 | crossAxisCount: 4, | 370 | crossAxisCount: 4, |
371 | direction: Axis.vertical, | 371 | direction: Axis.vertical, |
@@ -390,7 +390,7 @@ void main() { | @@ -390,7 +390,7 @@ void main() { | ||
390 | Color(PdfColors.cyanAccent700, 'Cyan', 'Accent 700'), | 390 | Color(PdfColors.cyanAccent700, 'Cyan', 'Accent 700'), |
391 | ]), | 391 | ]), |
392 | NewPage(), | 392 | NewPage(), |
393 | - Header(text: 'Teal'), | 393 | + Header(text: 'Teal', outlineColor: PdfColors.teal), |
394 | GridView( | 394 | GridView( |
395 | crossAxisCount: 4, | 395 | crossAxisCount: 4, |
396 | direction: Axis.vertical, | 396 | direction: Axis.vertical, |
@@ -415,7 +415,7 @@ void main() { | @@ -415,7 +415,7 @@ void main() { | ||
415 | Color(PdfColors.tealAccent700, 'Teal', 'Accent 700'), | 415 | Color(PdfColors.tealAccent700, 'Teal', 'Accent 700'), |
416 | ]), | 416 | ]), |
417 | NewPage(), | 417 | NewPage(), |
418 | - Header(text: 'Green'), | 418 | + Header(text: 'Green', outlineColor: PdfColors.green), |
419 | GridView( | 419 | GridView( |
420 | crossAxisCount: 4, | 420 | crossAxisCount: 4, |
421 | direction: Axis.vertical, | 421 | direction: Axis.vertical, |
@@ -440,7 +440,7 @@ void main() { | @@ -440,7 +440,7 @@ void main() { | ||
440 | Color(PdfColors.greenAccent700, 'Green', 'Accent 700'), | 440 | Color(PdfColors.greenAccent700, 'Green', 'Accent 700'), |
441 | ]), | 441 | ]), |
442 | NewPage(), | 442 | NewPage(), |
443 | - Header(text: 'Light Green'), | 443 | + Header(text: 'Light Green', outlineColor: PdfColors.lightGreen), |
444 | GridView( | 444 | GridView( |
445 | crossAxisCount: 4, | 445 | crossAxisCount: 4, |
446 | direction: Axis.vertical, | 446 | direction: Axis.vertical, |
@@ -469,7 +469,7 @@ void main() { | @@ -469,7 +469,7 @@ void main() { | ||
469 | 'Accent700'), | 469 | 'Accent700'), |
470 | ]), | 470 | ]), |
471 | NewPage(), | 471 | NewPage(), |
472 | - Header(text: 'Lime'), | 472 | + Header(text: 'Lime', outlineColor: PdfColors.lime), |
473 | GridView( | 473 | GridView( |
474 | crossAxisCount: 4, | 474 | crossAxisCount: 4, |
475 | direction: Axis.vertical, | 475 | direction: Axis.vertical, |
@@ -494,7 +494,7 @@ void main() { | @@ -494,7 +494,7 @@ void main() { | ||
494 | Color(PdfColors.limeAccent700, 'Lime', 'Accent 700'), | 494 | Color(PdfColors.limeAccent700, 'Lime', 'Accent 700'), |
495 | ]), | 495 | ]), |
496 | NewPage(), | 496 | NewPage(), |
497 | - Header(text: 'Yellow'), | 497 | + Header(text: 'Yellow', outlineColor: PdfColors.yellow), |
498 | GridView( | 498 | GridView( |
499 | crossAxisCount: 4, | 499 | crossAxisCount: 4, |
500 | direction: Axis.vertical, | 500 | direction: Axis.vertical, |
@@ -519,7 +519,7 @@ void main() { | @@ -519,7 +519,7 @@ void main() { | ||
519 | Color(PdfColors.yellowAccent700, 'Yellow', 'Accent 700'), | 519 | Color(PdfColors.yellowAccent700, 'Yellow', 'Accent 700'), |
520 | ]), | 520 | ]), |
521 | NewPage(), | 521 | NewPage(), |
522 | - Header(text: 'Amber'), | 522 | + Header(text: 'Amber', outlineColor: PdfColors.amber), |
523 | GridView( | 523 | GridView( |
524 | crossAxisCount: 4, | 524 | crossAxisCount: 4, |
525 | direction: Axis.vertical, | 525 | direction: Axis.vertical, |
@@ -544,7 +544,7 @@ void main() { | @@ -544,7 +544,7 @@ void main() { | ||
544 | Color(PdfColors.amberAccent700, 'Amber', 'Accent 700'), | 544 | Color(PdfColors.amberAccent700, 'Amber', 'Accent 700'), |
545 | ]), | 545 | ]), |
546 | NewPage(), | 546 | NewPage(), |
547 | - Header(text: 'Orange'), | 547 | + Header(text: 'Orange', outlineColor: PdfColors.orange), |
548 | GridView( | 548 | GridView( |
549 | crossAxisCount: 4, | 549 | crossAxisCount: 4, |
550 | direction: Axis.vertical, | 550 | direction: Axis.vertical, |
@@ -569,7 +569,7 @@ void main() { | @@ -569,7 +569,7 @@ void main() { | ||
569 | Color(PdfColors.orangeAccent700, 'Orange', 'Accent 700'), | 569 | Color(PdfColors.orangeAccent700, 'Orange', 'Accent 700'), |
570 | ]), | 570 | ]), |
571 | NewPage(), | 571 | NewPage(), |
572 | - Header(text: 'Deep Orange'), | 572 | + Header(text: 'Deep Orange', outlineColor: PdfColors.deepOrange), |
573 | GridView( | 573 | GridView( |
574 | crossAxisCount: 4, | 574 | crossAxisCount: 4, |
575 | direction: Axis.vertical, | 575 | direction: Axis.vertical, |
@@ -598,7 +598,7 @@ void main() { | @@ -598,7 +598,7 @@ void main() { | ||
598 | 'Accent 700'), | 598 | 'Accent 700'), |
599 | ]), | 599 | ]), |
600 | NewPage(), | 600 | NewPage(), |
601 | - Header(text: 'Brown'), | 601 | + Header(text: 'Brown', outlineColor: PdfColors.brown), |
602 | GridView( | 602 | GridView( |
603 | crossAxisCount: 4, | 603 | crossAxisCount: 4, |
604 | direction: Axis.vertical, | 604 | direction: Axis.vertical, |
@@ -619,7 +619,7 @@ void main() { | @@ -619,7 +619,7 @@ void main() { | ||
619 | Color(PdfColors.brown900, 'Brown', '900'), | 619 | Color(PdfColors.brown900, 'Brown', '900'), |
620 | ]), | 620 | ]), |
621 | NewPage(), | 621 | NewPage(), |
622 | - Header(text: 'Blue Grey'), | 622 | + Header(text: 'Blue Grey', outlineColor: PdfColors.blueGrey), |
623 | GridView( | 623 | GridView( |
624 | crossAxisCount: 4, | 624 | crossAxisCount: 4, |
625 | direction: Axis.vertical, | 625 | direction: Axis.vertical, |
@@ -640,7 +640,7 @@ void main() { | @@ -640,7 +640,7 @@ void main() { | ||
640 | Color(PdfColors.blueGrey900, 'Blue Grey', '900'), | 640 | Color(PdfColors.blueGrey900, 'Blue Grey', '900'), |
641 | ]), | 641 | ]), |
642 | NewPage(), | 642 | NewPage(), |
643 | - Header(text: 'Grey'), | 643 | + Header(text: 'Grey', outlineColor: PdfColors.grey), |
644 | GridView( | 644 | GridView( |
645 | crossAxisCount: 4, | 645 | crossAxisCount: 4, |
646 | direction: Axis.vertical, | 646 | direction: Axis.vertical, |
@@ -677,7 +677,7 @@ void main() { | @@ -677,7 +677,7 @@ void main() { | ||
677 | pdf.addPage(Page( | 677 | pdf.addPage(Page( |
678 | build: (Context context) => Column( | 678 | build: (Context context) => Column( |
679 | children: <Widget>[ | 679 | children: <Widget>[ |
680 | - Header(text: name), | 680 | + Header(text: name, outlineStyle: PdfOutlineStyle.italic), |
681 | SizedBox( | 681 | SizedBox( |
682 | height: context.page.pageFormat.availableWidth, | 682 | height: context.page.pageFormat.availableWidth, |
683 | child: ColorWheel( | 683 | child: ColorWheel( |
pdf/test/widget_outline_test.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 | +// ignore_for_file: omit_local_variable_types | ||
18 | + | ||
19 | +import 'dart:io'; | ||
20 | +import 'dart:math'; | ||
21 | + | ||
22 | +import 'package:pdf/pdf.dart'; | ||
23 | +import 'package:pdf/widgets.dart'; | ||
24 | +import 'package:test/test.dart'; | ||
25 | + | ||
26 | +Document pdf; | ||
27 | + | ||
28 | +final LoremText lorem = LoremText(random: Random(42)); | ||
29 | + | ||
30 | +Iterable<Widget> level(int i) sync* { | ||
31 | + final String text = lorem.sentence(5); | ||
32 | + int p = 0; | ||
33 | + PdfColor color; | ||
34 | + PdfOutlineStyle style = PdfOutlineStyle.normal; | ||
35 | + | ||
36 | + if (i >= 3 && i <= 6) { | ||
37 | + p++; | ||
38 | + } | ||
39 | + | ||
40 | + if (i >= 5 && i <= 6) { | ||
41 | + p++; | ||
42 | + } | ||
43 | + | ||
44 | + if (i == 15) { | ||
45 | + p = 10; | ||
46 | + color = PdfColors.amber; | ||
47 | + style = PdfOutlineStyle.bold; | ||
48 | + } | ||
49 | + | ||
50 | + if (i == 17) { | ||
51 | + color = PdfColors.red; | ||
52 | + style = PdfOutlineStyle.italic; | ||
53 | + } | ||
54 | + | ||
55 | + if (i == 18) { | ||
56 | + color = PdfColors.blue; | ||
57 | + style = PdfOutlineStyle.italicBold; | ||
58 | + } | ||
59 | + | ||
60 | + yield Outline( | ||
61 | + child: Text(text), | ||
62 | + name: 'anchor$i', | ||
63 | + title: text, | ||
64 | + level: p, | ||
65 | + color: color, | ||
66 | + style: style, | ||
67 | + ); | ||
68 | + | ||
69 | + yield SizedBox(height: 300); | ||
70 | +} | ||
71 | + | ||
72 | +void main() { | ||
73 | + setUpAll(() { | ||
74 | + Document.debug = true; | ||
75 | + pdf = Document(pageMode: PdfPageMode.outlines); | ||
76 | + }); | ||
77 | + | ||
78 | + test('Outline Widget', () { | ||
79 | + pdf.addPage( | ||
80 | + MultiPage( | ||
81 | + build: (Context context) => <Widget>[ | ||
82 | + for (int i = 0; i < 20; i++) ...level(i), | ||
83 | + ], | ||
84 | + ), | ||
85 | + ); | ||
86 | + }); | ||
87 | + | ||
88 | + tearDownAll(() { | ||
89 | + final File file = File('widgets-outline.pdf'); | ||
90 | + file.writeAsBytesSync(pdf.save()); | ||
91 | + }); | ||
92 | +} |
No preview for this file type
test/golden/widgets-outline.pdf
0 → 100644
No preview for this file type
-
Please register or login to post a comment