带有ReportLab的旋转文档(垂直文本)

时间:2012-10-25 04:25:25

标签: python reportlab

我正在尝试获取类似以下代码段的内容,以实际将此文档旋转90度。 pagesize已经是我最终想要它的方式,但文本仍然是水平的。如何旋转文本使其垂直?

style = getSampleStyleSheet()
normal = style["Normal"]
normal.alignment = TA_CENTER
normal.fontName = "Helvetica"
normal.fontSize = 15

pdf = SimpleDocTemplate("testplatypus.pdf", pagesize = (80, 250), rightMargin=10, leftMargin=10, topMargin=20,bottomMargin=20)
story = []
text = "I really need this to be wrapped and vertical!"

para = Paragraph(text, normal)
story.append(para)
pdf.build(story)

5 个答案:

答案 0 :(得分:6)

这是此问题的最佳google结果,所以我想我会发布一个更好的解决方案。我的答案直接来自here

如果您使用的是doc模板,则可以使用非常轻量级的Flowable,它将在特定的表格单元格中创建垂直文本。

# rotatedtext.py
from reportlab.platypus.flowables import Flowable


class verticalText(Flowable):

'''Rotates a text in a table cell.'''

def __init__(self, text):
    Flowable.__init__(self)
    self.text = text

def draw(self):
    canvas = self.canv
    canvas.rotate(90)
    fs = canvas._fontsize
    canvas.translate(1, -fs/1.2)  # canvas._leading?
    canvas.drawString(0, 0, self.text)

def wrap(self, aW, aH):
    canv = self.canv
    fn, fs = canv._fontname, canv._fontsize
    return canv._leading, 1 + canv.stringWidth(self.text, fn, fs)

然后在doc中使用它:

# vertical_text_table.py
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib import colors
from reportlab.lib.colors import HexColor
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.platypus import (
      BaseDocTemplate, Frame, Paragraph, NextPageTemplate,
      PageBreak, PageTemplate, Image, Table, TableStyle, Spacer)
from rotatedtext import verticalText

document = BaseDocTemplate(
    'Vertical.pdf')

Elements = []

titleFrame_1 = Frame(
    0.5*inch, 0.75*inch, 7*inch, 9*inch, id='col1', showBoundary=0)
titleTemplate_1 = PageTemplate(
    id='OneCol', frames=titleFrame_1)
document.addPageTemplates([titleTemplate_1])

cw = [1.2*inch] + [1*inch]*6
rh = [0.25*inch] + [.6*inch] + [0.25*inch]*7

data = [
    ['Some', 'Reporting', '', 'Data', '', 'Here', ''],
    ['', verticalText('Vertical'), verticalText('Text'),
        verticalText('Vertical'), verticalText('Text'),
        verticalText('Vertical'), verticalText('Text')],
    ['Row1', '0', '0', '69', '803', '20751', '11627'],
    ['Row2', '0', '0', '1', '0', '1096', '103'],
    ['Row3', '0', '0', '0', '0', '233', '1'],
    ['Row4', '0', '0', '0', '0', '694', '38'],
    ['Row5', '0', '0', '23', '2', '1319', '2'],
    ['Row6', '0', '0', '0', '0', '0', '0'],
    ['TOTAL', '0', '0', '93', '805', '24093', '11771'],
    ]

ts = [
    ('GRID', (0, 0), (-1, -1), 0.5, colors.black),
    ('SPAN', (1, 0), (2, 0)),
    ('SPAN', (3, 0), (4, 0)),
    ('SPAN', (5, 0), (6, 0)),
    ('SPAN', (0, 0), (0, 1)),
    ('ALIGN', (0, 0), (-1, 1), 'CENTER'),
    ('ALIGN', (0, 2), (-1, -1), 'RIGHT'),
    ('VALIGN', (0, 0), (-1, -2), 'MIDDLE'),
    ('FONT', (0, 0), (-1, 1), 'Helvetica-Bold', 7, 7),
    ('FONT', (0, 2), (0, -2), 'Helvetica-Bold', 7, 7),
    ('FONT', (1, 2), (-1, -2), 'Helvetica', 7, 7),
    ('FONT', (0, -1), (-1, -1), 'Helvetica-Bold', 8, 8),
    ('TEXTCOLOR', (0, -1), (-1, -1), colors.white),
    ('BACKGROUND', (0, -1), (-1, -1), colors.black),
]

