我正在尝试获取类似以下代码片段的内容来实际绘制旋转 90 度的文档。页面大小已经是我最终想要的样子,但文本仍然是水平的。如何旋转文本使其垂直?
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)
这是这个问题的最佳谷歌结果,所以我想我应该发布一个更好的解决方案。我的答案直接来自这里
如果您使用文档模板,则可以使用非常轻量级的 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)
然后在文档中使用它:
# 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)
这给出了:
我找到了一个简单的方法来解决这个问题,使用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
受到 KJYDavis 发布的解决方案的启发,我制作了一个 VerticalParagraph,以便它支持段落具有的样式功能,例如 ParagraphStyle、XML 标记标签和段落内标记(Reportlab 文档第 6 章)
from reportlab.platypus import Paragraph
class VerticalParagraph(Paragraph):
"""Paragraph that is printed vertically (rotated 90 degrees counterclockwise"""
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 或类似的东西,这会很好。
也许您可以通过添加构建方法来做到这一点。
是这样的。
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()
如果您不需要
Paragraph
的文本换行功能,但您想要比原始画布更流畅的支持,则可以将旋转文本放入 Drawing
中。这是一个简单的例子:
from reportlab.graphics.shapes import Drawing, Group, String
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate, Paragraph
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_lines = ["I really need this to be",
"wrapped and vertical!"]
para = Paragraph('Basic text.', normal)
story.append(para)
drawing = Drawing(50, 110)
group = Group()
group.rotate(-90)
for i, line in enumerate(text_lines):
group.add(String(-100, 15*(2-i), line, fontName='Helvetica'))
drawing.add(group)
story.append(drawing)
para2 = Paragraph('More text.', normal)
story.append(para2)
pdf.build(story)
如果你想将水平文本转换为垂直文本,我找到了一个简单直接的方法。
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))