Showing
20 changed files
with
1185 additions
and
167 deletions
| @@ -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 | +} |
pdf/lib/src/graphic_stream.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 | +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'); |
| 279 | } | 260 | } |
| 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,7 +121,7 @@ class AnnotationSignature extends AnnotationBuilder { | @@ -128,7 +121,7 @@ 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), |
| 132 | fieldName: name, | 125 | fieldName: name, |
| 133 | border: border, | 126 | border: border, |
| 134 | flags: flags, | 127 | flags: flags, |
| @@ -140,6 +133,82 @@ class AnnotationSignature extends AnnotationBuilder { | @@ -140,6 +133,82 @@ class AnnotationSignature extends AnnotationBuilder { | ||
| 140 | } | 133 | } |
| 141 | } | 134 | } |
| 142 | 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), | ||
| 191 | + fieldName: name, | ||
| 192 | + border: border, | ||
| 193 | + flags: flags, | ||
| 194 | + date: date, | ||
| 195 | + color: color, | ||
| 196 | + backgroundColor: backgroundColor, | ||
| 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, | ||
| 207 | + ), | ||
| 208 | + ); | ||
| 209 | + } | ||
| 210 | +} | ||
| 211 | + | ||
| 143 | class Annotation extends SingleChildWidget { | 212 | class Annotation extends SingleChildWidget { |
| 144 | Annotation({Widget child, this.builder}) : super(child: child); | 213 | Annotation({Widget child, this.builder}) : super(child: child); |
| 145 | 214 | ||
| @@ -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 | +} |
pdf/lib/widgets/forms.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 | +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()); |
pdf/test/widget_form_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 | + | ||
| 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 | +} |
test/golden/widgets-form.pdf
0 → 100644
No preview for this file type
-
Please register or login to post a comment