背景: 有限的资源下,异步并发生成PDF报错,内存不足。
目的: 在有限资源的情况下,并发生成PDF,并且耗费的资源较少(资源:CPU以及内存),并且并发生成PDF的速度不能太慢,生成的PDF样式要丰富,并且生成的PDF内容要完整。
根据我调研的生成pdf的方式(python)有reportlab、pdfkit、xhtml2pdf、django-easy-pdf.
一、reportlab库
这个库可自己绘制各种图表,只是依赖于这个reportlab库,其次字体问题,可以引入字体文件进行解决。
简单的样例:
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph,SimpleDocTemplate
from reportlab.lib import colors
# 字体
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont('song', STSONG.ttf))
Style=getSampleStyleSheet()
bt = Style['Normal'] #字体的样式
# bt.fontName='song' #使用的字体
bt.fontSize=14 #字号
bt.wordWrap = 'CJK' #该属性支持自动换行,'CJK'是中文模式换行,用于英文中会截断单词造成阅读困难,可改为'Normal'
bt.firstLineIndent = 32 #该属性支持第一行开头空格
bt.leading = 20 #该属性是设置行距
ct=Style['Normal']
# ct.fontName='song'
ct.fontSize=12
ct.alignment=1 #居中
ct.textColor = colors.red
t = Paragraph('hello',bt)
pdf=SimpleDocTemplate('ppff.pdf')
pdf.multiBuild([t])
二、pdfkit依赖
这个可根据url、html、字符串生成pdf文件,确实很好用,但是也有缺陷,也存在字体问题以及样式问题,字体需要在环境中设置字体,过于复杂或者高级的css样式不支持。
代码样例:
# pdfkit.from_string() # 将字符串转成pdf文件,如果字符串是html代码,pdf也是识别的
# pdfkit.from_file() # 将文件转成pdf文件
# pdfkit.from_url() # 将网址的整个内容转成pdf文件
path_wk = BKAPP_WLS_PATH
config = pdfkit.configuration(wkhtmltopdf=path_wk)
try:
result = pdfkit.from_url(instance.task_url,
path,
options={'encoding': "utf-8"},
configuration=config)
except Exception as e:
logger.error('%s' % str(e))
result = False
三、xhtml2pdf和django-easy-pdf
这两个都是走的模板渲染方式、但是很多的css样式无法支持,并且也存在字体和css样式问题。
代码样例:
from xhtml2pdf import pisa
sourceHtml = 'http://www.baidu.com/'
outputFilename = "test.pdf"
def convertHtmlToPdf(sourceHtml, outputFilename):
resultFile = open(outputFilename, "w+b")
pisaStatus = pisa.CreatePDF(sourceHtml,resultFile)
resultFile.close()
return pisaStatus.err
if __name__=="__main__":
pisa.showLogging()
convertHtmlToPdf(sourceHtml, outputFilename)
个人整理对比:
方式 | 优点 | 缺点 | 个人见解 |
---|---|---|---|
reportlab | 基本上报表、巡检报告等涉及的都能实现 | 字体需要引入字体文件(14M大小) | 字体问题很容易解决,生成的pdf可以有各种数据图表的生成甚至图片样式等,但是使用起来过于繁琐,相当于自己用代码进行绘图(包括各个元素在pdf的位置),其次有关短时间内大量生成pdf消耗的cpu、内存还没有进行测试 , 但可以进行异步或者多进程批量生成 |
pdfkit | 生成的pdf美观、其次支持的样式也很多,使用简单 | 需要依赖于wkhtmltopdf这个轻量级的软件(感觉是最大的败笔),如果项目部署在docker上,需要在docker内设置字体,其次过于高级的css样式不支持,比如css3的一些样式 | 如果没有特别的要求,基本能满足需求,通过批量测试,pdfkit可以同时批量生成pdf,但是耗cpu和内存,当生成的PDF越大,内容越多,耗得cpu、内存也越多,如果用于生产环境,同时短时间内生成大量的pdf,不建议使用,毕竟环境的稳定大于一切 |
xhtml2pdf/django-easy-pdf | 可生成pdf,但美观程度一般,采用的模板渲染方式生成pdf | 字体问题需要引入字体文件、其次只支持部分样式,样式上很少 | 简单的pdf可以使用,如果生成复杂的pdf,估计样式上很难给予支持 |
注意:
pdfkit经过测试生成一个1M的PDF,页数11页,内容各种图表,经测试一个WK的启动消耗内存大概50M-70M;
生成一个4M的PDF,PDF页数有600页,内容有各种图表,大部分都是字体描述,经测试一个WK的启动消耗内存大概220M-270M。
所以当生成的PDF大小越大,页数越多,我认为最好不要使用并发生成PDF,如果非要使用并发,最好根据消耗以及现有的环境在代码层控制生成PDF任务数。