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