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