t = Table(
    data, style=ts,
    colWidths=cw, rowHeights=rh)

Elements.append(t)
document.build(Elements)

给出了:

Table with vertical text.

答案 1 :(得分:1)

也许你可以通过添加构建方法来做到这一点。

就是这样。

pdf = SimpleDocTemplate("testplatypus.pdf", pagesize = (80, 250), rightMargin=10,  leftMargin=10, topMargin=20,bottomMargin=20)
pdf.build(Story, onFirstPage = myFirstPage, onLaterPages=myLaterPages)

def myFirstPage(canvas, doc):
            canvas.saveState()
            canvas.rotate(90)
            canvas.restoreState()


def myLaterPages(canvas, doc):
            canvas.saveState()
            canvas.rotate(90)
            canvas.restoreState()

答案 2 :(得分:1)

我发现了一种使用canvas.drawString()的简单方法。它在常规的python函数中。以下示例中的“任何文本”将在您的pdf上垂直渲染文本。阅读代码中的注释以完全了解如何实现此目的。

def lista_privados(request, pk):
    g1 = get_object_or_404(Grupo, pk=pk)
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="{}"'.format(g1)
    buffer = BytesIO()
    c = canvas.Canvas(buffer, pagesize=A4)
    c.setPageSize(landscape(letter))

    #Whatever your other code is

重要的是,它仅在showPage()结束之前才起作用

    c.rotate(90)
    c.drawString(16*cm, -14*cm, "WHATEVER TEXT 1")
    c.drawString(16*cm, -14.4*cm, "WHATEVER TEXT 2")
            #c.drawString(x*cm, y*cm, "TEXT YOU WANT TO DISPLAY VERICALLY")
            #Note the '-' is VERY IMPORTANT OR IT WON'T WORK
            #ONLY WRITE THE c.rotate(90) one, you can list as many 'c.drawString(16*cm, -14*cm, "WHATEVER TEXT")' as you wish
            #The font size will be the last one you set on your code, so if for example you do "c.setFont('Helvetica', 5)" just the "c.rotate(90)", "WHATEVER TEXT" will be Helvetica, 5.

    c.showPage() #save page

    c.save()
    pdf = buffer.getvalue()
    buffer.close()
    response.write(pdf)
    template = 'privados/imp_list.html'
    return response

答案 3 :(得分:0)

受 KJYDavis 发布的解决方案的启发,我制作了一个 VerticalParagraph,以便它支持段落具有的样式功能,例如 ParaghaphStyle、XML 标记标签和段落内标记 (Reportlab Docs Chapter 6)

from reportlab.platypus import Paragraph


class VerticalParagraph(Paragraph):
"""Paragraph that is printed vertically"""

    def __init__(self, args, **kwargs):
        super().__init__(args, **kwargs)
        self.horizontal_position = -self.style.leading

    def draw(self):
        """ Draw text """
        canvas = self.canv
        canvas.rotate(90)
        canvas.translate(1, self.horizontal_position)
        super().draw()

    def wrap(self, available_width, _):
        """ Wrap text in table """
        string_width = self.canv.stringWidth(
            self.getPlainText(), self.style.fontName, self.style.fontSize
        )
        self.horizontal_position = - (available_width + self.style.leading) / 2
        height, _ = super().wrap(availWidth=1 + string_width, availHeight=available_width)
        return self.style.leading, height

它可以像使用 Paragraph Flowable 一样使用,尽管我只在表格中尝试过。

stylesheet = getSampleStyleSheet()
text = VerticalParagraph('<para align="CENTER">Some <b>BOLD</b> <i>Text</i></para>', stylesheet['BodyText'])

另一个好处是这个版本不需要直接访问 Canvas 的私有成员,例如 _fontname_fontsize_leading,如果您的项目使用 pylint 或类似的东西。

答案 4 :(得分:-1)

如果要将水平文本转换为垂直文本,我发现了一种简单的直接方法。

def your_function_name(request, pk):
    g1 = get_object_or_404(Grupo, pk=pk)
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=Plista2.pdf'
    buffer = BytesIO()
    c = canvas.Canvas(buffer, pagesize=A4)
c.setPageSize(landscape(letter))