Reportlab PDF:不能 space 段落按比例跨帧
Reportlab PDF: cannot space paragraphs proportionally across a frame
我正在尝试制作一个脚本,从 Google 日历中提取事件数据,并且每天在两列中显示日期的事件,它们之间的间隔与时间成正比(事件之间的时间越长,段落之间的 space 越多)。每个事件都是一个 Reportlab Platypus 段落,它们之间有 spacers。 Full code here(我保证很快就会评论)。
我的问题是我无法计算出将每个段落准确放入一个框架所需的确切间距:我总是高估或低估,无论公式如何,最后一段永远不会恰好落在底部框架。
主要计算从add_events_to_frame()开始。为每个事件制作段落并存储可用的 space,请求 spacer 高度值并将故事写入 canvas:
def add_events_to_frame(frame, events, canvas):
story = []
free_space = frame.height
for event in events:
paragraph = get_event_paragraph(event)
story.append(paragraph)
free_space -= paragraph.wrap(frame_width, frame_height)[1] - 1
real_story = []
if free_space > 0:
spaces = Collector.get_space_after(events, free_space)
for i, paragraph in enumerate(story):
real_story.append(paragraph)
real_story.append(Spacer(1, spaces[i] + 1))
frame.addFromList(real_story, canvas)
return frame
get_event_paragraph() 看起来像这样:
def get_event_paragraph(event, spaceAfter=0, borderPadding=2):
event_style = ParagraphStyle(
"event",
fontName="Times-Roman",
fontSize=5,
backColor=event['color'],
textColor='white',
leading=6,
borderPadding=borderPadding,
spaceAfter=spaceAfter + 2 * borderPadding
)
beginTime = event['start'].strftime("%H:%M")
endTime = event['end'].strftime("%H:%M")
eventStringList = [f"<b>{beginTime}-{endTime}</b>"]
eventStringList.append(event['summary'])
return Paragraph(' '.join(eventStringList), event_style)
以及 spacer 高度计算器:
def get_space_after(events, free_space):
"""
Calculate spaces between events in percentages based on sum of free time and constraints.
:param events:
:return:
"""
timesum = timedelta(seconds=1)
time_list = []
for i in range(len(events) - 1):
time_diff = events[i + 1]['start'] - events[i]['end']
timesum += time_diff
time_list.append(time_diff)
time_list.append(timedelta(hours=0))
spaces = []
for diff in time_list:
spaces.append(round(diff/timesum * free_space, 4))
return spaces
我已经尝试过 KeepInFrame(),但是当它发挥作用时,它会使设计不均匀且丑陋。我还尝试从 free_space 变量中以各种组合排除框架填充、段落填充和段落之间的 1px space,但同样,没有完全匹配。做什么?
我已经找到免费 space 东西的确切公式。以下是精确计算段落之间总空闲 space 的公式,它源于段落 borderPadding 只是一个序言,所有计算都是在帧填充和段落高度的上下文中完成的。所有变量都按照题中的代码。
首先,我们需要考虑框架顶部和底部的框架填充:
free_space = frame.height - frame.topPadding - frame.bottomPadding
其次,对于我们框架中的每个段落,我们需要减去框架填充上下文中的包裹高度,并向它们添加浪费在段落边框填充上的高度(注意:这适用于 borderPadding 值是所有段落都相同)和段落之间所需的 space(在本例中为末尾的 1):
free_space -= paragraph.wrap(
frame_width - frame.lefPadding - frame.rightPadding + 2 * paragraph.style.borderPadding, \
frame_height - frame.topPadding - frame.bottomPadding)[1] \
+ paragraph.style.borderPadding * 2 + 1
最后,您必须将段落的 borderPadding 值添加到 free_space 的两倍,否则您将达不到要求:不考虑 borderPadding,仅考虑段落边缘,因此我们需要填充第一段和最后一段使用 free space 使段落的边缘与框架填充的对齐:
free_space += paragraph.style.borderPadding * 2
这将使段落和框架之间变得清晰space:
frame.{any padding} - paragraph.style.borderPadding
我正在尝试制作一个脚本,从 Google 日历中提取事件数据,并且每天在两列中显示日期的事件,它们之间的间隔与时间成正比(事件之间的时间越长,段落之间的 space 越多)。每个事件都是一个 Reportlab Platypus 段落,它们之间有 spacers。 Full code here(我保证很快就会评论)。
我的问题是我无法计算出将每个段落准确放入一个框架所需的确切间距:我总是高估或低估,无论公式如何,最后一段永远不会恰好落在底部框架。
主要计算从add_events_to_frame()开始。为每个事件制作段落并存储可用的 space,请求 spacer 高度值并将故事写入 canvas:
def add_events_to_frame(frame, events, canvas):
story = []
free_space = frame.height
for event in events:
paragraph = get_event_paragraph(event)
story.append(paragraph)
free_space -= paragraph.wrap(frame_width, frame_height)[1] - 1
real_story = []
if free_space > 0:
spaces = Collector.get_space_after(events, free_space)
for i, paragraph in enumerate(story):
real_story.append(paragraph)
real_story.append(Spacer(1, spaces[i] + 1))
frame.addFromList(real_story, canvas)
return frame
get_event_paragraph() 看起来像这样:
def get_event_paragraph(event, spaceAfter=0, borderPadding=2):
event_style = ParagraphStyle(
"event",
fontName="Times-Roman",
fontSize=5,
backColor=event['color'],
textColor='white',
leading=6,
borderPadding=borderPadding,
spaceAfter=spaceAfter + 2 * borderPadding
)
beginTime = event['start'].strftime("%H:%M")
endTime = event['end'].strftime("%H:%M")
eventStringList = [f"<b>{beginTime}-{endTime}</b>"]
eventStringList.append(event['summary'])
return Paragraph(' '.join(eventStringList), event_style)
以及 spacer 高度计算器:
def get_space_after(events, free_space):
"""
Calculate spaces between events in percentages based on sum of free time and constraints.
:param events:
:return:
"""
timesum = timedelta(seconds=1)
time_list = []
for i in range(len(events) - 1):
time_diff = events[i + 1]['start'] - events[i]['end']
timesum += time_diff
time_list.append(time_diff)
time_list.append(timedelta(hours=0))
spaces = []
for diff in time_list:
spaces.append(round(diff/timesum * free_space, 4))
return spaces
我已经尝试过 KeepInFrame(),但是当它发挥作用时,它会使设计不均匀且丑陋。我还尝试从 free_space 变量中以各种组合排除框架填充、段落填充和段落之间的 1px space,但同样,没有完全匹配。做什么?
我已经找到免费 space 东西的确切公式。以下是精确计算段落之间总空闲 space 的公式,它源于段落 borderPadding 只是一个序言,所有计算都是在帧填充和段落高度的上下文中完成的。所有变量都按照题中的代码。
首先,我们需要考虑框架顶部和底部的框架填充:
free_space = frame.height - frame.topPadding - frame.bottomPadding
其次,对于我们框架中的每个段落,我们需要减去框架填充上下文中的包裹高度,并向它们添加浪费在段落边框填充上的高度(注意:这适用于 borderPadding 值是所有段落都相同)和段落之间所需的 space(在本例中为末尾的 1):
free_space -= paragraph.wrap(
frame_width - frame.lefPadding - frame.rightPadding + 2 * paragraph.style.borderPadding, \
frame_height - frame.topPadding - frame.bottomPadding)[1] \
+ paragraph.style.borderPadding * 2 + 1
最后,您必须将段落的 borderPadding 值添加到 free_space 的两倍,否则您将达不到要求:不考虑 borderPadding,仅考虑段落边缘,因此我们需要填充第一段和最后一段使用 free space 使段落的边缘与框架填充的对齐:
free_space += paragraph.style.borderPadding * 2
这将使段落和框架之间变得清晰space:
frame.{any padding} - paragraph.style.borderPadding