David PHAM-VAN

Add AcroForm widgets

@@ -52,3 +52,4 @@ ref @@ -52,3 +52,4 @@ ref
52 cache_* 52 cache_*
53 53
54 .vscode 54 .vscode
  55 +package.json
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 ## 1.13.0 3 ## 1.13.0
4 4
5 - Implement different border radius on all corners 5 - Implement different border radius on all corners
  6 +- Add AcroForm widgets
6 7
7 ## 1.12.0 8 ## 1.12.0
8 9
@@ -50,6 +50,7 @@ part 'src/font_metrics.dart'; @@ -50,6 +50,7 @@ part 'src/font_metrics.dart';
50 part 'src/formxobject.dart'; 50 part 'src/formxobject.dart';
51 part 'src/function.dart'; 51 part 'src/function.dart';
52 part 'src/graphic_state.dart'; 52 part 'src/graphic_state.dart';
  53 +part 'src/graphic_stream.dart';
53 part 'src/graphics.dart'; 54 part 'src/graphics.dart';
54 part 'src/image.dart'; 55 part 'src/image.dart';
55 part 'src/info.dart'; 56 part 'src/info.dart';
@@ -42,20 +42,45 @@ class PdfAnnot extends PdfObject { @@ -42,20 +42,45 @@ class PdfAnnot extends PdfObject {
42 } 42 }
43 43
44 enum PdfAnnotFlags { 44 enum PdfAnnotFlags {
  45 + /// 1
45 invisible, 46 invisible,
  47 +
  48 + /// 2
46 hidden, 49 hidden,
  50 +
  51 + /// 3
47 print, 52 print,
  53 +
  54 + /// 4
48 noZoom, 55 noZoom,
  56 +
  57 + /// 5
49 noRotate, 58 noRotate,
  59 +
  60 + /// 6
50 noView, 61 noView,
  62 +
  63 + /// 7
51 readOnly, 64 readOnly,
  65 +
  66 + /// 8
52 locked, 67 locked,
  68 +
  69 + /// 9
53 toggleNoView, 70 toggleNoView,
54 - lockedContent 71 +
  72 + /// 10
  73 + lockedContent,
  74 +}
  75 +
  76 +enum PdfAnnotApparence {
  77 + normal,
  78 + rollover,
  79 + down,
55 } 80 }
56 81
57 abstract class PdfAnnotBase { 82 abstract class PdfAnnotBase {
58 - const PdfAnnotBase({ 83 + PdfAnnotBase({
59 @required this.subtype, 84 @required this.subtype,
60 @required this.rect, 85 @required this.rect,
61 this.border, 86 this.border,
@@ -90,9 +115,66 @@ abstract class PdfAnnotBase { @@ -90,9 +115,66 @@ abstract class PdfAnnotBase {
90 /// Color 115 /// Color
91 final PdfColor color; 116 final PdfColor color;
92 117
93 - int get flagValue => flags  
94 - ?.map<int>((PdfAnnotFlags e) => 1 >> e.index)  
95 - ?.reduce((int a, int b) => a | b); 118 + final Map<String, PdfDataType> _appearances = <String, PdfDataType>{};
  119 +
  120 + int get flagValue {
  121 + if (flags == null || flags.isEmpty) {
  122 + return 0;
  123 + }
  124 +
  125 + return flags
  126 + .map<int>((PdfAnnotFlags e) => 1 << e.index)
  127 + .reduce((int a, int b) => a | b);
  128 + }
  129 +
  130 + PdfGraphics appearance(
  131 + PdfDocument pdfDocument,
  132 + PdfAnnotApparence type, {
  133 + String name,
  134 + Matrix4 matrix,
  135 + PdfRect boundingBox,
  136 + }) {
  137 + final PdfGraphicXObject s = PdfGraphicXObject(pdfDocument, '/Form');
  138 + String n;
  139 + switch (type) {
  140 + case PdfAnnotApparence.normal:
  141 + n = '/N';
  142 + break;
  143 + case PdfAnnotApparence.rollover:
  144 + n = '/R';
  145 + break;
  146 + case PdfAnnotApparence.down:
  147 + n = '/D';
  148 + break;
  149 + }
  150 + if (name == null) {
  151 + _appearances[n] = s.ref();
  152 + } else {
  153 + if (_appearances[n] is! PdfDict) {
  154 + _appearances[n] = PdfDict();
  155 + }
  156 + final PdfDict d = _appearances[n];
  157 + d[name] = s.ref();
  158 + }
  159 +
  160 + if (matrix != null) {
  161 + s.params['/Matrix'] = PdfArray.fromNum(<double>[
  162 + matrix[0],
  163 + matrix[1],
  164 + matrix[4],
  165 + matrix[5],
  166 + matrix[12],
  167 + matrix[13]
  168 + ]);
  169 + }
  170 +
  171 + final PdfRect bbox =
  172 + boundingBox ?? PdfRect.fromPoints(PdfPoint.zero, rect.size);
  173 + s.params['/BBox'] =
  174 + PdfArray.fromNum(<double>[bbox.x, bbox.y, bbox.width, bbox.height]);
  175 + final PdfGraphics g = PdfGraphics(s, s.buf);
  176 + return g;
  177 + }
96 178
97 @protected 179 @protected
98 @mustCallSuper 180 @mustCallSuper
@@ -118,7 +200,7 @@ abstract class PdfAnnotBase { @@ -118,7 +200,7 @@ abstract class PdfAnnotBase {
118 params['/NM'] = PdfSecString.fromString(object, name); 200 params['/NM'] = PdfSecString.fromString(object, name);
119 } 201 }
120 202
121 - if (flags != null) { 203 + if (flags != null && flags.isNotEmpty) {
122 params['/F'] = PdfNum(flagValue); 204 params['/F'] = PdfNum(flagValue);
123 } 205 }
124 206
@@ -127,13 +209,14 @@ abstract class PdfAnnotBase { @@ -127,13 +209,14 @@ abstract class PdfAnnotBase {
127 } 209 }
128 210
129 if (color != null) { 211 if (color != null) {
130 - if (color is PdfColorCmyk) {  
131 - final PdfColorCmyk k = color;  
132 - params['/C'] =  
133 - PdfArray.fromNum(<double>[k.cyan, k.magenta, k.yellow, k.black]);  
134 - } else {  
135 - params['/C'] =  
136 - PdfArray.fromNum(<double>[color.red, color.green, color.blue]); 212 + params['/C'] = PdfColorType(color);
  213 + }
  214 +
  215 + if (_appearances.isNotEmpty) {
  216 + params['/AP'] = PdfDict(_appearances);
  217 + if (_appearances['/N'] is PdfDict) {
  218 + final PdfDict n = _appearances['/N'];
  219 + params['/AS'] = PdfName(n.values.keys.first);
137 } 220 }
138 } 221 }
139 } 222 }
@@ -141,7 +224,7 @@ abstract class PdfAnnotBase { @@ -141,7 +224,7 @@ abstract class PdfAnnotBase {
141 224
142 class PdfAnnotText extends PdfAnnotBase { 225 class PdfAnnotText extends PdfAnnotBase {
143 /// Create a text annotation 226 /// Create a text annotation
144 - const PdfAnnotText({ 227 + PdfAnnotText({
145 @required PdfRect rect, 228 @required PdfRect rect,
146 @required String content, 229 @required String content,
147 PdfBorder border, 230 PdfBorder border,
@@ -163,7 +246,7 @@ class PdfAnnotText extends PdfAnnotBase { @@ -163,7 +246,7 @@ class PdfAnnotText extends PdfAnnotBase {
163 246
164 class PdfAnnotNamedLink extends PdfAnnotBase { 247 class PdfAnnotNamedLink extends PdfAnnotBase {
165 /// Create a named link annotation 248 /// Create a named link annotation
166 - const PdfAnnotNamedLink({ 249 + PdfAnnotNamedLink({
167 @required PdfRect rect, 250 @required PdfRect rect,
168 @required this.dest, 251 @required this.dest,
169 PdfBorder border, 252 PdfBorder border,
@@ -195,7 +278,7 @@ class PdfAnnotNamedLink extends PdfAnnotBase { @@ -195,7 +278,7 @@ class PdfAnnotNamedLink extends PdfAnnotBase {
195 278
196 class PdfAnnotUrlLink extends PdfAnnotBase { 279 class PdfAnnotUrlLink extends PdfAnnotBase {
197 /// Create an url link annotation 280 /// Create an url link annotation
198 - const PdfAnnotUrlLink({ 281 + PdfAnnotUrlLink({
199 @required PdfRect rect, 282 @required PdfRect rect,
200 @required this.url, 283 @required this.url,
201 PdfBorder border, 284 PdfBorder border,
@@ -228,15 +311,16 @@ class PdfAnnotUrlLink extends PdfAnnotBase { @@ -228,15 +311,16 @@ class PdfAnnotUrlLink extends PdfAnnotBase {
228 enum PdfAnnotHighlighting { none, invert, outline, push, toggle } 311 enum PdfAnnotHighlighting { none, invert, outline, push, toggle }
229 312
230 abstract class PdfAnnotWidget extends PdfAnnotBase { 313 abstract class PdfAnnotWidget extends PdfAnnotBase {
231 - /// Create an url link annotation  
232 - const PdfAnnotWidget(  
233 - PdfRect rect,  
234 - this.fieldType, { 314 + /// Create a widget annotation
  315 + PdfAnnotWidget({
  316 + @required PdfRect rect,
  317 + @required this.fieldType,
235 this.fieldName, 318 this.fieldName,
236 PdfBorder border, 319 PdfBorder border,
237 Set<PdfAnnotFlags> flags, 320 Set<PdfAnnotFlags> flags,
238 DateTime date, 321 DateTime date,
239 PdfColor color, 322 PdfColor color,
  323 + this.backgroundColor,
240 this.highlighting, 324 this.highlighting,
241 }) : super( 325 }) : super(
242 subtype: '/Widget', 326 subtype: '/Widget',
@@ -253,6 +337,8 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { @@ -253,6 +337,8 @@ abstract class PdfAnnotWidget extends PdfAnnotBase {
253 337
254 final PdfAnnotHighlighting highlighting; 338 final PdfAnnotHighlighting highlighting;
255 339
  340 + final PdfColor backgroundColor;
  341 +
256 @override 342 @override
257 void build(PdfPage page, PdfObject object, PdfDict params) { 343 void build(PdfPage page, PdfObject object, PdfDict params) {
258 super.build(page, object, params); 344 super.build(page, object, params);
@@ -262,12 +348,45 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { @@ -262,12 +348,45 @@ abstract class PdfAnnotWidget extends PdfAnnotBase {
262 if (fieldName != null) { 348 if (fieldName != null) {
263 params['/T'] = PdfSecString.fromString(object, fieldName); 349 params['/T'] = PdfSecString.fromString(object, fieldName);
264 } 350 }
  351 +
  352 + final PdfDict mk = PdfDict();
  353 + if (color != null) {
  354 + mk.values['/BC'] = PdfColorType(color);
  355 + }
  356 +
  357 + if (backgroundColor != null) {
  358 + mk.values['/BG'] = PdfColorType(backgroundColor);
  359 + }
  360 +
  361 + if (mk.values.isNotEmpty) {
  362 + params['/MK'] = mk;
  363 + }
  364 +
  365 + if (highlighting != null) {
  366 + switch (highlighting) {
  367 + case PdfAnnotHighlighting.none:
  368 + params['/H'] = const PdfName('/N');
  369 + break;
  370 + case PdfAnnotHighlighting.invert:
  371 + params['/H'] = const PdfName('/I');
  372 + break;
  373 + case PdfAnnotHighlighting.outline:
  374 + params['/H'] = const PdfName('/O');
  375 + break;
  376 + case PdfAnnotHighlighting.push:
  377 + params['/H'] = const PdfName('/P');
  378 + break;
  379 + case PdfAnnotHighlighting.toggle:
  380 + params['/H'] = const PdfName('/T');
  381 + break;
  382 + }
  383 + }
265 } 384 }
266 } 385 }
267 386
268 class PdfAnnotSign extends PdfAnnotWidget { 387 class PdfAnnotSign extends PdfAnnotWidget {
269 - const PdfAnnotSign(  
270 - PdfRect rect, { 388 + PdfAnnotSign({
  389 + @required PdfRect rect,
271 String fieldName, 390 String fieldName,
272 PdfBorder border, 391 PdfBorder border,
273 Set<PdfAnnotFlags> flags, 392 Set<PdfAnnotFlags> flags,
@@ -275,8 +394,8 @@ class PdfAnnotSign extends PdfAnnotWidget { @@ -275,8 +394,8 @@ class PdfAnnotSign extends PdfAnnotWidget {
275 PdfColor color, 394 PdfColor color,
276 PdfAnnotHighlighting highlighting, 395 PdfAnnotHighlighting highlighting,
277 }) : super( 396 }) : super(
278 - rect,  
279 - '/Sig', 397 + rect: rect,
  398 + fieldType: '/Sig',
280 fieldName: fieldName, 399 fieldName: fieldName,
281 border: border, 400 border: border,
282 flags: flags, 401 flags: flags,
@@ -292,3 +411,284 @@ class PdfAnnotSign extends PdfAnnotWidget { @@ -292,3 +411,284 @@ class PdfAnnotSign extends PdfAnnotWidget {
292 params['/V'] = page.pdfDocument.sign.ref(); 411 params['/V'] = page.pdfDocument.sign.ref();
293 } 412 }
294 } 413 }
  414 +
  415 +enum PdfFieldFlags {
  416 + /// 1 - If set, the user may not change the value of the field.
  417 + readOnly,
  418 +
  419 + /// 2 - If set, the field shall have a value at the time it is exported by
  420 + /// a submit-form action.
  421 + mandatory,
  422 +
  423 + /// 3 - If set, the field shall not be exported by a submit-form action.
  424 + noExport,
  425 +
  426 + /// 4
  427 + reserved4,
  428 +
  429 + /// 5
  430 + reserved5,
  431 +
  432 + /// 6
  433 + reserved6,
  434 +
  435 + /// 7
  436 + reserved7,
  437 +
  438 + /// 8
  439 + reserved8,
  440 +
  441 + /// 9
  442 + reserved9,
  443 +
  444 + /// 10
  445 + reserved10,
  446 +
  447 + /// 11
  448 + reserved11,
  449 +
  450 + /// 12
  451 + reserved12,
  452 +
  453 + /// 13 - If set, the field may contain multiple lines of text; if clear,
  454 + /// the field’s text shall be restricted to a single line.
  455 + multiline,
  456 +
  457 + /// 14 - If set, the field is intended for entering a secure password that
  458 + /// should not be echoed visibly to the screen. Characters typed from
  459 + /// the keyboard shall instead be echoed in some unreadable form, such
  460 + /// as asterisks or bullet characters.
  461 + password,
  462 +
  463 + /// 15 - If set, exactly one radio button shall be selected at all times.
  464 + noToggleToOff,
  465 +
  466 + /// 16 - If set, the field is a set of radio buttons; if clear,
  467 + /// the field is a check box.
  468 + radio,
  469 +
  470 + /// 17 - If set, the field is a pushbutton that does not retain
  471 + /// a permanent value.
  472 + pushButton,
  473 +
  474 + /// 18 - If set, the field is a combo box; if clear, the field is a list box.
  475 + combo,
  476 +
  477 + /// 19 - If set, the combo box shall include an editable text box as well
  478 + /// as a drop-down list
  479 + edit,
  480 +
  481 + /// 20 - If set, the field’s option items shall be sorted alphabetically.
  482 + sort,
  483 +
  484 + /// 21 - If set, the text entered in the field represents the pathname
  485 + /// of a file whose contents shall be submitted as the value of the field.
  486 + fileSelect,
  487 +
  488 + /// 22 - If set, more than one of the field’s option items may be selected
  489 + /// simultaneously
  490 + multiSelect,
  491 +
  492 + /// 23 - If set, text entered in the field shall not be spell-checked.
  493 + doNotSpellCheck,
  494 +
  495 + /// 24 - If set, the field shall not scroll to accommodate more text
  496 + /// than fits within its annotation rectangle.
  497 + doNotScroll,
  498 +
  499 + /// 25 - If set, the field shall be automatically divided into as many
  500 + /// equally spaced positions, or combs, as the value of MaxLen,
  501 + /// and the text is laid out into those combs.
  502 + comb,
  503 +
  504 + /// 26 - If set, a group of radio buttons within a radio button field
  505 + /// that use the same value for the on state will turn on and off in unison.
  506 + radiosInUnison,
  507 +
  508 + /// 27 - If set, the new value shall be committed as soon as a selection
  509 + /// is made.
  510 + commitOnSelChange,
  511 +}
  512 +
  513 +class PdfFormField extends PdfAnnotWidget {
  514 + PdfFormField({
  515 + @required String fieldType,
  516 + @required PdfRect rect,
  517 + String fieldName,
  518 + this.alternateName,
  519 + this.mappingName,
  520 + PdfBorder border,
  521 + Set<PdfAnnotFlags> flags,
  522 + DateTime date,
  523 + PdfColor color,
  524 + PdfColor backgroundColor,
  525 + PdfAnnotHighlighting highlighting,
  526 + this.fieldFlags,
  527 + }) : super(
  528 + rect: rect,
  529 + fieldType: fieldType,
  530 + fieldName: fieldName,
  531 + border: border,
  532 + flags: flags,
  533 + date: date,
  534 + backgroundColor: backgroundColor,
  535 + color: color,
  536 + highlighting: highlighting,
  537 + );
  538 +
  539 + final String alternateName;
  540 +
  541 + final String mappingName;
  542 +
  543 + final Set<PdfFieldFlags> fieldFlags;
  544 +
  545 + int get fieldFlagsValue {
  546 + if (fieldFlags == null || fieldFlags.isEmpty) {
  547 + return 0;
  548 + }
  549 +
  550 + return fieldFlags
  551 + .map<int>((PdfFieldFlags e) => 1 << e.index)
  552 + .reduce((int a, int b) => a | b);
  553 + }
  554 +
  555 + @override
  556 + void build(PdfPage page, PdfObject object, PdfDict params) {
  557 + super.build(page, object, params);
  558 + if (alternateName != null) {
  559 + params['/TU'] = PdfSecString.fromString(object, alternateName);
  560 + }
  561 + if (mappingName != null) {
  562 + params['/TM'] = PdfSecString.fromString(object, mappingName);
  563 + }
  564 +
  565 + params['/Ff'] = PdfNum(fieldFlagsValue);
  566 + }
  567 +}
  568 +
  569 +enum PdfTextFieldAlign { left, center, right }
  570 +
  571 +class PdfTextField extends PdfFormField {
  572 + PdfTextField({
  573 + @required PdfRect rect,
  574 + String fieldName,
  575 + String alternateName,
  576 + String mappingName,
  577 + PdfBorder border,
  578 + Set<PdfAnnotFlags> flags,
  579 + DateTime date,
  580 + PdfColor color,
  581 + PdfColor backgroundColor,
  582 + PdfAnnotHighlighting highlighting,
  583 + Set<PdfFieldFlags> fieldFlags,
  584 + this.value,
  585 + this.defaultValue,
  586 + this.maxLength,
  587 + @required this.font,
  588 + @required this.fontSize,
  589 + @required this.textColor,
  590 + this.textAlign,
  591 + }) : assert(fontSize != null),
  592 + assert(textColor != null),
  593 + assert(font != null),
  594 + super(
  595 + rect: rect,
  596 + fieldType: '/Tx',
  597 + fieldName: fieldName,
  598 + border: border,
  599 + flags: flags,
  600 + date: date,
  601 + color: color,
  602 + backgroundColor: backgroundColor,
  603 + highlighting: highlighting,
  604 + alternateName: alternateName,
  605 + mappingName: mappingName,
  606 + fieldFlags: fieldFlags,
  607 + );
  608 +
  609 + final int maxLength;
  610 +
  611 + final String value;
  612 +
  613 + final String defaultValue;
  614 +
  615 + final PdfFont font;
  616 +
  617 + final double fontSize;
  618 +
  619 + final PdfColor textColor;
  620 +
  621 + final PdfTextFieldAlign textAlign;
  622 +
  623 + @override
  624 + void build(PdfPage page, PdfObject object, PdfDict params) {
  625 + super.build(page, object, params);
  626 + if (maxLength != null) {
  627 + params['/MaxLen'] = PdfNum(maxLength);
  628 + }
  629 +
  630 + final PdfStream buf = PdfStream();
  631 + final PdfGraphics g = PdfGraphics(page, buf);
  632 + g.setFillColor(textColor);
  633 + g.setFont(font, fontSize);
  634 + params['/DA'] = PdfSecString.fromStream(object, buf);
  635 +
  636 + if (value != null) {
  637 + params['/V'] = PdfSecString.fromString(object, value);
  638 + }
  639 + if (defaultValue != null) {
  640 + params['/DV'] = PdfSecString.fromString(object, defaultValue);
  641 + }
  642 + if (textAlign != null) {
  643 + params['/Q'] = PdfNum(textAlign.index);
  644 + }
  645 + }
  646 +}
  647 +
  648 +class PdfButtonField extends PdfFormField {
  649 + PdfButtonField({
  650 + @required PdfRect rect,
  651 + String fieldName,
  652 + String alternateName,
  653 + String mappingName,
  654 + PdfBorder border,
  655 + Set<PdfAnnotFlags> flags,
  656 + DateTime date,
  657 + PdfColor color,
  658 + PdfColor backgroundColor,
  659 + PdfAnnotHighlighting highlighting,
  660 + Set<PdfFieldFlags> fieldFlags,
  661 + this.value,
  662 + this.defaultValue,
  663 + }) : super(
  664 + rect: rect,
  665 + fieldType: '/Btn',
  666 + fieldName: fieldName,
  667 + border: border,
  668 + flags: flags,
  669 + date: date,
  670 + color: color,
  671 + backgroundColor: backgroundColor,
  672 + highlighting: highlighting,
  673 + alternateName: alternateName,
  674 + mappingName: mappingName,
  675 + fieldFlags: fieldFlags,
  676 + );
  677 +
  678 + final bool value;
  679 +
  680 + final bool defaultValue;
  681 +
  682 + @override
  683 + void build(PdfPage page, PdfObject object, PdfDict params) {
  684 + super.build(page, object, params);
  685 +
  686 + if (value != null) {
  687 + params['/V'] = value ? const PdfName('/Yes') : const PdfName('/Off');
  688 + }
  689 + if (defaultValue != null) {
  690 + params['/DV'] =
  691 + defaultValue ? const PdfName('/Yes') : const PdfName('/Off');
  692 + }
  693 + }
  694 +}
@@ -98,6 +98,11 @@ class PdfString extends PdfDataType { @@ -98,6 +98,11 @@ class PdfString extends PdfDataType {
98 return PdfString(_string(value), PdfStringFormat.litteral); 98 return PdfString(_string(value), PdfStringFormat.litteral);
99 } 99 }
100 100
  101 + factory PdfString.fromStream(PdfObject object, PdfStream value,
  102 + [PdfStringFormat format = PdfStringFormat.litteral]) {
  103 + return PdfString(value.output(), format);
  104 + }
  105 +
101 factory PdfString.fromDate(DateTime date) { 106 factory PdfString.fromDate(DateTime date) {
102 return PdfString(_date(date)); 107 return PdfString(_date(date));
103 } 108 }
@@ -203,11 +208,28 @@ class PdfSecString extends PdfString { @@ -203,11 +208,28 @@ class PdfSecString extends PdfString {
203 : super(value, format); 208 : super(value, format);
204 209
205 factory PdfSecString.fromString(PdfObject object, String value) { 210 factory PdfSecString.fromString(PdfObject object, String value) {
206 - return PdfSecString(object, PdfString._string(value)); 211 + return PdfSecString(
  212 + object,
  213 + PdfString._string(value),
  214 + PdfStringFormat.litteral,
  215 + );
  216 + }
  217 +
  218 + factory PdfSecString.fromStream(PdfObject object, PdfStream value,
  219 + [PdfStringFormat format = PdfStringFormat.litteral]) {
  220 + return PdfSecString(
  221 + object,
  222 + value.output(),
  223 + PdfStringFormat.litteral,
  224 + );
207 } 225 }
208 226
209 factory PdfSecString.fromDate(PdfObject object, DateTime date) { 227 factory PdfSecString.fromDate(PdfObject object, DateTime date) {
210 - return PdfSecString(object, PdfString._date(date)); 228 + return PdfSecString(
  229 + object,
  230 + PdfString._date(date),
  231 + PdfStringFormat.litteral,
  232 + );
211 } 233 }
212 234
213 final PdfObject object; 235 final PdfObject object;
@@ -340,3 +362,28 @@ class PdfDict extends PdfDataType { @@ -340,3 +362,28 @@ class PdfDict extends PdfDataType {
340 return values.containsKey(key); 362 return values.containsKey(key);
341 } 363 }
342 } 364 }
  365 +
  366 +class PdfColorType extends PdfDataType {
  367 + const PdfColorType(this.color);
  368 +
  369 + final PdfColor color;
  370 +
  371 + @override
  372 + void output(PdfStream s) {
  373 + if (color is PdfColorCmyk) {
  374 + final PdfColorCmyk k = color;
  375 + PdfArray.fromNum(<double>[
  376 + k.cyan,
  377 + k.magenta,
  378 + k.yellow,
  379 + k.black,
  380 + ]).output(s);
  381 + } else {
  382 + PdfArray.fromNum(<double>[
  383 + color.red,
  384 + color.green,
  385 + color.blue,
  386 + ]).output(s);
  387 + }
  388 + }
  389 +}
  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 +part of pdf;
  20 +
  21 +mixin PdfGraphicStream on PdfObject {
  22 + /// Isolated transparency: If this flag is true, objects within the group
  23 + /// shall be composited against a fully transparent initial backdrop;
  24 + /// if false, they shall be composited against the group’s backdrop
  25 + bool isolatedTransparency = false;
  26 +
  27 + /// Whether the transparency group is a knockout group.
  28 + /// If this flag is false, later objects within the group shall be composited
  29 + /// with earlier ones with which they overlap; if true, they shall be
  30 + /// composited with the group’s initial backdrop and shall overwrite any
  31 + /// earlier overlapping objects.
  32 + bool knockoutTransparency = false;
  33 +
  34 + /// The fonts associated with this page
  35 + final Map<String, PdfFont> fonts = <String, PdfFont>{};
  36 +
  37 + /// The fonts associated with this page
  38 + final Map<String, PdfShading> shading = <String, PdfShading>{};
  39 +
  40 + /// The xobjects or other images in the pdf
  41 + final Map<String, PdfXObject> xObjects = <String, PdfXObject>{};
  42 +
  43 + void addFont(PdfFont font) {
  44 + if (!fonts.containsKey(font.name)) {
  45 + fonts[font.name] = font;
  46 + }
  47 + }
  48 +
  49 + void addShader(PdfShading shader) {
  50 + if (!shading.containsKey(shader.name)) {
  51 + shading[shader.name] = shader;
  52 + }
  53 + }
  54 +
  55 + void addXObject(PdfXObject object) {
  56 + if (!xObjects.containsKey(object.name)) {
  57 + xObjects[object.name] = object;
  58 + }
  59 + }
  60 +
  61 + PdfFont getDefaultFont() {
  62 + if (pdfDocument.fonts.isEmpty) {
  63 + PdfFont.helvetica(pdfDocument);
  64 + }
  65 +
  66 + return pdfDocument.fonts.elementAt(0);
  67 + }
  68 +
  69 + String stateName(PdfGraphicState state) {
  70 + return pdfDocument.graphicStates.stateName(state);
  71 + }
  72 +
  73 + @override
  74 + void _prepare() {
  75 + super._prepare();
  76 +
  77 + // This holds any resources for this page
  78 + final PdfDict resources = PdfDict();
  79 +
  80 + resources['/ProcSet'] = PdfArray(const <PdfName>[
  81 + PdfName('/PDF'),
  82 + PdfName('/Text'),
  83 + PdfName('/ImageB'),
  84 + PdfName('/ImageC'),
  85 + ]);
  86 +
  87 + // fonts
  88 + if (fonts.isNotEmpty) {
  89 + resources['/Font'] = PdfDict.fromObjectMap(fonts);
  90 + }
  91 +
  92 + // shading
  93 + if (shading.isNotEmpty) {
  94 + resources['/Shading'] = PdfDict.fromObjectMap(shading);
  95 + }
  96 +
  97 + // Now the XObjects
  98 + if (xObjects.isNotEmpty) {
  99 + resources['/XObject'] = PdfDict.fromObjectMap(xObjects);
  100 + }
  101 +
  102 + if (pdfDocument.hasGraphicStates) {
  103 + // Declare Transparency Group settings
  104 + params['/Group'] = PdfDict(<String, PdfDataType>{
  105 + '/Type': const PdfName('/Group'),
  106 + '/S': const PdfName('/Transparency'),
  107 + '/CS': const PdfName('/DeviceRGB'),
  108 + '/I': PdfBool(isolatedTransparency),
  109 + '/K': PdfBool(knockoutTransparency),
  110 + });
  111 +
  112 + resources['/ExtGState'] = pdfDocument.graphicStates.ref();
  113 + }
  114 +
  115 + params['/Resources'] = resources;
  116 + }
  117 +}
  118 +
  119 +class PdfGraphicXObject extends PdfXObject with PdfGraphicStream {
  120 + PdfGraphicXObject(
  121 + PdfDocument pdfDocument, [
  122 + String subtype,
  123 + ]) : super(pdfDocument, subtype);
  124 +}
@@ -55,7 +55,7 @@ class _PdfGraphicsContext { @@ -55,7 +55,7 @@ class _PdfGraphicsContext {
55 } 55 }
56 56
57 class PdfGraphics { 57 class PdfGraphics {
58 - PdfGraphics(this.page, this.buf) { 58 + PdfGraphics(this._page, this.buf) {
59 _context = _PdfGraphicsContext(ctm: Matrix4.identity()); 59 _context = _PdfGraphicsContext(ctm: Matrix4.identity());
60 } 60 }
61 61
@@ -66,17 +66,11 @@ class PdfGraphics { @@ -66,17 +66,11 @@ class PdfGraphics {
66 _PdfGraphicsContext _context; 66 _PdfGraphicsContext _context;
67 final Queue<_PdfGraphicsContext> _contextQueue = Queue<_PdfGraphicsContext>(); 67 final Queue<_PdfGraphicsContext> _contextQueue = Queue<_PdfGraphicsContext>();
68 68
69 - final PdfPage page; 69 + final PdfGraphicStream _page;
70 70
71 final PdfStream buf; 71 final PdfStream buf;
72 72
73 - PdfFont get defaultFont {  
74 - if (page.pdfDocument.fonts.isEmpty) {  
75 - PdfFont.helvetica(page.pdfDocument);  
76 - }  
77 -  
78 - return page.pdfDocument.fonts.elementAt(0);  
79 - } 73 + PdfFont get defaultFont => _page.getDefaultFont();
80 74
81 void fillPath() { 75 void fillPath() {
82 buf.putString('f\n'); 76 buf.putString('f\n');
@@ -97,7 +91,7 @@ class PdfGraphics { @@ -97,7 +91,7 @@ class PdfGraphics {
97 /// Apply a shader 91 /// Apply a shader
98 void applyShader(PdfShading shader) { 92 void applyShader(PdfShading shader) {
99 // The shader needs to be registered in the page resources 93 // The shader needs to be registered in the page resources
100 - page.shading[shader.name] = shader; 94 + _page.addShader(shader);
101 buf.putString('${shader.name} sh\n'); 95 buf.putString('${shader.name} sh\n');
102 } 96 }
103 97
@@ -139,7 +133,7 @@ class PdfGraphics { @@ -139,7 +133,7 @@ class PdfGraphics {
139 h ??= img.height.toDouble() * w / img.width.toDouble(); 133 h ??= img.height.toDouble() * w / img.width.toDouble();
140 134
141 // The image needs to be registered in the page resources 135 // The image needs to be registered in the page resources
142 - page.xObjects[img.name] = img; 136 + _page.addXObject(img);
143 137
144 // q w 0 0 h x y cm % the coordinate matrix 138 // q w 0 0 h x y cm % the coordinate matrix
145 buf.putString('q '); 139 buf.putString('q ');
@@ -232,51 +226,68 @@ class PdfGraphics { @@ -232,51 +226,68 @@ class PdfGraphics {
232 lineTo(x, y + rv); 226 lineTo(x, y + rv);
233 } 227 }
234 228
235 - /// This draws a string.  
236 - ///  
237 - /// @param x coordinate  
238 - /// @param y coordinate  
239 - /// @param s String to draw  
240 - void drawString( 229 + /// Set the current font and size
  230 + void setFont(
241 PdfFont font, 231 PdfFont font,
242 - double size,  
243 - String s,  
244 - double x,  
245 - double y, { 232 + double size, {
246 double charSpace = 0, 233 double charSpace = 0,
247 double wordSpace = 0, 234 double wordSpace = 0,
248 double scale = 1, 235 double scale = 1,
249 PdfTextRenderingMode mode = PdfTextRenderingMode.fill, 236 PdfTextRenderingMode mode = PdfTextRenderingMode.fill,
250 double rise = 0, 237 double rise = 0,
251 }) { 238 }) {
252 - if (!page.fonts.containsKey(font.name)) {  
253 - page.fonts[font.name] = font;  
254 - }  
255 -  
256 - buf.putString('BT ');  
257 - PdfNumList(<double>[x, y]).output(buf);  
258 - buf.putString(' Td ${font.name} '); 239 + buf.putString('${font.name} ');
259 PdfNum(size).output(buf); 240 PdfNum(size).output(buf);
260 - buf.putString(' Tf '); 241 + buf.putString(' Tf\n');
261 if (charSpace != 0) { 242 if (charSpace != 0) {
262 PdfNum(charSpace).output(buf); 243 PdfNum(charSpace).output(buf);
263 - buf.putString(' Tc '); 244 + buf.putString(' Tc\n');
264 } 245 }
265 if (wordSpace != 0) { 246 if (wordSpace != 0) {
266 PdfNum(wordSpace).output(buf); 247 PdfNum(wordSpace).output(buf);
267 - buf.putString(' Tw '); 248 + buf.putString(' Tw\n');
268 } 249 }
269 if (scale != 1) { 250 if (scale != 1) {
270 PdfNum(scale * 100).output(buf); 251 PdfNum(scale * 100).output(buf);
271 - buf.putString(' Tz '); 252 + buf.putString(' Tz\n');
272 } 253 }
273 if (rise != 0) { 254 if (rise != 0) {
274 PdfNum(rise).output(buf); 255 PdfNum(rise).output(buf);
275 - buf.putString(' Ts '); 256 + buf.putString(' Ts\n');
276 } 257 }
277 if (mode != PdfTextRenderingMode.fill) { 258 if (mode != PdfTextRenderingMode.fill) {
278 - buf.putString('${mode.index} Tr '); 259 + buf.putString('${mode.index} Tr\n');
  260 + }
279 } 261 }
  262 +
  263 + /// This draws a string.
  264 + ///
  265 + /// @param x coordinate
  266 + /// @param y coordinate
  267 + /// @param s String to draw
  268 + void drawString(
  269 + PdfFont font,
  270 + double size,
  271 + String s,
  272 + double x,
  273 + double y, {
  274 + double charSpace = 0,
  275 + double wordSpace = 0,
  276 + double scale = 1,
  277 + PdfTextRenderingMode mode = PdfTextRenderingMode.fill,
  278 + double rise = 0,
  279 + }) {
  280 + _page.addFont(font);
  281 +
  282 + buf.putString('BT ');
  283 + PdfNumList(<double>[x, y]).output(buf);
  284 + buf.putString(' Td ');
  285 + setFont(font, size,
  286 + charSpace: charSpace,
  287 + mode: mode,
  288 + rise: rise,
  289 + scale: scale,
  290 + wordSpace: wordSpace);
280 buf.putString('['); 291 buf.putString('[');
281 font.putText(buf, s); 292 font.putText(buf, s);
282 buf.putString(']TJ ET\n'); 293 buf.putString(']TJ ET\n');
@@ -320,7 +331,7 @@ class PdfGraphics { @@ -320,7 +331,7 @@ class PdfGraphics {
320 331
321 /// Set the graphic state for drawing 332 /// Set the graphic state for drawing
322 void setGraphicState(PdfGraphicState state) { 333 void setGraphicState(PdfGraphicState state) {
323 - final String name = page.pdfDocument.graphicStates.stateName(state); 334 + final String name = _page.stateName(state);
324 buf.putString('$name gs\n'); 335 buf.putString('$name gs\n');
325 } 336 }
326 337
@@ -199,5 +199,6 @@ class PdfImage extends PdfXObject { @@ -199,5 +199,6 @@ class PdfImage extends PdfXObject {
199 final PdfImageOrientation orientation; 199 final PdfImageOrientation orientation;
200 200
201 /// Name of the image 201 /// Name of the image
  202 + @override
202 String get name => '/I$objser'; 203 String get name => '/I$objser';
203 } 204 }
@@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
18 18
19 part of pdf; 19 part of pdf;
20 20
21 -class PdfPage extends PdfObject { 21 +class PdfPage extends PdfObject with PdfGraphicStream {
22 /// This constructs a Page object, which will hold any contents for this 22 /// This constructs a Page object, which will hold any contents for this
23 /// page. 23 /// page.
24 /// 24 ///
@@ -41,30 +41,9 @@ class PdfPage extends PdfObject { @@ -41,30 +41,9 @@ class PdfPage extends PdfObject {
41 /// -1 indicates no thumbnail. 41 /// -1 indicates no thumbnail.
42 PdfObject thumbnail; 42 PdfObject thumbnail;
43 43
44 - /// Isolated transparency: If this flag is true, objects within the group  
45 - /// shall be composited against a fully transparent initial backdrop;  
46 - /// if false, they shall be composited against the group’s backdrop  
47 - bool isolatedTransparency = false;  
48 -  
49 - /// Whether the transparency group is a knockout group.  
50 - /// If this flag is false, later objects within the group shall be composited  
51 - /// with earlier ones with which they overlap; if true, they shall be  
52 - /// composited with the group’s initial backdrop and shall overwrite any  
53 - /// earlier overlapping objects.  
54 - bool knockoutTransparency = false;  
55 -  
56 /// This holds any Annotations contained within this page. 44 /// This holds any Annotations contained within this page.
57 List<PdfAnnot> annotations = <PdfAnnot>[]; 45 List<PdfAnnot> annotations = <PdfAnnot>[];
58 46
59 - /// The fonts associated with this page  
60 - final Map<String, PdfFont> fonts = <String, PdfFont>{};  
61 -  
62 - /// The fonts associated with this page  
63 - final Map<String, PdfShading> shading = <String, PdfShading>{};  
64 -  
65 - /// The xobjects or other images in the pdf  
66 - final Map<String, PdfXObject> xObjects = <String, PdfXObject>{};  
67 -  
68 /// This returns a [PdfGraphics] object, which can then be used to render 47 /// This returns a [PdfGraphics] object, which can then be used to render
69 /// on to this page. If a previous [PdfGraphics] object was used, this object 48 /// on to this page. If a previous [PdfGraphics] object was used, this object
70 /// is appended to the page, and will be drawn over the top of any previous 49 /// is appended to the page, and will be drawn over the top of any previous
@@ -88,7 +67,6 @@ class PdfPage extends PdfObject { @@ -88,7 +67,6 @@ class PdfPage extends PdfObject {
88 annotations.add(ob); 67 annotations.add(ob);
89 } 68 }
90 69
91 - /// @param os OutputStream to send the object to  
92 @override 70 @override
93 void _prepare() { 71 void _prepare() {
94 super._prepare(); 72 super._prepare();
@@ -116,47 +94,6 @@ class PdfPage extends PdfObject { @@ -116,47 +94,6 @@ class PdfPage extends PdfObject {
116 } 94 }
117 } 95 }
118 96
119 - // Now the resources  
120 - /// This holds any resources for this page  
121 - final PdfDict resources = PdfDict();  
122 -  
123 - resources['/ProcSet'] = PdfArray(const <PdfName>[  
124 - PdfName('/PDF'),  
125 - PdfName('/Text'),  
126 - PdfName('/ImageB'),  
127 - PdfName('/ImageC'),  
128 - ]);  
129 -  
130 - // fonts  
131 - if (fonts.isNotEmpty) {  
132 - resources['/Font'] = PdfDict.fromObjectMap(fonts);  
133 - }  
134 -  
135 - // shading  
136 - if (shading.isNotEmpty) {  
137 - resources['/Shading'] = PdfDict.fromObjectMap(shading);  
138 - }  
139 -  
140 - // Now the XObjects  
141 - if (xObjects.isNotEmpty) {  
142 - resources['/XObject'] = PdfDict.fromObjectMap(xObjects);  
143 - }  
144 -  
145 - if (pdfDocument.hasGraphicStates) {  
146 - // Declare Transparency Group settings  
147 - params['/Group'] = PdfDict(<String, PdfDataType>{  
148 - '/Type': const PdfName('/Group'),  
149 - '/S': const PdfName('/Transparency'),  
150 - '/CS': const PdfName('/DeviceRGB'),  
151 - '/I': PdfBool(isolatedTransparency),  
152 - '/K': PdfBool(knockoutTransparency),  
153 - });  
154 -  
155 - resources['/ExtGState'] = pdfDocument.graphicStates.ref();  
156 - }  
157 -  
158 - params['/Resources'] = resources;  
159 -  
160 // The thumbnail 97 // The thumbnail
161 if (thumbnail != null) { 98 if (thumbnail != null) {
162 params['/Thumb'] = thumbnail.ref(); 99 params['/Thumb'] = thumbnail.ref();
@@ -21,4 +21,6 @@ class PdfXObject extends PdfObjectStream { @@ -21,4 +21,6 @@ class PdfXObject extends PdfObjectStream {
21 : super(pdfDocument, type: '/XObject', isBinary: isBinary) { 21 : super(pdfDocument, type: '/XObject', isBinary: isBinary) {
22 params['/Subtype'] = PdfName(subtype); 22 params['/Subtype'] = PdfName(subtype);
23 } 23 }
  24 +
  25 + String get name => 'X$objser';
24 } 26 }
@@ -45,6 +45,7 @@ part 'widgets/decoration.dart'; @@ -45,6 +45,7 @@ part 'widgets/decoration.dart';
45 part 'widgets/document.dart'; 45 part 'widgets/document.dart';
46 part 'widgets/flex.dart'; 46 part 'widgets/flex.dart';
47 part 'widgets/font.dart'; 47 part 'widgets/font.dart';
  48 +part 'widgets/forms.dart';
48 part 'widgets/geometry.dart'; 49 part 'widgets/geometry.dart';
49 part 'widgets/grid_view.dart'; 50 part 'widgets/grid_view.dart';
50 part 'widgets/image.dart'; 51 part 'widgets/image.dart';
@@ -45,13 +45,6 @@ class Anchor extends SingleChildWidget { @@ -45,13 +45,6 @@ class Anchor extends SingleChildWidget {
45 } 45 }
46 46
47 abstract class AnnotationBuilder { 47 abstract class AnnotationBuilder {
48 - PdfRect localToGlobal(Context context, PdfRect box) {  
49 - final Matrix4 mat = context.canvas.getTransform();  
50 - final Vector3 lt = mat.transform3(Vector3(box.left, box.bottom, 0));  
51 - final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0));  
52 - return PdfRect.fromLTRB(lt.x, lt.y, rb.x, rb.y);  
53 - }  
54 -  
55 void build(Context context, PdfRect box); 48 void build(Context context, PdfRect box);
56 } 49 }
57 50
@@ -65,7 +58,7 @@ class AnnotationLink extends AnnotationBuilder { @@ -65,7 +58,7 @@ class AnnotationLink extends AnnotationBuilder {
65 PdfAnnot( 58 PdfAnnot(
66 context.page, 59 context.page,
67 PdfAnnotNamedLink( 60 PdfAnnotNamedLink(
68 - rect: localToGlobal(context, box), 61 + rect: context.localToGlobal(box),
69 dest: destination, 62 dest: destination,
70 ), 63 ),
71 ); 64 );
@@ -82,7 +75,7 @@ class AnnotationUrl extends AnnotationBuilder { @@ -82,7 +75,7 @@ class AnnotationUrl extends AnnotationBuilder {
82 PdfAnnot( 75 PdfAnnot(
83 context.page, 76 context.page,
84 PdfAnnotUrlLink( 77 PdfAnnotUrlLink(
85 - rect: localToGlobal(context, box), 78 + rect: context.localToGlobal(box),
86 url: destination, 79 url: destination,
87 ), 80 ),
88 ); 81 );
@@ -128,13 +121,89 @@ class AnnotationSignature extends AnnotationBuilder { @@ -128,13 +121,89 @@ class AnnotationSignature extends AnnotationBuilder {
128 PdfAnnot( 121 PdfAnnot(
129 context.page, 122 context.page,
130 PdfAnnotSign( 123 PdfAnnotSign(
131 - localToGlobal(context, box), 124 + rect: context.localToGlobal(box),
  125 + fieldName: name,
  126 + border: border,
  127 + flags: flags,
  128 + date: date,
  129 + color: color,
  130 + highlighting: highlighting,
  131 + ),
  132 + );
  133 + }
  134 +}
  135 +
  136 +class AnnotationTextField extends AnnotationBuilder {
  137 + AnnotationTextField({
  138 + this.name,
  139 + this.border,
  140 + this.flags,
  141 + this.date,
  142 + this.color,
  143 + this.backgroundColor,
  144 + this.highlighting,
  145 + this.maxLength,
  146 + this.alternateName,
  147 + this.mappingName,
  148 + this.fieldFlags,
  149 + this.value,
  150 + this.defaultValue,
  151 + this.textStyle,
  152 + });
  153 +
  154 + final String name;
  155 +
  156 + final PdfBorder border;
  157 +
  158 + final Set<PdfAnnotFlags> flags;
  159 +
  160 + final DateTime date;
  161 +
  162 + final PdfColor color;
  163 +
  164 + final PdfColor backgroundColor;
  165 +
  166 + final PdfAnnotHighlighting highlighting;
  167 +
  168 + final int maxLength;
  169 +
  170 + final String value;
  171 +
  172 + final String defaultValue;
  173 +
  174 + final TextStyle textStyle;
  175 +
  176 + final String alternateName;
  177 +
  178 + final String mappingName;
  179 +
  180 + final Set<PdfFieldFlags> fieldFlags;
  181 +
  182 + @override
  183 + void build(Context context, PdfRect box) {
  184 + final TextStyle _textStyle =
  185 + Theme.of(context).defaultTextStyle.merge(textStyle);
  186 +
  187 + PdfAnnot(
  188 + context.page,
  189 + PdfTextField(
  190 + rect: context.localToGlobal(box),
132 fieldName: name, 191 fieldName: name,
133 border: border, 192 border: border,
134 flags: flags, 193 flags: flags,
135 date: date, 194 date: date,
136 color: color, 195 color: color,
  196 + backgroundColor: backgroundColor,
137 highlighting: highlighting, 197 highlighting: highlighting,
  198 + maxLength: maxLength,
  199 + alternateName: alternateName,
  200 + mappingName: mappingName,
  201 + fieldFlags: fieldFlags,
  202 + value: value,
  203 + defaultValue: defaultValue,
  204 + font: _textStyle.font.getFont(context),
  205 + fontSize: _textStyle.fontSize,
  206 + textColor: _textStyle.color,
138 ), 207 ),
139 ); 208 );
140 } 209 }
@@ -199,3 +268,42 @@ class Signature extends Annotation { @@ -199,3 +268,42 @@ class Signature extends Annotation {
199 highlighting: highlighting, 268 highlighting: highlighting,
200 )); 269 ));
201 } 270 }
  271 +
  272 +class TextField extends Annotation {
  273 + TextField({
  274 + Widget child,
  275 + double width = 120,
  276 + double height = 13,
  277 + String name,
  278 + PdfBorder border,
  279 + Set<PdfAnnotFlags> flags,
  280 + DateTime date,
  281 + PdfColor color,
  282 + PdfColor backgroundColor,
  283 + PdfAnnotHighlighting highlighting,
  284 + int maxLength,
  285 + String alternateName,
  286 + String mappingName,
  287 + Set<PdfFieldFlags> fieldFlags,
  288 + String value,
  289 + String defaultValue,
  290 + TextStyle textStyle,
  291 + }) : super(
  292 + child: child ?? SizedBox(width: width, height: height),
  293 + builder: AnnotationTextField(
  294 + name: name,
  295 + border: border,
  296 + flags: flags,
  297 + date: date,
  298 + color: color,
  299 + backgroundColor: backgroundColor,
  300 + highlighting: highlighting,
  301 + maxLength: maxLength,
  302 + alternateName: alternateName,
  303 + mappingName: mappingName,
  304 + fieldFlags: fieldFlags,
  305 + value: value,
  306 + defaultValue: defaultValue,
  307 + textStyle: textStyle,
  308 + ));
  309 +}
  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 +part of widget;
  20 +
  21 +class Checkbox extends SingleChildWidget {
  22 + Checkbox({
  23 + @required this.value,
  24 + this.defaultValue,
  25 + this.tristate = false,
  26 + this.activeColor = PdfColors.blue,
  27 + this.checkColor = PdfColors.white,
  28 + @required this.name,
  29 + double width = 13,
  30 + double height = 13,
  31 + BoxDecoration decoration,
  32 + }) : super(
  33 + child: Container(
  34 + width: width,
  35 + height: height,
  36 + margin: const EdgeInsets.all(1),
  37 + decoration: decoration ??
  38 + const BoxDecoration(
  39 + border: BoxBorder(
  40 + left: true,
  41 + top: true,
  42 + bottom: true,
  43 + right: true,
  44 + color: PdfColors.grey600,
  45 + width: 2,
  46 + ))));
  47 +
  48 + final bool value;
  49 +
  50 + final bool defaultValue;
  51 +
  52 + final bool tristate;
  53 +
  54 + final PdfColor activeColor;
  55 +
  56 + final PdfColor checkColor;
  57 +
  58 + final String name;
  59 +
  60 + @override
  61 + void paint(Context context) {
  62 + super.paint(context);
  63 + paintChild(context);
  64 +
  65 + final PdfButtonField bf = PdfButtonField(
  66 + rect: context.localToGlobal(box),
  67 + fieldName: name,
  68 + value: value,
  69 + defaultValue: value,
  70 + flags: <PdfAnnotFlags>{PdfAnnotFlags.print},
  71 + );
  72 +
  73 + final PdfGraphics g =
  74 + bf.appearance(context.document, PdfAnnotApparence.normal, name: '/Yes');
  75 + g.drawRect(0, 0, bf.rect.width, bf.rect.height);
  76 + g.setFillColor(activeColor);
  77 + g.fillPath();
  78 + g.moveTo(2, bf.rect.height / 2);
  79 + g.lineTo(bf.rect.width / 3, bf.rect.height / 4);
  80 + g.lineTo(bf.rect.width - 2, bf.rect.height / 4 * 3);
  81 + g.setStrokeColor(checkColor);
  82 + g.setLineWidth(2);
  83 + g.strokePath();
  84 +
  85 + bf.appearance(context.document, PdfAnnotApparence.normal, name: '/Off');
  86 +
  87 + PdfAnnot(context.page, bf);
  88 + }
  89 +}
  90 +
  91 +class FlatButton extends SingleChildWidget {
  92 + FlatButton({
  93 + PdfColor textColor = PdfColors.white,
  94 + PdfColor color = PdfColors.blue,
  95 + PdfColor colorDown = PdfColors.red,
  96 + PdfColor colorRollover = PdfColors.blueAccent,
  97 + EdgeInsets padding,
  98 + BoxDecoration decoration,
  99 + Widget child,
  100 + @required this.name,
  101 + }) : _childDown = Container(
  102 + child: DefaultTextStyle(
  103 + style: TextStyle(color: textColor),
  104 + child: child,
  105 + ),
  106 + decoration: decoration ??
  107 + BoxDecoration(
  108 + color: colorDown,
  109 + borderRadiusEx: const BorderRadius.all(Radius.circular(2)),
  110 + ),
  111 + padding: padding ??
  112 + const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
  113 + ),
  114 + _childRollover = Container(
  115 + child: DefaultTextStyle(
  116 + style: TextStyle(color: textColor),
  117 + child: child,
  118 + ),
  119 + decoration: decoration ??
  120 + BoxDecoration(
  121 + color: colorRollover,
  122 + borderRadiusEx: const BorderRadius.all(Radius.circular(2)),
  123 + ),
  124 + padding: padding ??
  125 + const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
  126 + ),
  127 + super(
  128 + child: Container(
  129 + child: DefaultTextStyle(
  130 + style: TextStyle(color: textColor),
  131 + child: child,
  132 + ),
  133 + decoration: decoration ??
  134 + BoxDecoration(
  135 + color: color,
  136 + borderRadiusEx: const BorderRadius.all(Radius.circular(2)),
  137 + ),
  138 + padding: padding ??
  139 + const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
  140 + ),
  141 + );
  142 +
  143 + // final PdfColor textColor;
  144 +
  145 + // final PdfColor color;
  146 +
  147 + // final EdgeInsets padding;
  148 +
  149 + final String name;
  150 +
  151 + final Widget _childDown;
  152 +
  153 + final Widget _childRollover;
  154 +
  155 + @override
  156 + void paint(Context context) {
  157 + super.paint(context);
  158 +
  159 + final PdfButtonField bf = PdfButtonField(
  160 + rect: context.localToGlobal(box),
  161 + fieldName: name,
  162 + flags: <PdfAnnotFlags>{PdfAnnotFlags.print},
  163 + fieldFlags: <PdfFieldFlags>{PdfFieldFlags.pushButton},
  164 + );
  165 +
  166 + final Matrix4 mat = context.canvas.getTransform();
  167 + final Vector3 translation = Vector3(0, 0, 0);
  168 + final Quaternion rotation = Quaternion(0, 0, 0, 0);
  169 + final Vector3 scale = Vector3(0, 0, 0);
  170 + mat
  171 + ..decompose(translation, rotation, scale)
  172 + ..leftTranslate(-translation.x, -translation.y)
  173 + ..translate(box.x, box.y);
  174 +
  175 + final Context cn = context.copyWith(
  176 + canvas: bf.appearance(context.document, PdfAnnotApparence.normal,
  177 + matrix: mat, boundingBox: box));
  178 + child.layout(
  179 + cn, BoxConstraints.tightFor(width: box.width, height: box.height));
  180 + child.paint(cn);
  181 +
  182 + final Context cd = context.copyWith(
  183 + canvas: bf.appearance(context.document, PdfAnnotApparence.down,
  184 + matrix: mat, boundingBox: box));
  185 + _childDown.layout(
  186 + cd, BoxConstraints.tightFor(width: box.width, height: box.height));
  187 + _childDown.paint(cd);
  188 +
  189 + final Context cr = context.copyWith(
  190 + canvas: bf.appearance(context.document, PdfAnnotApparence.rollover,
  191 + matrix: mat, boundingBox: box));
  192 + _childRollover.layout(
  193 + cr, BoxConstraints.tightFor(width: box.width, height: box.height));
  194 + _childRollover.paint(cr);
  195 +
  196 + PdfAnnot(context.page, bf);
  197 + }
  198 +}
@@ -79,6 +79,22 @@ class Context { @@ -79,6 +79,22 @@ class Context {
79 } 79 }
80 return copyWith(inherited: inherited); 80 return copyWith(inherited: inherited);
81 } 81 }
  82 +
  83 + PdfRect localToGlobal(PdfRect box) {
  84 + final Matrix4 mat = canvas.getTransform();
  85 + final Vector3 lt = mat.transform3(Vector3(box.left, box.bottom, 0));
  86 + final Vector3 lb = mat.transform3(Vector3(box.left, box.top, 0));
  87 + final Vector3 rt = mat.transform3(Vector3(box.right, box.bottom, 0));
  88 + final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0));
  89 + final List<double> x = <double>[lt.x, lb.x, rt.x, rb.x];
  90 + final List<double> y = <double>[lt.y, lb.y, rt.y, rb.y];
  91 + return PdfRect.fromLTRB(
  92 + x.reduce(math.min),
  93 + y.reduce(math.min),
  94 + x.reduce(math.max),
  95 + y.reduce(math.max),
  96 + );
  97 + }
82 } 98 }
83 99
84 class Inherited { 100 class Inherited {
@@ -36,6 +36,7 @@ import 'widget_chart_test.dart' as widget_chart; @@ -36,6 +36,7 @@ import 'widget_chart_test.dart' as widget_chart;
36 import 'widget_clip_test.dart' as widget_clip; 36 import 'widget_clip_test.dart' as widget_clip;
37 import 'widget_container_test.dart' as widget_container; 37 import 'widget_container_test.dart' as widget_container;
38 import 'widget_flex_test.dart' as widget_flex; 38 import 'widget_flex_test.dart' as widget_flex;
  39 +import 'widget_form_test.dart' as widget_form;
39 import 'widget_grid_view_test.dart' as widget_grid_view; 40 import 'widget_grid_view_test.dart' as widget_grid_view;
40 import 'widget_multipage_test.dart' as widget_multipage; 41 import 'widget_multipage_test.dart' as widget_multipage;
41 import 'widget_opacity_test.dart' as widget_opacity; 42 import 'widget_opacity_test.dart' as widget_opacity;
@@ -68,6 +69,7 @@ void main() { @@ -68,6 +69,7 @@ void main() {
68 widget_clip.main(); 69 widget_clip.main();
69 widget_container.main(); 70 widget_container.main();
70 widget_flex.main(); 71 widget_flex.main();
  72 + widget_form.main();
71 widget_grid_view.main(); 73 widget_grid_view.main();
72 widget_multipage.main(); 74 widget_multipage.main();
73 widget_opacity.main(); 75 widget_opacity.main();
@@ -35,17 +35,17 @@ void main() { @@ -35,17 +35,17 @@ void main() {
35 35
36 PdfAnnot( 36 PdfAnnot(
37 page, 37 page,
38 - const PdfAnnotText(  
39 - rect: PdfRect(100, 100, 50, 50), 38 + PdfAnnotText(
  39 + rect: const PdfRect(100, 100, 50, 50),
40 content: 'Hello', 40 content: 'Hello',
41 ), 41 ),
42 ); 42 );
43 43
44 PdfAnnot( 44 PdfAnnot(
45 page, 45 page,
46 - const PdfAnnotNamedLink( 46 + PdfAnnotNamedLink(
47 dest: 'target', 47 dest: 'target',
48 - rect: PdfRect(100, 150, 50, 50), 48 + rect: const PdfRect(100, 150, 50, 50),
49 ), 49 ),
50 ); 50 );
51 g.drawRect(100, 150, 50, 50); 51 g.drawRect(100, 150, 50, 50);
@@ -53,14 +53,27 @@ void main() { @@ -53,14 +53,27 @@ void main() {
53 53
54 PdfAnnot( 54 PdfAnnot(
55 page, 55 page,
56 - const PdfAnnotUrlLink(  
57 - rect: PdfRect(100, 250, 50, 50), 56 + PdfAnnotUrlLink(
  57 + rect: const PdfRect(100, 250, 50, 50),
58 url: 'https://github.com/DavBfr/dart_pdf/', 58 url: 'https://github.com/DavBfr/dart_pdf/',
59 ), 59 ),
60 ); 60 );
61 g.drawRect(100, 250, 50, 50); 61 g.drawRect(100, 250, 50, 50);
62 g.strokePath(); 62 g.strokePath();
63 63
  64 + PdfAnnot(
  65 + page,
  66 + PdfTextField(
  67 + rect: const PdfRect(100, 50, 50, 20),
  68 + fieldName: 'test',
  69 + font: PdfFont.helvetica(pdf),
  70 + fontSize: 10,
  71 + textColor: PdfColors.blue,
  72 + ),
  73 + );
  74 + // g.drawRect(100, 50, 50, 20);
  75 + g.strokePath();
  76 +
64 final File file = File('annotations.pdf'); 77 final File file = File('annotations.pdf');
65 file.writeAsBytesSync(pdf.save()); 78 file.writeAsBytesSync(pdf.save());
66 }); 79 });
@@ -22,7 +22,8 @@ import 'dart:typed_data'; @@ -22,7 +22,8 @@ import 'dart:typed_data';
22 import 'package:pdf/pdf.dart'; 22 import 'package:pdf/pdf.dart';
23 import 'package:test/test.dart'; 23 import 'package:test/test.dart';
24 24
25 -void printText(PdfGraphics canvas, String text, PdfFont font, double top) { 25 +void printText(
  26 + PdfPage page, PdfGraphics canvas, String text, PdfFont font, double top) {
26 text = text + font.fontName; 27 text = text + font.fontName;
27 const double fontSize = 20; 28 const double fontSize = 20;
28 final PdfFontMetrics metrics = font.stringMetrics(text) * fontSize; 29 final PdfFontMetrics metrics = font.stringMetrics(text) * fontSize;
@@ -30,7 +31,7 @@ void printText(PdfGraphics canvas, String text, PdfFont font, double top) { @@ -30,7 +31,7 @@ void printText(PdfGraphics canvas, String text, PdfFont font, double top) {
30 const double deb = 5; 31 const double deb = 5;
31 32
32 const double x = 50; 33 const double x = 50;
33 - final double y = canvas.page.pageFormat.height - top; 34 + final double y = page.pageFormat.height - top;
34 35
35 canvas 36 canvas
36 ..drawRect(x + metrics.left, y + metrics.top, metrics.width, metrics.height) 37 ..drawRect(x + metrics.left, y + metrics.top, metrics.width, metrics.height)
@@ -51,12 +52,13 @@ void printText(PdfGraphics canvas, String text, PdfFont font, double top) { @@ -51,12 +52,13 @@ void printText(PdfGraphics canvas, String text, PdfFont font, double top) {
51 ..drawString(font, fontSize, text, x, y); 52 ..drawString(font, fontSize, text, x, y);
52 } 53 }
53 54
54 -void printTextTtf(PdfGraphics canvas, String text, File ttfFont, double top) { 55 +void printTextTtf(
  56 + PdfPage page, PdfGraphics canvas, String text, File ttfFont, double top) {
55 final Uint8List fontData = ttfFont.readAsBytesSync(); 57 final Uint8List fontData = ttfFont.readAsBytesSync();
56 final PdfTtfFont font = 58 final PdfTtfFont font =
57 - PdfTtfFont(canvas.page.pdfDocument, fontData.buffer.asByteData()); 59 + PdfTtfFont(page.pdfDocument, fontData.buffer.asByteData());
58 60
59 - printText(canvas, text, font, top); 61 + printText(page, canvas, text, font, top);
60 } 62 }
61 63
62 void main() { 64 void main() {
@@ -69,11 +71,12 @@ void main() { @@ -69,11 +71,12 @@ void main() {
69 int top = 0; 71 int top = 0;
70 const String s = 'Hello Lukáča '; 72 const String s = 'Hello Lukáča ';
71 73
72 - printTextTtf(g, s, File('open-sans.ttf'), 30.0 + 30.0 * top++);  
73 - printTextTtf(g, s, File('open-sans-bold.ttf'), 30.0 + 30.0 * top++);  
74 - printTextTtf(g, s, File('roboto.ttf'), 30.0 + 30.0 * top++);  
75 - printTextTtf(g, s, File('noto-sans.ttf'), 30.0 + 30.0 * top++);  
76 - printTextTtf(g, '你好 檯號 ', File('genyomintw.ttf'), 30.0 + 30.0 * top++); 74 + printTextTtf(page, g, s, File('open-sans.ttf'), 30.0 + 30.0 * top++);
  75 + printTextTtf(page, g, s, File('open-sans-bold.ttf'), 30.0 + 30.0 * top++);
  76 + printTextTtf(page, g, s, File('roboto.ttf'), 30.0 + 30.0 * top++);
  77 + printTextTtf(page, g, s, File('noto-sans.ttf'), 30.0 + 30.0 * top++);
  78 + printTextTtf(
  79 + page, g, '你好 檯號 ', File('genyomintw.ttf'), 30.0 + 30.0 * top++);
77 80
78 final File file = File('ttf.pdf'); 81 final File file = File('ttf.pdf');
79 file.writeAsBytesSync(pdf.save()); 82 file.writeAsBytesSync(pdf.save());
@@ -21,7 +21,8 @@ import 'dart:io'; @@ -21,7 +21,8 @@ import 'dart:io';
21 import 'package:pdf/pdf.dart'; 21 import 'package:pdf/pdf.dart';
22 import 'package:test/test.dart'; 22 import 'package:test/test.dart';
23 23
24 -void printText(PdfGraphics canvas, String text, PdfFont font, double top) { 24 +void printText(
  25 + PdfPage page, PdfGraphics canvas, String text, PdfFont font, double top) {
25 text = text + font.fontName; 26 text = text + font.fontName;
26 const double fontSize = 20; 27 const double fontSize = 20;
27 final PdfFontMetrics metrics = font.stringMetrics(text) * fontSize; 28 final PdfFontMetrics metrics = font.stringMetrics(text) * fontSize;
@@ -29,7 +30,7 @@ void printText(PdfGraphics canvas, String text, PdfFont font, double top) { @@ -29,7 +30,7 @@ void printText(PdfGraphics canvas, String text, PdfFont font, double top) {
29 const double deb = 5; 30 const double deb = 5;
30 31
31 const double x = 50; 32 const double x = 50;
32 - final double y = canvas.page.pageFormat.height - top; 33 + final double y = page.pageFormat.height - top;
33 34
34 canvas 35 canvas
35 ..drawRect(x + metrics.left, y + metrics.top, metrics.width, metrics.height) 36 ..drawRect(x + metrics.left, y + metrics.top, metrics.width, metrics.height)
@@ -60,23 +61,24 @@ void main() { @@ -60,23 +61,24 @@ void main() {
60 int top = 0; 61 int top = 0;
61 const String s = 'Hello '; 62 const String s = 'Hello ';
62 63
63 - printText(g, s, PdfFont.courier(pdf), 20.0 + 30.0 * top++);  
64 - printText(g, s, PdfFont.courierBold(pdf), 20.0 + 30.0 * top++);  
65 - printText(g, s, PdfFont.courierOblique(pdf), 20.0 + 30.0 * top++);  
66 - printText(g, s, PdfFont.courierBoldOblique(pdf), 20.0 + 30.0 * top++); 64 + printText(page, g, s, PdfFont.courier(pdf), 20.0 + 30.0 * top++);
  65 + printText(page, g, s, PdfFont.courierBold(pdf), 20.0 + 30.0 * top++);
  66 + printText(page, g, s, PdfFont.courierOblique(pdf), 20.0 + 30.0 * top++);
  67 + printText(page, g, s, PdfFont.courierBoldOblique(pdf), 20.0 + 30.0 * top++);
67 68
68 - printText(g, s, PdfFont.helvetica(pdf), 20.0 + 30.0 * top++);  
69 - printText(g, s, PdfFont.helveticaBold(pdf), 20.0 + 30.0 * top++);  
70 - printText(g, s, PdfFont.helveticaOblique(pdf), 20.0 + 30.0 * top++);  
71 - printText(g, s, PdfFont.helveticaBoldOblique(pdf), 20.0 + 30.0 * top++); 69 + printText(page, g, s, PdfFont.helvetica(pdf), 20.0 + 30.0 * top++);
  70 + printText(page, g, s, PdfFont.helveticaBold(pdf), 20.0 + 30.0 * top++);
  71 + printText(page, g, s, PdfFont.helveticaOblique(pdf), 20.0 + 30.0 * top++);
  72 + printText(
  73 + page, g, s, PdfFont.helveticaBoldOblique(pdf), 20.0 + 30.0 * top++);
72 74
73 - printText(g, s, PdfFont.times(pdf), 20.0 + 30.0 * top++);  
74 - printText(g, s, PdfFont.timesBold(pdf), 20.0 + 30.0 * top++);  
75 - printText(g, s, PdfFont.timesItalic(pdf), 20.0 + 30.0 * top++);  
76 - printText(g, s, PdfFont.timesBoldItalic(pdf), 20.0 + 30.0 * top++); 75 + printText(page, g, s, PdfFont.times(pdf), 20.0 + 30.0 * top++);
  76 + printText(page, g, s, PdfFont.timesBold(pdf), 20.0 + 30.0 * top++);
  77 + printText(page, g, s, PdfFont.timesItalic(pdf), 20.0 + 30.0 * top++);
  78 + printText(page, g, s, PdfFont.timesBoldItalic(pdf), 20.0 + 30.0 * top++);
77 79
78 - printText(g, s, PdfFont.symbol(pdf), 20.0 + 30.0 * top++);  
79 - printText(g, s, PdfFont.zapfDingbats(pdf), 20.0 + 30.0 * top++); 80 + printText(page, g, s, PdfFont.symbol(pdf), 20.0 + 30.0 * top++);
  81 + printText(page, g, s, PdfFont.zapfDingbats(pdf), 20.0 + 30.0 * top++);
80 82
81 final File file = File('type1.pdf'); 83 final File file = File('type1.pdf');
82 file.writeAsBytesSync(pdf.save()); 84 file.writeAsBytesSync(pdf.save());
  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 +
  21 +import 'package:test/test.dart';
  22 +import 'package:pdf/pdf.dart';
  23 +import 'package:pdf/widgets.dart';
  24 +
  25 +Document pdf;
  26 +
  27 +class Label extends StatelessWidget {
  28 + Label({this.label, this.width});
  29 +
  30 + final String label;
  31 +
  32 + final double width;
  33 +
  34 + @override
  35 + Widget build(Context context) {
  36 + return Container(
  37 + child: Text(label),
  38 + width: width,
  39 + alignment: Alignment.centerRight,
  40 + margin: const EdgeInsets.only(right: 5),
  41 + );
  42 + }
  43 +}
  44 +
  45 +class Decorated extends StatelessWidget {
  46 + Decorated({this.child, this.color});
  47 +
  48 + final Widget child;
  49 +
  50 + final PdfColor color;
  51 +
  52 + @override
  53 + Widget build(Context context) {
  54 + return Container(
  55 + child: child,
  56 + padding: const EdgeInsets.all(2),
  57 + decoration: BoxDecoration(
  58 + color: color ?? PdfColors.yellow100,
  59 + border: const BoxBorder(
  60 + left: true,
  61 + top: true,
  62 + right: true,
  63 + bottom: true,
  64 + color: PdfColors.grey,
  65 + width: .5,
  66 + ),
  67 + ),
  68 + );
  69 + }
  70 +}
  71 +
  72 +void main() {
  73 + setUpAll(() {
  74 + // Document.debug = true;
  75 + pdf = Document();
  76 + });
  77 +
  78 + test(
  79 + 'Form',
  80 + () {
  81 + pdf.addPage(
  82 + Page(
  83 + build: (Context context) => Wrap(
  84 + crossAxisAlignment: WrapCrossAlignment.center,
  85 + children: <Widget>[
  86 + Label(label: 'Given Name:', width: 100),
  87 + Decorated(
  88 + child: TextField(
  89 + name: 'Given Name',
  90 + textStyle: const TextStyle(color: PdfColors.amber),
  91 + )),
  92 + //
  93 + SizedBox(width: double.infinity, height: 10),
  94 + //
  95 + Label(label: 'Family Name:', width: 100),
  96 + Decorated(child: TextField(name: 'Family Name')),
  97 + //
  98 + SizedBox(width: double.infinity, height: 10),
  99 + //
  100 + Label(label: 'Address:', width: 100),
  101 + Decorated(child: TextField(name: 'Address')),
  102 + //
  103 + SizedBox(width: double.infinity, height: 10),
  104 + //
  105 + Label(label: 'Postcode:', width: 100),
  106 + Decorated(
  107 + child: TextField(name: 'Postcode', width: 60, maxLength: 6)),
  108 + //
  109 + Label(label: 'City:', width: 30),
  110 + Decorated(child: TextField(name: 'City')),
  111 + //
  112 + SizedBox(width: double.infinity, height: 10),
  113 + //
  114 + Label(label: 'Country:', width: 100),
  115 + Decorated(
  116 + child: TextField(
  117 + name: 'Country',
  118 + color: PdfColors.blue,
  119 + )),
  120 + //
  121 + SizedBox(width: double.infinity, height: 10),
  122 + //
  123 + Label(label: 'Checkbox:', width: 100),
  124 + Checkbox(
  125 + name: 'Checkbox',
  126 + value: true,
  127 + defaultValue: true,
  128 + ),
  129 + //
  130 + SizedBox(width: double.infinity, height: 10),
  131 + //
  132 + Transform.rotateBox(
  133 + angle: .7,
  134 + child: FlatButton(
  135 + name: 'submit',
  136 + child: Text('Submit'),
  137 + ),
  138 + )
  139 + ],
  140 + ),
  141 + ),
  142 + );
  143 + },
  144 + );
  145 +
  146 + tearDownAll(() {
  147 + final File file = File('widgets-form.pdf');
  148 + file.writeAsBytesSync(pdf.save());
  149 + });
  150 +}
No preview for this file type