Пример #1
0
 def get_pages(klass,
               fp,
               pagenos=None,
               maxpages=0,
               password='',
               caching=True,
               check_extractable=True):
     # Create a PDF parser object associated with the file object.
     parser = PDFParser(fp)
     # Create a PDF document object that stores the document structure.
     doc = PDFDocument(parser, caching=caching)
     # Supply the document password for initialization.
     # (If no password is set, give an empty string.)
     doc.initialize(password)
     # Check if the document allows text extraction. If not, abort.
     if check_extractable and not doc.is_extractable:
         raise klass.PDFTextExtractionNotAllowed(
             'Text extraction is not allowed: %r' % fp)
     # Process each page contained in the document.
     for (pageno, page) in enumerate(klass.create_pages(doc)):
         if pagenos and (pageno not in pagenos):
             continue
         yield page
         if maxpages and maxpages <= pageno + 1:
             break
     return
Пример #2
0
    def __init__(self,
                 filepath,
                 orientation="P",
                 layout="letter",
                 font_list=None,
                 font_dir=None):
        if font_dir is not None:
            FontLoader.load_from_dir(font_dir)
        elif font_list is not None:
            FontLoader.load_from_list(font_list)
        else:
            FontLoader.load_fonts()

        self.filepath = filepath
        self.destination = None

        if hasattr(self.filepath, 'write'):
            self.destination = self.filepath
        elif self.filepath == 'string':
            self.destination = 'string'

        # Create session and document objects
        self.session = _Session(self)
        self.document = PDFDocument(self.session, orientation, layout)

        # Full width display mode default
        self.set_display_mode()
        # Set default PDF version number
        self.pdf_version = '1.7'

        # Initialize PDF information
        self.set_information()
        self.set_compression()
Пример #3
0
    def __init__(self, filepath, orientation="P", layout="letter", font_list=None, font_dir=None):
        if font_dir is not None:
            FontLoader.load_from_dir(font_dir)
        elif font_list is not None:
            FontLoader.load_from_list(font_list)
        else:
            FontLoader.load_fonts()

        self.filepath = filepath
        self.destination = None

        if hasattr(self.filepath, 'write'):
            self.destination = self.filepath
        elif self.filepath == 'string':
            self.destination = 'string'

        # Create session and document objects
        self.session = _Session(self)
        self.document = PDFDocument(self.session, orientation, layout)

        # Full width display mode default
        self.set_display_mode()
        # Set default PDF version number
        self.pdf_version = '1.7'

        # Initialize PDF information
        self.set_information()
        self.set_compression()
Пример #4
0
 def get_pages(klass, fp,
               pagenos=None, maxpages=0, password='',
               caching=True, check_extractable=True):
     # Create a PDF parser object associated with the file object.
     parser = PDFParser(fp)
     # Create a PDF document object that stores the document structure.
     doc = PDFDocument(parser, caching=caching)
     # Supply the document password for initialization.
     # (If no password is set, give an empty string.)
     doc.initialize(password)
     # Check if the document allows text extraction. If not, abort.
     if check_extractable and not doc.is_extractable:
         raise klass.PDFTextExtractionNotAllowed('Text extraction is not allowed: %r' % fp)
     # Process each page contained in the document.
     for (pageno,page) in enumerate(klass.create_pages(doc)):
         if pagenos and (pageno not in pagenos): continue
         yield page
         if maxpages and maxpages <= pageno+1: break
     return
Пример #5
0
    def __init__(self, filepath):
        self.filepath = filepath

        self.SS = _Session(self)
        self.document = PDFDocument(self.SS)

        # Full width display mode default
        self.setDisplayMode()
        # Set default PDF version number
        self.pdf_version = '1.3'

        #Initialize PDF information
        self.setInformation()
        self.setCompression()
