基于borb的PDF表格:实现超链接图标与多标签圆角背景
解决borb库PDF表格的两个核心需求
问题背景
需用borb生成交易记录PDF表格,核心需求:
- 第4列添加带在线文档超链接的回形针表情
- 第6列每个标签设置带圆角矩形的专属背景色,且同一单元格内不同标签背景可差异化
现有实现无法满足单单元格多标签的差异化背景,不想用跨行合并方案浪费空间,原有代码如下:
from datetime import datetime from decimal import Decimal from pathlib import Path from borb.pdf.canvas.font.simple_font.true_type_font import TrueTypeFont from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable as Table from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.layout.annotation.remote_go_to_annotation import RemoteGoToAnnotation from borb.pdf.canvas.geometry.rectangle import Rectangle from borb.pdf.canvas.layout.emoji.emoji import Emojis rubik = TrueTypeFont.true_type_font_from_file(Path(__file__).parent / "fonts/Rubik-Regular.ttf") rubik_medium = TrueTypeFont.true_type_font_from_file(Path(__file__).parent / "fonts/Rubik-Medium.ttf") background_color = HexColor("#FF5733") def generate_table(transactions): # 原代码column_widths长度与列数不匹配,此处修正为6个宽度值 table = Table(number_of_rows=1 + len(transactions), number_of_columns=6, horizontal_alignment=Alignment.JUSTIFIED, column_widths=[Decimal(60), Decimal(60), Decimal(220), Decimal(30), Decimal(50), Decimal(80)]) table.add(TableCell(Paragraph("Date", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Account", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Description", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Attachment", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Value", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Tags", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) for transaction in transactions: # Column 1 table.add(TableCell(Paragraph(datetime.strftime(transaction[0], '%d/%m/%y'), font=rubik, font_size=Decimal(8)))) # Column 2 table.add(TableCell(Paragraph(transaction[1], font=rubik, font_size=Decimal(8), horizontal_alignment=Alignment.CENTERED))) # Column 3 table.add(TableCell(Paragraph(transaction[2], font=rubik, font_size=Decimal(8), horizontal_alignment=Alignment.CENTERED))) # 原第4列错误实现:分开添加注释和表情 table.add(TableCell(RemoteGoToAnnotation(Rectangle(Decimal(32), Decimal(32), Decimal(32), Decimal(32)), uri=transaction[3]))) table.add(TableCell(Emojis.PAPERCLIP.value)) # Column 5 table.add(TableCell(Paragraph(f"{transaction[4]:.2f}", font=rubik, font_size=Decimal(8), horizontal_alignment=Alignment.CENTERED))) # Column 6 table.add(TableCell(Paragraph("\n".join(transaction[5]), font=rubik, font_size=Decimal(8), border_radius_top_left=Decimal(10), border_radius_top_right=Decimal(10), border_radius_bottom_left=Decimal(10), border_radius_bottom_right=Decimal(10), background_color=background_color, horizontal_alignment=Alignment.CENTERED)))
解决方案
1. 实现第4列带超链接的回形针表情
核心思路:创建包含回形针表情的TableCell,给整个单元格添加超链接注释,确保点击表情区域即可跳转。
替换原第4列代码为:
# Column 4:带超链接的回形针 attachment_paragraph = Paragraph( Emojis.PAPERCLIP.value, font_size=Decimal(12), horizontal_alignment=Alignment.CENTERED ) attachment_cell = TableCell(attachment_paragraph) # 添加超链接注释,覆盖整个单元格范围 attachment_cell.add_annotation(RemoteGoToAnnotation( Rectangle(Decimal(0), Decimal(0), Decimal(30), Decimal(20)), # 对应列宽30,单元格高度可根据实际调整 uri=transaction[3] )) table.add(attachment_cell)
2. 实现第6列单单元格多标签差异化圆角背景
核心思路:用FlexBox水平排列每个标签,每个标签单独做成带背景和圆角的Paragraph,既节省空间又能实现差异化样式。
首先新增导入:
from borb.pdf.canvas.layout.layout_element import FlexBox
然后替换原第6列代码为:
# Column 6:多标签差异化背景 tag_container = FlexBox( horizontal_alignment=Alignment.CENTERED, vertical_alignment=Alignment.MIDDLE, spacing=Decimal(5), # 标签间间距 padding=Decimal(2) ) # 假设transaction[5]是包含(标签名, 背景色)的列表,例如[("餐饮", "#FF5733"), ("交通", "#33FF57")] for tag_name, bg_color in transaction[5]: tag = Paragraph( tag_name, font=rubik, font_size=Decimal(8), padding_top=Decimal(2), padding_bottom=Decimal(2), padding_left=Decimal(8), padding_right=Decimal(8), background_color=HexColor(bg_color), border_radius=Decimal(10), text_color=HexColor("#FFFFFF") # 可选:白色文字提升可读性 ) tag_container.add(tag) table.add(TableCell(tag_container))
完整修改后的代码
from datetime import datetime from decimal import Decimal from pathlib import Path from borb.pdf.canvas.font.simple_font.true_type_font import TrueTypeFont from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.layout.layout_element import Alignment, FlexBox from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable as Table from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.layout.annotation.remote_go_to_annotation import RemoteGoToAnnotation from borb.pdf.canvas.geometry.rectangle import Rectangle from borb.pdf.canvas.layout.emoji.emoji import Emojis rubik = TrueTypeFont.true_type_font_from_file(Path(__file__).parent / "fonts/Rubik-Regular.ttf") rubik_medium = TrueTypeFont.true_type_font_from_file(Path(__file__).parent / "fonts/Rubik-Medium.ttf") def generate_table(transactions): table = Table(number_of_rows=1 + len(transactions), number_of_columns=6, horizontal_alignment=Alignment.JUSTIFIED, column_widths=[Decimal(60), Decimal(60), Decimal(220), Decimal(30), Decimal(50), Decimal(80)]) # 表头 table.add(TableCell(Paragraph("Date", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Account", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Description", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Attachment", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Value", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) table.add(TableCell(Paragraph("Tags", font=rubik_medium, font_size=Decimal(11), horizontal_alignment=Alignment.CENTERED))) for transaction in transactions: # Column 1:日期 table.add(TableCell(Paragraph(datetime.strftime(transaction[0], '%d/%m/%y'), font=rubik, font_size=Decimal(8)))) # Column 2:账户 table.add(TableCell(Paragraph(transaction[1], font=rubik, font_size=Decimal(8), horizontal_alignment=Alignment.CENTERED))) # Column 3:描述 table.add(TableCell(Paragraph(transaction[2], font=rubik, font_size=Decimal(8), horizontal_alignment=Alignment.CENTERED))) # Column 4:带超链接的回形针 attachment_paragraph = Paragraph( Emojis.PAPERCLIP.value, font_size=Decimal(12), horizontal_alignment=Alignment.CENTERED ) attachment_cell = TableCell(attachment_paragraph) attachment_cell.add_annotation(RemoteGoToAnnotation( Rectangle(Decimal(0), Decimal(0), Decimal(30), Decimal(20)), uri=transaction[3] )) table.add(attachment_cell) # Column 5:金额 table.add(TableCell(Paragraph(f"{transaction[4]:.2f}", font=rubik, font_size=Decimal(8), horizontal_alignment=Alignment.CENTERED))) # Column 6:多标签差异化背景 tag_container = FlexBox( horizontal_alignment=Alignment.CENTERED, vertical_alignment=Alignment.MIDDLE, spacing=Decimal(5), padding=Decimal(2) ) for tag_name, bg_color in transaction[5]: tag = Paragraph( tag_name, font=rubik, font_size=Decimal(8), padding_top=Decimal(2), padding_bottom=Decimal(2), padding_left=Decimal(8), padding_right=Decimal(8), background_color=HexColor(bg_color), border_radius=Decimal(10), text_color=HexColor("#FFFFFF") ) tag_container.add(tag) table.add(TableCell(tag_container)) return table
内容的提问来源于stack exchange,提问作者Blue Owl
相关产品推荐
相关产品推荐

