如何构建 PDF(使用 FPDF)以便 table 列跨页?
How to construct PDF (with FPDF) so that table columns span pages?
嘿,我在 python 中使用 fpdf 来显示列表,
下面是我的代码:
from fpdf import FPDF
pdf = FPDF("L", 'mm', 'Legal')
pdf.add_page()
pdf.set_font('helvetica', 'B', 16)
headers = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7']
body = [
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']
]
print(pdf.w)
print(pdf.get_x())
for r in headers:
pdf.cell(70, 10, f'{r}')
pdf.set_font('helvetica', '', 16)
for d in range(len(body)):
row = body[d]
for i in range(len(row)):
if i == len(row)-1:
pdf.cell(70, 10, f'{row[i]}', 0, ln=1)
else:
pdf.cell(70, 10, f'{row[i]}', 0)
# pdf.cell(5, 10, '')
pdf.output('/home/chandan/Documents/tournament.pdf')
注意:页眉和正文的长度始终相同
列 H6、H7 超出了页边距,所以我如何让一个 pdf 页面显示 5 列,其余列显示在下一页
现在 pdf 页面看起来像 this
现在我怎样才能做到这一点
我们需要一些简单的数学运算,最重要的是,我们需要一些关于如何打印 columns/rows 和单个单元格的清晰思路。
首先,我们需要决定每页要打印多少行和多少列。
我将其称为“打印分辨率”。我们的 table 输入数据可以是任意大小(按高度排列),但它必须显示在每页不超过 5 行 x 10 列的网格中,因此我们的 分辨率 是“每页 5 行 x 10 列”。
接下来,我们需要找到页面的 print-able 区域,以确定这些行和列的大小。
FPDF 用 pdf.w
和 pdf.h
告诉我们页面的整体尺寸,它还告诉我们设置的页边距,用 pdf.t_margin
(上边距)和左侧 (l_margin
)、右侧 (r_margin
) 和底部 (b_margin
) 依此类推:
总宽度减去左右页边距告诉我们页面上有多少 space 适合我们之前选择的 10 列。
总高度减去顶部和底部边距告诉我们页面上有多少 space 适合 5 行。
选择了我们的打印分辨率并了解了这些原则table 尺寸后,我们现在可以计算出每个单元格的大小:
Printable-width / 10
等于各个单元格完全填满页面网格所需的宽度。
Printable-height / 5
给我们相同的单元格高度。
所以,让我们打印一个 5 行 10 列的网格,均匀地填满页面:
from fpdf import FPDF
from my_table import table
pdf = FPDF("L", "mm", "Letter")
pdf.set_font("Arial", "", 16)
# Set desired "resolution" of printed grid
rows_per_page = 5
cols_per_page = 10
# Calculate dimensions of print-able area
print_h = pdf.h - pdf.t_margin - pdf.b_margin
print_w = pdf.w - pdf.l_margin - pdf.r_margin
# Actual size of grid cells on the page is available space divided by desired resolution, in each dimension
c_h = print_h / rows_per_page
c_w = print_w / cols_per_page
# Add a page and draw a border to visualize the page
pdf.add_page()
pdf.set_draw_color(255, 0, 0)
pdf.set_line_width(1)
pdf.rect(0, 0, pdf.w, pdf.h, "D")
pdf.set_draw_color(0, 0, 0)
pdf.set_line_width(0.2)
pdf.rect(0.5, 0.5, pdf.w - 0.5, pdf.h - 0.5, "D")
for i in range(rows_per_page):
for j in range(cols_per_page):
# Create "A1 Notation" for our reference
char = chr(65 + j) # "A", then "B", ...
s = f"{char}{i+1}"
pdf.cell(c_w, c_h, s, border=1, ln=0, align="C")
pdf.ln()
pdf.output("simple_5-by-10.pdf", dest="F")
我得到:
我决定在打印一行单元格的末尾使用 pdf.ln()
,因为它不需要任何逻辑:因为我们在列循环之外,所以我们肯定知道我们已经完成该行并需要移至下一行的开头。
现在我们有了一个漂亮的网格和所需的分辨率,我们可以继续处理 table 大于打印分辨率的信息,以及如何处理溢出。
我认为我们要做的是选择适合页面的一批行,然后从 left-to-right 打印适合页面的一批列移动这些行:
- 将 row-counter 设置为 0
- 从 table 的 row-counter 开始,然后 select 接下来的 number-of-rows-per-page 行。
- 将 column-counter 设置为 0
- 从 table 的 column-counter 开始,然后 select 接下来的 number-of-columns-per-page 列。
- 打印该行和列范围内的所有单元格。
- 推进列计数器,并重复步骤 4 和 5,直到打印完所有列。
- 增加行计数器,重复步骤 2 - 6 直到打印完所有行。
# Same as above...
c_h = print_h / rows_per_page
c_w = print_w / cols_per_page
# Get table's dimensions
num_rows = len(table)
num_cols = len(table[0])
# Track how far "down" the table we've moved
row_offset = 0
while row_offset < num_rows:
# Limit this batch of rows to either the maximum (rows_per_page), unless we're at the end of the table, limit to the remaining of rows
row_max = row_offset + rows_per_page
if row_max > num_rows:
row_max = num_rows
# Track how far "across" this batch of rows we've moved
col_offset = 0
while col_offset < num_cols:
# Limit this batch of columns to the either the maximum (columns_per_page), unless we're at the end of the batch of rows, limit to the remaining columns
col_max = col_offset + cols_per_page
if col_max > num_cols:
col_max = num_cols
# Ready to actually start printing, so create page
pdf.add_page()
# Print a grid of cells, no bigger than rows_per_page-high by cols_per_page-wide
for i in range(row_offset, row_max):
for j in range(col_offset, col_max):
cell_value = table[i][j]
pdf.cell(c_w, c_h, cell_value, border=1, ln=0, align="C")
pdf.ln()
# Advance to the right, "across" the batch of rows, for the next batch of columns
col_offset += cols_per_page
# Advance "down" the table, for the next batch of rows
row_offset += rows_per_page
pdf.output("span_cols.pdf", dest="F")
如果我给它这个table:
table = [
['A1' , 'B1' , 'C1' , 'D1' , 'E1' , 'F1' , 'G1' , 'H1' , 'I1' , 'J1' , 'K1' , 'L1'],
['A2' , 'B2' , 'C2' , 'D2' , 'E2' , 'F2' , 'G2' , 'H2' , 'I2' , 'J2' , 'K2' , 'L2'],
['A3' , 'B3' , 'C3' , 'D3' , 'E3' , 'F3' , 'G3' , 'H3' , 'I3' , 'J3' , 'K3' , 'L3'],
['A4' , 'B4' , 'C4' , 'D4' , 'E4' , 'F4' , 'G4' , 'H4' , 'I4' , 'J4' , 'K4' , 'L4'],
['A5' , 'B5' , 'C5' , 'D5' , 'E5' , 'F5' , 'G5' , 'H5' , 'I5' , 'J5' , 'K5' , 'L5'],
['A6' , 'B6' , 'C6' , 'D6' , 'E6' , 'F6' , 'G6' , 'H6' , 'I6' , 'J6' , 'K6' , 'L6'],
['A7' , 'B7' , 'C7' , 'D7' , 'E7' , 'F7' , 'G7' , 'H7' , 'I7' , 'J7' , 'K7' , 'L7'],
['A8' , 'B8' , 'C8' , 'D8' , 'E8' , 'F8' , 'G8' , 'H8' , 'I8' , 'J8' , 'K8' , 'L8'],
['A9' , 'B9' , 'C9' , 'D9' , 'E9' , 'F9' , 'G9' , 'H9' , 'I9' , 'J9' , 'K9' , 'L9'],
['A10', 'B10', 'C10', 'D10', 'E10', 'F10', 'G10', 'H10', 'I10', 'J10', 'K10', 'L10'],
['A11', 'B11', 'C11', 'D11', 'E11', 'F11', 'G11', 'H11', 'I11', 'J11', 'K11', 'L11'],
['A12', 'B12', 'C12', 'D12', 'E12', 'F12', 'G12', 'H12', 'I12', 'J12', 'K12', 'L12']
]
并选择 5 行 10 列的相同分辨率,我得到以下结果:
我没有时间或精力来说明如何处理 header,但我认为可以简单地 if i == 0 then header-style else normal-style
检查一下您是否处理了第一行。并且,将 header 包含在数据中,不要尝试将它们 handle/print 作为单独的数据结构(那样会弄乱数学)。
我也在想,如果你想要每个页面上的 header,请查看 FPDF 教程中关于 Headers, Footers 的部分。我不确定添加 header 会如何影响页边距,所以请四处看看。
嘿,我在 python 中使用 fpdf 来显示列表, 下面是我的代码:
from fpdf import FPDF
pdf = FPDF("L", 'mm', 'Legal')
pdf.add_page()
pdf.set_font('helvetica', 'B', 16)
headers = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7']
body = [
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']
]
print(pdf.w)
print(pdf.get_x())
for r in headers:
pdf.cell(70, 10, f'{r}')
pdf.set_font('helvetica', '', 16)
for d in range(len(body)):
row = body[d]
for i in range(len(row)):
if i == len(row)-1:
pdf.cell(70, 10, f'{row[i]}', 0, ln=1)
else:
pdf.cell(70, 10, f'{row[i]}', 0)
# pdf.cell(5, 10, '')
pdf.output('/home/chandan/Documents/tournament.pdf')
注意:页眉和正文的长度始终相同
列 H6、H7 超出了页边距,所以我如何让一个 pdf 页面显示 5 列,其余列显示在下一页 现在 pdf 页面看起来像 this 现在我怎样才能做到这一点
我们需要一些简单的数学运算,最重要的是,我们需要一些关于如何打印 columns/rows 和单个单元格的清晰思路。
首先,我们需要决定每页要打印多少行和多少列。
我将其称为“打印分辨率”。我们的 table 输入数据可以是任意大小(按高度排列),但它必须显示在每页不超过 5 行 x 10 列的网格中,因此我们的 分辨率 是“每页 5 行 x 10 列”。
接下来,我们需要找到页面的 print-able 区域,以确定这些行和列的大小。
FPDF 用 pdf.w
和 pdf.h
告诉我们页面的整体尺寸,它还告诉我们设置的页边距,用 pdf.t_margin
(上边距)和左侧 (l_margin
)、右侧 (r_margin
) 和底部 (b_margin
) 依此类推:
总宽度减去左右页边距告诉我们页面上有多少 space 适合我们之前选择的 10 列。
总高度减去顶部和底部边距告诉我们页面上有多少 space 适合 5 行。
选择了我们的打印分辨率并了解了这些原则table 尺寸后,我们现在可以计算出每个单元格的大小:
Printable-width / 10
等于各个单元格完全填满页面网格所需的宽度。Printable-height / 5
给我们相同的单元格高度。
所以,让我们打印一个 5 行 10 列的网格,均匀地填满页面:
from fpdf import FPDF
from my_table import table
pdf = FPDF("L", "mm", "Letter")
pdf.set_font("Arial", "", 16)
# Set desired "resolution" of printed grid
rows_per_page = 5
cols_per_page = 10
# Calculate dimensions of print-able area
print_h = pdf.h - pdf.t_margin - pdf.b_margin
print_w = pdf.w - pdf.l_margin - pdf.r_margin
# Actual size of grid cells on the page is available space divided by desired resolution, in each dimension
c_h = print_h / rows_per_page
c_w = print_w / cols_per_page
# Add a page and draw a border to visualize the page
pdf.add_page()
pdf.set_draw_color(255, 0, 0)
pdf.set_line_width(1)
pdf.rect(0, 0, pdf.w, pdf.h, "D")
pdf.set_draw_color(0, 0, 0)
pdf.set_line_width(0.2)
pdf.rect(0.5, 0.5, pdf.w - 0.5, pdf.h - 0.5, "D")
for i in range(rows_per_page):
for j in range(cols_per_page):
# Create "A1 Notation" for our reference
char = chr(65 + j) # "A", then "B", ...
s = f"{char}{i+1}"
pdf.cell(c_w, c_h, s, border=1, ln=0, align="C")
pdf.ln()
pdf.output("simple_5-by-10.pdf", dest="F")
我得到:
我决定在打印一行单元格的末尾使用 pdf.ln()
,因为它不需要任何逻辑:因为我们在列循环之外,所以我们肯定知道我们已经完成该行并需要移至下一行的开头。
现在我们有了一个漂亮的网格和所需的分辨率,我们可以继续处理 table 大于打印分辨率的信息,以及如何处理溢出。
我认为我们要做的是选择适合页面的一批行,然后从 left-to-right 打印适合页面的一批列移动这些行:
- 将 row-counter 设置为 0
- 从 table 的 row-counter 开始,然后 select 接下来的 number-of-rows-per-page 行。
- 将 column-counter 设置为 0
- 从 table 的 column-counter 开始,然后 select 接下来的 number-of-columns-per-page 列。
- 打印该行和列范围内的所有单元格。
- 推进列计数器,并重复步骤 4 和 5,直到打印完所有列。
- 增加行计数器,重复步骤 2 - 6 直到打印完所有行。
# Same as above...
c_h = print_h / rows_per_page
c_w = print_w / cols_per_page
# Get table's dimensions
num_rows = len(table)
num_cols = len(table[0])
# Track how far "down" the table we've moved
row_offset = 0
while row_offset < num_rows:
# Limit this batch of rows to either the maximum (rows_per_page), unless we're at the end of the table, limit to the remaining of rows
row_max = row_offset + rows_per_page
if row_max > num_rows:
row_max = num_rows
# Track how far "across" this batch of rows we've moved
col_offset = 0
while col_offset < num_cols:
# Limit this batch of columns to the either the maximum (columns_per_page), unless we're at the end of the batch of rows, limit to the remaining columns
col_max = col_offset + cols_per_page
if col_max > num_cols:
col_max = num_cols
# Ready to actually start printing, so create page
pdf.add_page()
# Print a grid of cells, no bigger than rows_per_page-high by cols_per_page-wide
for i in range(row_offset, row_max):
for j in range(col_offset, col_max):
cell_value = table[i][j]
pdf.cell(c_w, c_h, cell_value, border=1, ln=0, align="C")
pdf.ln()
# Advance to the right, "across" the batch of rows, for the next batch of columns
col_offset += cols_per_page
# Advance "down" the table, for the next batch of rows
row_offset += rows_per_page
pdf.output("span_cols.pdf", dest="F")
如果我给它这个table:
table = [
['A1' , 'B1' , 'C1' , 'D1' , 'E1' , 'F1' , 'G1' , 'H1' , 'I1' , 'J1' , 'K1' , 'L1'],
['A2' , 'B2' , 'C2' , 'D2' , 'E2' , 'F2' , 'G2' , 'H2' , 'I2' , 'J2' , 'K2' , 'L2'],
['A3' , 'B3' , 'C3' , 'D3' , 'E3' , 'F3' , 'G3' , 'H3' , 'I3' , 'J3' , 'K3' , 'L3'],
['A4' , 'B4' , 'C4' , 'D4' , 'E4' , 'F4' , 'G4' , 'H4' , 'I4' , 'J4' , 'K4' , 'L4'],
['A5' , 'B5' , 'C5' , 'D5' , 'E5' , 'F5' , 'G5' , 'H5' , 'I5' , 'J5' , 'K5' , 'L5'],
['A6' , 'B6' , 'C6' , 'D6' , 'E6' , 'F6' , 'G6' , 'H6' , 'I6' , 'J6' , 'K6' , 'L6'],
['A7' , 'B7' , 'C7' , 'D7' , 'E7' , 'F7' , 'G7' , 'H7' , 'I7' , 'J7' , 'K7' , 'L7'],
['A8' , 'B8' , 'C8' , 'D8' , 'E8' , 'F8' , 'G8' , 'H8' , 'I8' , 'J8' , 'K8' , 'L8'],
['A9' , 'B9' , 'C9' , 'D9' , 'E9' , 'F9' , 'G9' , 'H9' , 'I9' , 'J9' , 'K9' , 'L9'],
['A10', 'B10', 'C10', 'D10', 'E10', 'F10', 'G10', 'H10', 'I10', 'J10', 'K10', 'L10'],
['A11', 'B11', 'C11', 'D11', 'E11', 'F11', 'G11', 'H11', 'I11', 'J11', 'K11', 'L11'],
['A12', 'B12', 'C12', 'D12', 'E12', 'F12', 'G12', 'H12', 'I12', 'J12', 'K12', 'L12']
]
并选择 5 行 10 列的相同分辨率,我得到以下结果:
我没有时间或精力来说明如何处理 header,但我认为可以简单地 if i == 0 then header-style else normal-style
检查一下您是否处理了第一行。并且,将 header 包含在数据中,不要尝试将它们 handle/print 作为单独的数据结构(那样会弄乱数学)。
我也在想,如果你想要每个页面上的 header,请查看 FPDF 教程中关于 Headers, Footers 的部分。我不确定添加 header 会如何影响页边距,所以请四处看看。