You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于borb的PDF表格:实现超链接图标与多标签圆角背景

解决borb库PDF表格的两个核心需求

问题背景

需用borb生成交易记录PDF表格,核心需求:

  1. 第4列添加带在线文档超链接的回形针表情
  2. 第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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 15:34:57