Showing
2 changed files
with
83 additions
and
49 deletions
| @@ -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 | } |
-
Please register or login to post a comment