systori/bericht

View on GitHub
bericht/pdf/document.py

Summary

Maintainability
A
0 mins
Test Coverage
from .reference import PDFReference
from .letterhead import PDFLetterhead
from .page import PDFPage
from .font import read_font

__all__ = ('PDFDocument',)


class PDFDocument:

    def __init__(self, css, letterhead=None, layout='portrait'):
        self.css = css
        self.ref_ids = 0
        self.offset = 0
        self.references = []
        self.page = None
        self.layout = layout
        self.root = self.ref({
            'Type': 'Catalog',
            'Pages': self.ref({
                'Type': 'Pages',
                'Count': 0,
                'Kids': []
            })
        })
        self.info = self.ref({
            'Producer': '(bericht)',
        })
        self.letterhead = PDFLetterhead(self, letterhead) if letterhead else None

        # font id (/F1) -> Reference object (7 0 R)
        self.font_references = {}
        # required by reportlab fonts handling code:
        self.fontMapping = {}  # font name (Helvetica) -> font id (/F1)
        self.delayedFonts = []  # fonts to be rendered

    def header(self):
        src = b"%PDF-1.7\n%\xc3\xbf\xc3\xbf\xc3\xbf\xc3\xbf\n"
        self.offset += len(src)
        yield src
        if self.letterhead:
            yield from self.letterhead.read()

    def finalize_reference(self, ref):
        ref.offset = self.offset
        for chunk in ref.read():
            self.offset += len(chunk)
            yield chunk

    @property
    def footer_refs(self):
        yield self.info
        yield self.root
        yield self.root.meta['Pages']

    def footer(self):
        for ref in self.footer_refs:
            yield from self.finalize_reference(ref)

        for font in self.delayedFonts:
            yield from read_font(self, font)

        yield b"xref\n"
        yield "0 {}\n".format(len(self.references) + 1).encode()
        yield b"0000000000 65535 f \n"
        for ref in self.references:
            yield "{:0>10} 00000 n \n".format(ref.offset).encode()

        yield b"trailer\n"
        yield from self.ref({
            'Size': len(self.references) + 1,
            'Root': self.root,
            'Info': self.info
        }).read_meta()

        yield b"startxref\n"
        yield str(self.offset).encode()
        yield b"\n%%EOF\n"

    def ref(self, meta=None, name=None):
        self.ref_ids += 1
        ref = PDFReference(self.ref_ids, meta, name)
        self.references.append(ref)
        return ref

    def add_page(self):
        pages = self.root.meta['Pages'].meta
        pages['Count'] += 1
        self.page = PDFPage(self, pages['Count'], self.css, 'a4', self.layout)
        pages['Kids'].append(self.page.dictionary)
        return self.page