Пример #6
0
class PDFLite(object):
    """ PDF generator, this class creates a document,
        session object, and the PDF outline.

        There are some overall pdf options to set, like
        the meta-data in information (this won't print
        anywhere in the document, but can be seen in
        Properties, in Adobe reader.)

        When using this module, start by creating an
        instance of PDFLite, then request the document
        object with get_document. Make your inputs to that
        object, and finish by closing the PDFLite.

    """
    def __init__(self,
                 filepath,
                 orientation="P",
                 layout="letter",
                 font_list=None,
                 font_dir=None):
        if font_dir is not None:
            FontLoader.load_from_dir(font_dir)
        elif font_list is not None:
            FontLoader.load_from_list(font_list)
        else:
            FontLoader.load_fonts()

        self.filepath = filepath
        self.destination = None

        if hasattr(self.filepath, 'write'):
            self.destination = self.filepath
        elif self.filepath == 'string':
            self.destination = 'string'

        # Create session and document objects
        self.session = _Session(self)
        self.document = PDFDocument(self.session, orientation, layout)

        # Full width display mode default
        self.set_display_mode()
        # Set default PDF version number
        self.pdf_version = '1.7'

        # Initialize PDF information
        self.set_information()
        self.set_compression()

    def set_compression(self, value=True):
        # False is easier to read with a text editor.
        self.session._set_compression(value)

    def get_document(self):
        return self.document

    def set_information(self,
                        title=None,
                        subject=None,
                        author=None,
                        keywords=None,
                        creator=None):
        """ Convenience function to add property info, can set any attribute and leave the others blank, it won't over-write
            previously set items. """
        info_dict = {
            "title": title,
            "subject": subject,
            "author": author,
            "keywords": keywords,
            "creator": creator
        }

        for att, value in info_dict.iteritems():
            if hasattr(self, att):
                if value:
                    setattr(self, att, value)
            else:
                setattr(self, att, None)

    def set_display_mode(self, zoom='fullpage', layout='continuous'):
        """ Set the default viewing options. """
        self.zoom_options = ["fullpage", "fullwidth", "real", "default"]
        self.layout_options = ["single", "continuous", "two", "default"]

        if zoom in self.zoom_options or (isinstance(zoom, int)
                                         and 0 < zoom <= 100):
            self.zoom_mode = zoom
        else:
            raise Exception('Incorrect zoom display mode: ' + zoom)

        if layout in self.layout_options:
            self.layout_mode = layout
        else:
            raise Exception('Incorrect layout display mode: ' + layout)

    def close(self):
        """ Prompt the objects to output pdf code, and save to file. """
        self.document._set_page_numbers()
        # Places header, pages, page content first.
        self._put_header()
        self._put_pages()
        self._put_resources()
        # Information object
        self._put_information()
        # Catalog object
        self._put_catalog()
        # Cross-reference object
        #self._put_cross_reference()
        # Trailer object
        self._put_trailer()

        if hasattr(self.destination, "write"):
            output = self._output_to_io()
        elif self.destination == 'string':
            output = self._output_to_string()
        else:
            self._output_to_file()
            output = None
        return output

    # Private Methods for building the PDF
    def _put_header(self):
        """ Standard first line in a PDF. """
        self.session._out('%%PDF-%s' % self.pdf_version)
        if self.session.compression:
            self.session.buffer += '%' + chr(235) + chr(236) + chr(237) + chr(
                238) + "\n"

    def _put_pages(self):
        """ First, the Document object does the heavy-lifting for the
            individual page objects and content.

            Then, the overall "Pages" object is generated.

        """
        self.document._get_orientation_changes()
        self.document._output_pages()

        # Pages Object, provides reference to page objects (Kids list).
        self.session._add_object(1)
        self.session._out('<</Type /Pages')
        kids = '/Kids ['
        for i in xrange(0, len(self.document.pages)):
            kids += str(3 + 2 * i) + ' 0 R '
        self.session._out(kids + ']')
        self.session._out('/Count %s' % len(self.document.pages))

        # Overall size of the default PDF page
        self.session._out(
            '/MediaBox [0 0 %.2f %.2f]' %
            (self.document.page.width, self.document.page.height))
        self.session._out('>>')
        self.session._out('endobj')

    def _put_resources(self):
        """ Resource objects can be used several times throughout the document,
        but the pdf code defining them are all defined here.

        """
        self._put_fonts()
        self._put_images()

        # Resource dictionary
        self._put_resource_dict()

    def _put_fonts(self):
        """ Fonts definitions objects.

        """
        self.document._output_fonts()

    def _put_images(self):
        """ Image definition objects.

        """
        self.document._output_images()

    def _put_resource_dict(self):
        """ Creates PDF reference to resource objects.

        """
        self.session._add_object(2)
        self.session._out('<<')
        self.session._out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]')
        self.session._out('/Font <<')
        for font in self.document.fonts:
            self.session._out('/F%s %s 0 R' % (font.index, font.number))
        self.session._out('>>')
        if self.document.images:
            self.session._out('/XObject <<')
            for image in self.document.images:
                self.session._out('/I%s %s 0 R' % (image.index, image.number))
            self.session._out('>>')
        self.session._out('>>')
        self.session._out('endobj')

    def _put_information(self):
        """PDF Information object."""
        self.session._add_object()
        self.session._out('<<')
        self.session._out(
            '/Producer ' +
            self._text_to_string('PDFLite, https://github.com/katerina7479'))
        if self.title:
            self.session._out('/Title ' + self._text_to_string(self.title))
        if self.subject:
            self.session._out('/Subject ' + self._text_to_string(self.subject))
        if self.author:
            self.session._out('/Author ' + self._text_to_string(self.author))
        if self.keywords:
            self.session._out('/Keywords ' +
                              self._text_to_string(self.keywords))
        if self.creator:
            self.session._out('/Creator ' + self._text_to_string(self.creator))
        self.session._out('/CreationDate ' + self._text_to_string(
            'D:' + datetime.now().strftime('%Y%m%d%H%M%S')))
        self.session._out('>>')
        self.session._out('endobj')

    def _put_catalog(self):
        """Catalog object."""
        self.session._add_object()
        self.session._out('<<')

        self.session._out('/Type /Catalog')
        self.session._out('/Pages 1 0 R')
        if self.zoom_mode == 'fullpage':
            self.session._out('/OpenAction [3 0 R /Fit]')
        elif self.zoom_mode == 'fullwidth':
            self.session._out('/OpenAction [3 0 R /FitH null]')
        elif self.zoom_mode == 'real':
            self.session._out('/OpenAction [3 0 R /XYZ null null 1]')
        elif not isinstance(self.zoom_mode, basestring):
            self.session._out('/OpenAction [3 0 R /XYZ null null ' +
                              (self.zoom_mode / 100) + ']')

        if self.layout_mode == 'single':
            self.session._out('/PageLayout /SinglePage')
        elif self.layout_mode == 'continuous':
            self.session._out('/PageLayout /OneColumn')
        elif self.layout_mode == 'two':
            self.session._out('/PageLayout /TwoColumnLeft')
        self.session._out('>>')
        self.session._out('endobj')

    def _put_cross_reference(self):
        """ Cross Reference Object, calculates
            the position in bytes to the start
            (first number) of each object in
            order by number (zero is special)
            from the beginning of the file.

        """
        self.session._out('xref')
        self.session._out('0 %s' % len(self.session.objects))
        self.session._out('0000000000 65535 f ')
        for obj in self.session.objects:
            if isinstance(obj, basestring):
                pass
            else:
                self.session._out('%010d 00000 n ' % obj.offset)

    def _put_trailer(self):
        """ Final Trailer calculations, and end-of-file
            reference.

        """
        startxref = len(self.session.buffer)

        self._put_cross_reference()

        md5 = hashlib.md5()
        md5.update(datetime.now().strftime('%Y%m%d%H%M%S'))
        try:
            md5.update(self.filepath)
        except TypeError:
            pass
        if self.title:
            md5.update(self.title)
        if self.subject:
            md5.update(self.subject)
        if self.author:
            md5.update(self.author)
        if self.keywords:
            md5.update(self.keywords)
        if self.creator:
            md5.update(self.creator)

        objnum = len(self.session.objects)
        self.session._out('trailer')
        self.session._out('<<')
        self.session._out('/Size %s' % objnum)
        self.session._out('/Root %s 0 R' % (objnum - 1))
        self.session._out('/Info %s 0 R' % (objnum - 2))
        self.session._out('/ID [ <%s> <%s>]' %
                          (md5.hexdigest(), md5.hexdigest()))
        self.session._out('>>')
        self.session._out('startxref')
        self.session._out(startxref)
        self.session._out('%%EOF')

    def _output_to_file(self):
        """ Save to filepath specified on
            init. (Will throw an error if
            the document is already open).

        """
        f = open(self.filepath, 'wb')
        if not f:
            raise Exception('Unable to create output file: ', self.filepath)
        f.write(self.session.buffer)
        f.close()

    def _output_to_string(self):
        return self.session.buffer

    def _output_to_io(self):
        self.destination.write(self.session.buffer)
        return self.destination

    def _text_to_string(self, text):
        """ Provides for escape characters and converting to
            pdf text object (pdf strings are in parantheses).
            Mainly for use in the information block here, this
            functionality is also present in the text object.

        """
        if text:
            for i, j in [("\\", "\\\\"), (")", "\\)"), ("(", "\\(")]:
                text = text.replace(i, j)
            text = "(%s)" % text
        else:
            text = 'None'
        return text
