David PHAM-VAN

Reorganize data types

Showing 57 changed files with 1257 additions and 876 deletions
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 - Add support for deleted objects 11 - Add support for deleted objects
12 - Draw page content only if not empty 12 - Draw page content only if not empty
13 - Fix Page Content 13 - Fix Page Content
  14 +- Reorganize data types
14 15
15 ## 3.9.0 16 ## 3.9.0
16 17
@@ -21,6 +21,8 @@ export 'src/pdf/document_parser.dart'; @@ -21,6 +21,8 @@ export 'src/pdf/document_parser.dart';
21 export 'src/pdf/exif.dart'; 21 export 'src/pdf/exif.dart';
22 export 'src/pdf/font/font_metrics.dart'; 22 export 'src/pdf/font/font_metrics.dart';
23 export 'src/pdf/font/ttf_parser.dart'; 23 export 'src/pdf/font/ttf_parser.dart';
  24 +export 'src/pdf/format/name.dart';
  25 +export 'src/pdf/format/object_base.dart' show DeflateCallback, PdfVersion;
24 export 'src/pdf/graphic_state.dart'; 26 export 'src/pdf/graphic_state.dart';
25 export 'src/pdf/graphics.dart'; 27 export 'src/pdf/graphics.dart';
26 export 'src/pdf/obj/annotation.dart'; 28 export 'src/pdf/obj/annotation.dart';
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 'dart:collection';  
18 -import 'dart:convert';  
19 -import 'dart:math' as math;  
20 -import 'dart:typed_data';  
21 -  
22 -import 'package:meta/meta.dart';  
23 -  
24 -import 'ascii85.dart';  
25 -import 'color.dart';  
26 -import 'obj/object.dart';  
27 -import 'stream.dart';  
28 -  
29 -const _kIndentSize = 2;  
30 -  
31 -abstract class PdfDataType {  
32 - const PdfDataType();  
33 -  
34 - void output(PdfStream s, [int? indent]);  
35 -  
36 - PdfStream _toStream() {  
37 - final s = PdfStream();  
38 - output(s);  
39 - return s;  
40 - }  
41 -  
42 - @override  
43 - String toString() {  
44 - return String.fromCharCodes(_toStream().output());  
45 - }  
46 -  
47 - @visibleForTesting  
48 - Uint8List toList() {  
49 - return _toStream().output();  
50 - }  
51 -}  
52 -  
53 -class PdfBool extends PdfDataType {  
54 - const PdfBool(this.value);  
55 -  
56 - final bool value;  
57 -  
58 - @override  
59 - void output(PdfStream s, [int? indent]) {  
60 - s.putString(value ? 'true' : 'false');  
61 - }  
62 -  
63 - @override  
64 - bool operator ==(Object other) {  
65 - if (other is PdfBool) {  
66 - return value == other.value;  
67 - }  
68 -  
69 - return false;  
70 - }  
71 -  
72 - @override  
73 - int get hashCode => value.hashCode;  
74 -}  
75 -  
76 -class PdfNum extends PdfDataType {  
77 - const PdfNum(this.value)  
78 - : assert(value != double.infinity),  
79 - assert(value != double.negativeInfinity);  
80 -  
81 - static const int precision = 5;  
82 -  
83 - final num value;  
84 -  
85 - @override  
86 - void output(PdfStream s, [int? indent]) {  
87 - assert(!value.isNaN);  
88 - assert(!value.isInfinite);  
89 -  
90 - if (value is int) {  
91 - s.putString(value.toInt().toString());  
92 - } else {  
93 - var r = value.toStringAsFixed(precision);  
94 - if (r.contains('.')) {  
95 - var n = r.length - 1;  
96 - while (r[n] == '0') {  
97 - n--;  
98 - }  
99 - if (r[n] == '.') {  
100 - n--;  
101 - }  
102 - r = r.substring(0, n + 1);  
103 - }  
104 - s.putString(r);  
105 - }  
106 - }  
107 -  
108 - @override  
109 - bool operator ==(Object other) {  
110 - if (other is PdfNum) {  
111 - return value == other.value;  
112 - }  
113 -  
114 - return false;  
115 - }  
116 -  
117 - PdfNum operator |(PdfNum other) {  
118 - return PdfNum(value.toInt() | other.value.toInt());  
119 - }  
120 -  
121 - @override  
122 - int get hashCode => value.hashCode;  
123 -}  
124 -  
125 -class PdfNumList extends PdfDataType {  
126 - const PdfNumList(this.values);  
127 -  
128 - final List<num> values;  
129 -  
130 - @override  
131 - void output(PdfStream s, [int? indent]) {  
132 - for (var n = 0; n < values.length; n++) {  
133 - if (n > 0) {  
134 - s.putByte(0x20);  
135 - }  
136 - PdfNum(values[n]).output(s, indent);  
137 - }  
138 - }  
139 -  
140 - @override  
141 - bool operator ==(Object other) {  
142 - if (other is PdfNumList) {  
143 - return values == other.values;  
144 - }  
145 -  
146 - return false;  
147 - }  
148 -  
149 - @override  
150 - int get hashCode => values.hashCode;  
151 -}  
152 -  
153 -enum PdfStringFormat { binary, literal }  
154 -  
155 -class PdfString extends PdfDataType {  
156 - const PdfString(this.value, [this.format = PdfStringFormat.literal]);  
157 -  
158 - factory PdfString.fromString(String value) {  
159 - return PdfString(_string(value), PdfStringFormat.literal);  
160 - }  
161 -  
162 - factory PdfString.fromStream(PdfStream value,  
163 - [PdfStringFormat format = PdfStringFormat.literal]) {  
164 - return PdfString(value.output(), format);  
165 - }  
166 -  
167 - factory PdfString.fromDate(DateTime date) {  
168 - return PdfString(_date(date));  
169 - }  
170 -  
171 - final Uint8List value;  
172 -  
173 - final PdfStringFormat format;  
174 -  
175 - static Uint8List _string(String value) {  
176 - try {  
177 - return latin1.encode(value);  
178 - } catch (e) {  
179 - return Uint8List.fromList(<int>[0xfe, 0xff] + _encodeUtf16be(value));  
180 - }  
181 - }  
182 -  
183 - static Uint8List _date(DateTime date) {  
184 - final utcDate = date.toUtc();  
185 - final year = utcDate.year.toString().padLeft(4, '0');  
186 - final month = utcDate.month.toString().padLeft(2, '0');  
187 - final day = utcDate.day.toString().padLeft(2, '0');  
188 - final hour = utcDate.hour.toString().padLeft(2, '0');  
189 - final minute = utcDate.minute.toString().padLeft(2, '0');  
190 - final second = utcDate.second.toString().padLeft(2, '0');  
191 - return _string('D:$year$month$day$hour$minute${second}Z');  
192 - }  
193 -  
194 - /// Produce a list of UTF-16BE encoded bytes.  
195 - static List<int> _encodeUtf16be(String str) {  
196 - const unicodeReplacementCharacterCodePoint = 0xfffd;  
197 - const unicodeByteZeroMask = 0xff;  
198 - const unicodeByteOneMask = 0xff00;  
199 - const unicodeValidRangeMax = 0x10ffff;  
200 - const unicodePlaneOneMax = 0xffff;  
201 - const unicodeUtf16ReservedLo = 0xd800;  
202 - const unicodeUtf16ReservedHi = 0xdfff;  
203 - const unicodeUtf16Offset = 0x10000;  
204 - const unicodeUtf16SurrogateUnit0Base = 0xd800;  
205 - const unicodeUtf16SurrogateUnit1Base = 0xdc00;  
206 - const unicodeUtf16HiMask = 0xffc00;  
207 - const unicodeUtf16LoMask = 0x3ff;  
208 -  
209 - final encoding = <int>[];  
210 -  
211 - void add(int unit) {  
212 - encoding.add((unit & unicodeByteOneMask) >> 8);  
213 - encoding.add(unit & unicodeByteZeroMask);  
214 - }  
215 -  
216 - for (final unit in str.codeUnits) {  
217 - if ((unit >= 0 && unit < unicodeUtf16ReservedLo) ||  
218 - (unit > unicodeUtf16ReservedHi && unit <= unicodePlaneOneMax)) {  
219 - add(unit);  
220 - } else if (unit > unicodePlaneOneMax && unit <= unicodeValidRangeMax) {  
221 - final base = unit - unicodeUtf16Offset;  
222 - add(unicodeUtf16SurrogateUnit0Base +  
223 - ((base & unicodeUtf16HiMask) >> 10));  
224 - add(unicodeUtf16SurrogateUnit1Base + (base & unicodeUtf16LoMask));  
225 - } else {  
226 - add(unicodeReplacementCharacterCodePoint);  
227 - }  
228 - }  
229 - return encoding;  
230 - }  
231 -  
232 - /// Escape special characters  
233 - /// \ddd Character code ddd (octal)  
234 - void _putTextBytes(PdfStream s, List<int> b) {  
235 - for (final c in b) {  
236 - switch (c) {  
237 - case 0x0a: // \n Line feed (LF)  
238 - s.putByte(0x5c);  
239 - s.putByte(0x6e);  
240 - break;  
241 - case 0x0d: // \r Carriage return (CR)  
242 - s.putByte(0x5c);  
243 - s.putByte(0x72);  
244 - break;  
245 - case 0x09: // \t Horizontal tab (HT)  
246 - s.putByte(0x5c);  
247 - s.putByte(0x74);  
248 - break;  
249 - case 0x08: // \b Backspace (BS)  
250 - s.putByte(0x5c);  
251 - s.putByte(0x62);  
252 - break;  
253 - case 0x0c: // \f Form feed (FF)  
254 - s.putByte(0x5c);  
255 - s.putByte(0x66);  
256 - break;  
257 - case 0x28: // \( Left parenthesis  
258 - s.putByte(0x5c);  
259 - s.putByte(0x28);  
260 - break;  
261 - case 0x29: // \) Right parenthesis  
262 - s.putByte(0x5c);  
263 - s.putByte(0x29);  
264 - break;  
265 - case 0x5c: // \\ Backslash  
266 - s.putByte(0x5c);  
267 - s.putByte(0x5c);  
268 - break;  
269 - default:  
270 - s.putByte(c);  
271 - }  
272 - }  
273 - }  
274 -  
275 - /// Returns the ASCII/Unicode code unit corresponding to the hexadecimal digit  
276 - /// [digit].  
277 - int _codeUnitForDigit(int digit) =>  
278 - digit < 10 ? digit + 0x30 : digit + 0x61 - 10;  
279 -  
280 - void _output(PdfStream s, Uint8List value) {  
281 - switch (format) {  
282 - case PdfStringFormat.binary:  
283 - s.putByte(0x3c);  
284 - for (final byte in value) {  
285 - s.putByte(_codeUnitForDigit((byte & 0xF0) >> 4));  
286 - s.putByte(_codeUnitForDigit(byte & 0x0F));  
287 - }  
288 - s.putByte(0x3e);  
289 - break;  
290 - case PdfStringFormat.literal:  
291 - s.putByte(40);  
292 - _putTextBytes(s, value);  
293 - s.putByte(41);  
294 - break;  
295 - }  
296 - }  
297 -  
298 - @override  
299 - void output(PdfStream s, [int? indent]) {  
300 - _output(s, value);  
301 - }  
302 -  
303 - @override  
304 - bool operator ==(Object other) {  
305 - if (other is PdfString) {  
306 - return value == other.value;  
307 - }  
308 -  
309 - return false;  
310 - }  
311 -  
312 - @override  
313 - int get hashCode => value.hashCode;  
314 -}  
315 -  
316 -class PdfSecString extends PdfString {  
317 - const PdfSecString(this.object, Uint8List value,  
318 - [PdfStringFormat format = PdfStringFormat.binary])  
319 - : super(value, format);  
320 -  
321 - factory PdfSecString.fromString(  
322 - PdfObject object,  
323 - String value, [  
324 - PdfStringFormat format = PdfStringFormat.literal,  
325 - ]) {  
326 - return PdfSecString(  
327 - object,  
328 - PdfString._string(value),  
329 - format,  
330 - );  
331 - }  
332 -  
333 - factory PdfSecString.fromStream(  
334 - PdfObject object,  
335 - PdfStream value, [  
336 - PdfStringFormat format = PdfStringFormat.literal,  
337 - ]) {  
338 - return PdfSecString(  
339 - object,  
340 - value.output(),  
341 - format,  
342 - );  
343 - }  
344 -  
345 - factory PdfSecString.fromDate(PdfObject object, DateTime date) {  
346 - return PdfSecString(  
347 - object,  
348 - PdfString._date(date),  
349 - PdfStringFormat.literal,  
350 - );  
351 - }  
352 -  
353 - final PdfObject object;  
354 -  
355 - @override  
356 - void output(PdfStream s, [int? indent]) {  
357 - if (object.pdfDocument.encryption == null) {  
358 - return super.output(s, indent);  
359 - }  
360 -  
361 - final enc = object.pdfDocument.encryption!.encrypt(value, object);  
362 - _output(s, enc);  
363 - }  
364 -}  
365 -  
366 -class PdfName extends PdfDataType {  
367 - const PdfName(this.value);  
368 -  
369 - final String value;  
370 -  
371 - @override  
372 - void output(PdfStream s, [int? indent]) {  
373 - assert(value[0] == '/');  
374 - final bytes = <int>[];  
375 - for (final c in value.codeUnits) {  
376 - assert(c < 0xff && c > 0x00);  
377 -  
378 - if (c < 0x21 ||  
379 - c > 0x7E ||  
380 - c == 0x23 ||  
381 - (c == 0x2f && bytes.isNotEmpty) ||  
382 - c == 0x5b ||  
383 - c == 0x5d ||  
384 - c == 0x28 ||  
385 - c == 0x3c ||  
386 - c == 0x3e) {  
387 - bytes.add(0x23);  
388 - final x = c.toRadixString(16).padLeft(2, '0');  
389 - bytes.addAll(x.codeUnits);  
390 - } else {  
391 - bytes.add(c);  
392 - }  
393 - }  
394 - s.putBytes(bytes);  
395 - }  
396 -  
397 - @override  
398 - bool operator ==(Object other) {  
399 - if (other is PdfName) {  
400 - return value == other.value;  
401 - }  
402 -  
403 - return false;  
404 - }  
405 -  
406 - @override  
407 - int get hashCode => value.hashCode;  
408 -}  
409 -  
410 -class PdfNull extends PdfDataType {  
411 - const PdfNull();  
412 -  
413 - @override  
414 - void output(PdfStream s, [int? indent]) {  
415 - s.putString('null');  
416 - }  
417 -  
418 - @override  
419 - bool operator ==(Object other) {  
420 - return other is PdfNull;  
421 - }  
422 -  
423 - @override  
424 - int get hashCode => null.hashCode;  
425 -}  
426 -  
427 -class PdfIndirect extends PdfDataType {  
428 - const PdfIndirect(this.ser, this.gen);  
429 -  
430 - final int ser;  
431 -  
432 - final int gen;  
433 -  
434 - @override  
435 - void output(PdfStream s, [int? indent]) {  
436 - s.putString('$ser $gen R');  
437 - }  
438 -  
439 - @override  
440 - bool operator ==(Object other) {  
441 - if (other is PdfIndirect) {  
442 - return ser == other.ser && gen == other.gen;  
443 - }  
444 -  
445 - return false;  
446 - }  
447 -  
448 - @override  
449 - int get hashCode => ser.hashCode + gen.hashCode;  
450 -}  
451 -  
452 -class PdfArray<T extends PdfDataType> extends PdfDataType {  
453 - PdfArray([Iterable<T>? values]) {  
454 - if (values != null) {  
455 - this.values.addAll(values);  
456 - }  
457 - }  
458 -  
459 - static PdfArray<PdfIndirect> fromObjects(List<PdfObject> objects) {  
460 - return PdfArray(  
461 - objects.map<PdfIndirect>((PdfObject e) => e.ref()).toList());  
462 - }  
463 -  
464 - static PdfArray<PdfNum> fromNum(List<num> list) {  
465 - return PdfArray(list.map<PdfNum>((num e) => PdfNum(e)).toList());  
466 - }  
467 -  
468 - final List<T> values = <T>[];  
469 -  
470 - void add(T v) {  
471 - values.add(v);  
472 - }  
473 -  
474 - @override  
475 - void output(PdfStream s, [int? indent]) {  
476 - if (indent != null) {  
477 - s.putBytes(List<int>.filled(indent, 0x20));  
478 - indent += _kIndentSize;  
479 - }  
480 - s.putString('[');  
481 - if (values.isNotEmpty) {  
482 - for (var n = 0; n < values.length; n++) {  
483 - final val = values[n];  
484 - if (indent != null) {  
485 - s.putByte(0x0a);  
486 - if (val is! PdfDict && val is! PdfArray) {  
487 - s.putBytes(List<int>.filled(indent, 0x20));  
488 - }  
489 - } else {  
490 - if (n > 0 &&  
491 - !(val is PdfName ||  
492 - val is PdfString ||  
493 - val is PdfArray ||  
494 - val is PdfDict)) {  
495 - s.putByte(0x20);  
496 - }  
497 - }  
498 - val.output(s, indent);  
499 - }  
500 - if (indent != null) {  
501 - s.putByte(0x0a);  
502 - }  
503 - }  
504 - if (indent != null) {  
505 - indent -= _kIndentSize;  
506 - s.putBytes(List<int>.filled(indent, 0x20));  
507 - }  
508 - s.putString(']');  
509 - }  
510 -  
511 - /// Make all values unique, preserving the order  
512 - void uniq() {  
513 - if (values.length <= 1) {  
514 - return;  
515 - }  
516 -  
517 - // ignore: prefer_collection_literals  
518 - final uniques = LinkedHashMap<T, bool>();  
519 - for (final s in values) {  
520 - uniques[s] = true;  
521 - }  
522 - values.clear();  
523 - values.addAll(uniques.keys);  
524 - }  
525 -  
526 - @override  
527 - bool operator ==(Object other) {  
528 - if (other is PdfArray) {  
529 - return values == other.values;  
530 - }  
531 -  
532 - return false;  
533 - }  
534 -  
535 - bool get isEmpty => values.isEmpty;  
536 -  
537 - bool get isNotEmpty => values.isNotEmpty;  
538 -  
539 - @override  
540 - int get hashCode => values.hashCode;  
541 -}  
542 -  
543 -class PdfDict<T extends PdfDataType> extends PdfDataType {  
544 - factory PdfDict([Map<String, T>? values]) {  
545 - final _values = <String, T>{};  
546 - if (values != null) {  
547 - _values.addAll(values);  
548 - }  
549 - return PdfDict.values(_values);  
550 - }  
551 -  
552 - const PdfDict.values([this.values = const {}]);  
553 -  
554 - static PdfDict<PdfIndirect> fromObjectMap(Map<String, PdfObject> objects) {  
555 - return PdfDict(  
556 - objects.map<String, PdfIndirect>(  
557 - (String key, PdfObject value) =>  
558 - MapEntry<String, PdfIndirect>(key, value.ref()),  
559 - ),  
560 - );  
561 - }  
562 -  
563 - final Map<String, T> values;  
564 -  
565 - bool get isNotEmpty => values.isNotEmpty;  
566 -  
567 - operator []=(String k, T v) {  
568 - values[k] = v;  
569 - }  
570 -  
571 - T? operator [](String k) {  
572 - return values[k];  
573 - }  
574 -  
575 - @override  
576 - void output(PdfStream s, [int? indent]) {  
577 - if (indent != null) {  
578 - s.putBytes(List<int>.filled(indent, 0x20));  
579 - }  
580 - s.putBytes(const <int>[0x3c, 0x3c]);  
581 - var len = 0;  
582 - var n = 1;  
583 - if (indent != null) {  
584 - s.putByte(0x0a);  
585 - indent += _kIndentSize;  
586 - len = values.keys.fold<int>(0, (p, e) => math.max(p, e.length));  
587 - }  
588 - values.forEach((String k, T v) {  
589 - if (indent != null) {  
590 - s.putBytes(List<int>.filled(indent, 0x20));  
591 - n = len - k.length + 1;  
592 - }  
593 - s.putString(k);  
594 - if (indent != null) {  
595 - if (v is PdfDict || v is PdfArray) {  
596 - s.putByte(0x0a);  
597 - } else {  
598 - s.putBytes(List<int>.filled(n, 0x20));  
599 - }  
600 - } else {  
601 - if (v is PdfNum || v is PdfBool || v is PdfNull || v is PdfIndirect) {  
602 - s.putByte(0x20);  
603 - }  
604 - }  
605 - v.output(s, indent);  
606 - if (indent != null) {  
607 - s.putByte(0x0a);  
608 - }  
609 - });  
610 - if (indent != null) {  
611 - indent -= _kIndentSize;  
612 - s.putBytes(List<int>.filled(indent, 0x20));  
613 - }  
614 - s.putBytes(const <int>[0x3e, 0x3e]);  
615 - }  
616 -  
617 - bool containsKey(String key) {  
618 - return values.containsKey(key);  
619 - }  
620 -  
621 - void merge(PdfDict<T> other) {  
622 - for (final key in other.values.keys) {  
623 - final value = other[key]!;  
624 - final current = values[key];  
625 - if (current == null) {  
626 - values[key] = value;  
627 - } else if (value is PdfArray && current is PdfArray) {  
628 - current.values.addAll(value.values);  
629 - current.uniq();  
630 - } else if (value is PdfDict && current is PdfDict) {  
631 - current.merge(value);  
632 - } else {  
633 - values[key] = value;  
634 - }  
635 - }  
636 - }  
637 -  
638 - void addAll(PdfDict<T> other) {  
639 - values.addAll(other.values);  
640 - }  
641 -  
642 - @override  
643 - bool operator ==(Object other) {  
644 - if (other is PdfDict) {  
645 - return values == other.values;  
646 - }  
647 -  
648 - return false;  
649 - }  
650 -  
651 - @override  
652 - int get hashCode => values.hashCode;  
653 -}  
654 -  
655 -class PdfDictStream extends PdfDict<PdfDataType> {  
656 - factory PdfDictStream({  
657 - required PdfObject object,  
658 - Map<String, PdfDataType>? values,  
659 - Uint8List? data,  
660 - bool isBinary = false,  
661 - bool encrypt = true,  
662 - bool compress = true,  
663 - }) {  
664 - return PdfDictStream.values(  
665 - object: object,  
666 - values: values ?? {},  
667 - data: data ?? Uint8List(0),  
668 - encrypt: encrypt,  
669 - compress: compress,  
670 - isBinary: isBinary,  
671 - );  
672 - }  
673 -  
674 - PdfDictStream.values({  
675 - required this.object,  
676 - required Map<String, PdfDataType> values,  
677 - required this.data,  
678 - this.isBinary = false,  
679 - this.encrypt = true,  
680 - this.compress = true,  
681 - }) : super.values(values);  
682 -  
683 - Uint8List data;  
684 -  
685 - final PdfObject object;  
686 -  
687 - final bool isBinary;  
688 -  
689 - final bool encrypt;  
690 -  
691 - final bool compress;  
692 -  
693 - @override  
694 - void output(PdfStream s, [int? indent]) {  
695 - final _values = PdfDict(values);  
696 -  
697 - Uint8List? _data;  
698 -  
699 - if (_values.containsKey('/Filter')) {  
700 - // The data is already in the right format  
701 - _data = data;  
702 - } else if (compress && object.pdfDocument.compress) {  
703 - // Compress the data  
704 - final newData = Uint8List.fromList(object.pdfDocument.deflate!(data));  
705 - if (newData.lengthInBytes < data.lengthInBytes) {  
706 - _values['/Filter'] = const PdfName('/FlateDecode');  
707 - _data = newData;  
708 - }  
709 - }  
710 -  
711 - if (_data == null) {  
712 - if (isBinary) {  
713 - // This is an Ascii85 stream  
714 - final e = Ascii85Encoder();  
715 - _data = e.convert(data);  
716 - _values['/Filter'] = const PdfName('/ASCII85Decode');  
717 - } else {  
718 - // This is a non-deflated stream  
719 - _data = data;  
720 - }  
721 - }  
722 -  
723 - if (encrypt && object.pdfDocument.encryption != null) {  
724 - _data = object.pdfDocument.encryption!.encrypt(_data, object);  
725 - }  
726 -  
727 - _values['/Length'] = PdfNum(_data.length);  
728 -  
729 - _values.output(s, indent);  
730 - if (indent != null) {  
731 - s.putByte(0x0a);  
732 - }  
733 - s.putString('stream\n');  
734 - s.putBytes(_data);  
735 - s.putString('\nendstream\n');  
736 - }  
737 -}  
738 -  
739 -class PdfColorType extends PdfDataType {  
740 - const PdfColorType(this.color);  
741 -  
742 - final PdfColor color;  
743 -  
744 - @override  
745 - void output(PdfStream s, [int? indent]) {  
746 - if (color is PdfColorCmyk) {  
747 - final k = color as PdfColorCmyk;  
748 - PdfArray.fromNum(<double>[  
749 - k.cyan,  
750 - k.magenta,  
751 - k.yellow,  
752 - k.black,  
753 - ]).output(s, indent);  
754 - } else {  
755 - PdfArray.fromNum(<double>[  
756 - color.red,  
757 - color.green,  
758 - color.blue,  
759 - ]).output(s, indent);  
760 - }  
761 - }  
762 -  
763 - @override  
764 - bool operator ==(Object other) {  
765 - if (other is PdfColorType) {  
766 - return color == other.color;  
767 - }  
768 -  
769 - return false;  
770 - }  
771 -  
772 - @override  
773 - int get hashCode => color.hashCode;  
774 -}  
@@ -20,6 +20,9 @@ import 'dart:typed_data'; @@ -20,6 +20,9 @@ import 'dart:typed_data';
20 import 'package:crypto/crypto.dart'; 20 import 'package:crypto/crypto.dart';
21 21
22 import 'document_parser.dart'; 22 import 'document_parser.dart';
  23 +import 'format/object_base.dart';
  24 +import 'format/stream.dart';
  25 +import 'format/xref.dart';
