David PHAM-VAN

Improve Cross-Reference Table

@@ -34,8 +34,8 @@ class PdfOutput { @@ -34,8 +34,8 @@ class PdfOutput {
34 /// This is the actual [PdfStream] used to write to. 34 /// This is the actual [PdfStream] used to write to.
35 final PdfStream os; 35 final PdfStream os;
36 36
37 - /// This vector contains offsets of each object  
38 - List<PdfXref> offsets = <PdfXref>[]; 37 + /// Cross reference table
  38 + final xref = PdfXrefTable();
39 39
40 /// This is used to track the /Root object (catalog) 40 /// This is used to track the /Root object (catalog)
41 PdfObject? rootID; 41 PdfObject? rootID;
@@ -63,41 +63,18 @@ class PdfOutput { @@ -63,41 +63,18 @@ class PdfOutput {
63 signatureID = ob; 63 signatureID = ob;
64 } 64 }
65 65
66 - offsets.add(PdfXref(ob.objser, os.offset)); 66 + xref.add(PdfXref(ob.objser, os.offset));
67 ob.write(os); 67 ob.write(os);
68 } 68 }
69 69
70 /// This closes the Stream, writing the xref table 70 /// This closes the Stream, writing the xref table
71 Future<void> close() async { 71 Future<void> close() async {
72 - final xref = os.offset;  
73 - os.putString('xref\n');  
74 -  
75 - // Now scan through the offsets list. They should be in sequence.  
76 - offsets.sort((a, b) => a.id.compareTo(b.id));  
77 -  
78 - var firstid = 0; // First id in block  
79 - var lastid = 0; // The last id used  
80 - final block = <PdfXref>[]; // xrefs in this block  
81 -  
82 - // We need block 0 to exist  
83 - block.add(PdfXref(0, 0, generation: 65535));  
84 -  
85 - for (var x in offsets) {  
86 - // check to see if block is in range  
87 - if (x.id != (lastid + 1)) {  
88 - // no, so write this block, and reset  
89 - writeblock(firstid, block);  
90 - block.clear();  
91 - firstid = x.id;  
92 - }  
93 -  
94 - // now add to block  
95 - block.add(x);  
96 - lastid = x.id; 72 + if (rootID == null) {
  73 + throw Exception('Root object is not present in document');
97 } 74 }
98 75
99 - // now write the last block  
100 - writeblock(firstid, block); 76 + final _xref = os.offset;
  77 + xref.output(os);
101 78
102 // now the trailer object 79 // now the trailer object
103 os.putString('trailer\n'); 80 os.putString('trailer\n');
@@ -108,14 +85,10 @@ class PdfOutput { @@ -108,14 +85,10 @@ class PdfOutput {
108 params['/Size'] = PdfNum(rootID!.pdfDocument.objser); 85 params['/Size'] = PdfNum(rootID!.pdfDocument.objser);
109 86
110 // the /Root catalog indirect reference (REQUIRED) 87 // the /Root catalog indirect reference (REQUIRED)
111 - if (rootID != null) {  
112 - params['/Root'] = rootID!.ref();  
113 - final id =  
114 - PdfString(rootID!.pdfDocument.documentID, PdfStringFormat.binary);  
115 - params['/ID'] = PdfArray([id, id]);  
116 - } else {  
117 - throw Exception('Root object is not present in document');  
118 - } 88 + params['/Root'] = rootID!.ref();
  89 + final id =
  90 + PdfString(rootID!.pdfDocument.documentID, PdfStringFormat.binary);
  91 + params['/ID'] = PdfArray([id, id]);
119 92
120 // the /Info reference (OPTIONAL) 93 // the /Info reference (OPTIONAL)
121 if (infoID != null) { 94 if (infoID != null) {
@@ -133,20 +106,10 @@ class PdfOutput { @@ -133,20 +106,10 @@ class PdfOutput {
133 106
134 // end the trailer object 107 // end the trailer object
135 params.output(os); 108 params.output(os);
136 - os.putString('\nstartxref\n$xref\n%%EOF\n'); 109 + os.putString('\nstartxref\n$_xref\n%%EOF\n');
137 110
138 if (signatureID != null) { 111 if (signatureID != null) {
139 await signatureID!.writeSignature(os); 112 await signatureID!.writeSignature(os);
140 } 113 }
141 } 114 }
142 -  
143 - /// Writes a block of references to the Pdf file  
144 - void writeblock(int firstid, List<PdfXref> block) {  
145 - os.putString('$firstid ${block.length}\n');  
146 -  
147 - for (var x in block) {  
148 - os.putString(x.ref());  
149 - os.putString('\n');  
150 - }  
151 - }  
152 } 115 }
@@ -14,6 +14,11 @@ @@ -14,6 +14,11 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
  17 +import 'package:pdf/src/pdf/stream.dart';
  18 +
  19 +import 'data_types.dart';
  20 +import 'object.dart';
  21 +
17 /// Cross-reference for a Pdf Object 22 /// Cross-reference for a Pdf Object
18 class PdfXref { 23 class PdfXref {
19 /// Creates a cross-reference for a Pdf Object 24 /// Creates a cross-reference for a Pdf Object
@@ -41,5 +46,71 @@ class PdfXref { @@ -41,5 +46,71 @@ class PdfXref {
41 } 46 }
42 47
43 @override 48 @override
  49 + bool operator ==(Object other) {
  50 + if (other is PdfXref) {
  51 + return offset == other.offset;
  52 + }
  53 +
  54 + return false;
  55 + }
  56 +
  57 + @override
44 String toString() => '$runtimeType $id $generation $offset'; 58 String toString() => '$runtimeType $id $generation $offset';
  59 +
  60 + @override
  61 + int get hashCode => offset;
  62 +}
  63 +
  64 +class PdfXrefTable extends PdfDataType {
  65 + PdfXrefTable();
  66 +
  67 + /// Contains offsets of each object
  68 + final offsets = <PdfXref>[];
  69 +
  70 + /// Add a xross reference element to the set
  71 + void add(PdfXref xref) {
  72 + offsets.add(xref);
  73 + }
  74 +
  75 + /// Writes a block of references to the Pdf file
  76 + void _writeblock(PdfStream s, int firstid, List<PdfXref> block) {
  77 + s.putString('$firstid ${block.length}\n');
  78 +
  79 + for (var x in block) {
  80 + s.putString(x.ref());
  81 + s.putByte(0x0a);
  82 + }
  83 + }
  84 +
  85 + @override
  86 + void output(PdfStream s) {
  87 + s.putString('xref\n');
  88 +
  89 + // Now scan through the offsets list. They should be in sequence.
  90 + offsets.sort((a, b) => a.id.compareTo(b.id));
  91 +
  92 + var firstid = 0; // First id in block
  93 + var lastid = 0; // The last id used
  94 + final block = <PdfXref>[]; // xrefs in this block
  95 +
  96 + // We need block 0 to exist
  97 + block.add(PdfXref(0, 0, generation: 65535));
  98 +
  99 + for (var x in offsets) {
  100 + // check to see if block is in range
  101 + if (x.id != (lastid + 1)) {
  102 + // no, so write this block, and reset
  103 + _writeblock(s, firstid, block);
  104 + block.clear();
  105 + firstid = x.id;
  106 + }
  107 +
  108 + // now add to block
  109 + block.add(x);
  110 + lastid = x.id;
  111 + }
  112 +
  113 + // now write the last block
  114 + _writeblock(s, firstid, block);
  115 + }
45 } 116 }