Пример #7
0
class PDFLite(object):
    """ PDF Generator, this class creates a document,
        session object, and creates the PDF outline.

        Has some overall pdf options to set, like
        the meta-data in Information (it won't print
        anywhere in the document, but can be seen in
        Properties, in Adobe reader.)

        When using this module, start by creating an
        instance of PDFLite, then request the document
        object with getDocument. Make your inputs to that
        object, and finish by closing through PDFLite.

    """

    def __init__(self, filepath):
        self.filepath = filepath

        self.SS = _Session(self)
        self.document = PDFDocument(self.SS)

        # Full width display mode default
        self.setDisplayMode()
        # Set default PDF version number
        self.pdf_version = '1.3'

        #Initialize PDF information
        self.setInformation()
        self.setCompression()

    def setCompression(self, value=False):
        # False is easier to read with a text editor.
        self.SS._setCompression(value)

    def getDocument(self):
        return self.document

    def setInformation(self, title=None, subject=None, author=None, keywords=None, creator=None):
        """ Convinence function to add property info, can set any
            attribute and leave the others blank, it won't over-write
            previously set items, but to delete, you must set the attribute
            directly to None. (Since it is expected this will be in a generating
            program the likely-hood of such usage would be minimal.)

        """
        testdict = {"title": title, "subject": subject, "author": author, "keywords": keywords, "creator": creator}

        for att, value in testdict.iteritems():
            if hasattr(self, att):
                if value is not None:
                    setattr(self, att, value)
                elif value is None:
                    pass
            else:
                setattr(self, att, None)

    def setDisplayMode(self, zoom='fullpage', layout='continuous'):
        "Set display mode in viewer"
        self.zoom_options = ["fullpage", "fullwidth", "real", "default"]
        self.layout_options = ["single", "continuous", "two", "default"]

        if zoom in self.zoom_options:
            self.zoom_mode = zoom
        else:
            raise Exception('Incorrect zoom display mode: ' + zoom)

        if layout in self.layout_options:
            self.layout_mode = layout
        else:
            raise Exception('Incorrect layout display mode: ' + layout)

    def close(self):
        "Generate the document"
        # Places header, pages, page content first.
        self._putHeader()
        self._putPages()
        self._putResources()
        # Information object
        self._putInformation()
        # Catalog object
        self._putCatalog()
        # Cross-reference object
        self._putCrossReference()
        # Trailer object
        self._putTrailer()
        self._outputToFile()

    def _putHeader(self):
        "Standard first line"
        self.SS._out('%%PDF-%s' % self.pdf_version)

    def _putPages(self):
        """ First, the Document object does the heavy-lifting for the
            individual page objects and content.

            Then, the overall "Pages" object is generated.

        """
        self.document._getOrientationChanges()
        self.document._outputPages()

        # Pages Object, provides reference to page objects (Kids list).
        self.SS._addObject(1)
        self.SS._out('<</Type /Pages')
        kids = '/Kids ['
        for i in xrange(0, len(self.document.pages)):
            kids += str(3 + 2*i) + ' 0 R '
        self.SS._out(kids + ']')
        self.SS._out('/Count %s' % len(self.document.pages))
        self.SS._out('/MediaBox [0 0 %.2f %.2f]' % (self.document.page.width, self.document.page.height))  # Overal size of the default PDF page
        self.SS._out('>>')
        self.SS._out('endobj')

    def _putResources(self):
        "Resource objects can be used several times, but are defined here."
        self._putFonts()
        self._putImages()

        #Resource dictionary
        self._putResourceDict()

    def _putFonts(self):
        "Fonts definitions objects."
        self.document._outputFonts()

    def _putImages(self):
        pass

    def _putResourceDict(self):
        "PDF reference to resource objects."
        self.SS._addObject(2)
        self.SS._out('<<')
        self.SS._out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]')
        self.SS._out('/Font <<')
        for font in self.document.fonts:
            self.SS._out('/F' + str(font.index) + ' ' + str(font.number) + ' 0 R')
        self.SS._out('>>')
        self.SS._out('>>')
        self.SS._out('endobj')

    def _putInformation(self):
        "PDF Information object."
        self.SS._addObject()
        self.SS._out('<<')
        self.SS._out('/Producer '+self._textstring('PDFLite, https://github.com/katerina7479'))
        if self.title is not None:
            self.SS._out('/Title '+self._textstring(self.title))
        if self.subject is not None:
            self.SS._out('/Subject '+self._textstring(self.subject))
        if self.author is not None:
            self.SS._out('/Author '+self._textstring(self.author))
        if self.keywords is not None:
            self.SS._out('/Keywords '+self._textstring(self.keywords))
        if self.creator is not None:
            self.SS._out('/Creator '+self._textstring(self.creator))
        self.SS._out('/CreationDate '+self._textstring('D:'+datetime.now().strftime('%Y%m%d%H%M%S')))
        self.SS._out('>>')
        self.SS._out('endobj')

    def _putCatalog(self):
        "Catalog object."
        self.SS._addObject()
        self.SS._out('<<')

        self.SS._out('/Type /Catalog')
        self.SS._out('/Pages 1 0 R')
        if(self.zoom_mode == 'fullpage'):
            self.SS._out('/OpenAction [3 0 R /Fit]')
        elif(self.zoom_mode == 'fullwidth'):
            self.SS._out('/OpenAction [3 0 R /FitH null]')
        elif(self.zoom_mode == 'real'):
            self.SS._out('/OpenAction [3 0 R /XYZ null null 1]')
        elif(not isinstance(self.zoom_mode, basestring)):
            self.SS._out('/OpenAction [3 0 R /XYZ null null '+(self.zoom_mode/100)+']')

        if(self.layout_mode == 'single'):
            self.SS._out('/PageLayout /SinglePage')
        elif(self.layout_mode == 'continuous'):
            self.SS._out('/PageLayout /OneColumn')
        elif(self.layout_mode == 'two'):
            self.SS._out('/PageLayout /TwoColumnLeft')
        self.SS._out('>>')
        self.SS._out('endobj')

    def _putCrossReference(self):
        """ Cross Reference Object, calculates
            the position in bytes to the start
            (first number) of each object in
            order by number (zero is special)
            from the begining of the file.

        """
        self.SS._out('xref')
        self.SS._out('0 %s' % len(self.SS.objects))
        self.SS._out('0000000000 65535 f ')
        for obj in self.SS.objects:
            if isinstance(obj, basestring):
                pass
            else:
                self.SS._out('%010d 00000 n ' % obj.offset)

    def _putTrailer(self):
        """ Final Trailer calculations, and EOF
            reference.

        """
        objnum = len(self.SS.objects)
        self.SS._out('trailer')
        self.SS._out('<<')
        self.SS._out('/Size %s' % objnum)
        self.SS._out('/Root %s 0 R' % (objnum-1))
        self.SS._out('/Info %s 0 R' % (objnum-2))
        self.SS._out('>>')
        self.SS._out('startxref')
        self.SS._out(len(self.SS.buffer))
        self.SS._out('%%EOF')

    def _outputToFile(self):
        """ Save to filepath specified on
            init. (Will throw an error if
            the document is already open).

        """
        f = open(self.filepath, 'wb')
        if(not f):
            raise Exception('Unable to create output file: ', self.filepath)
        f.write(self.SS.buffer)
        f.close()

    def _textstring(self, text):
        """ Provides for escape characters and converting to
            pdf text object (pdf strings are in parantheses).
            Mainly for use in the information block here, this
            functionality is replicated elsewhere.

        """
        if text is not None:
            for i, j in {"\\": "\\\\", ")": "\\)", "(": "\\("}.iteritems():
                text = text.replace(i, j)
            text = "(%s)" % text
        else:
            text = 'None'
        return text