23 import 'graphic_state.dart'; 26 import 'graphic_state.dart';
24 import 'io/vm.dart' if (dart.library.js) 'io/js.dart'; 27 import 'io/vm.dart' if (dart.library.js) 'io/js.dart';
25 import 'obj/catalog.dart'; 28 import 'obj/catalog.dart';
@@ -34,17 +37,6 @@ import 'obj/page_label.dart'; @@ -34,17 +37,6 @@ import 'obj/page_label.dart';
34 import 'obj/page_list.dart'; 37 import 'obj/page_list.dart';
35 import 'obj/signature.dart'; 38 import 'obj/signature.dart';
36 import 'output.dart'; 39 import 'output.dart';
37 -import 'stream.dart';  
38 -import 'xref.dart';  
39 -  
40 -/// PDF version to generate  
41 -enum PdfVersion {  
42 - /// PDF 1.4  
43 - pdf_1_4,  
44 -  
45 - /// PDF 1.5 to 1.7  
46 - pdf_1_5,  
47 -}  
48 40
49 /// Display hint for the PDF viewer 41 /// Display hint for the PDF viewer
50 enum PdfPageMode { 42 enum PdfPageMode {
@@ -66,9 +58,6 @@ enum PdfPageMode { @@ -66,9 +58,6 @@ enum PdfPageMode {
66 fullscreen 58 fullscreen
67 } 59 }
68 60
69 -/// Callback used to compress the data  
70 -typedef DeflateCallback = List<int> Function(List<int> data);  
71 -  
72 /// This class is the base of the Pdf generator. A [PdfDocument] class is 61 /// This class is the base of the Pdf generator. A [PdfDocument] class is
73 /// created for a document, and each page, object, annotation, 62 /// created for a document, and each page, object, annotation,
74 /// etc is added to the document. 63 /// etc is added to the document.
@@ -163,6 +152,7 @@ class PdfDocument { @@ -163,6 +152,7 @@ class PdfDocument {
163 152
164 bool get compress => deflate != null; 153 bool get compress => deflate != null;
165 154
  155 + /// Output a PDF document with comments and formatted data
166 final bool verbose; 156 final bool verbose;
167 157
168 /// Generates the document ID 158 /// Generates the document ID
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 import 'dart:typed_data'; 17 import 'dart:typed_data';
18 18
19 import 'document.dart'; 19 import 'document.dart';
  20 +import 'format/object_base.dart';
20 21
21 /// Base class for loading an existing PDF document. 22 /// Base class for loading an existing PDF document.
22 abstract class PdfDocumentParserBase { 23 abstract class PdfDocumentParserBase {
  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 'dart:collection';
  18 +
  19 +import '../color.dart';
  20 +import 'base.dart';
  21 +import 'dict.dart';
  22 +import 'indirect.dart';
  23 +import 'name.dart';
  24 +import 'num.dart';
  25 +import 'object_base.dart';
  26 +import 'stream.dart';
  27 +import 'string.dart';
  28 +
  29 +class PdfArray<T extends PdfDataType> extends PdfDataType {
  30 + PdfArray([Iterable<T>? values]) {
  31 + if (values != null) {
  32 + this.values.addAll(values);
  33 + }
  34 + }
  35 +
  36 + static PdfArray<PdfIndirect> fromObjects(List<PdfObjectBase> objects) {
  37 + return PdfArray(objects.map<PdfIndirect>((e) => e.ref()).toList());
  38 + }
  39 +
  40 + static PdfArray<PdfNum> fromNum(List<num> list) {
  41 + return PdfArray(list.map<PdfNum>((num e) => PdfNum(e)).toList());
  42 + }
  43 +
  44 + static PdfArray fromColor(PdfColor color) {
  45 + if (color is PdfColorCmyk) {
  46 + return PdfArray.fromNum(<double>[
  47 + color.cyan,
  48 + color.magenta,
  49 + color.yellow,
  50 + color.black,
  51 + ]);
  52 + } else {
  53 + return PdfArray.fromNum(<double>[
  54 + color.red,
  55 + color.green,
  56 + color.blue,
  57 + ]);
  58 + }
  59 + }
  60 +
  61 + final List<T> values = <T>[];
  62 +
  63 + void add(T v) {
  64 + values.add(v);
  65 + }
  66 +
  67 + @override
  68 + void output(PdfStream s, [int? indent]) {
  69 + if (indent != null) {
  70 + s.putBytes(List<int>.filled(indent, 0x20));
  71 + indent += kIndentSize;
  72 + }
  73 + s.putString('[');
  74 + if (values.isNotEmpty) {
  75 + for (var n = 0; n < values.length; n++) {
  76 + final val = values[n];
  77 + if (indent != null) {
  78 + s.putByte(0x0a);
  79 + if (val is! PdfDict && val is! PdfArray) {
  80 + s.putBytes(List<int>.filled(indent, 0x20));
  81 + }
  82 + } else {
  83 + if (n > 0 &&
  84 + !(val is PdfName ||
  85 + val is PdfString ||
  86 + val is PdfArray ||
  87 + val is PdfDict)) {
  88 + s.putByte(0x20);
  89 + }
  90 + }
  91 + val.output(s, indent);
  92 + }
  93 + if (indent != null) {
  94 + s.putByte(0x0a);
  95 + }
  96 + }
  97 + if (indent != null) {
  98 + indent -= kIndentSize;
  99 + s.putBytes(List<int>.filled(indent, 0x20));
  100 + }
  101 + s.putString(']');
  102 + }
  103 +
  104 + /// Make all values unique, preserving the order
  105 + void uniq() {
  106 + if (values.length <= 1) {
  107 + return;
  108 + }
  109 +
  110 + // ignore: prefer_collection_literals
  111 + final uniques = LinkedHashMap<T, bool>();
  112 + for (final s in values) {
  113 + uniques[s] = true;
  114 + }
  115 + values.clear();
  116 + values.addAll(uniques.keys);
  117 + }
  118 +
  119 + @override
  120 + bool operator ==(Object other) {
  121 + if (other is PdfArray) {
  122 + return values == other.values;
  123 + }
  124 +
  125 + return false;
  126 + }
  127 +
  128 + bool get isEmpty => values.isEmpty;
  129 +
  130 + bool get isNotEmpty => values.isNotEmpty;
  131 +
  132 + @override
  133 + int get hashCode => values.hashCode;
  134 +}
  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 'dart:typed_data';
  18 +
  19 +import 'package:meta/meta.dart';
  20 +
  21 +import 'stream.dart';
  22 +
  23 +const kIndentSize = 2;
  24 +
  25 +abstract class PdfDataType {
  26 + const PdfDataType();
  27 +
  28 + void output(PdfStream s, [int? indent]);
  29 +
  30 + PdfStream _toStream() {
  31 + final s = PdfStream();
  32 + output(s);
  33 + return s;
  34 + }
  35 +
  36 + @override
  37 + String toString() {
  38 + return String.fromCharCodes(_toStream().output());
  39 + }
  40 +
  41 + @visibleForTesting
  42 + Uint8List toList() {
  43 + return _toStream().output();
  44 + }
  45 +}
  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 'base.dart';
  18 +import 'stream.dart';
  19 +
  20 +class PdfBool extends PdfDataType {
  21 + const PdfBool(this.value);
  22 +
  23 + final bool value;
  24 +
  25 + @override
  26 + void output(PdfStream s, [int? indent]) {
  27 + s.putString(value ? 'true' : 'false');
  28 + }
  29 +
  30 + @override
  31 + bool operator ==(Object other) {
  32 + if (other is PdfBool) {
  33 + return value == other.value;
  34 + }
  35 +
  36 + return false;
  37 + }
  38 +
  39 + @override
  40 + int get hashCode => value.hashCode;
  41 +}
  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 'dart:math' as math;
  18 +
  19 +import 'array.dart';
  20 +import 'base.dart';
  21 +import 'bool.dart';
  22 +import 'indirect.dart';
  23 +import 'null.dart';
  24 +import 'num.dart';
  25 +import 'object_base.dart';
  26 +import 'stream.dart';
  27 +
  28 +class PdfDict<T extends PdfDataType> extends PdfDataType {
  29 + factory PdfDict([Map<String, T>? values]) {
  30 + final _values = <String, T>{};
  31 + if (values != null) {
  32 + _values.addAll(values);
  33 + }
  34 + return PdfDict.values(_values);
  35 + }
  36 +
  37 + const PdfDict.values([this.values = const {}]);
  38 +
  39 + static PdfDict<PdfIndirect> fromObjectMap(
  40 + Map<String, PdfObjectBase> objects) {
  41 + return PdfDict(
  42 + objects.map<String, PdfIndirect>(
  43 + (key, value) => MapEntry<String, PdfIndirect>(key, value.ref()),
  44 + ),
  45 + );
  46 + }
  47 +
  48 + final Map<String, T> values;
  49 +
  50 + bool get isNotEmpty => values.isNotEmpty;
  51 +
  52 + operator []=(String k, T v) {
  53 + values[k] = v;
  54 + }
  55 +
  56 + T? operator [](String k) {
  57 + return values[k];
  58 + }
  59 +
  60 + @override
  61 + void output(PdfStream s, [int? indent]) {
  62 + if (indent != null) {
  63 + s.putBytes(List<int>.filled(indent, 0x20));
  64 + }
  65 + s.putBytes(const <int>[0x3c, 0x3c]);
  66 + var len = 0;
  67 + var n = 1;
  68 + if (indent != null) {
  69 + s.putByte(0x0a);
  70 + indent += kIndentSize;
  71 + len = values.keys.fold<int>(0, (p, e) => math.max(p, e.length));
  72 + }
  73 + values.forEach((String k, T v) {
  74 + if (indent != null) {
  75 + s.putBytes(List<int>.filled(indent, 0x20));
  76 + n = len - k.length + 1;
  77 + }
  78 + s.putString(k);
  79 + if (indent != null) {
  80 + if (v is PdfDict || v is PdfArray) {
  81 + s.putByte(0x0a);
  82 + } else {
  83 + s.putBytes(List<int>.filled(n, 0x20));
  84 + }
  85 + } else {
  86 + if (v is PdfNum || v is PdfBool || v is PdfNull || v is PdfIndirect) {
  87 + s.putByte(0x20);
  88 + }
  89 + }
  90 + v.output(s, indent);
  91 + if (indent != null) {
  92 + s.putByte(0x0a);
  93 + }
  94 + });
  95 + if (indent != null) {
  96 + indent -= kIndentSize;
  97 + s.putBytes(List<int>.filled(indent, 0x20));
  98 + }
  99 + s.putBytes(const <int>[0x3e, 0x3e]);
  100 + }
  101 +
  102 + bool containsKey(String key) {
  103 + return values.containsKey(key);
  104 + }
  105 +
  106 + void merge(PdfDict<T> other) {
  107 + for (final key in other.values.keys) {
  108 + final value = other[key]!;
  109 + final current = values[key];
  110 + if (current == null) {
  111 + values[key] = value;
  112 + } else if (value is PdfArray && current is PdfArray) {
  113 + current.values.addAll(value.values);
  114 + current.uniq();
  115 + } else if (value is PdfDict && current is PdfDict) {
  116 + current.merge(value);
  117 + } else {
  118 + values[key] = value;
  119 + }
  120 + }
  121 + }
  122 +
  123 + void addAll(PdfDict<T> other) {
  124 + values.addAll(other.values);
  125 + }
  126 +
  127 + @override
  128 + bool operator ==(Object other) {
  129 + if (other is PdfDict) {
  130 + return values == other.values;
  131 + }
  132 +
  133 + return false;
  134 + }
  135 +
  136 + @override
  137 + int get hashCode => values.hashCode;
  138 +}
  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 'dart:typed_data';
  18 +
  19 +import 'ascii85.dart';
  20 +import 'base.dart';
  21 +import 'dict.dart';
  22 +import 'name.dart';
  23 +import 'num.dart';
  24 +import 'object_base.dart';
  25 +import 'stream.dart';
  26 +
  27 +class PdfDictStream extends PdfDict<PdfDataType> {
  28 + factory PdfDictStream({
  29 + required PdfObjectBase object,
  30 + Map<String, PdfDataType>? values,
  31 + Uint8List? data,
  32 + bool isBinary = false,
  33 + bool encrypt = true,
  34 + bool compress = true,
  35 + }) {
  36 + return PdfDictStream.values(
  37 + object: object,
  38 + values: values ?? {},
  39 + data: data ?? Uint8List(0),
  40 + encrypt: encrypt,
  41 + compress: compress,
  42 + isBinary: isBinary,
  43 + );
  44 + }
  45 +
  46 + PdfDictStream.values({
  47 + required this.object,
  48 + required Map<String, PdfDataType> values,
  49 + required this.data,
  50 + this.isBinary = false,
  51 + this.encrypt = true,
  52 + this.compress = true,
  53 + }) : super.values(values);
  54 +
  55 + Uint8List data;
  56 +
  57 + final PdfObjectBase object;
  58 +
  59 + final bool isBinary;
  60 +
  61 + final bool encrypt;
  62 +
  63 + final bool compress;
  64 +
  65 + @override
  66 + void output(PdfStream s, [int? indent]) {
  67 + final _values = PdfDict(values);
  68 +
  69 + Uint8List? _data;
  70 +
  71 + if (_values.containsKey('/Filter')) {
  72 + // The data is already in the right format
  73 + _data = data;
  74 + } else if (compress && object.deflate != null) {
  75 + // Compress the data
  76 + final newData = Uint8List.fromList(object.deflate!(data));
  77 + if (newData.lengthInBytes < data.lengthInBytes) {
  78 + _values['/Filter'] = const PdfName('/FlateDecode');
  79 + _data = newData;
  80 + }
  81 + }
  82 +
  83 + if (_data == null) {
  84 + if (isBinary) {
  85 + // This is an Ascii85 stream
  86 + final e = Ascii85Encoder();
  87 + _data = e.convert(data);
  88 + _values['/Filter'] = const PdfName('/ASCII85Decode');
  89 + } else {
  90 + // This is a non-deflated stream
  91 + _data = data;
  92 + }
  93 + }
  94 +
  95 + if (encrypt && object.encryptCallback != null) {
  96 + _data = object.encryptCallback!(_data, object);
  97 + }
  98 +
  99 + _values['/Length'] = PdfNum(_data.length);
  100 +
  101 + _values.output(s, indent);
  102 + if (indent != null) {
  103 + s.putByte(0x0a);
  104 + }
  105 + s.putString('stream\n');
  106 + s.putBytes(_data);
  107 + s.putString('\nendstream\n');
  108 + }
  109 +}
  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 'base.dart';
  18 +import 'stream.dart';
  19 +
  20 +class PdfIndirect extends PdfDataType {
  21 + const PdfIndirect(this.ser, this.gen);
  22 +
  23 + final int ser;
  24 +
  25 + final int gen;
  26 +
  27 + @override
  28 + void output(PdfStream s, [int? indent]) {
  29 + s.putString('$ser $gen R');
  30 + }
  31 +
  32 + @override
  33 + bool operator ==(Object other) {
  34 + if (other is PdfIndirect) {
  35 + return ser == other.ser && gen == other.gen;
  36 + }
  37 +
  38 + return false;
  39 + }
  40 +
  41 + @override
  42 + int get hashCode => ser.hashCode + gen.hashCode;
  43 +}
  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 'base.dart';
  18 +import 'stream.dart';
  19 +
  20 +class PdfName extends PdfDataType {
  21 + const PdfName(this.value);
  22 +
  23 + final String value;
  24 +
  25 + @override
  26 + void output(PdfStream s, [int? indent]) {
  27 + assert(value[0] == '/');
  28 + final bytes = <int>[];
  29 + for (final c in value.codeUnits) {
  30 + assert(c < 0xff && c > 0x00);
  31 +
  32 + if (c < 0x21 ||
  33 + c > 0x7E ||
  34 + c == 0x23 ||
  35 + (c == 0x2f && bytes.isNotEmpty) ||
  36 + c == 0x5b ||
  37 + c == 0x5d ||
  38 + c == 0x28 ||
  39 + c == 0x3c ||
  40 + c == 0x3e) {
  41 + bytes.add(0x23);
  42 + final x = c.toRadixString(16).padLeft(2, '0');
  43 + bytes.addAll(x.codeUnits);
  44 + } else {
  45 + bytes.add(c);
  46 + }
  47 + }
  48 + s.putBytes(bytes);
  49 + }
  50 +
  51 + @override
  52 + bool operator ==(Object other) {
  53 + if (other is PdfName) {
  54 + return value == other.value;
  55 + }
  56 +
  57 + return false;
  58 + }
  59 +
  60 + @override
  61 + int get hashCode => value.hashCode;
  62 +}
  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 'base.dart';
  18 +import 'stream.dart';
  19 +
  20 +class PdfNull extends PdfDataType {
  21 + const PdfNull();
  22 +
  23 + @override
  24 + void output(PdfStream s, [int? indent]) {
  25 + s.putString('null');
  26 + }
  27 +
  28 + @override
  29 + bool operator ==(Object other) {
  30 + return other is PdfNull;
  31 + }
  32 +
  33 + @override
  34 + int get hashCode => null.hashCode;
  35 +}
  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 'base.dart';
  18 +import 'stream.dart';
  19 +
  20 +class PdfNum extends PdfDataType {
  21 + const PdfNum(this.value)
  22 + : assert(value != double.infinity),
  23 + assert(value != double.negativeInfinity);
  24 +
  25 + static const int precision = 5;
  26 +
  27 + final num value;
  28 +
  29 + @override
  30 + void output(PdfStream s, [int? indent]) {
  31 + assert(!value.isNaN);
  32 + assert(!value.isInfinite);
  33 +
  34 + if (value is int) {
  35 + s.putString(value.toInt().toString());
  36 + } else {
  37 + var r = value.toStringAsFixed(precision);
  38 + if (r.contains('.')) {
  39 + var n = r.length - 1;
  40 + while (r[n] == '0') {
  41 + n--;
  42 + }
  43 + if (r[n] == '.') {
  44 + n--;
  45 + }
  46 + r = r.substring(0, n + 1);
  47 + }
  48 + s.putString(r);
  49 + }
  50 + }
  51 +
  52 + @override
  53 + bool operator ==(Object other) {
  54 + if (other is PdfNum) {
  55 + return value == other.value;
  56 + }
  57 +
  58 + return false;
  59 + }
  60 +
  61 + PdfNum operator |(PdfNum other) {
  62 + return PdfNum(value.toInt() | other.value.toInt());
  63 + }
  64 +
  65 + @override
  66 + int get hashCode => value.hashCode;
  67 +}
  68 +
  69 +class PdfNumList extends PdfDataType {
  70 + const PdfNumList(this.values);
  71 +
  72 + final List<num> values;
  73 +
  74 + @override
  75 + void output(PdfStream s, [int? indent]) {
  76 + for (var n = 0; n < values.length; n++) {
  77 + if (n > 0) {
  78 + s.putByte(0x20);
  79 + }
  80 + PdfNum(values[n]).output(s, indent);
  81 + }
  82 + }
  83 +
  84 + @override
  85 + bool operator ==(Object other) {
  86 + if (other is PdfNumList) {
  87 + return values == other.values;
  88 + }
  89 +
  90 + return false;
  91 + }
  92 +
  93 + @override
  94 + int get hashCode => values.hashCode;
  95 +}
  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 'dart:typed_data';
  18 +
  19 +import 'indirect.dart';
  20 +
  21 +/// Callback used to compress the data
  22 +typedef DeflateCallback = List<int> Function(List<int> data);
  23 +
  24 +/// Callback used to encrypt the value of a [PdfDictStream] or a [PdfEncStream]
  25 +typedef PdfEncryptCallback = Uint8List Function(
  26 + Uint8List input, PdfObjectBase object);
  27 +
  28 +/// PDF version to generate
  29 +enum PdfVersion {
  30 + /// PDF 1.4
  31 + pdf_1_4,
  32 +
  33 + /// PDF 1.5 to 1.7
  34 + pdf_1_5,
  35 +}
  36 +
  37 +mixin PdfObjectBase {
  38 + /// This is the unique serial number for this object.
  39 + int get objser;
  40 +
  41 + /// This is the generation number for this object.
  42 + int get objgen => 0;
  43 +
  44 + /// Callback used to compress the data
  45 + DeflateCallback? get deflate => null;
  46 +
  47 + /// Callback used to encrypt the value of a [PdfDictStream] or a [PdfEncStream]
  48 + PdfEncryptCallback? get encryptCallback => null;
  49 +
  50 + /// Output a PDF document with comments and formatted data
  51 + bool get verbose => false;
  52 +
  53 + PdfVersion get version => PdfVersion.pdf_1_5;
  54 +
  55 + /// Returns the unique serial number in Pdf format
  56 + PdfIndirect ref() => PdfIndirect(objser, objgen);
  57 +}
  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 'dart:convert';
  18 +import 'dart:typed_data';
  19 +
  20 +import 'base.dart';
  21 +import 'object_base.dart';
  22 +import 'stream.dart';
  23 +
  24 +enum PdfStringFormat { binary, literal }
  25 +
  26 +class PdfString extends PdfDataType {
  27 + const PdfString(this.value, [this.format = PdfStringFormat.literal]);
  28 +
  29 + factory PdfString.fromString(String value) {
  30 + return PdfString(_string(value), PdfStringFormat.literal);
  31 + }
  32 +
  33 + factory PdfString.fromStream(PdfStream value,
  34 + [PdfStringFormat format = PdfStringFormat.literal]) {
  35 + return PdfString(value.output(), format);
  36 + }
  37 +
  38 + factory PdfString.fromDate(DateTime date) {
  39 + return PdfString(_date(date));
  40 + }
  41 +
  42 + final Uint8List value;
  43 +
  44 + final PdfStringFormat format;
  45 +
  46 + static Uint8List _string(String value) {
  47 + try {
  48 + return latin1.encode(value);
  49 + } catch (e) {
  50 + return Uint8List.fromList(<int>[0xfe, 0xff] + _encodeUtf16be(value));
  51 + }
  52 + }
  53 +
  54 + static Uint8List _date(DateTime date) {
  55 + final utcDate = date.toUtc();
  56 + final year = utcDate.year.toString().padLeft(4, '0');
  57 + final month = utcDate.month.toString().padLeft(2, '0');
  58 + final day = utcDate.day.toString().padLeft(2, '0');
  59 + final hour = utcDate.hour.toString().padLeft(2, '0');
  60 + final minute = utcDate.minute.toString().padLeft(2, '0');
  61 + final second = utcDate.second.toString().padLeft(2, '0');
  62 + return _string('D:$year$month$day$hour$minute${second}Z');
  63 + }
  64 +
  65 + /// Produce a list of UTF-16BE encoded bytes.
  66 + static List<int> _encodeUtf16be(String str) {
  67 + const unicodeReplacementCharacterCodePoint = 0xfffd;
  68 + const unicodeByteZeroMask = 0xff;
  69 + const unicodeByteOneMask = 0xff00;
  70 + const unicodeValidRangeMax = 0x10ffff;
  71 + const unicodePlaneOneMax = 0xffff;
  72 + const unicodeUtf16ReservedLo = 0xd800;
  73 + const unicodeUtf16ReservedHi = 0xdfff;
  74 + const unicodeUtf16Offset = 0x10000;
  75 + const unicodeUtf16SurrogateUnit0Base = 0xd800;
  76 + const unicodeUtf16SurrogateUnit1Base = 0xdc00;
  77 + const unicodeUtf16HiMask = 0xffc00;
  78 + const unicodeUtf16LoMask = 0x3ff;
  79 +
  80 + final encoding = <int>[];
  81 +
  82 + void add(int unit) {
  83 + encoding.add((unit & unicodeByteOneMask) >> 8);
  84 + encoding.add(unit & unicodeByteZeroMask);
  85 + }
  86 +
  87 + for (final unit in str.codeUnits) {
  88 + if ((unit >= 0 && unit < unicodeUtf16ReservedLo) ||
  89 + (unit > unicodeUtf16ReservedHi && unit <= unicodePlaneOneMax)) {
  90 + add(unit);
  91 + } else if (unit > unicodePlaneOneMax && unit <= unicodeValidRangeMax) {
  92 + final base = unit - unicodeUtf16Offset;
  93 + add(unicodeUtf16SurrogateUnit0Base +
  94 + ((base & unicodeUtf16HiMask) >> 10));
  95 + add(unicodeUtf16SurrogateUnit1Base + (base & unicodeUtf16LoMask));
  96 + } else {
  97 + add(unicodeReplacementCharacterCodePoint);
  98 + }
  99 + }
  100 + return encoding;
  101 + }
  102 +
  103 + /// Escape special characters
  104 + /// \ddd Character code ddd (octal)
  105 + void _putTextBytes(PdfStream s, List<int> b) {
  106 + for (final c in b) {
  107 + switch (c) {
  108 + case 0x0a: // \n Line feed (LF)
  109 + s.putByte(0x5c);
  110 + s.putByte(0x6e);
  111 + break;
  112 + case 0x0d: // \r Carriage return (CR)
  113 + s.putByte(0x5c);
  114 + s.putByte(0x72);
  115 + break;
  116 + case 0x09: // \t Horizontal tab (HT)
  117 + s.putByte(0x5c);
  118 + s.putByte(0x74);
  119 + break;
  120 + case 0x08: // \b Backspace (BS)
  121 + s.putByte(0x5c);
  122 + s.putByte(0x62);
  123 + break;
  124 + case 0x0c: // \f Form feed (FF)
  125 + s.putByte(0x5c);
  126 + s.putByte(0x66);
  127 + break;
  128 + case 0x28: // \( Left parenthesis
  129 + s.putByte(0x5c);
  130 + s.putByte(0x28);
  131 + break;
  132 + case 0x29: // \) Right parenthesis
  133 + s.putByte(0x5c);
  134 + s.putByte(0x29);
  135 + break;
  136 + case 0x5c: // \\ Backslash
  137 + s.putByte(0x5c);
  138 + s.putByte(0x5c);
  139 + break;
  140 + default:
  141 + s.putByte(c);
  142 + }
  143 + }
  144 + }
  145 +
  146 + /// Returns the ASCII/Unicode code unit corresponding to the hexadecimal digit
  147 + /// [digit].
  148 + int _codeUnitForDigit(int digit) =>
  149 + digit < 10 ? digit + 0x30 : digit + 0x61 - 10;
  150 +
  151 + void _output(PdfStream s, Uint8List value) {
  152 + switch (format) {
  153 + case PdfStringFormat.binary:
  154 + s.putByte(0x3c);
  155 + for (final byte in value) {
  156 + s.putByte(_codeUnitForDigit((byte & 0xF0) >> 4));
  157 + s.putByte(_codeUnitForDigit(byte & 0x0F));
  158 + }
  159 + s.putByte(0x3e);
  160 + break;
  161 + case PdfStringFormat.literal:
  162 + s.putByte(40);
  163 + _putTextBytes(s, value);
  164 + s.putByte(41);
  165 + break;
  166 + }
  167 + }
  168 +
  169 + @override
  170 + void output(PdfStream s, [int? indent]) {
  171 + _output(s, value);
  172 + }
  173 +
  174 + @override
  175 + bool operator ==(Object other) {
  176 + if (other is PdfString) {
  177 + return value == other.value;
  178 + }
  179 +
  180 + return false;
  181 + }
  182 +
  183 + @override
  184 + int get hashCode => value.hashCode;
  185 +}
  186 +
  187 +class PdfSecString extends PdfString {
  188 + const PdfSecString(this.object, Uint8List value,
  189 + [PdfStringFormat format = PdfStringFormat.binary])
  190 + : super(value, format);
  191 +
  192 + factory PdfSecString.fromString(
  193 + PdfObjectBase object,
  194 + String value, [
  195 + PdfStringFormat format = PdfStringFormat.literal,
  196 + ]) {
  197 + return PdfSecString(
  198 + object,
  199 + PdfString._string(value),
  200 + format,
  201 + );
  202 + }
  203 +
  204 + factory PdfSecString.fromStream(
  205 + PdfObjectBase object,
  206 + PdfStream value, [
  207 + PdfStringFormat format = PdfStringFormat.literal,
  208 + ]) {
  209 + return PdfSecString(
  210 + object,
  211 + value.output(),
  212 + format,
  213 + );
  214 + }
  215 +
  216 + factory PdfSecString.fromDate(PdfObjectBase object, DateTime date) {
  217 + return PdfSecString(
  218 + object,
  219 + PdfString._date(date),
  220 + PdfStringFormat.literal,
  221 + );
  222 + }
  223 +
  224 + final PdfObjectBase object;
  225 +
  226 + @override
  227 + void output(PdfStream s, [int? indent]) {
  228 + if (object.encryptCallback == null) {
  229 + return super.output(s, indent);
  230 + }
  231 +
  232 + final enc = object.encryptCallback!(value, object);
  233 + _output(s, enc);
  234 + }
  235 +}
@@ -17,8 +17,14 @@ @@ -17,8 +17,14 @@
17 import 'dart:math' as math; 17 import 'dart:math' as math;
18 import 'dart:typed_data'; 18 import 'dart:typed_data';
19 19
20 -import 'data_types.dart';  
21 -import 'obj/object.dart'; 20 +import 'array.dart';
  21 +import 'base.dart';
  22 +import 'dict.dart';
  23 +import 'dict_stream.dart';
  24 +import 'indirect.dart';
  25 +import 'name.dart';
  26 +import 'num.dart';
  27 +import 'object_base.dart';
22 import 'stream.dart'; 28 import 'stream.dart';
23 29
24 enum PdfCrossRefEntryType { free, inUse, compressed } 30 enum PdfCrossRefEntryType { free, inUse, compressed }
@@ -49,14 +55,14 @@ class PdfXref { @@ -49,14 +55,14 @@ class PdfXref {
49 final PdfCrossRefEntryType type; 55 final PdfCrossRefEntryType type;
50 56
51 /// The xref in the format of the xref section in the Pdf file 57 /// The xref in the format of the xref section in the Pdf file
52 - String ref() { 58 + String _legacyRef() {
53 return '${offset.toString().padLeft(10, '0')} ${generation.toString().padLeft(5, '0')}${type == PdfCrossRefEntryType.inUse ? ' n ' : ' f '}'; 59 return '${offset.toString().padLeft(10, '0')} ${generation.toString().padLeft(5, '0')}${type == PdfCrossRefEntryType.inUse ? ' n ' : ' f '}';
54 } 60 }
55 61
56 PdfIndirect? get container => object == null ? null : PdfIndirect(object!, 0); 62 PdfIndirect? get container => object == null ? null : PdfIndirect(object!, 0);
57 63
58 /// The xref in the format of the compressed xref section in the Pdf file 64 /// The xref in the format of the compressed xref section in the Pdf file
59 - int cref(ByteData o, int ofs, List<int> w) { 65 + int _compressedRef(ByteData o, int ofs, List<int> w) {
60 assert(w.length >= 3); 66 assert(w.length >= 3);
61 67
62 void setVal(int l, int v) { 68 void setVal(int l, int v) {
@@ -105,7 +111,7 @@ class PdfXrefTable extends PdfDataType { @@ -105,7 +111,7 @@ class PdfXrefTable extends PdfDataType {
105 s.putString('$firstId ${block.length}\n'); 111 s.putString('$firstId ${block.length}\n');
106 112
107 for (final x in block) { 113 for (final x in block) {
108 - s.putString(x.ref()); 114 + s.putString(x._legacyRef());
109 s.putByte(0x0a); 115 s.putByte(0x0a);
110 } 116 }
111 } 117 }
@@ -122,15 +128,15 @@ class PdfXrefTable extends PdfDataType { @@ -122,15 +128,15 @@ class PdfXrefTable extends PdfDataType {
122 return s.toString(); 128 return s.toString();
123 } 129 }
124 130
125 - int outputLegacy(PdfObject object, PdfStream s, PdfDict params) { 131 + int outputLegacy(PdfObjectBase object, PdfStream s, PdfDict params) {
126 // Now scan through the offsets list. They should be in sequence. 132 // Now scan through the offsets list. They should be in sequence.
127 offsets.sort((a, b) => a.id.compareTo(b.id)); 133 offsets.sort((a, b) => a.id.compareTo(b.id));
128 134
129 assert(() { 135 assert(() {
130 - if (object.pdfDocument.verbose) { 136 + if (object.verbose) {
131 s.putComment(''); 137 s.putComment('');
132 s.putComment('-' * 78); 138 s.putComment('-' * 78);
133 - s.putComment('$runtimeType ${object.pdfDocument.version.name}\n$this'); 139 + s.putComment('$runtimeType ${object.version.name}\n$this');
134 } 140 }
135 return true; 141 return true;
136 }()); 142 }());
@@ -169,20 +175,20 @@ class PdfXrefTable extends PdfDataType { @@ -169,20 +175,20 @@ class PdfXrefTable extends PdfDataType {
169 175
170 // the trailer object 176 // the trailer object
171 assert(() { 177 assert(() {
172 - if (object.pdfDocument.verbose) { 178 + if (object.verbose) {
173 s.putComment(''); 179 s.putComment('');
174 } 180 }
175 return true; 181 return true;
176 }()); 182 }());
177 s.putString('trailer\n'); 183 s.putString('trailer\n');
178 - params.output(s, object.pdfDocument.verbose ? 0 : null); 184 + params.output(s, object.verbose ? 0 : null);
179 s.putByte(0x0a); 185 s.putByte(0x0a);
180 186
181 return objOffset; 187 return objOffset;
182 } 188 }
183 189
184 /// Output a compressed cross-reference table 190 /// Output a compressed cross-reference table
185 - int outputCompressed(PdfObject object, PdfStream s, PdfDict params) { 191 + int outputCompressed(PdfObjectBase object, PdfStream s, PdfDict params) {
186 final offset = s.offset; 192 final offset = s.offset;
187 193
188 // Sort all references 194 // Sort all references
@@ -229,15 +235,15 @@ class PdfXrefTable extends PdfDataType { @@ -229,15 +235,15 @@ class PdfXrefTable extends PdfDataType {
229 ofs += wl; 235 ofs += wl;
230 236
231 for (final x in offsets) { 237 for (final x in offsets) {
232 - ofs = x.cref(o, ofs, w); 238 + ofs = x._compressedRef(o, ofs, w);
233 } 239 }
234 240
235 // Write the object 241 // Write the object
236 assert(() { 242 assert(() {
237 - if (object.pdfDocument.verbose) { 243 + if (object.verbose) {
238 s.putComment(''); 244 s.putComment('');
239 s.putComment('-' * 78); 245 s.putComment('-' * 78);
240 - s.putComment('$runtimeType ${object.pdfDocument.version.name}\n$this'); 246 + s.putComment('$runtimeType ${object.version.name}\n$this');
241 } 247 }
242 return true; 248 return true;
243 }()); 249 }());
@@ -252,7 +258,7 @@ class PdfXrefTable extends PdfDataType { @@ -252,7 +258,7 @@ class PdfXrefTable extends PdfDataType {
252 isBinary: false, 258 isBinary: false,
253 encrypt: false, 259 encrypt: false,
254 values: params.values, 260 values: params.values,
255 - ).output(s, object.pdfDocument.verbose ? 0 : null); 261 + ).output(s, object.verbose ? 0 : null);
256 262
257 s.putString('endobj\n'); 263 s.putString('endobj\n');
258 return objOffset; 264 return objOffset;
@@ -18,8 +18,10 @@ @@ -18,8 +18,10 @@
18 18
19 import 'package:meta/meta.dart'; 19 import 'package:meta/meta.dart';
20 20
21 -import 'data_types.dart';  
22 import 'document.dart'; 21 import 'document.dart';
  22 +import 'format/dict.dart';
  23 +import 'format/name.dart';
  24 +import 'format/num.dart';
23 import 'obj/function.dart'; 25 import 'obj/function.dart';
24 import 'obj/object_dict.dart'; 26 import 'obj/object_dict.dart';
25 import 'obj/smask.dart'; 27 import 'obj/smask.dart';
@@ -22,7 +22,10 @@ import 'package:path_parsing/path_parsing.dart'; @@ -22,7 +22,10 @@ import 'package:path_parsing/path_parsing.dart';
22 import 'package:vector_math/vector_math_64.dart'; 22 import 'package:vector_math/vector_math_64.dart';
23 23
24 import 'color.dart'; 24 import 'color.dart';
25 -import 'data_types.dart'; 25 +import 'format/array.dart';
  26 +import 'format/name.dart';
  27 +import 'format/num.dart';
  28 +import 'format/stream.dart';
26 import 'graphic_state.dart'; 29 import 'graphic_state.dart';
27 import 'obj/font.dart'; 30 import 'obj/font.dart';
28 import 'obj/graphic_stream.dart'; 31 import 'obj/graphic_stream.dart';
@@ -31,7 +34,6 @@ import 'obj/page.dart'; @@ -31,7 +34,6 @@ import 'obj/page.dart';
31 import 'obj/pattern.dart'; 34 import 'obj/pattern.dart';
32 import 'obj/shading.dart'; 35 import 'obj/shading.dart';
33 import 'rect.dart'; 36 import 'rect.dart';
34 -import 'stream.dart';  
35 37
36 /// Shape to be used at the corners of paths that are stroked 38 /// Shape to be used at the corners of paths that are stroked
37 enum PdfLineJoin { 39 enum PdfLineJoin {
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 import 'package:archive/archive.dart'; 17 import 'package:archive/archive.dart';
18 18
19 -import '../document.dart'; 19 +import '../format/object_base.dart';
20 20
21 /// Zip compression function 21 /// Zip compression function
22 DeflateCallback defaultDeflate = const ZLibEncoder().encode; 22 DeflateCallback defaultDeflate = const ZLibEncoder().encode;
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 import 'dart:io'; 17 import 'dart:io';
18 18
19 -import '../document.dart'; 19 +import '../format/object_base.dart';
20 20
21 /// Zip compression function 21 /// Zip compression function
22 DeflateCallback defaultDeflate = zlib.encode; 22 DeflateCallback defaultDeflate = zlib.encode;
@@ -18,12 +18,18 @@ import 'package:meta/meta.dart'; @@ -18,12 +18,18 @@ import 'package:meta/meta.dart';
18 import 'package:vector_math/vector_math_64.dart'; 18 import 'package:vector_math/vector_math_64.dart';
19 19
20 import '../color.dart'; 20 import '../color.dart';
21 -import '../data_types.dart';  
22 import '../document.dart'; 21 import '../document.dart';
  22 +import '../format/array.dart';
  23 +import '../format/base.dart';
  24 +import '../format/dict.dart';
  25 +import '../format/name.dart';
  26 +import '../format/null.dart';
  27 +import '../format/num.dart';
  28 +import '../format/stream.dart';
  29 +import '../format/string.dart';
23 import '../graphics.dart'; 30 import '../graphics.dart';
24 import '../point.dart'; 31 import '../point.dart';
25 import '../rect.dart'; 32 import '../rect.dart';
26 -import '../stream.dart';  
27 import 'border.dart'; 33 import 'border.dart';
28 import 'font.dart'; 34 import 'font.dart';
29 import 'graphic_stream.dart'; 35 import 'graphic_stream.dart';
@@ -295,7 +301,7 @@ abstract class PdfAnnotBase { @@ -295,7 +301,7 @@ abstract class PdfAnnotBase {
295 } 301 }
296 302
297 if (color != null) { 303 if (color != null) {
298 - params['/C'] = PdfColorType(color!); 304 + params['/C'] = PdfArray.fromColor(color!);
299 } 305 }
300 306
301 if (subject != null) { 307 if (subject != null) {
@@ -441,7 +447,7 @@ class PdfAnnotSquare extends PdfAnnotBase { @@ -441,7 +447,7 @@ class PdfAnnotSquare extends PdfAnnotBase {
441 void build(PdfPage page, PdfObject object, PdfDict params) { 447 void build(PdfPage page, PdfObject object, PdfDict params) {
442 super.build(page, object, params); 448 super.build(page, object, params);
443 if (interiorColor != null) { 449 if (interiorColor != null) {
444 - params['/IC'] = PdfColorType(interiorColor!); 450 + params['/IC'] = PdfArray.fromColor(interiorColor!);
445 } 451 }
446 } 452 }
447 } 453 }
@@ -474,7 +480,7 @@ class PdfAnnotCircle extends PdfAnnotBase { @@ -474,7 +480,7 @@ class PdfAnnotCircle extends PdfAnnotBase {
474 void build(PdfPage page, PdfObject object, PdfDict params) { 480 void build(PdfPage page, PdfObject object, PdfDict params) {
475 super.build(page, object, params); 481 super.build(page, object, params);
476 if (interiorColor != null) { 482 if (interiorColor != null) {
477 - params['/IC'] = PdfColorType(interiorColor!); 483 + params['/IC'] = PdfArray.fromColor(interiorColor!);
478 } 484 }
479 } 485 }
480 } 486 }
@@ -525,7 +531,7 @@ class PdfAnnotPolygon extends PdfAnnotBase { @@ -525,7 +531,7 @@ class PdfAnnotPolygon extends PdfAnnotBase {
525 params['/Vertices'] = PdfArray.fromNum(verticies); 531 params['/Vertices'] = PdfArray.fromNum(verticies);
526 532
527 if (interiorColor != null) { 533 if (interiorColor != null) {
528 - params['/IC'] = PdfColorType(interiorColor!); 534 + params['/IC'] = PdfArray.fromColor(interiorColor!);
529 } 535 }
530 } 536 }
531 } 537 }
@@ -631,11 +637,11 @@ abstract class PdfAnnotWidget extends PdfAnnotBase { @@ -631,11 +637,11 @@ abstract class PdfAnnotWidget extends PdfAnnotBase {
631 637
632 final mk = PdfDict(); 638 final mk = PdfDict();
633 if (color != null) { 639 if (color != null) {
634 - mk.values['/BC'] = PdfColorType(color!); 640 + mk.values['/BC'] = PdfArray.fromColor(color!);
635 } 641 }
636 642
637 if (backgroundColor != null) { 643 if (backgroundColor != null) {
638 - mk.values['/BG'] = PdfColorType(backgroundColor!); 644 + mk.values['/BG'] = PdfArray.fromColor(backgroundColor!);
639 } 645 }
640 646
641 if (mk.values.isNotEmpty) { 647 if (mk.values.isNotEmpty) {
@@ -14,8 +14,8 @@ @@ -14,8 +14,8 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
19 import 'object.dart'; 19 import 'object.dart';
20 20
21 /// An array object 21 /// An array object
@@ -14,8 +14,10 @@ @@ -14,8 +14,10 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/name.dart';
  20 +import '../format/num.dart';
19 import 'annotation.dart'; 21 import 'annotation.dart';
20 import 'object_dict.dart'; 22 import 'object_dict.dart';
21 23
@@ -14,8 +14,11 @@ @@ -14,8 +14,11 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/dict.dart';
  20 +import '../format/name.dart';
  21 +import '../format/num.dart';
19 import 'annotation.dart'; 22 import 'annotation.dart';
20 import 'metadata.dart'; 23 import 'metadata.dart';
21 import 'names.dart'; 24 import 'names.dart';
@@ -2,7 +2,7 @@ import 'dart:math' as math; @@ -2,7 +2,7 @@ import 'dart:math' as math;
2 2
3 import 'package:meta/meta.dart'; 3 import 'package:meta/meta.dart';
4 4
5 -import '../stream.dart'; 5 +import '../format/stream.dart';
6 6
7 mixin PdfDiagnostic { 7 mixin PdfDiagnostic {
8 static const _maxSize = 300; 8 static const _maxSize = 300;
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 import 'dart:typed_data'; 17 import 'dart:typed_data';
18 18
19 import '../document.dart'; 19 import '../document.dart';
20 -import 'object.dart'; 20 +import '../format/object_base.dart';
21 import 'object_dict.dart'; 21 import 'object_dict.dart';
22 22
23 /// Encryption object 23 /// Encryption object
@@ -26,5 +26,5 @@ abstract class PdfEncryption extends PdfObjectDict { @@ -26,5 +26,5 @@ abstract class PdfEncryption extends PdfObjectDict {
26 PdfEncryption(PdfDocument pdfDocument) : super(pdfDocument); 26 PdfEncryption(PdfDocument pdfDocument) : super(pdfDocument);
27 27
28 /// Encrypt some data 28 /// Encrypt some data
29 - Uint8List encrypt(Uint8List input, PdfObject object); 29 + Uint8List encrypt(Uint8List input, PdfObjectBase object);
30 } 30 }
@@ -16,12 +16,13 @@ @@ -16,12 +16,13 @@
16 16
17 import 'dart:convert'; 17 import 'dart:convert';
18 18
19 -import '../data_types.dart';  
20 import '../document.dart'; 19 import '../document.dart';
21 import '../font/font_metrics.dart'; 20 import '../font/font_metrics.dart';
22 import '../font/type1_fonts.dart'; 21 import '../font/type1_fonts.dart';
  22 +import '../format/name.dart';
  23 +import '../format/stream.dart';
  24 +import '../format/string.dart';
23 import '../point.dart'; 25 import '../point.dart';
24 -import '../stream.dart';  
25 import 'object_dict.dart'; 26 import 'object_dict.dart';
26 import 'type1_font.dart'; 27 import 'type1_font.dart';
27 28
@@ -14,7 +14,9 @@ @@ -14,7 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart'; 17 +import '../format/array.dart';
  18 +import '../format/name.dart';
  19 +import '../format/num.dart';
18 import 'object_dict.dart'; 20 import 'object_dict.dart';
19 import 'object_stream.dart'; 21 import 'object_stream.dart';
20 import 'ttffont.dart'; 22 import 'ttffont.dart';
@@ -16,8 +16,10 @@ @@ -16,8 +16,10 @@
16 16
17 import 'package:vector_math/vector_math_64.dart'; 17 import 'package:vector_math/vector_math_64.dart';
18 18
19 -import '../data_types.dart';  
20 import '../document.dart'; 19 import '../document.dart';
  20 +import '../format/array.dart';
  21 +import '../format/dict.dart';
  22 +import '../format/num.dart';
21 import 'font.dart'; 23 import 'font.dart';
22 import 'xobject.dart'; 24 import 'xobject.dart';
23 25
@@ -15,8 +15,9 @@ @@ -15,8 +15,9 @@
15 */ 15 */
16 16
17 import '../color.dart'; 17 import '../color.dart';
18 -import '../data_types.dart';  
19 import '../document.dart'; 18 import '../document.dart';
  19 +import '../format/array.dart';
  20 +import '../format/num.dart';
20 import 'object_dict.dart'; 21 import 'object_dict.dart';
21 import 'object_stream.dart'; 22 import 'object_stream.dart';
22 23
@@ -14,8 +14,11 @@ @@ -14,8 +14,11 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/bool.dart';
  20 +import '../format/dict.dart';
  21 +import '../format/name.dart';
19 import '../graphic_state.dart'; 22 import '../graphic_state.dart';
20 import 'font.dart'; 23 import 'font.dart';
21 import 'object_dict.dart'; 24 import 'object_dict.dart';
@@ -18,9 +18,11 @@ import 'dart:typed_data'; @@ -18,9 +18,11 @@ import 'dart:typed_data';
18 18
19 import 'package:image/image.dart' as im; 19 import 'package:image/image.dart' as im;
20 20
21 -import '../data_types.dart';  
22 import '../document.dart'; 21 import '../document.dart';
23 import '../exif.dart'; 22 import '../exif.dart';
  23 +import '../format/indirect.dart';
  24 +import '../format/name.dart';
  25 +import '../format/num.dart';
24 import '../raster.dart'; 26 import '../raster.dart';
25 import 'xobject.dart'; 27 import 'xobject.dart';
26 28
@@ -14,8 +14,8 @@ @@ -14,8 +14,8 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/string.dart';
19 import 'object_dict.dart'; 19 import 'object_dict.dart';
20 20
21 /// Information object 21 /// Information object
@@ -19,8 +19,9 @@ import 'dart:typed_data'; @@ -19,8 +19,9 @@ import 'dart:typed_data';
19 19
20 import 'package:xml/xml.dart'; 20 import 'package:xml/xml.dart';
21 21
22 -import '../data_types.dart';  
23 import '../document.dart'; 22 import '../document.dart';
  23 +import '../format/dict_stream.dart';
  24 +import '../format/name.dart';
24 import 'object.dart'; 25 import 'object.dart';
25 26
26 /// Pdf Metadata 27 /// Pdf Metadata
@@ -14,8 +14,14 @@ @@ -14,8 +14,14 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/base.dart';
  20 +import '../format/dict.dart';
  21 +import '../format/name.dart';
  22 +import '../format/null.dart';
  23 +import '../format/num.dart';
  24 +import '../format/string.dart';
19 import 'object_dict.dart'; 25 import 'object_dict.dart';
20 import 'page.dart'; 26 import 'page.dart';
21 27
@@ -16,13 +16,15 @@ @@ -16,13 +16,15 @@
16 16
17 import 'package:meta/meta.dart'; 17 import 'package:meta/meta.dart';
18 18
19 -import '../data_types.dart';  
20 import '../document.dart'; 19 import '../document.dart';
21 -import '../stream.dart'; 20 +import '../format/base.dart';
  21 +import '../format/object_base.dart';
  22 +import '../format/stream.dart';
22 import 'diagnostic.dart'; 23 import 'diagnostic.dart';
23 24
24 /// Base Object used in the PDF file 25 /// Base Object used in the PDF file
25 -abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic { 26 +abstract class PdfObject<T extends PdfDataType>
  27 + with PdfDiagnostic, PdfObjectBase {
26 /// This is usually called by extensors to this class, and sets the 28 /// This is usually called by extensors to this class, and sets the
27 /// Pdf Object Type 29 /// Pdf Object Type
28 PdfObject( 30 PdfObject(
@@ -37,10 +39,10 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic { @@ -37,10 +39,10 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic {
37 /// This is the object parameters. 39 /// This is the object parameters.
38 final T params; 40 final T params;
39 41
40 - /// This is the unique serial number for this object. 42 + @override
41 final int objser; 43 final int objser;
42 44
43 - /// This is the generation number for this object. 45 + @override
44 final int objgen; 46 final int objgen;
45 47
46 /// This allows any Pdf object to refer to the document being constructed. 48 /// This allows any Pdf object to refer to the document being constructed.
@@ -48,6 +50,18 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic { @@ -48,6 +50,18 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic {
48 50
49 var inUse = true; 51 var inUse = true;
50 52
  53 + @override
  54 + DeflateCallback? get deflate => pdfDocument.deflate;
  55 +
  56 + @override
  57 + PdfEncryptCallback? get encryptCallback => pdfDocument.encryption?.encrypt;
  58 +
  59 + @override
  60 + bool get verbose => pdfDocument.verbose;
  61 +
  62 + @override
  63 + PdfVersion get version => pdfDocument.version;
  64 +
51 /// Writes the object to the output stream. 65 /// Writes the object to the output stream.
52 void write(PdfStream os) { 66 void write(PdfStream os) {
53 prepare(); 67 prepare();
@@ -67,7 +81,7 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic { @@ -67,7 +81,7 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic {
67 } 81 }
68 82
69 void writeContent(PdfStream os) { 83 void writeContent(PdfStream os) {
70 - params.output(os, pdfDocument.verbose ? 0 : null); 84 + params.output(os, verbose ? 0 : null);
71 os.putByte(0x0a); 85 os.putByte(0x0a);
72 } 86 }
73 87
@@ -77,9 +91,6 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic { @@ -77,9 +91,6 @@ abstract class PdfObject<T extends PdfDataType> with PdfDiagnostic {
77 os.putString('endobj\n'); 91 os.putString('endobj\n');
78 } 92 }
79 93
80 - /// Returns the unique serial number in Pdf format  
81 - PdfIndirect ref() => PdfIndirect(objser, objgen);  
82 -  
83 @override 94 @override
84 String toString() => '$runtimeType $params'; 95 String toString() => '$runtimeType $params';
85 } 96 }
@@ -14,9 +14,10 @@ @@ -14,9 +14,10 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
19 -import '../stream.dart'; 18 +import '../format/dict.dart';
  19 +import '../format/name.dart';
  20 +import '../format/stream.dart';
20 import 'object.dart'; 21 import 'object.dart';
21 22
22 /// Object with a PdfDict used in the PDF file 23 /// Object with a PdfDict used in the PDF file
@@ -14,9 +14,9 @@ @@ -14,9 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
19 -import '../stream.dart'; 18 +import '../format/dict_stream.dart';
  19 +import '../format/stream.dart';
20 import 'object_dict.dart'; 20 import 'object_dict.dart';
21 21
22 /// Stream Object 22 /// Stream Object
@@ -15,8 +15,11 @@ @@ -15,8 +15,11 @@
15 */ 15 */
16 16
17 import '../color.dart'; 17 import '../color.dart';
18 -import '../data_types.dart';  
19 import '../document.dart'; 18 import '../document.dart';
  19 +import '../format/array.dart';
  20 +import '../format/name.dart';
  21 +import '../format/num.dart';
  22 +import '../format/string.dart';
20 import '../rect.dart'; 23 import '../rect.dart';
21 import 'object_dict.dart'; 24 import 'object_dict.dart';
22 import 'page.dart'; 25 import 'page.dart';
@@ -125,7 +128,7 @@ class PdfOutline extends PdfObjectDict { @@ -125,7 +128,7 @@ class PdfOutline extends PdfObjectDict {
125 params['/Title'] = PdfSecString.fromString(this, title!); 128 params['/Title'] = PdfSecString.fromString(this, title!);
126 129
127 if (color != null) { 130 if (color != null) {
128 - params['/C'] = PdfColorType(color!); 131 + params['/C'] = PdfArray.fromColor(color!);
129 } 132 }
130 133
131 if (style != PdfOutlineStyle.normal) { 134 if (style != PdfOutlineStyle.normal) {
@@ -14,8 +14,10 @@ @@ -14,8 +14,10 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/indirect.dart';
  20 +import '../format/num.dart';
19 import '../graphics.dart'; 21 import '../graphics.dart';
20 import '../page_format.dart'; 22 import '../page_format.dart';
21 import 'annotation.dart'; 23 import 'annotation.dart';
1 -import '../../priv.dart'; 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 +
2 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/dict.dart';
  20 +import '../format/name.dart';
  21 +import '../format/num.dart';
  22 +import '../format/string.dart';
  23 +import 'object.dart';
3 import 'object_dict.dart'; 24 import 'object_dict.dart';
4 25
5 enum PdfPageLabelStyle { 26 enum PdfPageLabelStyle {
@@ -14,8 +14,9 @@ @@ -14,8 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/num.dart';
19 import 'object_dict.dart'; 20 import 'object_dict.dart';
20 import 'page.dart'; 21 import 'page.dart';
21 22
@@ -16,8 +16,9 @@ @@ -16,8 +16,9 @@
16 16
17 import 'package:vector_math/vector_math_64.dart'; 17 import 'package:vector_math/vector_math_64.dart';
18 18
19 -import '../data_types.dart';  
20 import '../document.dart'; 19 import '../document.dart';
  20 +import '../format/array.dart';
  21 +import '../format/num.dart';
21 import '../graphic_state.dart'; 22 import '../graphic_state.dart';
22 import 'object_dict.dart'; 23 import 'object_dict.dart';
23 import 'shading.dart'; 24 import 'shading.dart';
@@ -14,8 +14,11 @@ @@ -14,8 +14,11 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/array.dart';
  19 +import '../format/bool.dart';
  20 +import '../format/name.dart';
  21 +import '../format/num.dart';
19 import '../point.dart'; 22 import '../point.dart';
20 import '../rect.dart'; 23 import '../rect.dart';
21 import 'function.dart'; 24 import 'function.dart';
@@ -16,9 +16,9 @@ @@ -16,9 +16,9 @@
16 16
17 import 'dart:typed_data'; 17 import 'dart:typed_data';
18 18
19 -import '../data_types.dart';  
20 import '../document.dart'; 19 import '../document.dart';
21 -import '../stream.dart'; 20 +import '../format/dict.dart';
  21 +import '../format/stream.dart';
22 import 'object.dart'; 22 import 'object.dart';
23 import 'object_dict.dart'; 23 import 'object_dict.dart';
24 import 'object_stream.dart'; 24 import 'object_stream.dart';
@@ -16,8 +16,11 @@ @@ -16,8 +16,11 @@
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */ 17 */
18 18
19 -import '../data_types.dart';  
20 import '../document.dart'; 19 import '../document.dart';
  20 +import '../format/array.dart';
  21 +import '../format/bool.dart';
  22 +import '../format/dict.dart';
  23 +import '../format/name.dart';
21 import '../graphics.dart'; 24 import '../graphics.dart';
22 import '../rect.dart'; 25 import '../rect.dart';
23 import 'function.dart'; 26 import 'function.dart';
@@ -17,13 +17,17 @@ @@ -17,13 +17,17 @@
17 import 'dart:convert'; 17 import 'dart:convert';
18 import 'dart:typed_data'; 18 import 'dart:typed_data';
19 19
20 -import '../data_types.dart';  
21 import '../document.dart'; 20 import '../document.dart';
22 import '../font/bidi_utils.dart' as bidi; 21 import '../font/bidi_utils.dart' as bidi;
23 import '../font/font_metrics.dart'; 22 import '../font/font_metrics.dart';
24 import '../font/ttf_parser.dart'; 23 import '../font/ttf_parser.dart';
25 import '../font/ttf_writer.dart'; 24 import '../font/ttf_writer.dart';
26 -import '../stream.dart'; 25 +import '../format/array.dart';
  26 +import '../format/dict.dart';
  27 +import '../format/name.dart';
  28 +import '../format/num.dart';
  29 +import '../format/stream.dart';
  30 +import '../format/string.dart';
27 import 'array.dart'; 31 import 'array.dart';
28 import 'font.dart'; 32 import 'font.dart';
29 import 'font_descriptor.dart'; 33 import 'font_descriptor.dart';
@@ -14,9 +14,9 @@ @@ -14,9 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
19 import '../font/font_metrics.dart'; 18 import '../font/font_metrics.dart';
  19 +import '../format/name.dart';
20 import 'font.dart'; 20 import 'font.dart';
21 import 'ttffont.dart'; 21 import 'ttffont.dart';
22 22
@@ -14,8 +14,8 @@ @@ -14,8 +14,8 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import '../data_types.dart';  
18 import '../document.dart'; 17 import '../document.dart';
  18 +import '../format/name.dart';
19 import 'object_stream.dart'; 19 import 'object_stream.dart';
20 20
21 class PdfXObject extends PdfObjectStream { 21 class PdfXObject extends PdfObjectStream {
@@ -14,16 +14,19 @@ @@ -14,16 +14,19 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -import 'data_types.dart';  
18 -import 'document.dart'; 17 +import 'format/array.dart';
  18 +import 'format/dict.dart';
  19 +import 'format/num.dart';
  20 +import 'format/object_base.dart';
  21 +import 'format/stream.dart';
  22 +import 'format/string.dart';
  23 +import 'format/xref.dart';
19 import 'obj/catalog.dart'; 24 import 'obj/catalog.dart';
20 import 'obj/diagnostic.dart'; 25 import 'obj/diagnostic.dart';
21 import 'obj/encryption.dart'; 26 import 'obj/encryption.dart';
22 import 'obj/info.dart'; 27 import 'obj/info.dart';
23 import 'obj/object.dart'; 28 import 'obj/object.dart';
24 import 'obj/signature.dart'; 29 import 'obj/signature.dart';
25 -import 'stream.dart';  
26 -import 'xref.dart';  
27 30
28 /// PDF document writer 31 /// PDF document writer
29 class PdfOutput with PdfDiagnostic { 32 class PdfOutput with PdfDiagnostic {
@@ -14,8 +14,19 @@ @@ -14,8 +14,19 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17 -export 'pdf/data_types.dart'; 17 +export 'pdf/format/array.dart';
  18 +export 'pdf/format/ascii85.dart';
  19 +export 'pdf/format/base.dart';
  20 +export 'pdf/format/bool.dart';
  21 +export 'pdf/format/dict.dart';
  22 +export 'pdf/format/dict_stream.dart';
  23 +export 'pdf/format/indirect.dart';
  24 +export 'pdf/format/name.dart';
  25 +export 'pdf/format/null.dart';
  26 +export 'pdf/format/num.dart';
  27 +export 'pdf/format/object_base.dart' hide DeflateCallback, PdfVersion;
  28 +export 'pdf/format/stream.dart';
  29 +export 'pdf/format/string.dart';
  30 +export 'pdf/format/xref.dart';
18 export 'pdf/obj/object.dart'; 31 export 'pdf/obj/object.dart';
19 export 'pdf/obj/object_stream.dart'; 32 export 'pdf/obj/object_stream.dart';
20 -export 'pdf/stream.dart';  
21 -export 'pdf/xref.dart';  
@@ -20,7 +20,6 @@ import 'dart:typed_data'; @@ -20,7 +20,6 @@ import 'dart:typed_data';
20 import 'package:vector_math/vector_math_64.dart'; 20 import 'package:vector_math/vector_math_64.dart';
21 21
22 import '../../pdf.dart'; 22 import '../../pdf.dart';
23 -import '../pdf/data_types.dart';  
24 import 'basic.dart'; 23 import 'basic.dart';
25 import 'border_radius.dart'; 24 import 'border_radius.dart';
26 import 'box_border.dart'; 25 import 'box_border.dart';
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 16
17 import 'dart:typed_data'; 17 import 'dart:typed_data';
18 18
19 -import 'package:pdf/src/pdf/data_types.dart'; 19 +import 'package:pdf/src/priv.dart';
20 import 'package:test/test.dart'; 20 import 'package:test/test.dart';
21 21
22 void main() { 22 void main() {
@@ -14,22 +14,87 @@ @@ -14,22 +14,87 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
  17 +import 'dart:convert';
17 import 'dart:io'; 18 import 'dart:io';
18 19
19 -import 'package:pdf/pdf.dart'; 20 +import 'package:pdf/src/priv.dart';
20 import 'package:test/test.dart'; 21 import 'package:test/test.dart';
21 22
  23 +class BasicObject with PdfObjectBase {
  24 + const BasicObject(this.objser);
  25 +
  26 + @override
  27 + final int objser;
  28 +
  29 + @override
  30 + bool get verbose => true;
  31 +
  32 + void write(PdfStream os, PdfDataType value) {
  33 + os.putString('$objser $objgen obj\n');
  34 + value.output(os, verbose ? 0 : null);
  35 + os.putByte(0x0a);
  36 + os.putString('endobj\n');
  37 + }
  38 +}
  39 +
22 void main() { 40 void main() {
23 test('Pdf Minimal', () async { 41 test('Pdf Minimal', () async {
24 - final pdf = PdfDocument(compress: false);  
25 - final page = PdfPage(pdf, pageFormat: PdfPageFormat.a4); 42 + final pages = PdfDict({
  43 + '/Type': const PdfName('/Pages'),
  44 + '/Count': const PdfNum(1),
  45 + });
  46 +
  47 + final page = PdfDict({
  48 + '/Type': const PdfName('/Page'),
  49 + '/Parent': const PdfIndirect(2, 0),
  50 + '/MediaBox': PdfArray.fromNum([0, 0, 595.27559, 841.88976]),
  51 + '/Resources': PdfDict({
  52 + '/ProcSet': PdfArray([
  53 + const PdfName('/PDF'),
  54 + ]),
  55 + }),
  56 + '/Contents': const PdfIndirect(4, 0),
  57 + });
  58 +
  59 + final content = PdfDictStream(
  60 + object: const BasicObject(1),
  61 + data: latin1.encode('30 811.88976 m 200 641.88976 l S'),
  62 + );
  63 +
  64 + pages['/Kids'] = PdfArray([const PdfIndirect(3, 0)]);
  65 +
  66 + final catalog = PdfDict({
  67 + '/Type': const PdfName('/Catalog'),
  68 + '/Pages': const PdfIndirect(2, 0),
  69 + });
  70 +
  71 + final os = PdfStream();
  72 +
  73 + final xref = PdfXrefTable();
  74 +
  75 + os.putString('%PDF-1.4\n');
  76 + os.putBytes(const <int>[0x25, 0xC2, 0xA5, 0xC2, 0xB1, 0xC3, 0xAB, 0x0A]);
  77 +
  78 + xref.add(PdfXref(1, os.offset));
  79 + final cat = const BasicObject(1)..write(os, catalog);
  80 + xref.add(PdfXref(2, os.offset));
  81 + const BasicObject(2).write(os, pages);
  82 + xref.add(PdfXref(3, os.offset));
  83 + const BasicObject(3).write(os, page);
  84 + xref.add(PdfXref(4, os.offset));
  85 + const BasicObject(4).write(os, content);
  86 +
  87 + final xrefOffset = xref.outputLegacy(
  88 + cat,
  89 + os,
  90 + PdfDict({
  91 + '/Size': PdfNum(xref.offsets.length + 1),
  92 + '/Root': const PdfIndirect(1, 0),
  93 + }));
26 94
27 - final g = page.getGraphics();  
28 - g.drawLine(  
29 - 30, page.pageFormat.height - 30.0, 200, page.pageFormat.height - 200.0);  
30 - g.strokePath(); 95 + os.putString('startxref\n$xrefOffset\n%%EOF\n');
31 96
32 final file = File('minimal.pdf'); 97 final file = File('minimal.pdf');
33 - await file.writeAsBytes(await pdf.save()); 98 + await file.writeAsBytes(os.output());
34 }); 99 });
35 } 100 }