Exemplo n.º 1
0
Arquivo: pdf.py Projeto: unikmhz/npui
    def end(self, tag):
        curctx = super(PDFParseTarget, self).end(tag)
        parent = self.parent
        ss = self.req.pdf_styles

        if (isinstance(curctx, npdml.NPDMLPageContext)
                and isinstance(parent, npdml.NPDMLPageTemplateContext)):
            self._page_tpls[curctx['id']] = curctx
        elif (isinstance(curctx, npdml.NPDMLFrameContext)
                and isinstance(parent, npdml.NPDMLPageContext)):
            parent['frames'].append(curctx)
        elif isinstance(curctx, npdml.NPDMLParagraphContext):
            btext = None
            if curctx.is_numbered:
                btext = self.get_bullet(curctx)
            para = Paragraph(curctx.get_data(),
                             ss[curctx.get('style', 'body')],
                             bulletText=btext)
            if isinstance(parent, npdml.NPDMLCanvasContext):
                parent.canvas.add((curctx, para))
            else:
                self.story.append(para)
        elif isinstance(curctx, npdml.NPDMLTableCellContext):
            para_style = 'body'
            if isinstance(parent, npdml.NPDMLTableHeaderContext):
                para_style = 'table_header'
            if 'width' in curctx:
                parent.widths.append(eval_length(curctx['width']))
            else:
                parent.widths.append(None)
            para = Paragraph(curctx.get_data(),
                             ss[curctx.get('style', para_style)])

            colspan = 1
            rowspan = 1
            if 'colspan' in curctx:
                try:
                    colspan = int(curctx['colspan'])
                except (TypeError, ValueError):
                    pass
            if 'rowspan' in curctx:
                try:
                    rowspan = int(curctx['rowspan'])
                except (TypeError, ValueError):
                    pass
            para.colspan = colspan
            para.rowspan = rowspan
            parent.cells.append(para)
            if colspan > 1:
                parent.cells.extend([''] * (colspan - 1))
        elif isinstance(curctx, npdml.NPDMLTableRowContext):
            parent.rows.append(curctx.cells)
            if isinstance(curctx, npdml.NPDMLTableHeaderContext):
                parent.has_header = True
            if len(parent.widths) < len(curctx.widths):
                parent.widths = curctx.widths
        elif isinstance(curctx, npdml.NPDMLTableContext):
            # FIXME: unhardcode spacing
            kwargs = {
                'colWidths':   curctx.widths,
                'spaceBefore': 8
            }
            if 'repeatRows' in curctx:
                try:
                    kwargs['repeatRows'] = int(curctx['repeatRows'])
                except (TypeError, ValueError):
                    pass
            if 'align' in curctx:
                value = curctx['align'].upper()
                if value in ('LEFT', 'RIGHT', 'CENTER'):
                    kwargs['hAlign'] = value

            extra_style = []
            rowspans = {}

            for rowidx, row in enumerate(curctx.rows):
                for colidx in list(rowspans):
                    rowspans[colidx] -= 1
                    if rowspans[colidx] == 0:
                        del rowspans[colidx]
                    row.insert(colidx, '')
                for colidx, col in enumerate(row):
                    if not isinstance(col, Paragraph):
                        continue
                    if col.colspan > 1 or col.rowspan > 1:
                        extra_style.append(('SPAN',
                                            (colidx, rowidx),
                                            (colidx + col.colspan - 1,
                                             rowidx + col.rowspan - 1)))
                        if col.rowspan > 1:
                            # FIXME: proper backgrounds of spanned cells
                            extra_style.append(('ROWBACKGROUNDS',
                                                (colidx, rowidx),
                                                (colidx + col.colspan - 1,
                                                 rowidx + col.rowspan - 1),
                                                (colors.white,)))
                            for idx in range(colidx, colidx + col.colspan):
                                rowspans[idx] = col.rowspan - 1

            table = Table(curctx.rows, **kwargs)
            table.setStyle(DefaultTableStyle(extra_style,
                                             has_header=curctx.has_header))
            self.story.append(table)
        elif isinstance(curctx, npdml.NPDMLAnchorContext):
            curctx.setdefault('color', 'blue')
            markup = '<a %s>%s</a>' % (_attr_str(curctx), curctx.get_data())
            parent.data.append(markup)
        elif isinstance(curctx, npdml.NPDMLBoldContext):
            markup = '<b>%s</b>' % (curctx.get_data(),)
            parent.data.append(markup)
        elif isinstance(curctx, npdml.NPDMLItalicContext):
            markup = '<i>%s</i>' % (curctx.get_data(),)
            parent.data.append(markup)
        elif isinstance(curctx, npdml.NPDMLUnderlineContext):
            markup = '<u>%s</u>' % (curctx.get_data(),)
            parent.data.append(markup)
        elif isinstance(curctx, npdml.NPDMLStrikethroughContext):
            markup = '<strike>%s</strike>' % (curctx.get_data(),)
            parent.data.append(markup)
        elif isinstance(curctx, npdml.NPDMLSuperscriptContext):
            markup = '<super>%s</super>' % (curctx.get_data(),)
            parent.data.append(markup)
        elif isinstance(curctx, npdml.NPDMLSubscriptContext):
            markup = '<sub>%s</sub>' % (curctx.get_data(),)
            parent.data.append(markup)
        elif isinstance(curctx, npdml.NPDMLFontContext):
            kwargs = {}
            for attr in ('name', 'size', 'color'):
                if attr in curctx:
                    kwargs[attr] = curctx[attr]
            if len(kwargs):
                markup = '<font %s>%s</font>' % (_attr_str(kwargs),
                                                 curctx.get_data())
                parent.data.append(markup)
            else:
                parent.data.append(curctx.get_data())
        elif isinstance(curctx, npdml.NPDMLImageContext):
            kwargs = {}
            src = urlparse.urlparse(curctx['src'])
            # TODO: Support http, https, and vfs URLs
            if src.scheme != 'file':
                raise NotImplementedError('Only "file://" URLs '
                                          'are implemented.')
            image = src.path
            if image.endswith('.svg') or image.endswith('.svgz'):
                image = svglib.svg2rlg(image)
            if isinstance(parent, npdml.NPDMLCanvasContext):
                if isinstance(image, shapes.Drawing):
                    parent.canvas.add((curctx, image))
                else:
                    x = eval_length(curctx.get('x', 0))
                    y = eval_length(curctx.get('y', 0))
                    # FIXME: we fail to position image properly when
                    #        width/height are not given.
                    width = eval_length(curctx.get('width', 0))
                    height = eval_length(curctx.get('height', 0))
                    image = shapes.Image(x, - y - height, width, height, image)
                    parent.canvas.add(image)
            else:
                # TODO: support different scaling modes (kind=)
                if 'width' in curctx:
                    kwargs['width'] = eval_length(curctx['width'])
                if 'height' in curctx:
                    kwargs['height'] = eval_length(curctx['height'])
                if 'align' in curctx:
                    value = curctx['align'].upper()
                    if value in ('LEFT', 'RIGHT', 'CENTER'):
                        kwargs['hAlign'] = value
                # TODO: vAlign
                if isinstance(image, shapes.Drawing):
                    for k, v in kwargs.items():
                        setattr(image, k, v)
                    self.story.append(image)
                else:
                    self.story.append(Image(image, **kwargs))
        elif isinstance(curctx, npdml.NPDMLTitleContext):
            if isinstance(parent, npdml.NPDMLPageContext):
                para = Paragraph(curctx.get_data(),
                                 ss[curctx.get('style', 'title')])
                self.story.append(para)
            elif isinstance(parent, npdml.NPDMLMetadataContext):
                self._title = curctx.get_data()
            elif isinstance(parent, npdml.NPDMLSectionContext):
                text = curctx.get_data()
                para_text = text
                sect_id = self.get_section_id()
                dlevel = parent.depth
                btext = None
                if parent.is_numbered:
                    btext = self.get_bullet(curctx)

                    if parent.in_toc and dlevel > 0:
                        para_text = '<a name="%s"/>%s' % (sect_id,
                                                          text)
                        outline = '%s%s' % (
                            '' if btext is None else btext + ' ',
                            text)
                        self.story.append(OutlineEntryFlowable(outline,
                                                               sect_id,
                                                               dlevel - 1))

                para = Paragraph(para_text,
                                 ss[curctx.get('style',
                                               'heading' + str(dlevel))],
                                 bulletText=btext)
                self.story.append(para)
        elif isinstance(curctx, npdml.NPDMLCanvasContext):
            self.story.append(curctx.canvas)

        # Process canvas-only elements
        if isinstance(parent, npdml.NPDMLCanvasContext):
            canvas = parent.canvas
            if isinstance(curctx, npdml.NPDMLLineContext):
                x1 = eval_length(curctx.pop('x1', 0))
                y1 = eval_length(curctx.pop('y1', 0))
                x2 = eval_length(curctx.pop('x2'))
                y2 = eval_length(curctx.pop('y2'))
                canvas.add(shapes.Line(x1, -y1, x2, -y2, **curctx))
            elif isinstance(curctx, npdml.NPDMLRectangleContext):
                x = eval_length(curctx.pop('x', 0))
                y = eval_length(curctx.pop('y', 0))
                width = eval_length(curctx.pop('width'))
                height = eval_length(curctx.pop('height', width))
                rx = eval_length(curctx.pop('rx', 0))
                ry = eval_length(curctx.pop('ry', 0))
                curctx.setdefault('fillColor', None)
                canvas.add(shapes.Rect(x, - y - height,
                                       width, height,
                                       rx, ry,
                                       **curctx))
            elif isinstance(curctx, npdml.NPDMLLabelContext):
                x = eval_length(curctx.pop('x', 0))
                y = eval_length(curctx.pop('y', 0))
                curctx.setdefault('fontName', DEFAULT_FONT)
                canvas.add(shapes.String(x, -y, curctx.get_data(), **curctx))
            elif isinstance(curctx, npdml.NPDMLCircleContext):
                cx = eval_length(curctx.pop('cx'))
                cy = eval_length(curctx.pop('cy'))
                radius = eval_length(curctx.pop('radius'))
                curctx.setdefault('fillColor', None)
                canvas.add(shapes.Circle(cx, -cy, radius, **curctx))
            elif isinstance(curctx, npdml.NPDMLEllipseContext):
                cx = eval_length(curctx.pop('cx'))
                cy = eval_length(curctx.pop('cy'))
                rx = eval_length(curctx.pop('rx'))
                ry = eval_length(curctx.pop('ry'))
                curctx.setdefault('fillColor', None)
                canvas.add(shapes.Ellipse(cx, -cy, rx, ry, **curctx))

        if isinstance(curctx, npdml.NPDMLBlock) and curctx._indenter:
            self.story.append(Indenter(-curctx._indenter.left,
                                       -curctx._indenter.right))