fpdf简介
fpdf
fpdf 的 github地址 fpdf 是从 PHP 的 FPDF 移植而来的,与其他 PDF 库相比,fpdf 简单、小巧、用途广泛,功能先进,易于学习、扩展和维护。
特征
- Python 2.5 到 3.4 支持
- Unicode (UTF-8) TrueType 字体子集嵌入
- 条码 I2of5 和 code39,二维码即将推出…
- PNG、GIF 和 JPG 支持(包括透明度和 Alpha 通道)
- 带有视觉设计师和基本 html2pdf 的模板
- 异常支持、其他小修复、改进和 PEP8 代码清
Tips: 暂时未整理 fpdf 写入中文操作
安装
pip install fpdf
pypdf2
pypdf2 的 github地址 , 能够拆分、合并、裁剪和转换 PDF 文件的页面。它还可以为 PDF 文件添加自定义数据、查看选项和密码。PyPDF2 也可以从 PDF 中检索文本和元数据。
安装
pip install PyPDF2
使用
fpdf
纯文字
# 最简单引用
from fpdf import FPDF
def hello_world():
pdf = FPDF(orientation="P", unit="mm", format="A4") # 竖版,A4,mm单位
pdf.add_page()
pdf.set_font(family="Arial", style="B", size=16)
pdf.cell(w=40, h=10, txt="hello world pdf")
pdf.text(x=60, y=140, txt="Some text.")
pdf.output(name="hello_world_pdf.pdf", dest="F")
图片,页眉页脚
# 添加图片,页眉,页脚等
# 继承FPDF 重写 header 页眉,footer页脚方法
class PDF(FPDF):
def header(self):
# Logo
self.image(name='img.png', x=10, y=10, w=5)
self.set_draw_color(0, 80, 180)
self.set_fill_color(230, 230, 0)
self.set_text_color(220, 50, 50)
# 设置页眉字体
self.set_font('Arial', '', 12)
# 设置页眉前空字符
# self.cell(100)
# 页眉标题文字
self.cell(0, 10, 'Title', 0, 0, 'C') # 居中
# self.cell(30, 10, 'Title', 1, 0, 'L') # 左对齐
# self.cell(30, 10, 'Title', 1, 0, 'R') # 右对齐
# 换行
self.ln(10)
def footer(self):
# 距离底部1.5cm
self.set_y(-15)
# 页脚字体
self.set_font('Arial', 'I', 8)
# 页数 当前页/总页数
self.cell(0, 10, str(self.page_no()) + " / {nb}", 0, 0, 'C')
# 添加副标题
def chapter_title(self, num, label):
# Arial 12
self.set_font('Arial', '', 12)
# Background color
self.set_fill_color(200, 220, 255)
# Title
self.cell(0, 6, 'Chapter %d : %s' % (num, label), 0, 1, 'L', 1)
# Line break
self.ln(4)
# 添加文件内容
def chapter_body(self, name):
# Read text file
with open(name, 'rb') as fh:
txt = fh.read().decode('latin-1')
# Times 12
self.set_font('Times', '', 12)
# Output justified text
self.multi_cell(0, 5, txt)
# Line break
self.ln()
# 设置链接
self.set_link(link=name, y=-1, page=-1)
# 斜体I,标记结束
self.set_font('', 'I')
self.cell(0, 5, '(end of excerpt)')
# 组合副标题和文件内容
def print_chapter(self, num, title, name):
self.add_page()
self.chapter_title(num, title)
self.chapter_body(name)
if __name__ == '__main__':
pdf = PDF()
pdf.alias_nb_pages() # 定义总页数可以使用{nb}来获取
pdf.set_font('Times', '', 12)
pdf.set_title("page title")
pdf.set_author('yiwanliejiu')
pdf.print_chapter(1, 'first chapter', 'a.txt')
pdf.print_chapter(2, 'second chapter', 'b.txt')
pdf.output('hello_world.pdf', 'F')
添加表格,二维码,注释
import csv
from fpdf import FPDF
"""
生成表格的三种样式
"""
class PDF(FPDF):
def basic_table(self, headings, rows):
# 表头
for heading in headings:
self.cell(30, 7, heading, 1, align="C")
self.ln() # 换行
# 数据
for row in rows:
for col in row:
self.cell(40, 6, col, 1, align="L")
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") # 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()
# 底部闭合线:
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("a.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.add_page()
pdf.code39("*fpdf2*", x=30, y=50, w=4, h=20)
# 二维码
import qrcode
pdf.add_page()
img = qrcode.make("fpdf2")
pdf.image(img.get_image(), x=50, y=50)
# 文本注释
pdf.add_page()
pdf.set_font("Helvetica", size=24)
pdf.text(x=60, y=140, txt="Some text.")
pdf.text_annotation(
x=100,
y=130,
text="This is a text annotation.",
)
# 强调背景色,hover注释
pdf.add_page()
# pdf.add_font(family="youyuan", style="", fname="./SIMYOU.TTF", uni=False) # 添加一个本地字体
pdf.set_font("Helvetica", size=24)
with pdf.add_highlight("lingt ", title="title", color=(120, 230, 0)):
pdf.text(50, 50, "first")
pdf.set_y(50)
pdf.multi_cell(w=30, txt="second")
pdf.cell(w=60, txt="Not highlighted", border=1)
pdf.output("tuto5.pdf")
添加链接
from fpdf import FPDF, HTMLMixin
class MyFPDF(FPDF, HTMLMixin):
pass
pdf = MyFPDF()
# 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()
# 添加链接引用位置
pdf.write(5, "click here jump", link)
pdf.set_font()
# Second page:
pdf.add_page()
# 设置链接目标地址
pdf.set_link(link)
# 给图片添加 url链接
pdf.image(
"img.png", 10, 10, 50, 0, "", "https://pyfpdf.github.io/fpdf2/"
)
pdf.set_left_margin(60)
pdf.set_font_size(18)
# 在html格式数据内指定URL链接地址
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/" target="blank">https://pyfpdf.github.io/fpdf2/</a>,
or on an image: the logo is clickable!"""
)
pdf.output("tuto6.pdf")
目录大纲
from fpdf import FPDF, HTMLMixin, HTML2FPDF
class CustomHTML2FPDF(HTML2FPDF):
def render_toc(self, pdf, outline):
pdf.cell(txt='Table of contents:', new_x="LMARGIN", new_y="NEXT")
for section in outline:
pdf.cell(txt=f'* {section.name} (page {section.page_number})', new_x="LMARGIN", new_y="NEXT")
class PDF(FPDF, HTMLMixin):
HTML2FPDF_CLASS = CustomHTML2FPDF
pdf = PDF()
pdf.add_page()
pdf.write_html("""<toc></toc>
<h1>Level 1</h1>
<h2>Level 2</h2>
<h3>Level 3</h3>
<h4>Level 4</h4>
<h5>Level 5</h5>
<h6>Level 6</h6>
<p>paragraph<p>""")
pdf.output("html_toc.pdf")
fpdf2
# fpdf 生成水印
import fpdf
pdf = fpdf.FPDF()
# pdf.set_text_color(245, 245, 245)
pdf.set_text_color(250, 250, 250) # 设置文字颜色
pdf.set_font("Arial", size=20)
pdf.add_page()
pdf.text(80, 130, "yiwanliejiu") # 水印文案
pdf.output("waterMark.pdf")
# PyPDF2
from PyPDF2 import PdfFileReader, PdfFileWriter, PdfFileMerger
password = "123456"
reader = PdfFileReader("pypdf2_meta.pdf")
writer = PdfFileWriter()
merger = PdfFileMerger()
# 解密
if reader.isEncrypted:
reader.decrypt(password)
def reader_demo():
# 读
print(reader.numPages) # 获取总页数
print(reader.getNumPages()) # 获取总页数
info = reader.getDocumentInfo() # 获取文档信息元数据
print("author ", info.author)
print("creator ", info.creator)
print("producer ", info.producer)
print("title ", info.title)
print("subject ", info.subject)
page0 = reader.getPage(0)
print(page0.extractText()) # 读取文本内容
def wtiter_demo():
# 写
for pageNum in range(reader.numPages):
page = reader.getPage(pageNum)
writer.addPage(page)
# 写入元数据
writer.addMetadata({
"/Author": "yiwanliejiu",
"/Producer": "PyPDF2 writer",
"/Title": "ahaha"
})
# 添加密码
# writer.encrypt(password)
with open("pypdf2_meta.pdf", "wb") as f:
writer.write(f)
def merger_demo():
# 逐个添加合并pdf文件
# for pdf in ["tuto2.pdf", "tuto4.pdf"]:
# merger.append(pdf)
# merger.write("merger_demo.pdf")
# 指定合并的pdf具体页数,位置
input1 = open("tuto2.pdf", "rb")
input2 = open("tuto4.pdf", "rb")
input3 = open("tuto5.pdf", "rb")
merger.append(fileobj=input1, pages=(0, 2)) # 指定合并的页码 pages=[)
merger.merge(position=1, fileobj=input2, pages=(0, 1)) # 指定新页面插入的位置和页码
merger.append(input3) # 在最后位置插入全部页码
output = open("merger_more.pdf", "wb")
merger.write(output)
merger.close()
output.close()
# 水印旋转
def water():
watermark = PdfFileReader("water.pdf")
reader = PdfFileReader("none.pdf")
writer = PdfFileWriter()
page = reader.getPage(0)
page.mergeRotatedPage(watermark.getPage(0), 20) # 添加水印图片,旋转一定角度
writer.addPage(page)
with open("water2.pdf", "wb") as fp:
writer.write(fp)
def waterMark():
watermark = PdfFileReader("water.pdf")
reader = PdfFileReader("tuto2.pdf")
writer = PdfFileWriter()
page = reader.getPage(0)
# page.mergePage(watermark.getPage(0)) # 添加水印图片
# page.mergeRotatedPage(waterpage, 20) # 添加水印图片,旋转一定角度
# writer.addPage(page)
for page in reader.pages:
page.mergePage(watermark.getPage(0)) # 不知道为什么只能是水印在上面
writer.addPage(page)
with open("watermark.pdf", "wb") as fp:
writer.write(fp)
def add_attachment_note():
writer = PdfFileWriter()
writer.addBlankPage(width=2000, height=2000)
writer.addAttachment(fname="桌面壁纸马.jpg", fdata="这里是注释".encode("utf-8"))
with open("attach.pdf", "wb") as f:
writer.write(f)
def compress():
# 压缩文件
reader = PdfFileReader("waterMark.pdf")
writer = PdfFileWriter()
for page in reader.pages:
page.compressContentStreams() # 压缩
writer.addPage(page)
with open("waterMarkCompress.pdf", "wb") as f:
writer.write(f)