Showing
13 changed files
with
384 additions
and
31 deletions
| @@ -8,6 +8,7 @@ | @@ -8,6 +8,7 @@ | ||
| 8 | - Implement fallback font | 8 | - Implement fallback font |
| 9 | - Implement Emoji support | 9 | - Implement Emoji support |
| 10 | - Improve outlines containing non-sequential level increments [Roel Spilker] | 10 | - Improve outlines containing non-sequential level increments [Roel Spilker] |
| 11 | +- Add debugging information | ||
| 11 | 12 | ||
| 12 | ## 3.6.5 | 13 | ## 3.6.5 |
| 13 | 14 |
| @@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
| 16 | 16 | ||
| 17 | import 'dart:collection'; | 17 | import 'dart:collection'; |
| 18 | import 'dart:convert'; | 18 | import 'dart:convert'; |
| 19 | +import 'dart:math' as math; | ||
| 19 | import 'dart:typed_data'; | 20 | import 'dart:typed_data'; |
| 20 | 21 | ||
| 21 | import 'package:meta/meta.dart'; | 22 | import 'package:meta/meta.dart'; |
| @@ -25,10 +26,12 @@ import 'color.dart'; | @@ -25,10 +26,12 @@ import 'color.dart'; | ||
| 25 | import 'obj/object.dart'; | 26 | import 'obj/object.dart'; |
| 26 | import 'stream.dart'; | 27 | import 'stream.dart'; |
| 27 | 28 | ||
| 29 | +const _kIndentSize = 2; | ||
| 30 | + | ||
| 28 | abstract class PdfDataType { | 31 | abstract class PdfDataType { |
| 29 | const PdfDataType(); | 32 | const PdfDataType(); |
| 30 | 33 | ||
| 31 | - void output(PdfStream s); | 34 | + void output(PdfStream s, [int? indent]); |
| 32 | 35 | ||
| 33 | PdfStream _toStream() { | 36 | PdfStream _toStream() { |
| 34 | final s = PdfStream(); | 37 | final s = PdfStream(); |
| @@ -53,7 +56,7 @@ class PdfBool extends PdfDataType { | @@ -53,7 +56,7 @@ class PdfBool extends PdfDataType { | ||
| 53 | final bool value; | 56 | final bool value; |
| 54 | 57 | ||
| 55 | @override | 58 | @override |
| 56 | - void output(PdfStream s) { | 59 | + void output(PdfStream s, [int? indent]) { |
| 57 | s.putString(value ? 'true' : 'false'); | 60 | s.putString(value ? 'true' : 'false'); |
| 58 | } | 61 | } |
| 59 | 62 | ||
| @@ -81,7 +84,7 @@ class PdfNum extends PdfDataType { | @@ -81,7 +84,7 @@ class PdfNum extends PdfDataType { | ||
| 81 | final num value; | 84 | final num value; |
| 82 | 85 | ||
| 83 | @override | 86 | @override |
| 84 | - void output(PdfStream s) { | 87 | + void output(PdfStream s, [int? indent]) { |
| 85 | if (value is int) { | 88 | if (value is int) { |
| 86 | s.putString(value.toInt().toString()); | 89 | s.putString(value.toInt().toString()); |
| 87 | } else { | 90 | } else { |
| @@ -119,12 +122,12 @@ class PdfNumList extends PdfDataType { | @@ -119,12 +122,12 @@ class PdfNumList extends PdfDataType { | ||
| 119 | final List<num> values; | 122 | final List<num> values; |
| 120 | 123 | ||
| 121 | @override | 124 | @override |
| 122 | - void output(PdfStream s) { | 125 | + void output(PdfStream s, [int? indent]) { |
| 123 | for (var n = 0; n < values.length; n++) { | 126 | for (var n = 0; n < values.length; n++) { |
| 124 | if (n > 0) { | 127 | if (n > 0) { |
| 125 | s.putByte(0x20); | 128 | s.putByte(0x20); |
| 126 | } | 129 | } |
| 127 | - PdfNum(values[n]).output(s); | 130 | + PdfNum(values[n]).output(s, indent); |
| 128 | } | 131 | } |
| 129 | } | 132 | } |
| 130 | 133 | ||
| @@ -289,7 +292,7 @@ class PdfString extends PdfDataType { | @@ -289,7 +292,7 @@ class PdfString extends PdfDataType { | ||
| 289 | } | 292 | } |
| 290 | 293 | ||
| 291 | @override | 294 | @override |
| 292 | - void output(PdfStream s) { | 295 | + void output(PdfStream s, [int? indent]) { |
| 293 | _output(s, value); | 296 | _output(s, value); |
| 294 | } | 297 | } |
| 295 | 298 | ||
| @@ -346,9 +349,9 @@ class PdfSecString extends PdfString { | @@ -346,9 +349,9 @@ class PdfSecString extends PdfString { | ||
| 346 | final PdfObject object; | 349 | final PdfObject object; |
| 347 | 350 | ||
| 348 | @override | 351 | @override |
| 349 | - void output(PdfStream s) { | 352 | + void output(PdfStream s, [int? indent]) { |
| 350 | if (object.pdfDocument.encryption == null) { | 353 | if (object.pdfDocument.encryption == null) { |
| 351 | - return super.output(s); | 354 | + return super.output(s, indent); |
| 352 | } | 355 | } |
| 353 | 356 | ||
| 354 | final enc = object.pdfDocument.encryption!.encrypt(value, object); | 357 | final enc = object.pdfDocument.encryption!.encrypt(value, object); |
| @@ -362,7 +365,7 @@ class PdfName extends PdfDataType { | @@ -362,7 +365,7 @@ class PdfName extends PdfDataType { | ||
| 362 | final String value; | 365 | final String value; |
| 363 | 366 | ||
| 364 | @override | 367 | @override |
| 365 | - void output(PdfStream s) { | 368 | + void output(PdfStream s, [int? indent]) { |
| 366 | assert(value[0] == '/'); | 369 | assert(value[0] == '/'); |
| 367 | final bytes = <int>[]; | 370 | final bytes = <int>[]; |
| 368 | for (final c in value.codeUnits) { | 371 | for (final c in value.codeUnits) { |
| @@ -404,7 +407,7 @@ class PdfNull extends PdfDataType { | @@ -404,7 +407,7 @@ class PdfNull extends PdfDataType { | ||
| 404 | const PdfNull(); | 407 | const PdfNull(); |
| 405 | 408 | ||
| 406 | @override | 409 | @override |
| 407 | - void output(PdfStream s) { | 410 | + void output(PdfStream s, [int? indent]) { |
| 408 | s.putString('null'); | 411 | s.putString('null'); |
| 409 | } | 412 | } |
| 410 | 413 | ||
| @@ -425,7 +428,7 @@ class PdfIndirect extends PdfDataType { | @@ -425,7 +428,7 @@ class PdfIndirect extends PdfDataType { | ||
| 425 | final int gen; | 428 | final int gen; |
| 426 | 429 | ||
| 427 | @override | 430 | @override |
| 428 | - void output(PdfStream s) { | 431 | + void output(PdfStream s, [int? indent]) { |
| 429 | s.putString('$ser $gen R'); | 432 | s.putString('$ser $gen R'); |
| 430 | } | 433 | } |
| 431 | 434 | ||
| @@ -465,11 +468,21 @@ class PdfArray<T extends PdfDataType> extends PdfDataType { | @@ -465,11 +468,21 @@ class PdfArray<T extends PdfDataType> extends PdfDataType { | ||
| 465 | } | 468 | } |
| 466 | 469 | ||
| 467 | @override | 470 | @override |
| 468 | - void output(PdfStream s) { | 471 | + void output(PdfStream s, [int? indent]) { |
| 472 | + if (indent != null) { | ||
| 473 | + s.putBytes(List<int>.filled(indent, 0x20)); | ||
| 474 | + indent += _kIndentSize; | ||
| 475 | + } | ||
| 469 | s.putString('['); | 476 | s.putString('['); |
| 470 | if (values.isNotEmpty) { | 477 | if (values.isNotEmpty) { |
| 471 | for (var n = 0; n < values.length; n++) { | 478 | for (var n = 0; n < values.length; n++) { |
| 472 | final val = values[n]; | 479 | final val = values[n]; |
| 480 | + if (indent != null) { | ||
| 481 | + s.putByte(0x0a); | ||
| 482 | + if (val is! PdfDict && val is! PdfArray) { | ||
| 483 | + s.putBytes(List<int>.filled(indent, 0x20)); | ||
| 484 | + } | ||
| 485 | + } else { | ||
| 473 | if (n > 0 && | 486 | if (n > 0 && |
| 474 | !(val is PdfName || | 487 | !(val is PdfName || |
| 475 | val is PdfString || | 488 | val is PdfString || |
| @@ -477,8 +490,16 @@ class PdfArray<T extends PdfDataType> extends PdfDataType { | @@ -477,8 +490,16 @@ class PdfArray<T extends PdfDataType> extends PdfDataType { | ||
| 477 | val is PdfDict)) { | 490 | val is PdfDict)) { |
| 478 | s.putByte(0x20); | 491 | s.putByte(0x20); |
| 479 | } | 492 | } |
| 480 | - val.output(s); | ||
| 481 | } | 493 | } |
| 494 | + val.output(s, indent); | ||
| 495 | + } | ||
| 496 | + if (indent != null) { | ||
| 497 | + s.putByte(0x0a); | ||
| 498 | + } | ||
| 499 | + } | ||
| 500 | + if (indent != null) { | ||
| 501 | + indent -= _kIndentSize; | ||
| 502 | + s.putBytes(List<int>.filled(indent, 0x20)); | ||
| 482 | } | 503 | } |
| 483 | s.putString(']'); | 504 | s.putString(']'); |
| 484 | } | 505 | } |
| @@ -544,15 +565,44 @@ class PdfDict<T extends PdfDataType> extends PdfDataType { | @@ -544,15 +565,44 @@ class PdfDict<T extends PdfDataType> extends PdfDataType { | ||
| 544 | } | 565 | } |
| 545 | 566 | ||
| 546 | @override | 567 | @override |
| 547 | - void output(PdfStream s) { | 568 | + void output(PdfStream s, [int? indent]) { |
| 569 | + if (indent != null) { | ||
| 570 | + s.putBytes(List<int>.filled(indent, 0x20)); | ||
| 571 | + } | ||
| 548 | s.putBytes(const <int>[0x3c, 0x3c]); | 572 | s.putBytes(const <int>[0x3c, 0x3c]); |
| 573 | + var len = 0; | ||
| 574 | + var n = 1; | ||
| 575 | + if (indent != null) { | ||
| 576 | + s.putByte(0x0a); | ||
| 577 | + indent += _kIndentSize; | ||
| 578 | + len = values.keys.fold<int>(0, (p, e) => math.max(p, e.length)); | ||
| 579 | + } | ||
| 549 | values.forEach((String k, T v) { | 580 | values.forEach((String k, T v) { |
| 581 | + if (indent != null) { | ||
| 582 | + s.putBytes(List<int>.filled(indent, 0x20)); | ||
| 583 | + n = len - k.length + 1; | ||
| 584 | + } | ||
| 550 | s.putString(k); | 585 | s.putString(k); |
| 586 | + if (indent != null) { | ||
| 587 | + if (v is PdfDict || v is PdfArray) { | ||
| 588 | + s.putByte(0x0a); | ||
| 589 | + } else { | ||
| 590 | + s.putBytes(List<int>.filled(n, 0x20)); | ||
| 591 | + } | ||
| 592 | + } else { | ||
| 551 | if (v is PdfNum || v is PdfBool || v is PdfNull || v is PdfIndirect) { | 593 | if (v is PdfNum || v is PdfBool || v is PdfNull || v is PdfIndirect) { |
| 552 | s.putByte(0x20); | 594 | s.putByte(0x20); |
| 553 | } | 595 | } |
| 554 | - v.output(s); | 596 | + } |
| 597 | + v.output(s, indent); | ||
| 598 | + if (indent != null) { | ||
| 599 | + s.putByte(0x0a); | ||
| 600 | + } | ||
| 555 | }); | 601 | }); |
| 602 | + if (indent != null) { | ||
| 603 | + indent -= _kIndentSize; | ||
| 604 | + s.putBytes(List<int>.filled(indent, 0x20)); | ||
| 605 | + } | ||
| 556 | s.putBytes(const <int>[0x3e, 0x3e]); | 606 | s.putBytes(const <int>[0x3e, 0x3e]); |
| 557 | } | 607 | } |
| 558 | 608 | ||
| @@ -633,7 +683,7 @@ class PdfDictStream extends PdfDict<PdfDataType> { | @@ -633,7 +683,7 @@ class PdfDictStream extends PdfDict<PdfDataType> { | ||
| 633 | final bool compress; | 683 | final bool compress; |
| 634 | 684 | ||
| 635 | @override | 685 | @override |
| 636 | - void output(PdfStream s) { | 686 | + void output(PdfStream s, [int? indent]) { |
| 637 | final _values = PdfDict(values); | 687 | final _values = PdfDict(values); |
| 638 | 688 | ||
| 639 | Uint8List? _data; | 689 | Uint8List? _data; |
| @@ -641,7 +691,7 @@ class PdfDictStream extends PdfDict<PdfDataType> { | @@ -641,7 +691,7 @@ class PdfDictStream extends PdfDict<PdfDataType> { | ||
| 641 | if (_values.containsKey('/Filter')) { | 691 | if (_values.containsKey('/Filter')) { |
| 642 | // The data is already in the right format | 692 | // The data is already in the right format |
| 643 | _data = data; | 693 | _data = data; |
| 644 | - } else if (compress && object.pdfDocument.deflate != null) { | 694 | + } else if (compress && object.pdfDocument.compress) { |
| 645 | // Compress the data | 695 | // Compress the data |
| 646 | final newData = Uint8List.fromList(object.pdfDocument.deflate!(data)); | 696 | final newData = Uint8List.fromList(object.pdfDocument.deflate!(data)); |
| 647 | if (newData.lengthInBytes < data.lengthInBytes) { | 697 | if (newData.lengthInBytes < data.lengthInBytes) { |
| @@ -668,7 +718,10 @@ class PdfDictStream extends PdfDict<PdfDataType> { | @@ -668,7 +718,10 @@ class PdfDictStream extends PdfDict<PdfDataType> { | ||
| 668 | 718 | ||
| 669 | _values['/Length'] = PdfNum(_data.length); | 719 | _values['/Length'] = PdfNum(_data.length); |
| 670 | 720 | ||
| 671 | - _values.output(s); | 721 | + _values.output(s, indent); |
| 722 | + if (indent != null) { | ||
| 723 | + s.putByte(0x0a); | ||
| 724 | + } | ||
| 672 | s.putString('stream\n'); | 725 | s.putString('stream\n'); |
| 673 | s.putBytes(_data); | 726 | s.putBytes(_data); |
| 674 | s.putString('\nendstream\n'); | 727 | s.putString('\nendstream\n'); |
| @@ -681,7 +734,7 @@ class PdfColorType extends PdfDataType { | @@ -681,7 +734,7 @@ class PdfColorType extends PdfDataType { | ||
| 681 | final PdfColor color; | 734 | final PdfColor color; |
| 682 | 735 | ||
| 683 | @override | 736 | @override |
| 684 | - void output(PdfStream s) { | 737 | + void output(PdfStream s, [int? indent]) { |
| 685 | if (color is PdfColorCmyk) { | 738 | if (color is PdfColorCmyk) { |
| 686 | final k = color as PdfColorCmyk; | 739 | final k = color as PdfColorCmyk; |
| 687 | PdfArray.fromNum(<double>[ | 740 | PdfArray.fromNum(<double>[ |
| @@ -689,13 +742,13 @@ class PdfColorType extends PdfDataType { | @@ -689,13 +742,13 @@ class PdfColorType extends PdfDataType { | ||
| 689 | k.magenta, | 742 | k.magenta, |
| 690 | k.yellow, | 743 | k.yellow, |
| 691 | k.black, | 744 | k.black, |
| 692 | - ]).output(s); | 745 | + ]).output(s, indent); |
| 693 | } else { | 746 | } else { |
| 694 | PdfArray.fromNum(<double>[ | 747 | PdfArray.fromNum(<double>[ |
| 695 | color.red, | 748 | color.red, |
| 696 | color.green, | 749 | color.green, |
| 697 | color.blue, | 750 | color.blue, |
| 698 | - ]).output(s); | 751 | + ]).output(s, indent); |
| 699 | } | 752 | } |
| 700 | } | 753 | } |
| 701 | 754 |
| @@ -161,6 +161,8 @@ class PdfDocument { | @@ -161,6 +161,8 @@ class PdfDocument { | ||
| 161 | 161 | ||
| 162 | Uint8List? _documentID; | 162 | Uint8List? _documentID; |
| 163 | 163 | ||
| 164 | + bool get compress => deflate != null; | ||
| 165 | + | ||
| 164 | /// Generates the document ID | 166 | /// Generates the document ID |
| 165 | Uint8List get documentID { | 167 | Uint8List get documentID { |
| 166 | if (_documentID == null) { | 168 | if (_documentID == null) { |
| @@ -203,7 +205,7 @@ class PdfDocument { | @@ -203,7 +205,7 @@ class PdfDocument { | ||
| 203 | 205 | ||
| 204 | /// This writes the document to an OutputStream. | 206 | /// This writes the document to an OutputStream. |
| 205 | Future<void> _write(PdfStream os) async { | 207 | Future<void> _write(PdfStream os) async { |
| 206 | - final pos = PdfOutput(os, version); | 208 | + final pos = PdfOutput(os, version, compress); |
| 207 | 209 | ||
| 208 | // Write each object to the [PdfStream]. We call via the output | 210 | // Write each object to the [PdfStream]. We call via the output |
| 209 | // as that builds the xref table | 211 | // as that builds the xref table |
| @@ -109,6 +109,10 @@ class PdfGraphicState { | @@ -109,6 +109,10 @@ class PdfGraphicState { | ||
| 109 | /// Color transfer function | 109 | /// Color transfer function |
| 110 | final PdfFunction? transferFunction; | 110 | final PdfFunction? transferFunction; |
| 111 | 111 | ||
| 112 | + @override | ||
| 113 | + String toString() => | ||
| 114 | + '$runtimeType fillOpacity:$fillOpacity strokeOpacity:$strokeOpacity blendMode:$blendMode softMask:$softMask transferFunction:$transferFunction'; | ||
| 115 | + | ||
| 112 | PdfDict output() { | 116 | PdfDict output() { |
| 113 | final params = PdfDict(); | 117 | final params = PdfDict(); |
| 114 | 118 |
| @@ -122,33 +122,75 @@ class PdfGraphics { | @@ -122,33 +122,75 @@ class PdfGraphics { | ||
| 122 | /// Draw a surface on the previously defined shape | 122 | /// Draw a surface on the previously defined shape |
| 123 | /// set evenOdd to false to use the nonzero winding number rule to determine the region to fill and to true to use the even-odd rule to determine the region to fill | 123 | /// set evenOdd to false to use the nonzero winding number rule to determine the region to fill and to true to use the even-odd rule to determine the region to fill |
| 124 | void fillPath({bool evenOdd = false}) { | 124 | void fillPath({bool evenOdd = false}) { |
| 125 | + assert(() { | ||
| 126 | + if (!_page.pdfDocument.compress) { | ||
| 127 | + _buf.putComment('fillPath evenOdd:$evenOdd'); | ||
| 128 | + } | ||
| 129 | + return true; | ||
| 130 | + }()); | ||
| 131 | + | ||
| 125 | _buf.putString('f${evenOdd ? '*' : ''}\n'); | 132 | _buf.putString('f${evenOdd ? '*' : ''}\n'); |
| 126 | } | 133 | } |
| 127 | 134 | ||
| 128 | /// Draw the contour of the previously defined shape | 135 | /// Draw the contour of the previously defined shape |
| 129 | void strokePath({bool close = false}) { | 136 | void strokePath({bool close = false}) { |
| 137 | + assert(() { | ||
| 138 | + if (!_page.pdfDocument.compress) { | ||
| 139 | + _buf.putComment('strokePath close:$close'); | ||
| 140 | + } | ||
| 141 | + return true; | ||
| 142 | + }()); | ||
| 143 | + | ||
| 130 | _buf.putString('${close ? 's' : 'S'}\n'); | 144 | _buf.putString('${close ? 's' : 'S'}\n'); |
| 131 | } | 145 | } |
| 132 | 146 | ||
| 133 | /// Close the path with a line | 147 | /// Close the path with a line |
| 134 | void closePath() { | 148 | void closePath() { |
| 149 | + assert(() { | ||
| 150 | + if (!_page.pdfDocument.compress) { | ||
| 151 | + _buf.putComment('closePath'); | ||
| 152 | + } | ||
| 153 | + return true; | ||
| 154 | + }()); | ||
| 155 | + | ||
| 135 | _buf.putString('h\n'); | 156 | _buf.putString('h\n'); |
| 136 | } | 157 | } |
| 137 | 158 | ||
| 138 | /// Create a clipping surface from the previously defined shape, | 159 | /// Create a clipping surface from the previously defined shape, |
| 139 | /// to prevent any further drawing outside | 160 | /// to prevent any further drawing outside |
| 140 | void clipPath({bool evenOdd = false, bool end = true}) { | 161 | void clipPath({bool evenOdd = false, bool end = true}) { |
| 162 | + assert(() { | ||
| 163 | + if (!_page.pdfDocument.compress) { | ||
| 164 | + _buf.putComment('clipPath evenOdd:$evenOdd end:$end'); | ||
| 165 | + } | ||
| 166 | + return true; | ||
| 167 | + }()); | ||
| 168 | + | ||
| 141 | _buf.putString('W${evenOdd ? '*' : ''}${end ? ' n' : ''}\n'); | 169 | _buf.putString('W${evenOdd ? '*' : ''}${end ? ' n' : ''}\n'); |
| 142 | } | 170 | } |
| 143 | 171 | ||
| 144 | /// Draw a surface on the previously defined shape and then draw the contour | 172 | /// Draw a surface on the previously defined shape and then draw the contour |
| 145 | /// set evenOdd to false to use the nonzero winding number rule to determine the region to fill and to true to use the even-odd rule to determine the region to fill | 173 | /// set evenOdd to false to use the nonzero winding number rule to determine the region to fill and to true to use the even-odd rule to determine the region to fill |
| 146 | void fillAndStrokePath({bool evenOdd = false, bool close = false}) { | 174 | void fillAndStrokePath({bool evenOdd = false, bool close = false}) { |
| 175 | + assert(() { | ||
| 176 | + if (!_page.pdfDocument.compress) { | ||
| 177 | + _buf.putComment('fillAndStrokePath evenOdd:$evenOdd close:$close'); | ||
| 178 | + } | ||
| 179 | + return true; | ||
| 180 | + }()); | ||
| 181 | + | ||
| 147 | _buf.putString('${close ? 'b' : 'B'}${evenOdd ? '*' : ''}\n'); | 182 | _buf.putString('${close ? 'b' : 'B'}${evenOdd ? '*' : ''}\n'); |
| 148 | } | 183 | } |
| 149 | 184 | ||
| 150 | /// Apply a shader | 185 | /// Apply a shader |
| 151 | void applyShader(PdfShading shader) { | 186 | void applyShader(PdfShading shader) { |
| 187 | + assert(() { | ||
| 188 | + if (!_page.pdfDocument.compress) { | ||
| 189 | + _buf.putComment('applyShader'); | ||
| 190 | + } | ||
| 191 | + return true; | ||
| 192 | + }()); | ||
| 193 | + | ||
| 152 | // The shader needs to be registered in the page resources | 194 | // The shader needs to be registered in the page resources |
| 153 | _page.addShader(shader); | 195 | _page.addShader(shader); |
| 154 | _buf.putString('${shader.name} sh\n'); | 196 | _buf.putString('${shader.name} sh\n'); |
| @@ -160,6 +202,13 @@ class PdfGraphics { | @@ -160,6 +202,13 @@ class PdfGraphics { | ||
| 160 | /// When using [PdfPage], you can create another fresh Graphics instance, | 202 | /// When using [PdfPage], you can create another fresh Graphics instance, |
| 161 | /// which will draw over this one. | 203 | /// which will draw over this one. |
| 162 | void restoreContext() { | 204 | void restoreContext() { |
| 205 | + assert(() { | ||
| 206 | + if (!_page.pdfDocument.compress) { | ||
| 207 | + _buf.putComment('restoreContext'); | ||
| 208 | + } | ||
| 209 | + return true; | ||
| 210 | + }()); | ||
| 211 | + | ||
| 163 | if (_contextQueue.isNotEmpty) { | 212 | if (_contextQueue.isNotEmpty) { |
| 164 | // restore graphics context | 213 | // restore graphics context |
| 165 | _buf.putString('Q\n'); | 214 | _buf.putString('Q\n'); |
| @@ -169,12 +218,26 @@ class PdfGraphics { | @@ -169,12 +218,26 @@ class PdfGraphics { | ||
| 169 | 218 | ||
| 170 | /// Save the graphc context | 219 | /// Save the graphc context |
| 171 | void saveContext() { | 220 | void saveContext() { |
| 221 | + assert(() { | ||
| 222 | + if (!_page.pdfDocument.compress) { | ||
| 223 | + _buf.putComment('saveContext'); | ||
| 224 | + } | ||
| 225 | + return true; | ||
| 226 | + }()); | ||
| 227 | + | ||
| 172 | _buf.putString('q\n'); | 228 | _buf.putString('q\n'); |
| 173 | _contextQueue.addLast(_context.copy()); | 229 | _contextQueue.addLast(_context.copy()); |
| 174 | } | 230 | } |
| 175 | 231 | ||
| 176 | /// Draws an image onto the page. | 232 | /// Draws an image onto the page. |
| 177 | void drawImage(PdfImage img, double x, double y, [double? w, double? h]) { | 233 | void drawImage(PdfImage img, double x, double y, [double? w, double? h]) { |
| 234 | + assert(() { | ||
| 235 | + if (!_page.pdfDocument.compress) { | ||
| 236 | + _buf.putComment('drawImage x:$x y:$y'); | ||
| 237 | + } | ||
| 238 | + return true; | ||
| 239 | + }()); | ||
| 240 | + | ||
| 178 | w ??= img.width.toDouble(); | 241 | w ??= img.width.toDouble(); |
| 179 | h ??= img.height.toDouble() * w / img.width.toDouble(); | 242 | h ??= img.height.toDouble() * w / img.width.toDouble(); |
| 180 | 243 | ||
| @@ -215,6 +278,13 @@ class PdfGraphics { | @@ -215,6 +278,13 @@ class PdfGraphics { | ||
| 215 | 278 | ||
| 216 | /// Draws a line between two coordinates. | 279 | /// Draws a line between two coordinates. |
| 217 | void drawLine(double x1, double y1, double x2, double y2) { | 280 | void drawLine(double x1, double y1, double x2, double y2) { |
| 281 | + assert(() { | ||
| 282 | + if (!_page.pdfDocument.compress) { | ||
| 283 | + _buf.putComment('drawLine x1:$x1 y1:$y1 x2:$x2 y2:$y2'); | ||
| 284 | + } | ||
| 285 | + return true; | ||
| 286 | + }()); | ||
| 287 | + | ||
| 218 | moveTo(x1, y1); | 288 | moveTo(x1, y1); |
| 219 | lineTo(x2, y2); | 289 | lineTo(x2, y2); |
| 220 | } | 290 | } |
| @@ -224,6 +294,13 @@ class PdfGraphics { | @@ -224,6 +294,13 @@ class PdfGraphics { | ||
| 224 | /// Use clockwise=false to draw the inside of a donnnut | 294 | /// Use clockwise=false to draw the inside of a donnnut |
| 225 | void drawEllipse(double x, double y, double r1, double r2, | 295 | void drawEllipse(double x, double y, double r1, double r2, |
| 226 | {bool clockwise = true}) { | 296 | {bool clockwise = true}) { |
| 297 | + assert(() { | ||
| 298 | + if (!_page.pdfDocument.compress) { | ||
| 299 | + _buf.putComment('drawEllipse x:$x y:$y r1:$r1 r2:$r2'); | ||
| 300 | + } | ||
| 301 | + return true; | ||
| 302 | + }()); | ||
| 303 | + | ||
| 227 | moveTo(x, y - r2); | 304 | moveTo(x, y - r2); |
| 228 | if (clockwise) { | 305 | if (clockwise) { |
| 229 | curveTo(x + _m4 * r1, y - r2, x + r1, y - _m4 * r2, x + r1, y); | 306 | curveTo(x + _m4 * r1, y - r2, x + r1, y - _m4 * r2, x + r1, y); |
| @@ -245,6 +322,13 @@ class PdfGraphics { | @@ -245,6 +322,13 @@ class PdfGraphics { | ||
| 245 | double w, | 322 | double w, |
| 246 | double h, | 323 | double h, |
| 247 | ) { | 324 | ) { |
| 325 | + assert(() { | ||
| 326 | + if (!_page.pdfDocument.compress) { | ||
| 327 | + _buf.putComment('drawRect x:$x y:$y w:$w h:$h'); | ||
| 328 | + } | ||
| 329 | + return true; | ||
| 330 | + }()); | ||
| 331 | + | ||
| 248 | PdfNumList([x, y, w, h]).output(_buf); | 332 | PdfNumList([x, y, w, h]).output(_buf); |
| 249 | _buf.putString(' re\n'); | 333 | _buf.putString(' re\n'); |
| 250 | } | 334 | } |
| @@ -256,6 +340,13 @@ class PdfGraphics { | @@ -256,6 +340,13 @@ class PdfGraphics { | ||
| 256 | 340 | ||
| 257 | /// Draws a Rounded Rectangle | 341 | /// Draws a Rounded Rectangle |
| 258 | void drawRRect(double x, double y, double w, double h, double rv, double rh) { | 342 | void drawRRect(double x, double y, double w, double h, double rv, double rh) { |
| 343 | + assert(() { | ||
| 344 | + if (!_page.pdfDocument.compress) { | ||
| 345 | + _buf.putComment('drawRRect x:$x y:$y w:$w h:$h rv:$rv rh:$rh'); | ||
| 346 | + } | ||
| 347 | + return true; | ||
| 348 | + }()); | ||
| 349 | + | ||
| 259 | moveTo(x, y + rv); | 350 | moveTo(x, y + rv); |
| 260 | curveTo(x, y - _m4 * rv + rv, x - _m4 * rh + rh, y, x + rh, y); | 351 | curveTo(x, y - _m4 * rv + rv, x - _m4 * rh + rh, y, x + rh, y); |
| 261 | lineTo(x + w - rh, y); | 352 | lineTo(x + w - rh, y); |
| @@ -278,6 +369,13 @@ class PdfGraphics { | @@ -278,6 +369,13 @@ class PdfGraphics { | ||
| 278 | PdfTextRenderingMode? mode = PdfTextRenderingMode.fill, | 369 | PdfTextRenderingMode? mode = PdfTextRenderingMode.fill, |
| 279 | double? rise, | 370 | double? rise, |
| 280 | }) { | 371 | }) { |
| 372 | + assert(() { | ||
| 373 | + if (!_page.pdfDocument.compress) { | ||
| 374 | + _buf.putComment('setFont'); | ||
| 375 | + } | ||
| 376 | + return true; | ||
| 377 | + }()); | ||
| 378 | + | ||
| 281 | _buf.putString('${font.name} '); | 379 | _buf.putString('${font.name} '); |
| 282 | PdfNum(size).output(_buf); | 380 | PdfNum(size).output(_buf); |
| 283 | _buf.putString(' Tf\n'); | 381 | _buf.putString(' Tf\n'); |
| @@ -315,6 +413,13 @@ class PdfGraphics { | @@ -315,6 +413,13 @@ class PdfGraphics { | ||
| 315 | PdfTextRenderingMode mode = PdfTextRenderingMode.fill, | 413 | PdfTextRenderingMode mode = PdfTextRenderingMode.fill, |
| 316 | double rise = 0, | 414 | double rise = 0, |
| 317 | }) { | 415 | }) { |
| 416 | + assert(() { | ||
| 417 | + if (!_page.pdfDocument.compress) { | ||
| 418 | + _buf.putComment('drawString x:$x y:$y size:$size "$s"'); | ||
| 419 | + } | ||
| 420 | + return true; | ||
| 421 | + }()); | ||
| 422 | + | ||
| 318 | _page.addFont(font); | 423 | _page.addFont(font); |
| 319 | 424 | ||
| 320 | _buf.putString('BT '); | 425 | _buf.putString('BT '); |
| @@ -332,6 +437,13 @@ class PdfGraphics { | @@ -332,6 +437,13 @@ class PdfGraphics { | ||
| 332 | } | 437 | } |
| 333 | 438 | ||
| 334 | void reset() { | 439 | void reset() { |
| 440 | + assert(() { | ||
| 441 | + if (!_page.pdfDocument.compress) { | ||
| 442 | + _buf.putComment('reset'); | ||
| 443 | + } | ||
| 444 | + return true; | ||
| 445 | + }()); | ||
| 446 | + | ||
| 335 | _buf.putString('0 Tr\n'); | 447 | _buf.putString('0 Tr\n'); |
| 336 | } | 448 | } |
| 337 | 449 | ||
| @@ -343,6 +455,13 @@ class PdfGraphics { | @@ -343,6 +455,13 @@ class PdfGraphics { | ||
| 343 | 455 | ||
| 344 | /// Sets the fill color for drawing | 456 | /// Sets the fill color for drawing |
| 345 | void setFillColor(PdfColor? color) { | 457 | void setFillColor(PdfColor? color) { |
| 458 | + assert(() { | ||
| 459 | + if (!_page.pdfDocument.compress) { | ||
| 460 | + _buf.putComment('setFillColor ${color?.toHex()}'); | ||
| 461 | + } | ||
| 462 | + return true; | ||
| 463 | + }()); | ||
| 464 | + | ||
| 346 | if (color is PdfColorCmyk) { | 465 | if (color is PdfColorCmyk) { |
| 347 | PdfNumList(<double>[color.cyan, color.magenta, color.yellow, color.black]) | 466 | PdfNumList(<double>[color.cyan, color.magenta, color.yellow, color.black]) |
| 348 | .output(_buf); | 467 | .output(_buf); |
| @@ -355,6 +474,13 @@ class PdfGraphics { | @@ -355,6 +474,13 @@ class PdfGraphics { | ||
| 355 | 474 | ||
| 356 | /// Sets the stroke color for drawing | 475 | /// Sets the stroke color for drawing |
| 357 | void setStrokeColor(PdfColor? color) { | 476 | void setStrokeColor(PdfColor? color) { |
| 477 | + assert(() { | ||
| 478 | + if (!_page.pdfDocument.compress) { | ||
| 479 | + _buf.putComment('setStrokeColor ${color?.toHex()}'); | ||
| 480 | + } | ||
| 481 | + return true; | ||
| 482 | + }()); | ||
| 483 | + | ||
| 358 | if (color is PdfColorCmyk) { | 484 | if (color is PdfColorCmyk) { |
| 359 | PdfNumList(<double>[color.cyan, color.magenta, color.yellow, color.black]) | 485 | PdfNumList(<double>[color.cyan, color.magenta, color.yellow, color.black]) |
| 360 | .output(_buf); | 486 | .output(_buf); |
| @@ -367,6 +493,13 @@ class PdfGraphics { | @@ -367,6 +493,13 @@ class PdfGraphics { | ||
| 367 | 493 | ||
| 368 | /// Sets the fill pattern for drawing | 494 | /// Sets the fill pattern for drawing |
| 369 | void setFillPattern(PdfPattern pattern) { | 495 | void setFillPattern(PdfPattern pattern) { |
| 496 | + assert(() { | ||
| 497 | + if (!_page.pdfDocument.compress) { | ||
| 498 | + _buf.putComment('setFillPattern'); | ||
| 499 | + } | ||
| 500 | + return true; | ||
| 501 | + }()); | ||
| 502 | + | ||
| 370 | // The shader needs to be registered in the page resources | 503 | // The shader needs to be registered in the page resources |
| 371 | _page.addPattern(pattern); | 504 | _page.addPattern(pattern); |
| 372 | _buf.putString('/Pattern cs${pattern.name} scn\n'); | 505 | _buf.putString('/Pattern cs${pattern.name} scn\n'); |
| @@ -374,6 +507,13 @@ class PdfGraphics { | @@ -374,6 +507,13 @@ class PdfGraphics { | ||
| 374 | 507 | ||
| 375 | /// Sets the stroke pattern for drawing | 508 | /// Sets the stroke pattern for drawing |
| 376 | void setStrokePattern(PdfPattern pattern) { | 509 | void setStrokePattern(PdfPattern pattern) { |
| 510 | + assert(() { | ||
| 511 | + if (!_page.pdfDocument.compress) { | ||
| 512 | + _buf.putComment('setStrokePattern'); | ||
| 513 | + } | ||
| 514 | + return true; | ||
| 515 | + }()); | ||
| 516 | + | ||
| 377 | // The shader needs to be registered in the page resources | 517 | // The shader needs to be registered in the page resources |
| 378 | _page.addPattern(pattern); | 518 | _page.addPattern(pattern); |
| 379 | _buf.putString('/Pattern CS${pattern.name} SCN\n'); | 519 | _buf.putString('/Pattern CS${pattern.name} SCN\n'); |
| @@ -381,12 +521,26 @@ class PdfGraphics { | @@ -381,12 +521,26 @@ class PdfGraphics { | ||
| 381 | 521 | ||
| 382 | /// Set the graphic state for drawing | 522 | /// Set the graphic state for drawing |
| 383 | void setGraphicState(PdfGraphicState state) { | 523 | void setGraphicState(PdfGraphicState state) { |
| 524 | + assert(() { | ||
| 525 | + if (!_page.pdfDocument.compress) { | ||
| 526 | + _buf.putComment('setGraphicState $state'); | ||
| 527 | + } | ||
| 528 | + return true; | ||
| 529 | + }()); | ||
| 530 | + | ||
| 384 | final name = _page.stateName(state); | 531 | final name = _page.stateName(state); |
| 385 | _buf.putString('$name gs\n'); | 532 | _buf.putString('$name gs\n'); |
| 386 | } | 533 | } |
| 387 | 534 | ||
| 388 | /// Set the transformation Matrix | 535 | /// Set the transformation Matrix |
| 389 | void setTransform(Matrix4 t) { | 536 | void setTransform(Matrix4 t) { |
| 537 | + assert(() { | ||
| 538 | + if (!_page.pdfDocument.compress) { | ||
| 539 | + _buf.putComment('setTransform\n$t'); | ||
| 540 | + } | ||
| 541 | + return true; | ||
| 542 | + }()); | ||
| 543 | + | ||
| 390 | final s = t.storage; | 544 | final s = t.storage; |
| 391 | PdfNumList(<double>[s[0], s[1], s[4], s[5], s[12], s[13]]).output(_buf); | 545 | PdfNumList(<double>[s[0], s[1], s[4], s[5], s[12], s[13]]).output(_buf); |
| 392 | _buf.putString(' cm\n'); | 546 | _buf.putString(' cm\n'); |
| @@ -400,12 +554,26 @@ class PdfGraphics { | @@ -400,12 +554,26 @@ class PdfGraphics { | ||
| 400 | 554 | ||
| 401 | /// This adds a line segment to the current path | 555 | /// This adds a line segment to the current path |
| 402 | void lineTo(double x, double y) { | 556 | void lineTo(double x, double y) { |
| 557 | + assert(() { | ||
| 558 | + if (!_page.pdfDocument.compress) { | ||
| 559 | + _buf.putComment('lineTo x:$x y:$y'); | ||
| 560 | + } | ||
| 561 | + return true; | ||
| 562 | + }()); | ||
| 563 | + | ||
| 403 | PdfNumList([x, y]).output(_buf); | 564 | PdfNumList([x, y]).output(_buf); |
| 404 | _buf.putString(' l\n'); | 565 | _buf.putString(' l\n'); |
| 405 | } | 566 | } |
| 406 | 567 | ||
| 407 | /// This moves the current drawing point. | 568 | /// This moves the current drawing point. |
| 408 | void moveTo(double x, double y) { | 569 | void moveTo(double x, double y) { |
| 570 | + assert(() { | ||
| 571 | + if (!_page.pdfDocument.compress) { | ||
| 572 | + _buf.putComment('moveTo x:$x y:$y'); | ||
| 573 | + } | ||
| 574 | + return true; | ||
| 575 | + }()); | ||
| 576 | + | ||
| 409 | PdfNumList([x, y]).output(_buf); | 577 | PdfNumList([x, y]).output(_buf); |
| 410 | _buf.putString(' m\n'); | 578 | _buf.putString(' m\n'); |
| 411 | } | 579 | } |
| @@ -415,6 +583,13 @@ class PdfGraphics { | @@ -415,6 +583,13 @@ class PdfGraphics { | ||
| 415 | /// and (x2,y2) as the control point at the end of the curve. | 583 | /// and (x2,y2) as the control point at the end of the curve. |
| 416 | void curveTo( | 584 | void curveTo( |
| 417 | double x1, double y1, double x2, double y2, double x3, double y3) { | 585 | double x1, double y1, double x2, double y2, double x3, double y3) { |
| 586 | + assert(() { | ||
| 587 | + if (!_page.pdfDocument.compress) { | ||
| 588 | + _buf.putComment('curveTo x1:$x1 y1:$y1 x2:$x2 y2:$y2 x3:$x3 y3:$y3'); | ||
| 589 | + } | ||
| 590 | + return true; | ||
| 591 | + }()); | ||
| 592 | + | ||
| 418 | PdfNumList([x1, y1, x2, y2, x3, y3]).output(_buf); | 593 | PdfNumList([x1, y1, x2, y2, x3, y3]).output(_buf); |
| 419 | _buf.putString(' c\n'); | 594 | _buf.putString(' c\n'); |
| 420 | } | 595 | } |
| @@ -576,22 +751,50 @@ class PdfGraphics { | @@ -576,22 +751,50 @@ class PdfGraphics { | ||
| 576 | 751 | ||
| 577 | /// Set line starting and ending cap type | 752 | /// Set line starting and ending cap type |
| 578 | void setLineCap(PdfLineCap cap) { | 753 | void setLineCap(PdfLineCap cap) { |
| 754 | + assert(() { | ||
| 755 | + if (!_page.pdfDocument.compress) { | ||
| 756 | + _buf.putComment('setLineCap $cap'); | ||
| 757 | + } | ||
| 758 | + return true; | ||
| 759 | + }()); | ||
| 760 | + | ||
| 579 | _buf.putString('${cap.index} J\n'); | 761 | _buf.putString('${cap.index} J\n'); |
| 580 | } | 762 | } |
| 581 | 763 | ||
| 582 | /// Set line join type | 764 | /// Set line join type |
| 583 | void setLineJoin(PdfLineJoin join) { | 765 | void setLineJoin(PdfLineJoin join) { |
| 766 | + assert(() { | ||
| 767 | + if (!_page.pdfDocument.compress) { | ||
| 768 | + _buf.putComment('setLineJoin $join'); | ||
| 769 | + } | ||
| 770 | + return true; | ||
| 771 | + }()); | ||
| 772 | + | ||
| 584 | _buf.putString('${join.index} j\n'); | 773 | _buf.putString('${join.index} j\n'); |
| 585 | } | 774 | } |
| 586 | 775 | ||
| 587 | /// Set line width | 776 | /// Set line width |
| 588 | void setLineWidth(double width) { | 777 | void setLineWidth(double width) { |
| 778 | + assert(() { | ||
| 779 | + if (!_page.pdfDocument.compress) { | ||
| 780 | + _buf.putComment('setLineWidth $width'); | ||
| 781 | + } | ||
| 782 | + return true; | ||
| 783 | + }()); | ||
| 784 | + | ||
| 589 | PdfNum(width).output(_buf); | 785 | PdfNum(width).output(_buf); |
| 590 | _buf.putString(' w\n'); | 786 | _buf.putString(' w\n'); |
| 591 | } | 787 | } |
| 592 | 788 | ||
| 593 | /// Set line joint miter limit, applies if the | 789 | /// Set line joint miter limit, applies if the |
| 594 | void setMiterLimit(double limit) { | 790 | void setMiterLimit(double limit) { |
| 791 | + assert(() { | ||
| 792 | + if (!_page.pdfDocument.compress) { | ||
| 793 | + _buf.putComment('setMiterLimit $limit'); | ||
| 794 | + } | ||
| 795 | + return true; | ||
| 796 | + }()); | ||
| 797 | + | ||
| 595 | assert(limit >= 1.0); | 798 | assert(limit >= 1.0); |
| 596 | PdfNum(limit).output(_buf); | 799 | PdfNum(limit).output(_buf); |
| 597 | _buf.putString(' M\n'); | 800 | _buf.putString(' M\n'); |
| @@ -602,16 +805,37 @@ class PdfGraphics { | @@ -602,16 +805,37 @@ class PdfGraphics { | ||
| 602 | /// | 805 | /// |
| 603 | /// Example: [2 1] will create a dash pattern with 2 on, 1 off, 2 on, 1 off, ... | 806 | /// Example: [2 1] will create a dash pattern with 2 on, 1 off, 2 on, 1 off, ... |
| 604 | void setLineDashPattern([List<num> array = const <num>[], int phase = 0]) { | 807 | void setLineDashPattern([List<num> array = const <num>[], int phase = 0]) { |
| 808 | + assert(() { | ||
| 809 | + if (!_page.pdfDocument.compress) { | ||
| 810 | + _buf.putComment('setLineDashPattern $array phase:$phase'); | ||
| 811 | + } | ||
| 812 | + return true; | ||
| 813 | + }()); | ||
| 814 | + | ||
| 605 | PdfArray.fromNum(array).output(_buf); | 815 | PdfArray.fromNum(array).output(_buf); |
| 606 | _buf.putString(' $phase d\n'); | 816 | _buf.putString(' $phase d\n'); |
| 607 | } | 817 | } |
| 608 | 818 | ||
| 609 | void markContentBegin(PdfName tag) { | 819 | void markContentBegin(PdfName tag) { |
| 820 | + assert(() { | ||
| 821 | + if (!_page.pdfDocument.compress) { | ||
| 822 | + _buf.putComment('markContentBegin'); | ||
| 823 | + } | ||
| 824 | + return true; | ||
| 825 | + }()); | ||
| 826 | + | ||
| 610 | tag.output(_buf); | 827 | tag.output(_buf); |
| 611 | _buf.putString(' BMC\n'); | 828 | _buf.putString(' BMC\n'); |
| 612 | } | 829 | } |
| 613 | 830 | ||
| 614 | void markContentEnd() { | 831 | void markContentEnd() { |
| 832 | + assert(() { | ||
| 833 | + if (!_page.pdfDocument.compress) { | ||
| 834 | + _buf.putComment('markContentEnd'); | ||
| 835 | + } | ||
| 836 | + return true; | ||
| 837 | + }()); | ||
| 838 | + | ||
| 615 | _buf.putString('EMC\n'); | 839 | _buf.putString('EMC\n'); |
| 616 | } | 840 | } |
| 617 | } | 841 | } |
| @@ -60,11 +60,20 @@ abstract class PdfObject<T extends PdfDataType> { | @@ -60,11 +60,20 @@ abstract class PdfObject<T extends PdfDataType> { | ||
| 60 | /// The write method should call this before writing anything to the | 60 | /// The write method should call this before writing anything to the |
| 61 | /// OutputStream. This will send the standard header for each object. | 61 | /// OutputStream. This will send the standard header for each object. |
| 62 | void _writeStart(PdfStream os) { | 62 | void _writeStart(PdfStream os) { |
| 63 | + assert(() { | ||
| 64 | + if (!pdfDocument.compress) { | ||
| 65 | + os.putComment(''); | ||
| 66 | + os.putComment('-' * 78); | ||
| 67 | + os.putComment('$runtimeType'); | ||
| 68 | + } | ||
| 69 | + return true; | ||
| 70 | + }()); | ||
| 71 | + | ||
| 63 | os.putString('$objser $objgen obj\n'); | 72 | os.putString('$objser $objgen obj\n'); |
| 64 | } | 73 | } |
| 65 | 74 | ||
| 66 | void writeContent(PdfStream os) { | 75 | void writeContent(PdfStream os) { |
| 67 | - params.output(os); | 76 | + params.output(os, pdfDocument.compress ? null : 0); |
| 68 | os.putByte(0x0a); | 77 | os.putByte(0x0a); |
| 69 | } | 78 | } |
| 70 | 79 |
| @@ -37,7 +37,7 @@ class PdfObjectDict extends PdfObject<PdfDict> { | @@ -37,7 +37,7 @@ class PdfObjectDict extends PdfObject<PdfDict> { | ||
| 37 | @override | 37 | @override |
| 38 | void writeContent(PdfStream os) { | 38 | void writeContent(PdfStream os) { |
| 39 | if (params.isNotEmpty) { | 39 | if (params.isNotEmpty) { |
| 40 | - params.output(os); | 40 | + params.output(os, pdfDocument.compress ? null : 0); |
| 41 | os.putByte(0x0a); | 41 | os.putByte(0x0a); |
| 42 | } | 42 | } |
| 43 | } | 43 | } |
| @@ -41,6 +41,6 @@ class PdfObjectStream extends PdfObjectDict { | @@ -41,6 +41,6 @@ class PdfObjectStream extends PdfObjectDict { | ||
| 41 | isBinary: isBinary, | 41 | isBinary: isBinary, |
| 42 | values: params.values, | 42 | values: params.values, |
| 43 | data: buf.output(), | 43 | data: buf.output(), |
| 44 | - ).output(os); | 44 | + ).output(os, pdfDocument.compress ? null : 0); |
| 45 | } | 45 | } |
| 46 | } | 46 | } |
| @@ -62,6 +62,9 @@ class PdfSoftMask { | @@ -62,6 +62,9 @@ class PdfSoftMask { | ||
| 62 | 62 | ||
| 63 | PdfBaseFunction? _tr; | 63 | PdfBaseFunction? _tr; |
| 64 | 64 | ||
| 65 | + @override | ||
| 66 | + String toString() => '$runtimeType'; | ||
| 67 | + | ||
| 65 | PdfDict output() { | 68 | PdfDict output() { |
| 66 | final params = PdfDict({ | 69 | final params = PdfDict({ |
| 67 | '/S': const PdfName('/Luminosity'), | 70 | '/S': const PdfName('/Luminosity'), |
| @@ -34,7 +34,7 @@ class PdfUnicodeCmap extends PdfObjectStream { | @@ -34,7 +34,7 @@ class PdfUnicodeCmap extends PdfObjectStream { | ||
| 34 | cmap.fillRange(1, cmap.length, 0x20); | 34 | cmap.fillRange(1, cmap.length, 0x20); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | - buf.putString('/CIDInit/ProcSet findresource begin\n' | 37 | + buf.putString('/CIDInit/ProcSet\nfindresource begin\n' |
| 38 | '12 dict begin\n' | 38 | '12 dict begin\n' |
| 39 | 'begincmap\n' | 39 | 'begincmap\n' |
| 40 | '/CIDSystemInfo<<\n' | 40 | '/CIDSystemInfo<<\n' |
| @@ -27,7 +27,7 @@ import 'xref.dart'; | @@ -27,7 +27,7 @@ import 'xref.dart'; | ||
| 27 | /// PDF document writer | 27 | /// PDF document writer |
| 28 | class PdfOutput { | 28 | class PdfOutput { |
| 29 | /// This creates a Pdf [PdfStream] | 29 | /// This creates a Pdf [PdfStream] |
| 30 | - PdfOutput(this.os, this.version) { | 30 | + PdfOutput(this.os, this.version, bool compress) { |
| 31 | String v; | 31 | String v; |
| 32 | switch (version) { | 32 | switch (version) { |
| 33 | case PdfVersion.pdf_1_4: | 33 | case PdfVersion.pdf_1_4: |
| @@ -40,7 +40,21 @@ class PdfOutput { | @@ -40,7 +40,21 @@ class PdfOutput { | ||
| 40 | 40 | ||
| 41 | os.putString('%PDF-$v\n'); | 41 | os.putString('%PDF-$v\n'); |
| 42 | os.putBytes(const <int>[0x25, 0xC2, 0xA5, 0xC2, 0xB1, 0xC3, 0xAB, 0x0A]); | 42 | os.putBytes(const <int>[0x25, 0xC2, 0xA5, 0xC2, 0xB1, 0xC3, 0xAB, 0x0A]); |
| 43 | + assert(() { | ||
| 44 | + if (!compress) { | ||
| 45 | + _stopwatch = Stopwatch()..start(); | ||
| 46 | + os.putComment(''); | ||
| 47 | + os.putComment('Verbose dart_pdf'); | ||
| 48 | + os.putComment('Creation date: ${DateTime.now()}'); | ||
| 49 | + _comment = os.offset; | ||
| 50 | + os.putBytes(List<int>.filled(120, 0x20)); | ||
| 43 | } | 51 | } |
| 52 | + return true; | ||
| 53 | + }()); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + late final Stopwatch _stopwatch; | ||
| 57 | + var _comment = 0; | ||
| 44 | 58 | ||
| 45 | /// Pdf version to output | 59 | /// Pdf version to output |
| 46 | final PdfVersion version; | 60 | final PdfVersion version; |
| @@ -129,9 +143,32 @@ class PdfOutput { | @@ -129,9 +143,32 @@ class PdfOutput { | ||
| 129 | os.putByte(0x0a); | 143 | os.putByte(0x0a); |
| 130 | } | 144 | } |
| 131 | 145 | ||
| 146 | + assert(() { | ||
| 147 | + if (!rootID!.pdfDocument.compress) { | ||
| 148 | + os.putComment(''); | ||
| 149 | + os.putComment('-' * 78); | ||
| 150 | + } | ||
| 151 | + return true; | ||
| 152 | + }()); | ||
| 153 | + | ||
| 132 | // the reference to the xref object | 154 | // the reference to the xref object |
| 133 | os.putString('startxref\n$_xref\n%%EOF\n'); | 155 | os.putString('startxref\n$_xref\n%%EOF\n'); |
| 134 | 156 | ||
| 157 | + assert(() { | ||
| 158 | + if (!rootID!.pdfDocument.compress) { | ||
| 159 | + _stopwatch.stop(); | ||
| 160 | + final h = PdfStream(); | ||
| 161 | + h.putComment( | ||
| 162 | + 'Creation time: ${_stopwatch.elapsed.inMicroseconds / Duration.microsecondsPerSecond} seconds'); | ||
| 163 | + h.putComment('File size: ${os.offset} bytes'); | ||
| 164 | + h.putComment('Pages: ${rootID!.pdfDocument.pdfPageList.pages.length}'); | ||
| 165 | + h.putComment('Objects: ${xref.offsets.length}'); | ||
| 166 | + | ||
| 167 | + os.setBytes(_comment, h.output()); | ||
| 168 | + } | ||
| 169 | + return true; | ||
| 170 | + }()); | ||
| 171 | + | ||
| 135 | if (signatureID != null) { | 172 | if (signatureID != null) { |
| 136 | await signatureID!.writeSignature(os); | 173 | await signatureID!.writeSignature(os); |
| 137 | } | 174 | } |
| @@ -68,4 +68,16 @@ class PdfStream { | @@ -68,4 +68,16 @@ class PdfStream { | ||
| 68 | }()); | 68 | }()); |
| 69 | putBytes(s!.codeUnits); | 69 | putBytes(s!.codeUnits); |
| 70 | } | 70 | } |
| 71 | + | ||
| 72 | + void putComment(String s) { | ||
| 73 | + if (s.isEmpty) { | ||
| 74 | + putByte(0x0a); | ||
| 75 | + } else { | ||
| 76 | + for (final l in s.split('\n')) { | ||
| 77 | + if (l.isNotEmpty) { | ||
| 78 | + putBytes('% $l\n'.codeUnits); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | + } | ||
| 71 | } | 83 | } |
| @@ -107,7 +107,7 @@ class PdfXrefTable extends PdfDataType { | @@ -107,7 +107,7 @@ class PdfXrefTable extends PdfDataType { | ||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | @override | 109 | @override |
| 110 | - void output(PdfStream s) { | 110 | + void output(PdfStream s, [int? indent]) { |
| 111 | s.putString('xref\n'); | 111 | s.putString('xref\n'); |
| 112 | 112 | ||
| 113 | // Now scan through the offsets list. They should be in sequence. | 113 | // Now scan through the offsets list. They should be in sequence. |
| @@ -153,8 +153,6 @@ class PdfXrefTable extends PdfDataType { | @@ -153,8 +153,6 @@ class PdfXrefTable extends PdfDataType { | ||
| 153 | // Sort all references | 153 | // Sort all references |
| 154 | offsets.sort((a, b) => a.id.compareTo(b.id)); | 154 | offsets.sort((a, b) => a.id.compareTo(b.id)); |
| 155 | 155 | ||
| 156 | - s.putString('$id 0 obj\n'); | ||
| 157 | - | ||
| 158 | params['/Type'] = const PdfName('/XRef'); | 156 | params['/Type'] = const PdfName('/XRef'); |
| 159 | params['/Size'] = PdfNum(id + 1); | 157 | params['/Size'] = PdfNum(id + 1); |
| 160 | 158 | ||
| @@ -200,12 +198,22 @@ class PdfXrefTable extends PdfDataType { | @@ -200,12 +198,22 @@ class PdfXrefTable extends PdfDataType { | ||
| 200 | } | 198 | } |
| 201 | 199 | ||
| 202 | // Write the object | 200 | // Write the object |
| 201 | + assert(() { | ||
| 202 | + if (!object.pdfDocument.compress) { | ||
| 203 | + s.putComment(''); | ||
| 204 | + s.putComment('-' * 78); | ||
| 205 | + s.putComment('$runtimeType $this'); | ||
| 206 | + } | ||
| 207 | + return true; | ||
| 208 | + }()); | ||
| 209 | + s.putString('$id 0 obj\n'); | ||
| 210 | + | ||
| 203 | PdfDictStream( | 211 | PdfDictStream( |
| 204 | object: object, | 212 | object: object, |
| 205 | data: o.buffer.asUint8List(), | 213 | data: o.buffer.asUint8List(), |
| 206 | isBinary: false, | 214 | isBinary: false, |
| 207 | encrypt: false, | 215 | encrypt: false, |
| 208 | values: params.values, | 216 | values: params.values, |
| 209 | - ).output(s); | 217 | + ).output(s, object.pdfDocument.compress ? null : 0); |
| 210 | } | 218 | } |
| 211 | } | 219 | } |
-
Please register or login to post a comment