Пример #8
0
class PDFLite(object):

    """ PDF generator, this class creates a document,
        session object, and the PDF outline.

        There are some overall pdf options to set, like
        the meta-data in information (this won't print
        anywhere in the document, but can be seen in
        Properties, in Adobe reader.)

        When using this module, start by creating an
        instance of PDFLite, then request the document
        object with get_document. Make your inputs to that
        object, and finish by closing the PDFLite.

    """

    def __init__(self, filepath, orientation="P", layout="letter", font_list=None, font_dir=None):
        if font_dir is not None:
            FontLoader.load_from_dir(font_dir)
        elif font_list is not None:
            FontLoader.load_from_list(font_list)
        else:
            FontLoader.load_fonts()

        self.filepath = filepath
        self.destination = None

        if hasattr(self.filepath, 'write'):
            self.destination = self.filepath
        elif self.filepath == 'string':
            self.destination = 'string'

        # Create session and document objects
        self.session = _Session(self)
        self.document = PDFDocument(self.session, orientation, layout)

        # Full width display mode default
        self.set_display_mode()
        # Set default PDF version number
        self.pdf_version = '1.7'

        # Initialize PDF information
        self.set_information()
        self.set_compression()

    def set_compression(self, value=True):
        # False is easier to read with a text editor.
        self.session._set_compression(value)

    def get_document(self):
        return self.document

    def set_information(self, title=None, subject=None, author=None, keywords=None, creator=None):
        """ Convenience function to add property info, can set any attribute and leave the others blank, it won't over-write
            previously set items. """
        info_dict = {"title": title, "subject": subject,
                     "author": author, "keywords": keywords,
                     "creator": creator}

        for att, value in info_dict.iteritems():
            if hasattr(self, att):
                if value:
                    setattr(self, att, value)
            else:
                setattr(self, att, None)

    def set_display_mode(self, zoom='fullpage', layout='continuous'):
        """ Set the default viewing options. """
        self.zoom_options = ["fullpage", "fullwidth", "real", "default"]
        self.layout_options = ["single", "continuous", "two", "default"]

        if zoom in self.zoom_options or (isinstance(zoom, int) and 0 < zoom <= 100):
            self.zoom_mode = zoom
        else:
            raise Exception('Incorrect zoom display mode: ' + zoom)

        if layout in self.layout_options:
            self.layout_mode = layout
        else:
            raise Exception('Incorrect layout display mode: ' + layout)

    def close(self):
        """ Prompt the objects to output pdf code, and save to file. """
        self.document._set_page_numbers()
        # Places header, pages, page content first.
        self._put_header()
        self._put_pages()
        self._put_resources()
        # Information object
        self._put_information()
        # Catalog object
        self._put_catalog()
        # Cross-reference object
        #self._put_cross_reference()
        # Trailer object
        self._put_trailer()

        if hasattr(self.destination, "write"):
            output = self._output_to_io()
        elif self.destination == 'string':
            output = self._output_to_string()
        else:
            self._output_to_file()
            output = None
        return output

    # Private Methods for building the PDF
    def _put_header(self):
        """ Standard first line in a PDF. """
        self.session._out('%%PDF-%s' % self.pdf_version)
        if self.session.compression:
            self.session.buffer += '%' + chr(235) + chr(236) + chr(237) + chr(238) + "\n"

    def _put_pages(self):
        """ First, the Document object does the heavy-lifting for the
            individual page objects and content.

            Then, the overall "Pages" object is generated.

        """
        self.document._get_orientation_changes()
        self.document._output_pages()

        # Pages Object, provides reference to page objects (Kids list).
        self.session._add_object(1)
        self.session._out('<</Type /Pages')
        kids = '/Kids ['
        for i in xrange(0, len(self.document.pages)):
            kids += str(3 + 2 * i) + ' 0 R '
        self.session._out(kids + ']')
        self.session._out('/Count %s' % len(self.document.pages))

        # Overall size of the default PDF page
        self.session._out('/MediaBox [0 0 %.2f %.2f]' %
                          (self.document.page.width,
                           self.document.page.height))
        self.session._out('>>')
        self.session._out('endobj')

    def _put_resources(self):
        """ Resource objects can be used several times throughout the document,
        but the pdf code defining them are all defined here.

        """
        self._put_fonts()
        self._put_images()

        # Resource dictionary
        self._put_resource_dict()

    def _put_fonts(self):
        """ Fonts definitions objects.

        """
        self.document._output_fonts()

    def _put_images(self):
        """ Image definition objects.

        """
        self.document._output_images()

    def _put_resource_dict(self):
        """ Creates PDF reference to resource objects.

        """
        self.session._add_object(2)
        self.session._out('<<')
        self.session._out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]')
        self.session._out('/Font <<')
        for font in self.document.fonts:
            self.session._out('/F%s %s 0 R' % (font.index, font.number))
        self.session._out('>>')
        if self.document.images:
            self.session._out('/XObject <<')
            for image in self.document.images:
                self.session._out('/I%s %s 0 R' % (image.index, image.number))
            self.session._out('>>')
        self.session._out('>>')
        self.session._out('endobj')

    def _put_information(self):
        """PDF Information object."""
        self.session._add_object()
        self.session._out('<<')
        self.session._out('/Producer ' + self._text_to_string(
            'PDFLite, https://github.com/katerina7479'))
        if self.title:
            self.session._out('/Title ' + self._text_to_string(self.title))
        if self.subject:
            self.session._out('/Subject ' + self._text_to_string(self.subject))
        if self.author:
            self.session._out('/Author ' + self._text_to_string(self.author))
        if self.keywords:
            self.session._out('/Keywords ' +
                              self._text_to_string(self.keywords))
        if self.creator:
            self.session._out('/Creator ' + self._text_to_string(self.creator))
        self.session._out('/CreationDate ' + self._text_to_string(
            'D:' + datetime.now().strftime('%Y%m%d%H%M%S')))
        self.session._out('>>')
        self.session._out('endobj')

    def _put_catalog(self):
        """Catalog object."""
        self.session._add_object()
        self.session._out('<<')

        self.session._out('/Type /Catalog')
        self.session._out('/Pages 1 0 R')
        if self.zoom_mode == 'fullpage':
            self.session._out('/OpenAction [3 0 R /Fit]')
        elif self.zoom_mode == 'fullwidth':
            self.session._out('/OpenAction [3 0 R /FitH null]')
        elif self.zoom_mode == 'real':
            self.session._out('/OpenAction [3 0 R /XYZ null null 1]')
        elif not isinstance(self.zoom_mode, basestring):
            self.session._out(
                '/OpenAction [3 0 R /XYZ null null ' +
                (self.zoom_mode / 100) + ']')

        if self.layout_mode == 'single':
            self.session._out('/PageLayout /SinglePage')
        elif self.layout_mode == 'continuous':
            self.session._out('/PageLayout /OneColumn')
        elif self.layout_mode == 'two':
            self.session._out('/PageLayout /TwoColumnLeft')
        self.session._out('>>')
        self.session._out('endobj')

    def _put_cross_reference(self):
        """ Cross Reference Object, calculates
            the position in bytes to the start
            (first number) of each object in
            order by number (zero is special)
            from the beginning of the file.

        """
        self.session._out('xref')
        self.session._out('0 %s' % len(self.session.objects))
        self.session._out('0000000000 65535 f ')
        for obj in self.session.objects:
            if isinstance(obj, basestring):
                pass
            else:
                self.session._out('%010d 00000 n ' % obj.offset)

    def _put_trailer(self):
        """ Final Trailer calculations, and end-of-file
            reference.

        """
        startxref = len(self.session.buffer)
        
        self._put_cross_reference()
        
        md5 = hashlib.md5()
        md5.update(datetime.now().strftime('%Y%m%d%H%M%S'))
        try:
            md5.update(self.filepath)
        except TypeError:
            pass
        if self.title:
            md5.update(self.title)
        if self.subject:
            md5.update(self.subject)
        if self.author:
            md5.update(self.author)
        if self.keywords:
            md5.update(self.keywords)
        if self.creator:
            md5.update(self.creator)
        
        objnum = len(self.session.objects)
        self.session._out('trailer')
        self.session._out('<<')
        self.session._out('/Size %s' % objnum)
        self.session._out('/Root %s 0 R' % (objnum - 1))
        self.session._out('/Info %s 0 R' % (objnum - 2))
        self.session._out('/ID [ <%s> <%s>]' % (md5.hexdigest(),md5.hexdigest()))
        self.session._out('>>')
        self.session._out('startxref')
        self.session._out(startxref)
        self.session._out('%%EOF')

    def _output_to_file(self):
        """ Save to filepath specified on
            init. (Will throw an error if
            the document is already open).

        """
        f = open(self.filepath, 'wb')
        if not f:
            raise Exception('Unable to create output file: ', self.filepath)
        f.write(self.session.buffer)
        f.close()

    def _output_to_string(self):
        return self.session.buffer

    def _output_to_io(self):
        self.destination.write(self.session.buffer)
        return self.destination

    def _text_to_string(self, text):
        """ Provides for escape characters and converting to
            pdf text object (pdf strings are in parantheses).
            Mainly for use in the information block here, this
            functionality is also present in the text object.

        """
        if text:
            for i,j in [("\\","\\\\"),(")","\\)"),("(", "\\(")]:
                text = text.replace(i, j)
            text = "(%s)" % text
        else:
            text = 'None'
        return text