Skip to content

使用教程

完整说明文件: fpdf.FPDF API 文档

教程一 - 简单的示例

一个经典的示例:

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.set_font("helvetica", "B", 16)
pdf.cell(40, 10, "Hello World!")
pdf.output("tuto1.pdf")

生成的 PDF

引入库文件后,创建FPDF对象。 FPDF 构造函数在此使用默认值:页面 A4 纵向;单位毫米。 当然,这可以被明确定义:

pdf = FPDF(orientation="P", unit="mm", format="A4")

同时,也可以将 PDF 设置为横向模式 (L) 或使用其他页面格式 (如 LetterLegal)和度量单位(ptcmin)。

到此,文件暂无页面。调用 add_page 添加页面,原点位于页面左上角,当前位置默认为距边界 1 厘米处。 边距也可以调用 set_margins 更改。

在加入文本之前,必须选定字体 set_font ,否则文件无效。 选择字体 Helvetica,粗体,16号:

pdf.set_font('helvetica', 'B', 16)

使用 I 指定斜体,U 加下划线或空字符串指定常规字体。 请注意,字号单位是点数,而非毫米(或其他指定的单位)。 这是单位设置的唯一例外。其他内置字体有 TimesCourierSymbolZapfDingbats

调用 cell 创建一个单元格。单元格是一个矩形区域,可能带有外框, 其中包含一些文本,且置于当前位置。 单元格的尺寸,排版(居中或对齐),是否有边框 ,以及所放置的位置(向右,向下或换行)可配置的。 添加一个框架:

pdf.cell(40, 10, 'Hello World!', 1)

添加一个文本居中的新单元格并换行,如下:

pdf.cell(60, 10, 'Powered by FPDF.', new_x="LMARGIN", new_y="NEXT", align='C')

备注:换行也可调用 ln 实现。此方法允许指定换行行距。

最终,关闭文件并保存于给定路径 output。 无参数时,output()返回 PDF bytearray 缓冲区。

教程二 - 页眉、页脚、分页符与图像

此教程使用了下述包含页眉、页脚和徽标的示例:

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        # Rendering logo:
        self.image("../docs/fpdf2-logo.png", 10, 8, 33)
        # Setting font: helvetica bold 15
        self.set_font("helvetica", "B", 15)
        # Moving cursor to the right:
        self.cell(80)
        # Printing title:
        self.cell(30, 10, "Title", border=1, align="C")
        # Performing a line break:
        self.ln(20)

    def footer(self):
        # Position cursor at 1.5 cm from bottom:
        self.set_y(-15)
        # Setting font: helvetica italic 8
        self.set_font("helvetica", "I", 8)
        # Printing page number:
        self.cell(0, 10, f"Page {self.page_no()}/{{nb}}", align="C")


# Instantiation of inherited class
pdf = PDF()
pdf.add_page()
pdf.set_font("Times", size=12)
for i in range(1, 41):
    pdf.cell(0, 10, f"Printing line number {i}", new_x="LMARGIN", new_y="NEXT")
pdf.output("new-tuto2.pdf")

生成的 PDF

此示例使用 headerfooter 处理页眉和页脚。 虽然二者属于 FPDF 类,被自动调用,但默认是空置的, 因此需要扩展类从而覆盖缺省值。

调用 image 依照指定的起始坐标(左上角)与宽度添加图标。 高度将依照图像比例自动计算。

可将空值作为单元格宽度以打印页码。这使单元格延伸到页面的右边缘, 便于文本居中。当前页码由 page_no 返回。至于总页数,可以通过值{nb}获得。 {nb}将在文档关闭时被替换(此值调用 alias_nb_pages() 更改)。注意,调用 set_y 能够从顶部或底部起,设置在页面中的绝对位置。

示例中使用了另一个有趣的特性:自动分页。 一旦单元格会越过页面中的限制(默认距离底部 2 厘米处), 将执行中断并恢复字体设置。 虽然标题和页脚仍然使用自身的字体(helvetica),但正文将继续使用 Times 字体。 这种自动恢复机制同样适用于字体颜色与行距。 触发分页符的机制可以通过 set_auto_page_break 配置。

教程三 - 换行符和颜色

