Showing
10 changed files
with
914 additions
and
50 deletions
| @@ -99,6 +99,8 @@ abstract class PdfAnnotBase { | @@ -99,6 +99,8 @@ abstract class PdfAnnotBase { | ||
| 99 | this.flags, | 99 | this.flags, |
| 100 | this.date, | 100 | this.date, |
| 101 | this.color, | 101 | this.color, |
| 102 | + this.subject, | ||
| 103 | + this.author, | ||
| 102 | }); | 104 | }); |
| 103 | 105 | ||
| 104 | /// The subtype of the outline, ie text, note, etc | 106 | /// The subtype of the outline, ie text, note, etc |
| @@ -115,6 +117,12 @@ abstract class PdfAnnotBase { | @@ -115,6 +117,12 @@ abstract class PdfAnnotBase { | ||
| 115 | /// The internal name for a link | 117 | /// The internal name for a link |
| 116 | final String? name; | 118 | final String? name; |
| 117 | 119 | ||
| 120 | + /// The author of the annotation | ||
| 121 | + final String? author; | ||
| 122 | + | ||
| 123 | + /// The subject of the annotation | ||
| 124 | + final String? subject; | ||
| 125 | + | ||
| 118 | /// Flags specifying various characteristics of the annotation | 126 | /// Flags specifying various characteristics of the annotation |
| 119 | final Set<PdfAnnotFlags>? flags; | 127 | final Set<PdfAnnotFlags>? flags; |
| 120 | 128 | ||
| @@ -223,6 +231,14 @@ abstract class PdfAnnotBase { | @@ -223,6 +231,14 @@ abstract class PdfAnnotBase { | ||
| 223 | params['/C'] = PdfColorType(color!); | 231 | params['/C'] = PdfColorType(color!); |
| 224 | } | 232 | } |
| 225 | 233 | ||
| 234 | + if (subject != null) { | ||
| 235 | + params['/Subj'] = PdfSecString.fromString(object, subject!); | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + if (author != null) { | ||
| 239 | + params['/T'] = PdfSecString.fromString(object, author!); | ||
| 240 | + } | ||
| 241 | + | ||
| 226 | if (_appearances.isNotEmpty) { | 242 | if (_appearances.isNotEmpty) { |
| 227 | params['/AP'] = PdfDict(_appearances); | 243 | params['/AP'] = PdfDict(_appearances); |
| 228 | if (_as != null) { | 244 | if (_as != null) { |
| @@ -242,6 +258,8 @@ class PdfAnnotText extends PdfAnnotBase { | @@ -242,6 +258,8 @@ class PdfAnnotText extends PdfAnnotBase { | ||
| 242 | Set<PdfAnnotFlags>? flags, | 258 | Set<PdfAnnotFlags>? flags, |
| 243 | DateTime? date, | 259 | DateTime? date, |
| 244 | PdfColor? color, | 260 | PdfColor? color, |
| 261 | + String? subject, | ||
| 262 | + String? author, | ||
| 245 | }) : super( | 263 | }) : super( |
| 246 | subtype: '/Text', | 264 | subtype: '/Text', |
| 247 | rect: rect, | 265 | rect: rect, |
| @@ -251,6 +269,8 @@ class PdfAnnotText extends PdfAnnotBase { | @@ -251,6 +269,8 @@ class PdfAnnotText extends PdfAnnotBase { | ||
| 251 | flags: flags, | 269 | flags: flags, |
| 252 | date: date, | 270 | date: date, |
| 253 | color: color, | 271 | color: color, |
| 272 | + subject: subject, | ||
| 273 | + author: author, | ||
| 254 | ); | 274 | ); |
| 255 | } | 275 | } |
| 256 | 276 | ||
| @@ -263,6 +283,8 @@ class PdfAnnotNamedLink extends PdfAnnotBase { | @@ -263,6 +283,8 @@ class PdfAnnotNamedLink extends PdfAnnotBase { | ||
| 263 | Set<PdfAnnotFlags>? flags, | 283 | Set<PdfAnnotFlags>? flags, |
| 264 | DateTime? date, | 284 | DateTime? date, |
| 265 | PdfColor? color, | 285 | PdfColor? color, |
| 286 | + String? subject, | ||
| 287 | + String? author, | ||
| 266 | }) : super( | 288 | }) : super( |
| 267 | subtype: '/Link', | 289 | subtype: '/Link', |
| 268 | rect: rect, | 290 | rect: rect, |
| @@ -270,6 +292,8 @@ class PdfAnnotNamedLink extends PdfAnnotBase { | @@ -270,6 +292,8 @@ class PdfAnnotNamedLink extends PdfAnnotBase { | ||
| 270 | flags: flags, | 292 | flags: flags, |
| 271 | date: date, | 293 | date: date, |
| 272 | color: color, | 294 | color: color, |
| 295 | + subject: subject, | ||
| 296 | + author: author, | ||
| 273 | ); | 297 | ); |
| 274 | 298 | ||
| 275 | final String dest; | 299 | final String dest; |
| @@ -295,6 +319,8 @@ class PdfAnnotUrlLink extends PdfAnnotBase { | @@ -295,6 +319,8 @@ class PdfAnnotUrlLink extends PdfAnnotBase { | ||
| 295 | Set<PdfAnnotFlags>? flags, | 319 | Set<PdfAnnotFlags>? flags, |
| 296 | DateTime? date, | 320 | DateTime? date, |
| 297 | PdfColor? color, | 321 | PdfColor? color, |
| 322 | + String? subject, | ||
| 323 | + String? author, | ||
| 298 | }) : super( | 324 | }) : super( |
| 299 | subtype: '/Link', | 325 | subtype: '/Link', |
| 300 | rect: rect, | 326 | rect: rect, |
| @@ -302,6 +328,8 @@ class PdfAnnotUrlLink extends PdfAnnotBase { | @@ -302,6 +328,8 @@ class PdfAnnotUrlLink extends PdfAnnotBase { | ||
| 302 | flags: flags, | 328 | flags: flags, |
| 303 | date: date, | 329 | date: date, |
| 304 | color: color, | 330 | color: color, |
| 331 | + subject: subject, | ||
| 332 | + author: author, | ||
| 305 | ); | 333 | ); |
| 306 | 334 | ||
| 307 | final String url; | 335 | final String url; |
| @@ -318,6 +346,177 @@ class PdfAnnotUrlLink extends PdfAnnotBase { | @@ -318,6 +346,177 @@ class PdfAnnotUrlLink extends PdfAnnotBase { | ||
| 318 | } | 346 | } |
| 319 | } | 347 | } |
| 320 | 348 | ||
| 349 | +class PdfAnnotSquare extends PdfAnnotBase { | ||
| 350 | + /// Create an Square annotation | ||
| 351 | + PdfAnnotSquare({ | ||
| 352 | + required PdfRect rect, | ||
| 353 | + PdfBorder? border, | ||
| 354 | + Set<PdfAnnotFlags>? flags, | ||
| 355 | + DateTime? date, | ||
| 356 | + PdfColor? color, | ||
| 357 | + this.interiorColor, | ||
| 358 | + String? subject, | ||
| 359 | + String? author, | ||
| 360 | + }) : super( | ||
| 361 | + subtype: '/Square', | ||
| 362 | + rect: rect, | ||
| 363 | + border: border, | ||
| 364 | + flags: flags, | ||
| 365 | + date: date, | ||
| 366 | + color: color, | ||
| 367 | + subject: subject, | ||
| 368 | + author: author, | ||
| 369 | + ); | ||
| 370 | + | ||
| 371 | + final PdfColor? interiorColor; | ||
| 372 | + | ||
| 373 | + @override | ||
| 374 | + void build(PdfPage page, PdfObject object, PdfDict params) { | ||
| 375 | + super.build(page, object, params); | ||
| 376 | + if (interiorColor != null) { | ||
| 377 | + params['/IC'] = PdfColorType(interiorColor!); | ||
| 378 | + } | ||
| 379 | + } | ||
| 380 | +} | ||
| 381 | + | ||
| 382 | +class PdfAnnotCircle extends PdfAnnotBase { | ||
| 383 | + /// Create an Circle annotation | ||
| 384 | + PdfAnnotCircle({ | ||
| 385 | + required PdfRect rect, | ||
| 386 | + PdfBorder? border, | ||
| 387 | + Set<PdfAnnotFlags>? flags, | ||
| 388 | + DateTime? date, | ||
| 389 | + PdfColor? color, | ||
| 390 | + this.interiorColor, | ||
| 391 | + String? subject, | ||
| 392 | + String? author, | ||
| 393 | + }) : super( | ||
| 394 | + subtype: '/Circle', | ||
| 395 | + rect: rect, | ||
| 396 | + border: border, | ||
| 397 | + flags: flags, | ||
| 398 | + date: date, | ||
| 399 | + color: color, | ||
| 400 | + subject: subject, | ||
| 401 | + author: author, | ||
| 402 | + ); | ||
| 403 | + | ||
| 404 | + final PdfColor? interiorColor; | ||
| 405 | + | ||
| 406 | + @override | ||
| 407 | + void build(PdfPage page, PdfObject object, PdfDict params) { | ||
| 408 | + super.build(page, object, params); | ||
| 409 | + if (interiorColor != null) { | ||
| 410 | + params['/IC'] = PdfColorType(interiorColor!); | ||
| 411 | + } | ||
| 412 | + } | ||
| 413 | +} | ||
| 414 | + | ||
| 415 | +class PdfAnnotPolygon extends PdfAnnotBase { | ||
| 416 | + /// Create an Polygon annotation | ||
| 417 | + PdfAnnotPolygon(this.document, this.points, | ||
| 418 | + {required PdfRect rect, | ||
| 419 | + PdfBorder? border, | ||
| 420 | + Set<PdfAnnotFlags>? flags, | ||
| 421 | + DateTime? date, | ||
| 422 | + PdfColor? color, | ||
| 423 | + this.interiorColor, | ||
| 424 | + String? subject, | ||
| 425 | + String? author, | ||
| 426 | + bool closed = true}) | ||
| 427 | + : super( | ||
| 428 | + subtype: closed ? '/PolyLine' : '/Polygon', | ||
| 429 | + rect: rect, | ||
| 430 | + border: border, | ||
| 431 | + flags: flags, | ||
| 432 | + date: date, | ||
| 433 | + color: color, | ||
| 434 | + subject: subject, | ||
| 435 | + author: author, | ||
| 436 | + ); | ||
| 437 | + | ||
| 438 | + final PdfDocument document; | ||
| 439 | + | ||
| 440 | + final List<PdfPoint> points; | ||
| 441 | + | ||
| 442 | + final PdfColor? interiorColor; | ||
| 443 | + | ||
| 444 | + @override | ||
| 445 | + void build(PdfPage page, PdfObject object, PdfDict params) { | ||
| 446 | + super.build(page, object, params); | ||
| 447 | + | ||
| 448 | + // Flip the points on the Y axis. | ||
| 449 | + final flippedPoints = | ||
| 450 | + points.map((e) => PdfPoint(e.x, rect.height - e.y)).toList(); | ||
| 451 | + | ||
| 452 | + final verticies = <num>[]; | ||
| 453 | + for (var i = 0; i < flippedPoints.length; i++) { | ||
| 454 | + verticies.add(flippedPoints[i].x); | ||
| 455 | + verticies.add(flippedPoints[i].y); | ||
| 456 | + } | ||
| 457 | + | ||
| 458 | + params['/Vertices'] = PdfArray.fromNum(verticies); | ||
| 459 | + | ||
| 460 | + if (interiorColor != null) { | ||
| 461 | + params['/IC'] = PdfColorType(interiorColor!); | ||
| 462 | + } | ||
| 463 | + } | ||
| 464 | +} | ||
| 465 | + | ||
| 466 | +class PdfAnnotInk extends PdfAnnotBase { | ||
| 467 | + /// Create an Ink List annotation | ||
| 468 | + PdfAnnotInk( | ||
| 469 | + this.document, | ||
| 470 | + this.points, { | ||
| 471 | + required PdfRect rect, | ||
| 472 | + PdfBorder? border, | ||
| 473 | + Set<PdfAnnotFlags>? flags, | ||
| 474 | + DateTime? date, | ||
| 475 | + PdfColor? color, | ||
| 476 | + String? subject, | ||
| 477 | + String? author, | ||
| 478 | + String? content, | ||
| 479 | + }) : super( | ||
| 480 | + subtype: '/Ink', | ||
| 481 | + rect: rect, | ||
| 482 | + border: border, | ||
| 483 | + flags: flags, | ||
| 484 | + date: date, | ||
| 485 | + color: color, | ||
| 486 | + subject: subject, | ||
| 487 | + author: author, | ||
| 488 | + content: content, | ||
| 489 | + ); | ||
| 490 | + | ||
| 491 | + final PdfDocument document; | ||
| 492 | + | ||
| 493 | + final List<List<PdfPoint>> points; | ||
| 494 | + | ||
| 495 | + @override | ||
| 496 | + void build( | ||
| 497 | + PdfPage page, | ||
| 498 | + PdfObject object, | ||
| 499 | + PdfDict params, | ||
| 500 | + ) { | ||
| 501 | + super.build(page, object, params); | ||
| 502 | + | ||
| 503 | + final verticies = List<List<num>>.filled(points.length, <num>[]); | ||
| 504 | + for (var listIndex = 0; listIndex < points.length; listIndex++) { | ||
| 505 | + // Flip the points on the Y axis. | ||
| 506 | + final flippedPoints = points[listIndex] | ||
| 507 | + .map((e) => PdfPoint(e.x, rect.height - e.y)) | ||
| 508 | + .toList(); | ||
| 509 | + for (var i = 0; i < flippedPoints.length; i++) { | ||
| 510 | + verticies[listIndex].add(flippedPoints[i].x); | ||
| 511 | + verticies[listIndex].add(flippedPoints[i].y); | ||
| 512 | + } | ||
| 513 | + } | ||
| 514 | + | ||
| 515 | + params['/InkList'] = | ||
| 516 | + PdfArray(verticies.map((v) => PdfArray.fromNum(v)).toList()); | ||
| 517 | + } | ||
| 518 | +} | ||
| 519 | + | ||
| 321 | enum PdfAnnotHighlighting { none, invert, outline, push, toggle } | 520 | enum PdfAnnotHighlighting { none, invert, outline, push, toggle } |
| 322 | 521 | ||
| 323 | abstract class PdfAnnotWidget extends PdfAnnotBase { | 522 | abstract class PdfAnnotWidget extends PdfAnnotBase { |
| @@ -332,6 +531,8 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { | @@ -332,6 +531,8 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { | ||
| 332 | PdfColor? color, | 531 | PdfColor? color, |
| 333 | this.backgroundColor, | 532 | this.backgroundColor, |
| 334 | this.highlighting, | 533 | this.highlighting, |
| 534 | + String? subject, | ||
| 535 | + String? author, | ||
| 335 | }) : super( | 536 | }) : super( |
| 336 | subtype: '/Widget', | 537 | subtype: '/Widget', |
| 337 | rect: rect, | 538 | rect: rect, |
| @@ -339,6 +540,8 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { | @@ -339,6 +540,8 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { | ||
| 339 | flags: flags, | 540 | flags: flags, |
| 340 | date: date, | 541 | date: date, |
| 341 | color: color, | 542 | color: color, |
| 543 | + subject: subject, | ||
| 544 | + author: author, | ||
| 342 | ); | 545 | ); |
| 343 | 546 | ||
| 344 | final String fieldType; | 547 | final String fieldType; |
| @@ -531,6 +734,8 @@ class PdfFormField extends PdfAnnotWidget { | @@ -531,6 +734,8 @@ class PdfFormField extends PdfAnnotWidget { | ||
| 531 | PdfBorder? border, | 734 | PdfBorder? border, |
| 532 | Set<PdfAnnotFlags>? flags, | 735 | Set<PdfAnnotFlags>? flags, |
| 533 | DateTime? date, | 736 | DateTime? date, |
| 737 | + String? subject, | ||
| 738 | + String? author, | ||
| 534 | PdfColor? color, | 739 | PdfColor? color, |
| 535 | PdfColor? backgroundColor, | 740 | PdfColor? backgroundColor, |
| 536 | PdfAnnotHighlighting? highlighting, | 741 | PdfAnnotHighlighting? highlighting, |
| @@ -542,6 +747,8 @@ class PdfFormField extends PdfAnnotWidget { | @@ -542,6 +747,8 @@ class PdfFormField extends PdfAnnotWidget { | ||
| 542 | border: border, | 747 | border: border, |
| 543 | flags: flags, | 748 | flags: flags, |
| 544 | date: date, | 749 | date: date, |
| 750 | + subject: subject, | ||
| 751 | + author: author, | ||
| 545 | backgroundColor: backgroundColor, | 752 | backgroundColor: backgroundColor, |
| 546 | color: color, | 753 | color: color, |
| 547 | highlighting: highlighting, | 754 | highlighting: highlighting, |
| @@ -588,6 +795,8 @@ class PdfTextField extends PdfFormField { | @@ -588,6 +795,8 @@ class PdfTextField extends PdfFormField { | ||
| 588 | PdfBorder? border, | 795 | PdfBorder? border, |
| 589 | Set<PdfAnnotFlags>? flags, | 796 | Set<PdfAnnotFlags>? flags, |
| 590 | DateTime? date, | 797 | DateTime? date, |
| 798 | + String? subject, | ||
| 799 | + String? author, | ||
| 591 | PdfColor? color, | 800 | PdfColor? color, |
| 592 | PdfColor? backgroundColor, | 801 | PdfColor? backgroundColor, |
| 593 | PdfAnnotHighlighting? highlighting, | 802 | PdfAnnotHighlighting? highlighting, |
| @@ -606,6 +815,8 @@ class PdfTextField extends PdfFormField { | @@ -606,6 +815,8 @@ class PdfTextField extends PdfFormField { | ||
| 606 | border: border, | 815 | border: border, |
| 607 | flags: flags, | 816 | flags: flags, |
| 608 | date: date, | 817 | date: date, |
| 818 | + subject: subject, | ||
| 819 | + author: author, | ||
| 609 | color: color, | 820 | color: color, |
| 610 | backgroundColor: backgroundColor, | 821 | backgroundColor: backgroundColor, |
| 611 | highlighting: highlighting, | 822 | highlighting: highlighting, |
| @@ -57,4 +57,13 @@ class PdfRect { | @@ -57,4 +57,13 @@ class PdfRect { | ||
| 57 | PdfPoint get topRight => PdfPoint(right, y); | 57 | PdfPoint get topRight => PdfPoint(right, y); |
| 58 | PdfPoint get bottomLeft => PdfPoint(x, top); | 58 | PdfPoint get bottomLeft => PdfPoint(x, top); |
| 59 | PdfPoint get bottomRight => PdfPoint(right, top); | 59 | PdfPoint get bottomRight => PdfPoint(right, top); |
| 60 | + | ||
| 61 | + /// Returns a new rectangle with edges moved outwards by the given delta. | ||
| 62 | + PdfRect inflate(double delta) { | ||
| 63 | + return PdfRect.fromLTRB( | ||
| 64 | + left - delta, top - delta, right + delta, bottom + delta); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /// Returns a new rectangle with edges moved inwards by the given delta. | ||
| 68 | + PdfRect deflate(double delta) => inflate(-delta); | ||
| 60 | } | 69 | } |
| @@ -14,10 +14,13 @@ | @@ -14,10 +14,13 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | +import 'dart:math'; | ||
| 18 | + | ||
| 17 | import 'package:pdf/pdf.dart'; | 19 | import 'package:pdf/pdf.dart'; |
| 18 | import 'package:vector_math/vector_math_64.dart'; | 20 | import 'package:vector_math/vector_math_64.dart'; |
| 19 | 21 | ||
| 20 | import 'geometry.dart'; | 22 | import 'geometry.dart'; |
| 23 | +import 'shape.dart'; | ||
| 21 | import 'text_style.dart'; | 24 | import 'text_style.dart'; |
| 22 | import 'theme.dart'; | 25 | import 'theme.dart'; |
| 23 | import 'widget.dart'; | 26 | import 'widget.dart'; |
| @@ -63,7 +66,7 @@ class Anchor extends SingleChildWidget { | @@ -63,7 +66,7 @@ class Anchor extends SingleChildWidget { | ||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | abstract class AnnotationBuilder { | 68 | abstract class AnnotationBuilder { |
| 66 | - void build(Context context, PdfRect? box); | 69 | + PdfAnnot build(Context context, PdfRect? box); |
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | class AnnotationLink extends AnnotationBuilder { | 72 | class AnnotationLink extends AnnotationBuilder { |
| @@ -72,8 +75,8 @@ class AnnotationLink extends AnnotationBuilder { | @@ -72,8 +75,8 @@ class AnnotationLink extends AnnotationBuilder { | ||
| 72 | final String destination; | 75 | final String destination; |
| 73 | 76 | ||
| 74 | @override | 77 | @override |
| 75 | - void build(Context context, PdfRect? box) { | ||
| 76 | - PdfAnnot( | 78 | + PdfAnnot build(Context context, PdfRect? box) { |
| 79 | + return PdfAnnot( | ||
| 77 | context.page, | 80 | context.page, |
| 78 | PdfAnnotNamedLink( | 81 | PdfAnnotNamedLink( |
| 79 | rect: context.localToGlobal(box!), | 82 | rect: context.localToGlobal(box!), |
| @@ -84,28 +87,244 @@ class AnnotationLink extends AnnotationBuilder { | @@ -84,28 +87,244 @@ class AnnotationLink extends AnnotationBuilder { | ||
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | class AnnotationUrl extends AnnotationBuilder { | 89 | class AnnotationUrl extends AnnotationBuilder { |
| 87 | - AnnotationUrl(this.destination); | 90 | + AnnotationUrl( |
| 91 | + this.destination, { | ||
| 92 | + this.date, | ||
| 93 | + this.subject, | ||
| 94 | + this.author, | ||
| 95 | + }); | ||
| 88 | 96 | ||
| 89 | final String destination; | 97 | final String destination; |
| 90 | 98 | ||
| 99 | + final DateTime? date; | ||
| 100 | + | ||
| 101 | + final String? author; | ||
| 102 | + | ||
| 103 | + final String? subject; | ||
| 104 | + | ||
| 91 | @override | 105 | @override |
| 92 | - void build(Context context, PdfRect? box) { | ||
| 93 | - PdfAnnot( | 106 | + PdfAnnot build(Context context, PdfRect? box) { |
| 107 | + return PdfAnnot( | ||
| 94 | context.page, | 108 | context.page, |
| 95 | PdfAnnotUrlLink( | 109 | PdfAnnotUrlLink( |
| 96 | rect: context.localToGlobal(box!), | 110 | rect: context.localToGlobal(box!), |
| 97 | url: destination, | 111 | url: destination, |
| 112 | + date: date, | ||
| 113 | + author: author, | ||
| 114 | + subject: subject, | ||
| 115 | + ), | ||
| 116 | + ); | ||
| 117 | + } | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +class AnnotationSquare extends AnnotationBuilder { | ||
| 121 | + AnnotationSquare({ | ||
| 122 | + this.color, | ||
| 123 | + this.interiorColor, | ||
| 124 | + this.border, | ||
| 125 | + this.author, | ||
| 126 | + this.date, | ||
| 127 | + this.subject, | ||
| 128 | + this.content, | ||
| 129 | + }); | ||
| 130 | + | ||
| 131 | + final PdfColor? color; | ||
| 132 | + | ||
| 133 | + final PdfColor? interiorColor; | ||
| 134 | + | ||
| 135 | + final PdfBorder? border; | ||
| 136 | + | ||
| 137 | + final String? author; | ||
| 138 | + | ||
| 139 | + final DateTime? date; | ||
| 140 | + | ||
| 141 | + final String? subject; | ||
| 142 | + | ||
| 143 | + final String? content; | ||
| 144 | + | ||
| 145 | + @override | ||
| 146 | + PdfAnnot build(Context context, PdfRect? box) { | ||
| 147 | + return PdfAnnot( | ||
| 148 | + context.page, | ||
| 149 | + PdfAnnotSquare( | ||
| 150 | + rect: context.localToGlobal(box!), | ||
| 151 | + border: border, | ||
| 152 | + color: color, | ||
| 153 | + interiorColor: interiorColor, | ||
| 154 | + date: date, | ||
| 155 | + author: author, | ||
| 156 | + subject: subject, | ||
| 157 | + ), | ||
| 158 | + ); | ||
| 159 | + } | ||
| 160 | +} | ||
| 161 | + | ||
| 162 | +class AnnotationCircle extends AnnotationBuilder { | ||
| 163 | + AnnotationCircle({ | ||
| 164 | + this.color, | ||
| 165 | + this.interiorColor, | ||
| 166 | + this.border, | ||
| 167 | + this.author, | ||
| 168 | + this.date, | ||
| 169 | + this.subject, | ||
| 170 | + this.content, | ||
| 171 | + }); | ||
| 172 | + | ||
| 173 | + final PdfColor? color; | ||
| 174 | + | ||
| 175 | + final PdfColor? interiorColor; | ||
| 176 | + | ||
| 177 | + final PdfBorder? border; | ||
| 178 | + | ||
| 179 | + final String? author; | ||
| 180 | + | ||
| 181 | + final DateTime? date; | ||
| 182 | + | ||
| 183 | + final String? subject; | ||
| 184 | + | ||
| 185 | + final String? content; | ||
| 186 | + | ||
| 187 | + @override | ||
| 188 | + PdfAnnot build(Context context, PdfRect? box) { | ||
| 189 | + return PdfAnnot( | ||
| 190 | + context.page, | ||
| 191 | + PdfAnnotCircle( | ||
| 192 | + rect: context.localToGlobal(box!), | ||
| 193 | + border: border, | ||
| 194 | + color: color, | ||
| 195 | + interiorColor: interiorColor, | ||
| 196 | + date: date, | ||
| 197 | + author: author, | ||
| 198 | + subject: subject, | ||
| 98 | ), | 199 | ), |
| 99 | ); | 200 | ); |
| 100 | } | 201 | } |
| 101 | } | 202 | } |
| 102 | 203 | ||
| 204 | +class AnnotationPolygon extends AnnotationBuilder { | ||
| 205 | + AnnotationPolygon( | ||
| 206 | + this.points, { | ||
| 207 | + this.color, | ||
| 208 | + this.interiorColor, | ||
| 209 | + this.border, | ||
| 210 | + this.author, | ||
| 211 | + this.date, | ||
| 212 | + this.subject, | ||
| 213 | + this.content, | ||
| 214 | + }); | ||
| 215 | + | ||
| 216 | + final List<PdfPoint> points; | ||
| 217 | + | ||
| 218 | + final PdfColor? color; | ||
| 219 | + | ||
| 220 | + final PdfColor? interiorColor; | ||
| 221 | + | ||
| 222 | + final PdfBorder? border; | ||
| 223 | + | ||
| 224 | + final String? author; | ||
| 225 | + | ||
| 226 | + final DateTime? date; | ||
| 227 | + | ||
| 228 | + final String? subject; | ||
| 229 | + | ||
| 230 | + final String? content; | ||
| 231 | + | ||
| 232 | + @override | ||
| 233 | + PdfAnnot build(Context context, PdfRect? box) { | ||
| 234 | + final globalPoints = | ||
| 235 | + points.map((e) => context.localToGlobalPoint(e)).toList(); | ||
| 236 | + | ||
| 237 | + final rect = context.localToGlobal(PdfRect( | ||
| 238 | + points.map((point) => point.x).reduce(min), | ||
| 239 | + points.map((point) => point.y).reduce(min), | ||
| 240 | + points.map((point) => point.x).reduce(max) - | ||
| 241 | + points.map((point) => point.x).reduce(min), | ||
| 242 | + points.map((point) => point.y).reduce(max) - | ||
| 243 | + points.map((point) => point.y).reduce(min))); | ||
| 244 | + | ||
| 245 | + final pdfAnnotPolygon = PdfAnnotPolygon( | ||
| 246 | + context.document, | ||
| 247 | + globalPoints, | ||
| 248 | + rect: rect, | ||
| 249 | + border: border, | ||
| 250 | + color: color, | ||
| 251 | + interiorColor: interiorColor, | ||
| 252 | + date: date, | ||
| 253 | + author: author, | ||
| 254 | + subject: subject, | ||
| 255 | + ); | ||
| 256 | + | ||
| 257 | + return PdfAnnot(context.page, pdfAnnotPolygon); | ||
| 258 | + } | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +class AnnotationInk extends AnnotationBuilder { | ||
| 262 | + AnnotationInk( | ||
| 263 | + this.points, { | ||
| 264 | + this.color, | ||
| 265 | + this.border, | ||
| 266 | + this.author, | ||
| 267 | + this.date, | ||
| 268 | + this.subject, | ||
| 269 | + this.content, | ||
| 270 | + }); | ||
| 271 | + | ||
| 272 | + final List<List<PdfPoint>> points; | ||
| 273 | + | ||
| 274 | + final PdfColor? color; | ||
| 275 | + | ||
| 276 | + final PdfBorder? border; | ||
| 277 | + | ||
| 278 | + final String? author; | ||
| 279 | + | ||
| 280 | + final DateTime? date; | ||
| 281 | + | ||
| 282 | + final String? subject; | ||
| 283 | + | ||
| 284 | + final String? content; | ||
| 285 | + | ||
| 286 | + @override | ||
| 287 | + PdfAnnot build(Context context, PdfRect? box) { | ||
| 288 | + final globalPoints = points | ||
| 289 | + .map((pList) => pList | ||
| 290 | + .map((e) => context.localToGlobalPoint(e)) | ||
| 291 | + .toList(growable: false)) | ||
| 292 | + .toList(growable: false); | ||
| 293 | + | ||
| 294 | + final allPoints = | ||
| 295 | + points.expand((pointList) => pointList).toList(growable: false); | ||
| 296 | + | ||
| 297 | + final minX = allPoints.map((point) => point.x).reduce(min); | ||
| 298 | + final minY = allPoints.map((point) => point.y).reduce(min); | ||
| 299 | + final maxX = allPoints.map((point) => point.x).reduce(max); | ||
| 300 | + final maxY = allPoints.map((point) => point.y).reduce(max); | ||
| 301 | + final rect = | ||
| 302 | + context.localToGlobal(PdfRect(minX, minY, maxX - minX, maxY - minY)); | ||
| 303 | + | ||
| 304 | + final pdfAnnotInk = PdfAnnotInk( | ||
| 305 | + context.document, | ||
| 306 | + globalPoints, | ||
| 307 | + rect: rect, | ||
| 308 | + border: border, | ||
| 309 | + color: color, | ||
| 310 | + date: date, | ||
| 311 | + author: author, | ||
| 312 | + subject: subject, | ||
| 313 | + content: content, | ||
| 314 | + ); | ||
| 315 | + | ||
| 316 | + return PdfAnnot(context.page, pdfAnnotInk); | ||
| 317 | + } | ||
| 318 | +} | ||
| 319 | + | ||
| 103 | class AnnotationTextField extends AnnotationBuilder { | 320 | class AnnotationTextField extends AnnotationBuilder { |
| 104 | AnnotationTextField({ | 321 | AnnotationTextField({ |
| 105 | this.name, | 322 | this.name, |
| 106 | this.border, | 323 | this.border, |
| 107 | this.flags, | 324 | this.flags, |
| 108 | this.date, | 325 | this.date, |
| 326 | + this.subject, | ||
| 327 | + this.author, | ||
| 109 | this.color, | 328 | this.color, |
| 110 | this.backgroundColor, | 329 | this.backgroundColor, |
| 111 | this.highlighting, | 330 | this.highlighting, |
| @@ -146,11 +365,15 @@ class AnnotationTextField extends AnnotationBuilder { | @@ -146,11 +365,15 @@ class AnnotationTextField extends AnnotationBuilder { | ||
| 146 | 365 | ||
| 147 | final Set<PdfFieldFlags>? fieldFlags; | 366 | final Set<PdfFieldFlags>? fieldFlags; |
| 148 | 367 | ||
| 368 | + final String? author; | ||
| 369 | + | ||
| 370 | + final String? subject; | ||
| 371 | + | ||
| 149 | @override | 372 | @override |
| 150 | - void build(Context context, PdfRect? box) { | 373 | + PdfAnnot build(Context context, PdfRect? box) { |
| 151 | final _textStyle = Theme.of(context).defaultTextStyle.merge(textStyle); | 374 | final _textStyle = Theme.of(context).defaultTextStyle.merge(textStyle); |
| 152 | 375 | ||
| 153 | - PdfAnnot( | 376 | + return PdfAnnot( |
| 154 | context.page, | 377 | context.page, |
| 155 | PdfTextField( | 378 | PdfTextField( |
| 156 | rect: context.localToGlobal(box!), | 379 | rect: context.localToGlobal(box!), |
| @@ -158,6 +381,8 @@ class AnnotationTextField extends AnnotationBuilder { | @@ -158,6 +381,8 @@ class AnnotationTextField extends AnnotationBuilder { | ||
| 158 | border: border, | 381 | border: border, |
| 159 | flags: flags, | 382 | flags: flags, |
| 160 | date: date, | 383 | date: date, |
| 384 | + author: author, | ||
| 385 | + subject: subject, | ||
| 161 | color: color, | 386 | color: color, |
| 162 | backgroundColor: backgroundColor, | 387 | backgroundColor: backgroundColor, |
| 163 | highlighting: highlighting, | 388 | highlighting: highlighting, |
| @@ -208,6 +433,148 @@ class UrlLink extends Annotation { | @@ -208,6 +433,148 @@ class UrlLink extends Annotation { | ||
| 208 | }) : super(child: child, builder: AnnotationUrl(destination)); | 433 | }) : super(child: child, builder: AnnotationUrl(destination)); |
| 209 | } | 434 | } |
| 210 | 435 | ||
| 436 | +class SquareAnnotation extends Annotation { | ||
| 437 | + SquareAnnotation({ | ||
| 438 | + Widget? child, | ||
| 439 | + PdfColor? color, | ||
| 440 | + PdfColor? interiorColor, | ||
| 441 | + PdfBorder? border, | ||
| 442 | + String? author, | ||
| 443 | + DateTime? date, | ||
| 444 | + String? subject, | ||
| 445 | + String? content, | ||
| 446 | + }) : super( | ||
| 447 | + child: child ?? | ||
| 448 | + Rectangle( | ||
| 449 | + fillColor: interiorColor, | ||
| 450 | + strokeWidth: border?.width ?? 1.0, | ||
| 451 | + strokeColor: color), | ||
| 452 | + builder: AnnotationSquare( | ||
| 453 | + color: color, | ||
| 454 | + interiorColor: interiorColor, | ||
| 455 | + border: border, | ||
| 456 | + author: author, | ||
| 457 | + date: date, | ||
| 458 | + content: content, | ||
| 459 | + subject: subject, | ||
| 460 | + ), | ||
| 461 | + ); | ||
| 462 | +} | ||
| 463 | + | ||
| 464 | +class CircleAnnotation extends Annotation { | ||
| 465 | + CircleAnnotation({ | ||
| 466 | + Widget? child, | ||
| 467 | + PdfColor? color, | ||
| 468 | + PdfColor? interiorColor, | ||
| 469 | + PdfBorder? border, | ||
| 470 | + String? author, | ||
| 471 | + DateTime? date, | ||
| 472 | + String? subject, | ||
| 473 | + String? content, | ||
| 474 | + }) : super( | ||
| 475 | + child: child ?? | ||
| 476 | + Circle( | ||
| 477 | + fillColor: interiorColor, | ||
| 478 | + strokeWidth: border?.width ?? 1.0, | ||
| 479 | + strokeColor: color), | ||
| 480 | + builder: AnnotationCircle( | ||
| 481 | + color: color, | ||
| 482 | + interiorColor: interiorColor, | ||
| 483 | + border: border, | ||
| 484 | + author: author, | ||
| 485 | + date: date, | ||
| 486 | + content: content, | ||
| 487 | + subject: subject, | ||
| 488 | + ), | ||
| 489 | + ); | ||
| 490 | +} | ||
| 491 | + | ||
| 492 | +class PolygonAnnotation extends Annotation { | ||
| 493 | + PolygonAnnotation({ | ||
| 494 | + required List<PdfPoint> points, | ||
| 495 | + Widget? child, | ||
| 496 | + PdfColor? color, | ||
| 497 | + PdfColor? interiorColor, | ||
| 498 | + PdfBorder? border, | ||
| 499 | + String? author, | ||
| 500 | + DateTime? date, | ||
| 501 | + String? subject, | ||
| 502 | + String? content, | ||
| 503 | + }) : super( | ||
| 504 | + child: child ?? | ||
| 505 | + Polygon( | ||
| 506 | + points: points, | ||
| 507 | + strokeColor: color, | ||
| 508 | + fillColor: interiorColor, | ||
| 509 | + strokeWidth: border?.width ?? 1.0), | ||
| 510 | + builder: AnnotationPolygon( | ||
| 511 | + points, | ||
| 512 | + color: color, | ||
| 513 | + interiorColor: interiorColor, | ||
| 514 | + border: border, | ||
| 515 | + author: author, | ||
| 516 | + date: date, | ||
| 517 | + content: content, | ||
| 518 | + subject: subject, | ||
| 519 | + ), | ||
| 520 | + ); | ||
| 521 | +} | ||
| 522 | + | ||
| 523 | +class PolyLineAnnotation extends Annotation { | ||
| 524 | + PolyLineAnnotation({ | ||
| 525 | + required List<PdfPoint> points, | ||
| 526 | + PdfColor? color, | ||
| 527 | + PdfBorder? border, | ||
| 528 | + String? author, | ||
| 529 | + DateTime? date, | ||
| 530 | + String? content, | ||
| 531 | + String? subject, | ||
| 532 | + }) : super( | ||
| 533 | + child: Polygon( | ||
| 534 | + points: points, | ||
| 535 | + strokeColor: color, | ||
| 536 | + close: false, | ||
| 537 | + strokeWidth: border?.width ?? 1.0), | ||
| 538 | + builder: AnnotationPolygon( | ||
| 539 | + points, | ||
| 540 | + color: color, | ||
| 541 | + border: border, | ||
| 542 | + author: author, | ||
| 543 | + date: date, | ||
| 544 | + content: content, | ||
| 545 | + subject: subject, | ||
| 546 | + ), | ||
| 547 | + ); | ||
| 548 | +} | ||
| 549 | + | ||
| 550 | +class InkAnnotation extends Annotation { | ||
| 551 | + InkAnnotation({ | ||
| 552 | + required List<List<PdfPoint>> points, | ||
| 553 | + Widget? child, | ||
| 554 | + PdfColor? color, | ||
| 555 | + PdfBorder? border, | ||
| 556 | + String? author, | ||
| 557 | + DateTime? date, | ||
| 558 | + String? content, | ||
| 559 | + String? subject, | ||
| 560 | + }) : super( | ||
| 561 | + child: child ?? | ||
| 562 | + InkList( | ||
| 563 | + points: points, | ||
| 564 | + strokeColor: color, | ||
| 565 | + strokeWidth: border?.width ?? 1.0), | ||
| 566 | + builder: AnnotationInk( | ||
| 567 | + points, | ||
| 568 | + color: color, | ||
| 569 | + border: border, | ||
| 570 | + author: author, | ||
| 571 | + date: date, | ||
| 572 | + content: content, | ||
| 573 | + subject: subject, | ||
| 574 | + ), | ||
| 575 | + ); | ||
| 576 | +} | ||
| 577 | + | ||
| 211 | class Outline extends Anchor { | 578 | class Outline extends Anchor { |
| 212 | Outline({ | 579 | Outline({ |
| 213 | Widget? child, | 580 | Widget? child, |
pdf/lib/src/widgets/shape.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 | +import 'package:pdf/src/pdf/point.dart'; | ||
| 18 | +import 'package:pdf/src/widgets/geometry.dart'; | ||
| 19 | +import 'package:pdf/src/widgets/widget.dart'; | ||
| 20 | + | ||
| 21 | +import '../../pdf.dart'; | ||
| 22 | + | ||
| 23 | +class Circle extends Widget { | ||
| 24 | + Circle({this.fillColor, this.strokeColor, this.strokeWidth = 1.0}); | ||
| 25 | + | ||
| 26 | + final PdfColor? fillColor; | ||
| 27 | + final PdfColor? strokeColor; | ||
| 28 | + final double strokeWidth; | ||
| 29 | + | ||
| 30 | + @override | ||
| 31 | + void layout(Context context, BoxConstraints constraints, | ||
| 32 | + {bool parentUsesSize = false}) { | ||
| 33 | + box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @override | ||
| 37 | + void paint(Context context) { | ||
| 38 | + super.paint(context); | ||
| 39 | + | ||
| 40 | + final canvas = context.canvas; | ||
| 41 | + | ||
| 42 | + canvas.saveContext(); | ||
| 43 | + | ||
| 44 | + if (fillColor != null) { | ||
| 45 | + canvas.setFillColor(fillColor!); | ||
| 46 | + } | ||
| 47 | + if (strokeColor != null) { | ||
| 48 | + canvas.setStrokeColor(strokeColor); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + canvas.setLineWidth(strokeWidth); | ||
| 52 | + | ||
| 53 | + canvas.drawEllipse( | ||
| 54 | + box!.width / 2, box!.height / 2, box!.width / 2, box!.height / 2); | ||
| 55 | + | ||
| 56 | + if (strokeColor != null && fillColor != null) { | ||
| 57 | + canvas.fillAndStrokePath(); | ||
| 58 | + } else if (strokeColor != null) { | ||
| 59 | + canvas.strokePath(); | ||
| 60 | + } else { | ||
| 61 | + canvas.fillPath(); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + canvas.restoreContext(); | ||
| 65 | + } | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +class Rectangle extends Widget { | ||
| 69 | + Rectangle({this.fillColor, this.strokeColor, this.strokeWidth = 1.0}); | ||
| 70 | + | ||
| 71 | + final PdfColor? fillColor; | ||
| 72 | + final PdfColor? strokeColor; | ||
| 73 | + final double strokeWidth; | ||
| 74 | + | ||
| 75 | + @override | ||
| 76 | + void layout(Context context, BoxConstraints constraints, | ||
| 77 | + {bool parentUsesSize = false}) { | ||
| 78 | + box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @override | ||
| 82 | + void paint(Context context) { | ||
| 83 | + super.paint(context); | ||
| 84 | + | ||
| 85 | + final canvas = context.canvas; | ||
| 86 | + | ||
| 87 | + canvas.saveContext(); | ||
| 88 | + | ||
| 89 | + if (fillColor != null) { | ||
| 90 | + canvas.setFillColor(fillColor!); | ||
| 91 | + } | ||
| 92 | + if (strokeColor != null) { | ||
| 93 | + canvas.setStrokeColor(strokeColor); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + canvas.setLineWidth(strokeWidth); | ||
| 97 | + | ||
| 98 | + canvas.drawRect(0, 0, box!.width, box!.height); | ||
| 99 | + | ||
| 100 | + if (strokeColor != null && fillColor != null) { | ||
| 101 | + canvas.fillAndStrokePath(); | ||
| 102 | + } else if (strokeColor != null) { | ||
| 103 | + canvas.strokePath(); | ||
| 104 | + } else { | ||
| 105 | + canvas.fillPath(); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + canvas.restoreContext(); | ||
| 109 | + } | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +class Polygon extends Widget { | ||
| 113 | + Polygon( | ||
| 114 | + {required this.points, | ||
| 115 | + this.fillColor, | ||
| 116 | + this.strokeColor, | ||
| 117 | + this.strokeWidth = 1.0, | ||
| 118 | + this.close = true}); | ||
| 119 | + | ||
| 120 | + final List<PdfPoint> points; | ||
| 121 | + final PdfColor? fillColor; | ||
| 122 | + final PdfColor? strokeColor; | ||
| 123 | + final double strokeWidth; | ||
| 124 | + final bool close; | ||
| 125 | + | ||
| 126 | + @override | ||
| 127 | + void layout(Context context, BoxConstraints constraints, | ||
| 128 | + {bool parentUsesSize = false}) { | ||
| 129 | + box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest); | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + @override | ||
| 133 | + void paint(Context context) { | ||
| 134 | + super.paint(context); | ||
| 135 | + | ||
| 136 | + // Make sure there are enough points to draw anything | ||
| 137 | + if (points.length < 3) { | ||
| 138 | + return; | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + final canvas = context.canvas; | ||
| 142 | + | ||
| 143 | + canvas.saveContext(); | ||
| 144 | + | ||
| 145 | + if (fillColor != null) { | ||
| 146 | + canvas.setFillColor(fillColor!); | ||
| 147 | + } | ||
| 148 | + if (strokeColor != null) { | ||
| 149 | + canvas.setStrokeColor(strokeColor); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + canvas.setLineWidth(strokeWidth); | ||
| 153 | + | ||
| 154 | + // Flip the points on the Y axis. | ||
| 155 | + final flippedPoints = | ||
| 156 | + points.map((e) => PdfPoint(e.x, box!.height - e.y)).toList(); | ||
| 157 | + | ||
| 158 | + canvas.moveTo(flippedPoints[0].x, flippedPoints[0].y); | ||
| 159 | + for (var i = 0; i < flippedPoints.length; i++) { | ||
| 160 | + canvas.lineTo(flippedPoints[i].x, flippedPoints[i].y); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + if (close) { | ||
| 164 | + canvas.closePath(); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + if (strokeColor != null && fillColor != null) { | ||
| 168 | + canvas.fillAndStrokePath(); | ||
| 169 | + } else if (strokeColor != null) { | ||
| 170 | + canvas.strokePath(); | ||
| 171 | + } else { | ||
| 172 | + canvas.fillPath(); | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + canvas.restoreContext(); | ||
| 176 | + } | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | +class InkList extends Widget { | ||
| 180 | + InkList({required this.points, this.strokeColor, this.strokeWidth = 1.0}); | ||
| 181 | + | ||
| 182 | + final List<List<PdfPoint>> points; | ||
| 183 | + final PdfColor? strokeColor; | ||
| 184 | + final double strokeWidth; | ||
| 185 | + | ||
| 186 | + @override | ||
| 187 | + void layout(Context context, BoxConstraints constraints, | ||
| 188 | + {bool parentUsesSize = false}) { | ||
| 189 | + box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + @override | ||
| 193 | + void paint(Context context) { | ||
| 194 | + super.paint(context); | ||
| 195 | + | ||
| 196 | + final canvas = context.canvas; | ||
| 197 | + | ||
| 198 | + canvas.saveContext(); | ||
| 199 | + | ||
| 200 | + if (strokeColor != null) { | ||
| 201 | + canvas.setStrokeColor(strokeColor); | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + canvas.setLineWidth(strokeWidth); | ||
| 205 | + | ||
| 206 | + // Flip the points on the Y axis. | ||
| 207 | + | ||
| 208 | + for (var subLineIndex = 0; subLineIndex < points.length; subLineIndex++) { | ||
| 209 | + final flippedPoints = points[subLineIndex] | ||
| 210 | + .map((e) => PdfPoint(e.x, box!.height - e.y)) | ||
| 211 | + .toList(); | ||
| 212 | + canvas.moveTo(flippedPoints[0].x, flippedPoints[0].y); | ||
| 213 | + for (var i = 0; i < flippedPoints.length; i++) { | ||
| 214 | + canvas.lineTo(flippedPoints[i].x, flippedPoints[i].y); | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + canvas.strokePath(); | ||
| 219 | + | ||
| 220 | + canvas.restoreContext(); | ||
| 221 | + } | ||
| 222 | +} |
| @@ -112,6 +112,12 @@ class Context { | @@ -112,6 +112,12 @@ class Context { | ||
| 112 | y.reduce(math.max), | 112 | y.reduce(math.max), |
| 113 | ); | 113 | ); |
| 114 | } | 114 | } |
| 115 | + | ||
| 116 | + PdfPoint localToGlobalPoint(PdfPoint point) { | ||
| 117 | + final mat = canvas.getTransform(); | ||
| 118 | + final xy = mat.transform3(Vector3(point.x, point.y, 0)); | ||
| 119 | + return PdfPoint(xy.x, xy.y); | ||
| 120 | + } | ||
| 115 | } | 121 | } |
| 116 | 122 | ||
| 117 | class Inherited { | 123 | class Inherited { |
| @@ -49,6 +49,7 @@ export 'src/widgets/page_theme.dart'; | @@ -49,6 +49,7 @@ export 'src/widgets/page_theme.dart'; | ||
| 49 | export 'src/widgets/partitions.dart'; | 49 | export 'src/widgets/partitions.dart'; |
| 50 | export 'src/widgets/placeholders.dart'; | 50 | export 'src/widgets/placeholders.dart'; |
| 51 | export 'src/widgets/progress.dart'; | 51 | export 'src/widgets/progress.dart'; |
| 52 | +export 'src/widgets/shape.dart'; | ||
| 52 | export 'src/widgets/stack.dart'; | 53 | export 'src/widgets/stack.dart'; |
| 53 | export 'src/widgets/svg.dart'; | 54 | export 'src/widgets/svg.dart'; |
| 54 | export 'src/widgets/table.dart'; | 55 | export 'src/widgets/table.dart'; |
| @@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl | @@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl | ||
| 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf | 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf |
| 5 | repository: https://github.com/DavBfr/dart_pdf | 5 | repository: https://github.com/DavBfr/dart_pdf |
| 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues | 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues |
| 7 | -version: 3.4.2 | 7 | +version: 3.5.0 |
| 8 | 8 | ||
| 9 | environment: | 9 | environment: |
| 10 | sdk: ">=2.12.0 <3.0.0" | 10 | sdk: ">=2.12.0 <3.0.0" |
| @@ -17,59 +17,103 @@ | @@ -17,59 +17,103 @@ | ||
| 17 | import 'dart:io'; | 17 | import 'dart:io'; |
| 18 | 18 | ||
| 19 | import 'package:pdf/pdf.dart'; | 19 | import 'package:pdf/pdf.dart'; |
| 20 | +import 'package:pdf/widgets.dart'; | ||
| 20 | import 'package:test/test.dart'; | 21 | import 'package:test/test.dart'; |
| 21 | 22 | ||
| 22 | -void main() { | ||
| 23 | - test('Pdf Annotations', () async { | ||
| 24 | - final pdf = PdfDocument(); | ||
| 25 | - final page = PdfPage(pdf, pageFormat: const PdfPageFormat(500, 300)); | ||
| 26 | - final page1 = PdfPage(pdf, pageFormat: const PdfPageFormat(500, 300)); | ||
| 27 | - | ||
| 28 | - pdf.pdfNames.addDest('target', page1, posY: 100); | 23 | +late Document pdf; |
| 29 | 24 | ||
| 30 | - final g = page.getGraphics(); | 25 | +void main() { |
| 26 | + setUpAll(() { | ||
| 27 | + Document.debug = true; | ||
| 28 | + pdf = Document(); | ||
| 29 | + }); | ||
| 31 | 30 | ||
| 32 | - PdfAnnot( | ||
| 33 | - page, | ||
| 34 | - PdfAnnotText( | ||
| 35 | - rect: const PdfRect(100, 100, 50, 50), | ||
| 36 | - content: 'Hello', | 31 | + test('Pdf Link Annotations', () async { |
| 32 | + pdf.addPage( | ||
| 33 | + Page( | ||
| 34 | + build: (context) => Column( | ||
| 35 | + children: [ | ||
| 36 | + Link(child: Text('A link'), destination: 'destination'), | ||
| 37 | + UrlLink( | ||
| 38 | + child: Text('GitHub'), | ||
| 39 | + destination: 'https://github.com/DavBfr/dart_pdf/'), | ||
| 40 | + ], | ||
| 37 | ), | 41 | ), |
| 38 | - ); | ||
| 39 | - | ||
| 40 | - PdfAnnot( | ||
| 41 | - page, | ||
| 42 | - PdfAnnotNamedLink( | ||
| 43 | - dest: 'target', | ||
| 44 | - rect: const PdfRect(100, 150, 50, 50), | ||
| 45 | ), | 42 | ), |
| 46 | ); | 43 | ); |
| 47 | - g.drawRect(100, 150, 50, 50); | ||
| 48 | - g.strokePath(); | 44 | + }); |
| 49 | 45 | ||
| 50 | - PdfAnnot( | ||
| 51 | - page, | ||
| 52 | - PdfAnnotUrlLink( | ||
| 53 | - rect: const PdfRect(100, 250, 50, 50), | ||
| 54 | - url: 'https://github.com/DavBfr/dart_pdf/', | 46 | + test('Pdf Shape Annotations', () async { |
| 47 | + pdf.addPage( | ||
| 48 | + Page( | ||
| 49 | + build: (context) => Wrap( | ||
| 50 | + spacing: 20, | ||
| 51 | + runSpacing: 20, | ||
| 52 | + children: [ | ||
| 53 | + SizedBox( | ||
| 54 | + width: 200, | ||
| 55 | + height: 200, | ||
| 56 | + child: CircleAnnotation( | ||
| 57 | + color: PdfColors.blue, | ||
| 58 | + author: 'David PHAM-VAN', | ||
| 59 | + ), | ||
| 60 | + ), | ||
| 61 | + SizedBox( | ||
| 62 | + width: 200, | ||
| 63 | + height: 200, | ||
| 64 | + child: SquareAnnotation( | ||
| 65 | + color: PdfColors.red, | ||
| 66 | + ), | ||
| 67 | + ), | ||
| 68 | + SizedBox( | ||
| 69 | + width: 200, | ||
| 70 | + height: 100, | ||
| 71 | + child: PolyLineAnnotation( | ||
| 72 | + points: const [ | ||
| 73 | + PdfPoint(10, 10), | ||
| 74 | + PdfPoint(10, 30), | ||
| 75 | + PdfPoint(50, 70) | ||
| 76 | + ], | ||
| 77 | + color: PdfColors.purple, | ||
| 78 | + ), | ||
| 79 | + ), | ||
| 80 | + SizedBox( | ||
| 81 | + width: 200, | ||
| 82 | + height: 100, | ||
| 83 | + child: PolygonAnnotation( | ||
| 84 | + points: const [ | ||
| 85 | + PdfPoint(10, 10), | ||
| 86 | + PdfPoint(10, 30), | ||
| 87 | + PdfPoint(50, 70) | ||
| 88 | + ], | ||
| 89 | + color: PdfColors.orange, | ||
| 90 | + ), | ||
| 91 | + ), | ||
| 92 | + SizedBox( | ||
| 93 | + width: 200, | ||
| 94 | + height: 100, | ||
| 95 | + child: InkAnnotation( | ||
| 96 | + points: const [ | ||
| 97 | + [PdfPoint(10, 10), PdfPoint(10, 30), PdfPoint(50, 70)], | ||
| 98 | + [PdfPoint(100, 10), PdfPoint(100, 30), PdfPoint(150, 70)], | ||
| 99 | + ], | ||
| 100 | + color: PdfColors.green, | ||
| 101 | + ), | ||
| 102 | + ), | ||
| 103 | + ], | ||
| 55 | ), | 104 | ), |
| 56 | - ); | ||
| 57 | - g.drawRect(100, 250, 50, 50); | ||
| 58 | - g.strokePath(); | ||
| 59 | - | ||
| 60 | - PdfAnnot( | ||
| 61 | - page, | ||
| 62 | - PdfTextField( | ||
| 63 | - rect: const PdfRect(100, 50, 50, 20), | ||
| 64 | - fieldName: 'test', | ||
| 65 | - font: PdfFont.helvetica(pdf), | ||
| 66 | - fontSize: 10, | ||
| 67 | - textColor: PdfColors.blue, | ||
| 68 | ), | 105 | ), |
| 69 | ); | 106 | ); |
| 70 | - // g.drawRect(100, 50, 50, 20); | ||
| 71 | - g.strokePath(); | 107 | + }); |
| 108 | + | ||
| 109 | + test('Pdf Anchor Annotation', () async { | ||
| 110 | + pdf.addPage(Page( | ||
| 111 | + build: (context) => | ||
| 112 | + Anchor(child: Text('The destination'), name: 'destination'), | ||
| 113 | + )); | ||
| 114 | + }); | ||
| 72 | 115 | ||
| 116 | + tearDownAll(() async { | ||
| 73 | final file = File('annotations.pdf'); | 117 | final file = File('annotations.pdf'); |
| 74 | await file.writeAsBytes(await pdf.save()); | 118 | await file.writeAsBytes(await pdf.save()); |
| 75 | }); | 119 | }); |
No preview for this file type
-
Please register or login to post a comment