def write(self, stream, prev, startdata): stream.write(pdf.b_("\r\n")) positions = {2: 0} for i in range(2, len(self._objects)): idnum = i + 1 obj = self._objects[i] if obj is None: positions[idnum] = 0 continue positions[idnum] = startdata + stream.tell() stream.write(pdf.b_(str(idnum) + " 0 obj\n")) key = None if self._encrypt_key is not None: pack1 = struct.pack("<i", i + 1)[:3] pack2 = struct.pack("<i", 0)[:2] key = self._encrypt_key + pack1 + pack2 assert len(key) == (len(self._encrypt_key) + 5) md5_hash = hashlib.md5(key).digest() key = md5_hash[:min(16, len(self._encrypt_key) + 5)] obj.writeToStream(stream, key) stream.write(pdf.b_("\nendobj\n")) xref_location = startdata + stream.tell() if not prev.xrefstream: trailer = po.DictionaryObject() else: trailer = po.StreamObject() self._addObject(trailer) # xref table trailer.update({ po.NameObject("/Size"): po.NumberObject(len(self._objects) + 1), po.NameObject("/Root"): self.x_root, po.NameObject("/Info"): self.x_info, po.NameObject("/Prev"): po.NumberObject(prev.startxref), po.NameObject("/ID"): self._ID, }) if prev.isEncrypted: trailer[po.NameObject("/Encrypt")] = prev.trailer.raw_get( "/Encrypt") if not prev.xrefstream: stream.write(pdf.b_("xref\n")) stream.write(pdf.b_("0 1\n")) stream.write(pdf.b_("0000000000 65535 f \n")) keys = sorted(positions.keys()) i = 0 while i < len(keys): off = positions[keys[i]] if off == 0: while i < len(keys) and positions[keys[i]] == 0: i += 1 start = i while i < len(keys) and positions[keys[i]] != 0: i += 1 stream.write(pdf.b_("%d %d \n" % (keys[start], i - start))) i = start continue else: stream.write(pdf.b_("%010d %05d n \n" % (off, 0))) i += 1 # trailer stream.write(pdf.b_("trailer\n")) trailer.writeToStream(stream, None) else: def pack(offset): return struct.pack(">q", offset) dataindex = ["0 1"] dataxref = [b"\x00" + pack(0)] keys = sorted(positions.keys()) i = 0 while i < len(keys): off = positions[keys[i]] if off != 0: start = i while i < len(keys) and positions[keys[i]] != 0: dataxref.append(b"\x01" + pack(positions[keys[i]])) i += 1 stop = i dataindex.append("%d %d" % (keys[start], stop - start)) else: i += 1 dataindex = " ".join(dataindex) dataxref = b"".join(dataxref) trailer[po.NameObject("/Type")] = po.NameObject("/XRef") trailer[po.NameObject("/W")] = po.NameObject("[1 8 0]") trailer[po.NameObject("/Index")] = po.NameObject("[%s]" % dataindex) trailer._data = dataxref retval = trailer.flateEncode() trailer.update(retval) trailer._data = retval._data stream.write(pdf.b_("%d 0 obj\n" % (len(self._objects)))) trailer.writeToStream(stream, None) stream.write(pdf.b_("\nendobj")) # eof stream.write(pdf.b_("\nstartxref\n%s\n%%%%EOF\n" % (xref_location)))
def write(self, stream, prev, startxref): externalReferenceMap = {} # PDF objects sometimes have circular references to their /Page objects # inside their object tree (for example, annotations). Those will be # indirect references to objects that we've recreated in this PDF. To # address this problem, PageObject's store their original object # reference number, and we add it to the external reference map before # we sweep for indirect references. This forces self-page-referencing # trees to reference the correct new object location, rather than # copying in a new copy of the page object. for objIndex in range(len(self._objects)): obj = self._objects[objIndex] if isinstance(obj, pdf.PageObject) and obj.indirectRef != None: data = obj.indirectRef if data.pdf not in externalReferenceMap: externalReferenceMap[data.pdf] = {} if data.generation not in externalReferenceMap[data.pdf]: externalReferenceMap[data.pdf][data.generation] = {} externalReferenceMap[data.pdf][data.generation][ data.idnum] = po.IndirectObject(objIndex + 1, 0, self) self.stack = [] self._sweepIndirectReferences(externalReferenceMap, self._root) del self.stack # Begin writing: positions = {} for i in range(2, len(self._objects)): idnum = i + 1 obj = self._objects[i] if obj is None: continue positions[idnum] = startxref + stream.tell() stream.write(pdf.b_(str(idnum) + " 0 obj\n")) key = None if hasattr(self, "_encrypt") and idnum != self._encrypt.idnum: pack1 = struct.pack("<i", i + 1)[:3] pack2 = struct.pack("<i", 0)[:2] key = self._encrypt_key + pack1 + pack2 assert len(key) == (len(self._encrypt_key) + 5) md5_hash = hashlib.md5(key).digest() key = md5_hash[:min(16, len(self._encrypt_key) + 5)] obj.writeToStream(stream, key) stream.write(pdf.b_("\nendobj\n")) # xref table xref_location = startxref + stream.tell() stream.write(pdf.b_("xref\n")) stream.write(pdf.b_("0 1\n")) stream.write(pdf.b_("0000000000 65535 f\n")) stream.write(pdf.b_("9 %d\n" % (len(positions)))) for key in sorted(positions.keys()): stream.write(pdf.b_("%010d %05d n\n" % (positions[key], 0))) # trailer stream.write(pdf.b_("trailer\n")) trailer = po.DictionaryObject() trailer.update({ po.NameObject("/Size"): po.NumberObject(len(self._objects) + 1), po.NameObject("/Root"): self.x_root, po.NameObject("/Info"): self.x_info, po.NameObject("/Prev"): po.NumberObject(prev.startxref), }) if hasattr(self, "_ID"): trailer[po.NameObject("/ID")] = self._ID if hasattr(self, "_encrypt"): trailer[po.NameObject("/Encrypt")] = self._encrypt trailer.writeToStream(stream, None) # eof stream.write(pdf.b_("\nstartxref\n%s\n%%%%EOF\n" % (xref_location)))