让我们继续上述对齐段落的示例。此教程也将演示颜色的配置方法。

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        # Setting font: helvetica bold 15
        self.set_font("helvetica", "B", 15)
        # Calculating width of title and setting cursor position:
        width = self.get_string_width(self.title) + 6
        self.set_x((210 - width) / 2)
        # Setting colors for frame, background and text:
        self.set_draw_color(0, 80, 180)
        self.set_fill_color(230, 230, 0)
        self.set_text_color(220, 50, 50)
        # Setting thickness of the frame (1 mm)
        self.set_line_width(1)
        # Printing title:
        self.cell(
            width,
            9,
            self.title,
            border=1,
            new_x="LMARGIN",
            new_y="NEXT",
            align="C",
            fill=True,
        )
        # Performing a line break:
        self.ln(10)

    def footer(self):
        # Setting position at 1.5 cm from bottom:
        self.set_y(-15)
        # Setting font: helvetica italic 8
        self.set_font("helvetica", "I", 8)
        # Setting text color to gray:
        self.set_text_color(128)
        # Printing page number
        self.cell(0, 10, f"Page {self.page_no()}", align="C")

    def chapter_title(self, num, label):
        # Setting font: helvetica 12
        self.set_font("helvetica", "", 12)
        # Setting background color
        self.set_fill_color(200, 220, 255)
        # Printing chapter name:
        self.cell(
            0,
            6,
            f"Chapter {num} : {label}",
            new_x="LMARGIN",
            new_y="NEXT",
            align="L",
            fill=True,
        )
        # Performing a line break:
        self.ln(4)

    def chapter_body(self, filepath):
        # Reading text file:
        with open(filepath, "rb") as fh:
            txt = fh.read().decode("latin-1")
        # Setting font: Times 12
        self.set_font("Times", size=12)
        # Printing justified text:
        self.multi_cell(0, 5, txt)
        # Performing a line break:
        self.ln()
        # Final mention in italics:
        self.set_font(style="I")
        self.cell(0, 5, "(end of excerpt)")

    def print_chapter(self, num, title, filepath):
        self.add_page()
        self.chapter_title(num, title)
        self.chapter_body(filepath)


pdf = PDF()
pdf.set_title("20000 Leagues Under the Seas")
pdf.set_author("Jules Verne")
pdf.print_chapter(1, "A RUNAWAY REEF", "20k_c1.txt")
pdf.print_chapter(2, "THE PROS AND CONS", "20k_c1.txt")
pdf.output("tuto3.pdf")

生成的 PDF

