reportlab库是一个专门使用Python来制作,修改PDF的库。我们使用这些库,可以产生与Adobe Acrobat DC相同的效果。今天的文章先介绍如何用reportlab库来新建PDF文件,在PDF文件里写上文字。
打开命令提示符,输入:
pip install reportlab -i https://pypi.tuna.tsinghua.edu.cn/simple
安装完再输入pip list,看看有没有安装成功。
因为reportlab库里有许多功能,所以在这篇文章里导入一个就够了。
from reportlab.pdfgen import canvas
我们把类名叫做c。在canvas.Canvas里我们要加上PDF文件的名字。
c = canvas.Canvas('demo.pdf')
直接调用这个方法,程序结束后在程序旁边就有一个demo.pdf了。
c.save()
这时候有些人打开后会出现这样的界面
这是因为我们没有对里面进行写入操作。虽然里面什么都没有,但这样打开是会报错的。
所以,我们要在c.save()之前加上这一行代码
c.showPage()
这一个会让PDF转到下一页,同时如果前面什么也没有就只显示上一页。
&nbs完成!
我们在写字时会有两种方法
c.drawString(x, y, content) c.drawCentredString(x, y, content)
这两个方法的不同之处在于第一个是对准文字的左下角,第二个是对准文字的正中间。
这里注意,如果你在第一页写了东西,且不想创建新页的话就不要加c.showPage()了。
-
from reportlab.pdfgen
import canvas
-
import webbrowser
-
import os
-
-
c = canvas.Canvas(
'demo.pdf')
-
c.drawString(
0,
0,
'Hello, world!')
-
c.save()
-
-
webbrowser.
open(
'file://' + os.path.realpath(
'demo.pdf'))
这里的最后一行是直接用程序打开这个PDF文件。
成功!
如果把第5行的文字改成中文,会出现和matplotlib一样的黑色的字。
解决这个问题,首先需要一个含有中文字体的TTF文件 。如果没有现成的可以在windows系统下
设置>>个性化>>字体管理>>打开一个有中文字体示例的文件>>在其信息里找到保存的位置
-
from reportlab.pdfbase.ttfonts
import TTFont
-
from reportlab.pdfbase.pdfmetrics
import registerFont
registerFont(TTFont(name, file)) c.setFont(font, size)
第一行是把这个字体文件导入到程序里。
第二行是设置画布(PDF的类)的字体及大小。
如果要调整字体的大小,可以直接使用这个方法
c.setFontSize(size)
当然,这个字体是里面设置的字体。
-
from reportlab.pdfgen
import canvas
-
import webbrowser
-
import os
-
from reportlab.pdfbase.ttfonts
import TTFont
-
from reportlab.pdfbase.pdfmetrics
import registerFont
-
-
c = canvas.Canvas(
'demo.pdf')
-
registerFont(TTFont(
'fangzheng',
'fangzheng.TTF'))
-
c.setFont(
'fangzheng',
35)
-
c.drawString(
0,
0,
'你好,世界')
-
-
c.save()
-
webbrowser.
open(
'file://' + os.path.realpath(
'demo.pdf'))
成功!
有些读者再写字的时候会想把字写在右下角,左上角等等。但是,这下二位置的坐标是多少呢?我们要追根求源找一下。
在reportlab官网里对canvas.Canvas的类__init__方法有这么一个解释
在__init__里面有一个叫pagesize的参数。而这里的默认参数是按照A4纸张的大小来确定的。所以,我肯定地告诉大家,这个画布的大小是 (595.27, 841.89) 。
当然,如果想要改变画布的大小,可以在c = canvas.Canvas() 里面加上pagesize的参数。注意,参数是需要元组哦。
这里就把字符Hello, world打印在画布的正中间。
from reportlab.pdfgen import canvas
import webbrowser
import os
width = 595.27 # 画布的宽
height = 841.89 # 画布的高
c = canvas.Canvas('demo.pdf')
c.drawCentredString(width/2, height/2, 'Hello, world!')
c.save()
webbrowser.open('file://'+os.path.realpath('demo.pdf'))
成功!
在这里reportlab给出了两个方法
c.line(x1, y1, x2, y2)
c.setLineWidth(width)
from reportlab.pdfgen import canvas
import webbrowser
import os
width = 595.27 # 画布的宽
height = 841.89 # 画布的高
c = canvas.Canvas('demo.pdf')
c.setLineWidth(3) # 加粗线段
c.line(0, height/2, width, height/2) # 横向分割线
c.line(width/2, 0, width/2, height) # 纵向分割线
c.save()
webbrowser.open('file://'+os.path.realpath('demo.pdf'))
这里使用经典的工作安排四象限来做示例
{
"Do": [
"test",
"homework"
],
"Plan": [
"read",
"gym"
],
"Delegate": [
"movie"
],
"Eliminate": [
"game",
"shopping"
]
}
from reportlab.pdfgen import canvas
import webbrowser
import os
import json
with open('task.txt', 'r') as f:
task = json.load(f)
print(task)
c = canvas.Canvas("todolist.pdf") # 生成默认大小的画布
c.setLineWidth(3) # 加粗线段
c.line(0, 421, 595, 421) # 横向分割线
c.line(298, 0, 298, 841) # 纵向分割线
# 写上对应的四象限标注
c.drawCentredString(446, 841 - 30, "Do") # 第一象限
c.drawCentredString(149, 841 - 30, "Plan") # 第二象限
c.drawCentredString(149, 421 - 30, "Eliminate") # 第三象限
c.drawCentredString(446, 421 - 30, "Delegate") # 第四象限
# 自动书写内容
for i in task:
print(i)
if i == 'Do':
for j in range(len(task[i])):
c.drawCentredString(446, 841 - 30 - 40 *
(j + 1), task[i][j]) # 第一象限
if i == 'Plan':
for j in range(len(task[i])):
c.drawCentredString(149, 841 - 30 - 40 *
(j + 1), task[i][j]) # 第二象限
if i == 'Eliminate':
for j in range(len(task[i])):
c.drawCentredString(149, 421 - 30 - 40 *
(j + 1), task[i][j]) # 第三象限
if i == 'Delegate':
for j in range(len(task[i])):
c.drawCentredString(446, 421 - 30 - 40 *
(j + 1), task[i][j]) # 第四象限
c.save() # 保存pdf文件
webbrowser.open("file://" + os.path.realpath("todolist.pdf"))
插入图片再制作PDF时是非常实用的方法,应用面也非常得广。但它使用起来非常简单。
drawImage(image, x, y, width, height, mask)
from reportlab.pdfgen import canvas
import webbrowser
import os
c = canvas.Canvas('demo.pdf') # 创建canvas对象
c.drawImage('reportlab.png', 0,0) # 插入图片
c.save()
webbrowser.open('file://'+os.path.realpath('demo.pdf'))
再插入时,可能会出现许多特殊的情况,这时候使用里面的参数就可以轻松解决这些问题。
在官方文档里有对缩放图片的方法:
如果没有给出宽度和高度,则以像素为单位的图像的宽度和高度以1点对1像素的比例使用。
如果给定了宽度和高度,则图像将被拉伸以填充以(x,y,x+width,y-height)为界的给定矩形。
如果提供负的宽度和/或高度,它会反转它们并相应地调整x和y。
这里的话就是这个参数width, height就是插入的长,宽的大小。但是,像素为单位的图像的宽度和高度以1点对1像素的比例里点和像素又是什么“长度单位”?
其实,里面的点是PDF文件里的长度单位。在上一篇文章里讲过在reportlab里一张A4纸的大小是 (595.27, 841.89) ,但笔者没有讲过这里的单位。现在可以肯定地说,这里的单位是点。
from reportlab.pdfgen import canvas
import webbrowser
import os
width = 595.27 # 画布的宽
height = 841.89 # 画布的高
c = canvas.Canvas('demo.pdf')
c.drawImage('reportlab.png', 0, 0, 500, 500)
c.save()
webbrowser.open('file://' + os.path.realpath('demo.pdf'))
有些读者在插入一些有透明图层的图片时会遇到这种问题
为什么这些透明的地方会变成黑色的?不是“透明”码?
其实,reportlab官方在插入图片时是不会有透明度的,也就是原本是透明的,看不见的。而现在却能看见。但也不是全都会是透明的,得看像素点的坐标才能确定。
记得我在上面还没有讲的mask参数吗?其实只要在方法里把那参数设置为’auto’就可以了。对!就是这么简单!
from reportlab.pdfgen import canvas
import webbrowser
import os
width = 595.27 # 画布的宽
height = 841.89 # 画布的高
c = canvas.Canvas('demo.pdf')
c.drawImage('demo.png', 0, 0, mask='auto') # 开启透明模式
c.save()
webbrowser.open('file://' + os.path.realpath('demo.pdf'))
我们先看一看这一个是 Hello, world! 的二维码
zzz没办法,二维码全部显示会违规只能打码显示。看一下就行了zzz
这里的三个“回”字形的方块,它们是用来告诉扫描器的大小的。有这三个,即使是倒着的,斜着的二维码,我们都可以识别出来。
官方在生成二维码方面有些复杂,但理解后上手也是十分简单。
这里不详解了,就自己看看下文做一下阅读理解吧。
from reportlab.graphics.barcode import qr
from reportlab.graphics.shapes import Drawing
from reportlab.graphics import renderPDF
这里再官方文档里,生成的二维码不能像图片一样直接放在canvas里面,生成后需要先传到drawing对象上,最后再渲染在cavas画布上。
这里读者可能有些蒙,笔者在这里做一个比喻。
假如这个二维码是剁椒鱼头,你要吃肯定不会让厨师直接把鱼头扔到你手上叫你直接用手抓着吃,对吧?
我们按正常人的思路是先把剁椒鱼头做好,然后再放到盘子里,最后在放到桌子上。就像这样
在我们的代码实现里也是这样的。我们要先把二维码制作好,然后放在图片画布的盘子上。最后在放置到canvas画布上,给人们展示出来。
我们这一步骤就像在厨房里制作剁椒鱼头一样。
Qr_code = qr.QrCodeWidget(content, barWidth, barHeight, barBorder)
这里的图像画布和cavas画布不一样,这类似于盘子与桌子的区别。
drawing = Drawing(width,height)
这里就类似于把盘子准备好后把剁椒鱼头放置在盘子上面。
drawing.add(node)
renderPDF.draw(drawing, canvas, x, y)
以上的操着十分的繁琐,我们可以把它包装成一个函数来使用。
def createQrCodes(content, barWidth, barHeight, barBorer, x, y, self):
Qr_code = qr.QrCodeWidget(content, barWidth=barWidth, barHeight=barHeight, barBorder=barBorer)
drawing = Drawing(barWidth,barHeight)
drawing.add(Qr_code)
renderPDF.draw(drawing, self, x, y)
这里的参数在上面就有类似的说明,要想知道自己找。
其实这里只需要三个库:1. reportlab库,用来处理PDF文档的;2. Pillow库,来获取图片的大小;3. webbrowser库,用来打开PDF文档。
from reportlab.pdfgen import canvas
from PIL import Image
import webbrowser
这里读者可以自己修改成自己喜欢的样式。
img_file = input('请输入要转换的图片路径:')
pdf_file = input('请输入要保存的PDF文件路径:')
这里因为后面canvas画布也要访问图片,所以在获取图片大小后就要关闭图片。
img = Image.open(img_file)
size = img.size
img.close()
笔者对画布大小的修改也是讲过的。
c = canvas.Canvas(pdf_file, pagesize=img.size)
这里为了万一,就把mask设置成了auto,路径就是img_file,xy坐标自然是(0, 0)。
c.drawImage(img_file, 0, 0, mask='auto')
c.save()
print('转换成功!')
webbrowser.open('file://' + pdf_file)
from reportlab.pdfgen import canvas
from PIL import Image
import webbrowser
img_file = input('请输入要转换的图片路径:')
pdf_file = input('请输入要保存的PDF文件路径:')
img = Image.open(img_file)
size = img.size
img.close()
c = canvas.Canvas(pdf_file, pagesize=img.size)
c.drawImage(img_file, 0, 0, mask='auto')
c.save()
print('转换成功!')
webbrowser.open('file://' + pdf_file)
成功!