[儒勒·凡尔纳的原文](https://github.com/PyFPDF/fpdf2/raw/mast呃/教程/20k_c1.txt)

调用 get_string_width 函数设定当前字体下字符串的长度, 从而计算当前位置标题外框的宽度。 通过 set_draw_colorset_fill_colorset_text_color 设置颜色。行距由 set_line_width 设定为 1 mm(默认为 0.2)。 最终,输出单元格(末位参数 true 表示必须填充背景)。

调用multi_cell 函数打印段落(文本默认对齐)。 每当到达单元格的右端或遇到回车符 (\n) 时, 换行并在当前单元格下自动创建一个新的单元格。 自动换行在右起最近的空格或软连字符 (\u00ad) 触发。 当触发换行符时,软连字符将被普通连字符替换,否则将被忽略。

示例中设定了两个文档属性:标题 (set_title) 与作者 (set_author)。 文档的属性可以直接用 Acrobat 阅读器 打开, 在文件菜单中选择文档属性查看; 也可以使用插件,右击并选择 文档属性 查看。

教程四 - 多栏目

此示例是上一个示例的变体,展示了如何将文本放置在多个栏目中。

from fpdf import FPDF


class PDF(FPDF):
    def __init__(self):
        super().__init__()
        self.col = 0  # Current column
        self.y0 = 0  # Ordinate of column start

    def header(self):
        self.set_font("helvetica", "B", 15)
        width = self.get_string_width(self.title) + 6
        self.set_x((210 - width) / 2)
        self.set_draw_color(0, 80, 180)
        self.set_fill_color(230, 230, 0)
        self.set_text_color(220, 50, 50)
        self.set_line_width(1)
        self.cell(
            width,
            9,
            self.title,
            border=1,
            new_x="LMARGIN",
            new_y="NEXT",
            align="C",
            fill=True,
        )
        self.ln(10)
        # Saving ordinate position:
        self.y0 = self.get_y()

    def footer(self):
        self.set_y(-15)
        self.set_font("helvetica", "I", 8)
        self.set_text_color(128)
        self.cell(0, 10, f"Page {self.page_no()}", align="C")

    def set_col(self, col):
        # Set column position:
        self.col = col
        x = 10 + col * 65
        self.set_left_margin(x)
        self.set_x(x)

    @property
    def accept_page_break(self):
        if self.col < 2:
            # Go to next column:
            self.set_col(self.col + 1)
            # Set ordinate to top:
            self.set_y(self.y0)
            # Stay on the same page:
            return False
        # Go back to first column:
        self.set_col(0)
        # Trigger a page break:
        return True

    def chapter_title(self, num, label):
        self.set_font("helvetica", "", 12)
        self.set_fill_color(200, 220, 255)
        self.cell(
            0,
            6,
            f"Chapter {num} : {label}",
            new_x="LMARGIN",
            new_y="NEXT",
            border="L",
            fill=True,
        )
        self.ln(4)
        # Saving ordinate position:
        self.y0 = self.get_y()

    def chapter_body(self, name):
        # Reading text file:
        with open(name, "rb") as fh:
            txt = fh.read().decode("latin-1")
        # Setting font: Times 12
        self.set_font("Times", size=12)
        # Printing text in a 6cm width column:
        self.multi_cell(60, 5, txt)
        self.ln()
        # Final mention in italics:
        self.set_font(style="I")
        self.cell(0, 5, "(end of excerpt)")
        # Start back at first column:
        self.set_col(0)

    def print_chapter(self, num, title, name):
        self.add_page()
        self.chapter_title(num, title)
        self.chapter_body(name)


pdf = PDF()
pdf.set_title("20000 Leagues Under the Seas")
pdf.set_author("Jules Verne")
pdf.print_chapter(1, "A RUNAWAY REEF", "20k_c1.txt")
pdf.print_chapter(2, "THE PROS AND CONS", "20k_c1.txt")
pdf.output("tuto4.pdf")

生成的 PDF

儒勒·凡尔纳的原文

与上一个教程的主要区别在于使用了 accept_page_break 与 set_col 方法。

accept_page_break 函数中,一当单元格越过页面的底部, 若当前列号小于2(页面分为三列),则调用 set_col, 递增列号并移动到下一列的位置,继续打印文本。

一旦达到第三列的底部, accept_page_break 将分页并回到第一列。

教程五 - 创建表

本教程将演示如何创建表。

该代码创建了三个不同的表,演示了几个简单的表格配置。

import csv
from fpdf import FPDF


class PDF(FPDF):
    def basic_table(self, headings, rows):
        for heading in headings:
            self.cell(40, 7, heading, 1)
        self.ln()
        for row in rows:
            for col in row:
                self.cell(40, 6, col, 1)
            self.ln()

    def improved_table(self, headings, rows, col_widths=(42, 39, 35, 40)):
        for col_width, heading in zip(col_widths, headings):
            self.cell(col_width, 7, heading, border=1, align="C")
        self.ln()
        for row in rows:
            self.cell(col_widths[0], 6, row[0], border="LR")
            self.cell(col_widths[1], 6, row[1], border="LR")
            self.cell(col_widths[2], 6, row[2], border="LR", align="R")
            self.cell(col_widths[3], 6, row[3], border="LR", align="R")
            self.ln()
        # Closure line:
        self.cell(sum(col_widths), 0, "", border="T")

    def colored_table(self, headings, rows, col_widths=(42, 39, 35, 42)):
        # Colors, line width and bold font:
        self.set_fill_color(255, 100, 0)
        self.set_text_color(255)
        self.set_draw_color(255, 0, 0)
        self.set_line_width(0.3)
        self.set_font(style="B")
        for col_width, heading in zip(col_widths, headings):
            self.cell(col_width, 7, heading, border=1, align="C", fill=True)
        self.ln()
        # Color and font restoration:
        self.set_fill_color(224, 235, 255)
        self.set_text_color(0)
        self.set_font()
        fill = False
        for row in rows:
            self.cell(col_widths[0], 6, row[0], border="LR", align="L", fill=fill)
            self.cell(col_widths[1], 6, row[1], border="LR", align="L", fill=fill)
            self.cell(col_widths[2], 6, row[2], border="LR", align="R", fill=fill)
            self.cell(col_widths[3], 6, row[3], border="LR", align="R", fill=fill)
            self.ln()
            fill = not fill
        self.cell(sum(col_widths), 0, "", "T")


def load_data_from_csv(csv_filepath):
    headings, rows = [], []
    with open(csv_filepath, encoding="utf8") as csv_file:
        for row in csv.reader(csv_file, delimiter=","):
            if not headings:  # extracting column names from first row:
                headings = row
            else:
                rows.append(row)
    return headings, rows


col_names, data = load_data_from_csv("countries.txt")
pdf = PDF()
pdf.set_font("helvetica", size=14)
pdf.add_page()
pdf.basic_table(col_names, data)
pdf.add_page()
pdf.improved_table(col_names, data)
pdf.add_page()
pdf.colored_table(col_names, data)
pdf.output("tuto5.pdf")

生成的 PDF - 源文本

表格只是单元格的集合,因此由单元格便可构建一个表格。

第一张表以最基本的方式实现:带框的单元格,大小相同且左对齐。 虽然简陋,但操作便捷。

第二张表进行了一些改进:每列都设定了宽度,标题居中,数字右对齐。 此外,水平线也被删除。 上述设定由Cell() 的边界参数完成,在参数中指定需要绘制的 单元格边框。 在示例中,需要绘制左侧 (L) 和右侧 (R) 的边框。 水平的边框可使用两种方法设置: 对于循环中的最后一行,使用 LRB 作为边界参数; 或者,如示例中,在循环结束后添加一行。

第三张表与第二张表类似,但设置了颜色。 填充、文本和线条的颜色直接指定即可。行间的间隔着色可以 通过交替使用透明和填充的单元格实现。

教程六 - 创建链接和混合文本样式

本教程将演示几种在 pdf 文档中插入内部链接,或指向外部资源 的超链接的方法,以及几种在同一文本中使用不同文本样式 (粗体、斜体、下划线)的方法。

from fpdf import FPDF


pdf = FPDF()

# First page:
pdf.add_page()
pdf.set_font("helvetica", size=20)
pdf.write(5, "To find out what's new in self tutorial, click ")
pdf.set_font(style="U")
link = pdf.add_link(page=2)
pdf.write(5, "here", link)
pdf.set_font()

# Second page:
pdf.add_page()
pdf.image(
    "../docs/fpdf2-logo.png", 10, 10, 50, 0, "", "https://pyfpdf.github.io/fpdf2/"
)
pdf.set_left_margin(60)
pdf.set_font_size(18)
pdf.write_html(
    """You can print text mixing different styles using HTML tags: <b>bold</b>, <i>italic</i>,
<u>underlined</u>, or <b><i><u>all at once</u></i></b>!
<br><br>You can also insert links on text, such as <a href="https://pyfpdf.github.io/fpdf2/">https://pyfpdf.github.io/fpdf2/</a>,
or on an image: the logo is clickable!"""
)
pdf.output("tuto6.pdf")

生成的 PDF - fpdf2 图标

此处显示的打印文本的新方法是 write() ,类似于 multi_cell() 。二者主要区别在于:

  • 行尾在右边缘,下一行在左边缘开始
  • 当前位置移动到文本末尾。

因此,该方法允许在一段文本中更改字体样式,并从初始位置继续。 反之,它的缺点在于其不能如同 multi_cell() 对齐文本。

因为上述原因,在示例的第一页中,调用了 write() 打印常规字体,然后使用 set_font() 方法,切换到下划线样式并继续打印。

为添加指向第二页的内部链接,调用了 add_link() 。这将创建一个可点击区域,命名为“链接”,指向 文档中的另一页。

使用图像创建外部链接,则调用 image() 。该函数可将链接作为其参数之一。链接也可以指向内部或外部。

作为替代方案,更改字体样式和添加链接的另一种选择是 使用 write_html() 方法。这是一个 html 解析器, 允许添加文本,更改字体样式并添加链接。