zoukankan      html  css  js  c++  java
  • 【转】pyhton之Reportlab模块——生成pdf文件

    【转】pyhton之Reportlab模块

     reportlab模块是用python语言生成pdf文件的模块

    安装:pip install reportlab

    模块默认不支持中文,如果使用中文需要注册

    1.注册中文字体

    下载自己需要的.ttf字体,例如STSONG.ttf

        from reportlab.pdfbase import pdfmetrics

        from reportlab.pdfbase.ttfonts import TTFont

        pdfmetrics.registerFont(TTFont('song', STSONG.ttf))

    2.生成文字

    from reportlab.lib.styles import getSampleStyleSheet
    from reportlab.platypus import Paragraph,SimpleDocTemplate
    from reportlab.lib import  colors
    
    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])

        一份pdf文件可以定义多种字体样式,如bt和ct。字体有多种属性,这里只列举一些常用的属性,

    其中,

        wordWrap自动换行属性的参数'CJK'是按照中文方式换行(可以在字符之间换行),英文方式为'Normal'(在空格出换行)

        alignment:0  左对齐

           1  居中

           2  右对齐

    3.表格

    from reportlab.platypus import  Table

    t = Table(data)

    from reportlab.platypus import Paragraph, SimpleDocTemplate, Table,TableStyle
    from reportlab.lib.units import inch
    from reportlab.lib import colors
    
    
    def table_model(data):
        width = 7.2  # 总宽度
        colWidths = (width / len(data[0])) * inch   # 每列的宽度
    
        dis_list = []
        for x in data:
            # dis_list.append(map(lambda i: Paragraph('%s' % i, cn), x))
            dis_list.append(x)
    
        style = [
            # ('FONTNAME', (0, 0), (-1, -1), 'song'),  # 字体
            ('FONTSIZE', (0, 0), (-1, 0), 15),  # 字体大小
            ('BACKGROUND', (0, 0), (-1, 0), HexColor('#d5dae6')),  # 设置第一行背景颜色
            ('BACKGROUND', (0, 1), (-1, 1), HexColor('#d5dae6')),  # 设置第二行背景颜色
    
            # 合并 ('SPAN',(第一个方格的左上角坐标),(第二个方格的左上角坐标)),合并后的值为靠上一行的值,按照长方形合并
            ('SPAN',(0,0),(0,1)),
            ('SPAN',(1,0),(2,0)),
            ('SPAN',(3,0),(4,0)),
            ('SPAN',(5,0),(7,0)),
    
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),  # 对齐
            ('VALIGN', (-1, 0), (-2, 0), 'MIDDLE'),  # 对齐
            ('LINEBEFORE', (0, 0), (0, -1), 0.1, colors.grey),  # 设置表格左边线颜色为灰色,线宽为0.1
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.royalblue),  # 设置表格内文字颜色
            ('TEXTCOLOR', (0, -1), (-1, -1), colors.red),  # 设置表格内文字颜色
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),  # 设置表格框线为grey色,线宽为0.5
        ]
    
        component_table = Table(dis_list, colWidths=colWidths,style=style)
    
        return component_table
    
    
    
    Style=getSampleStyleSheet()
    n = Style['Normal']
    data = [[0,1,2,3,4,5,6,7],
            [00,11,22,33,44,55,66,77],
            [000,111,222,333,444,555,666,777],
            [0000,1111, 2222, 3333, 4444, 5555, 6666, 7777],]
    
    
    z = table_model(data)
    
    pdf = MyDocTemplate('ppff.pdf')
    
    pdf.multiBuild([Paragraph('Title',n),z])

    4.添加边框

    from reportlab.graphics.shapes import Drawing

    d = Drawing()

    参数有:

        d.width:边框宽度

        d.heigth:边框高度

        d.background:边框颜色

    等等。

    边框中可使用add()添加文字,图形等内容

    例:

    在边框中添加文字

    
    
    from reportlab.graphics.shapes import Drawing, Rect
    from reportlab.graphics.charts.textlabels import Label

    def
    autoLegender( title=''): width = 448 height = 230 d = Drawing(width,height) lab = Label() lab.x = 220 #x和y是文字的位置坐标 lab.y = 210 lab.setText(title) # lab.fontName = 'song' #增加对中文字体的支持 lab.fontSize = 20 d.add(lab) d.background = Rect(0,0,width,height,strokeWidth=1,strokeColor="#868686",fillColor=None) #边框颜色 return d l = autoLegender('hello') pdf=SimpleDocTemplate('ppff.pdf') pdf.multiBuild([l])
    # **这种方法可以给边框中的图例添加颜色说明**

    def autoLegender(chart, categories=[], use_colors=[], title=''): width = 448 height = 230 d = Drawing(width,height) lab = Label() lab.x = 220 #x和y是title文字的位置坐标 lab.y = 210 lab.setText(title) # lab.fontName = 'song' #增加对中文字体的支持 lab.fontSize = 20 d.add(lab) d.background = Rect(0,0,width,height,strokeWidth=1,strokeColor="#868686",fillColor=None) #边框颜色 d.add(chart) #颜色图例说明等 leg = Legend() leg.x = 500 # 说明的x轴坐标 leg.y = 0 # 说明的y轴坐标 leg.boxAnchor = 'se' # leg.strokeWidth = 4 leg.strokeColor = None leg.subCols[1].align = 'right' leg.columnMaximum = 10 # 图例说明一列最多显示的个数
    # leg.fontName = 'song' leg.alignment = 'right' leg.colorNamePairs = zip(use_colors, tuple(categories)) #增加颜色说明 d.add(leg) return d

     

    5.饼状图

     饼图需要添加在边框中

    from reportlab.lib import colors
    from reportlab.platypus import SimpleDocTemplate
    from reportlab.graphics.shapes import Drawing, Rect
    from reportlab.graphics.charts.textlabels import Label
    from reportlab.graphics.charts.piecharts import Pie
    
    def autoLegender( chart,title=''):
        width = 448
        height = 230
        d = Drawing(width,height)
        lab = Label()
        lab.x = 220  #x和y是文字的位置坐标
        lab.y = 210
        lab.setText(title)
        # lab.fontName = 'song' #增加对中文字体的支持
        lab.fontSize = 20
        d.add(lab)
        d.background = Rect(0,0,width,height,strokeWidth=1,strokeColor="#868686",fillColor=None) #边框颜色
        d.add(chart)
    
        return d
    
    
    def draw_pie(data=[], labels=[], use_colors=[], width=360,):
        '''更多属性请查询reportlab.graphics.charts.piecharts.WedgeProperties'''
    
        pie = Pie()
        pie.x = 60 # x,y饼图在框中的坐标
        pie.y = 20
        pie.slices.label_boxStrokeColor = colors.white  #标签边框的颜色
    
        pie.data = data      # 饼图上的数据
        pie.labels = labels  # 数据的标签
        pie.simpleLabels = 0 # 0 标签在标注线的右侧;1 在线上边
        pie.sameRadii = 1    # 0 饼图是椭圆;1 饼图是圆形
    
        pie.slices.strokeColor = colors.red       # 圆饼的边界颜色
        pie.strokeWidth=1                         # 圆饼周围空白区域的宽度
        pie.strokeColor= colors.white             # 整体饼图边界的颜色
        pie.slices.label_pointer_piePad = 10       # 圆饼和标签的距离
        pie.slices.label_pointer_edgePad = 25    # 标签和外边框的距离
        pie.width = width
        pie.direction = 'clockwise'
        pie.pointerLabelMode  = 'LeftRight'
        # for i in range(len(labels)):
        #     pie.slices[i].fontName = 'song' #设置中文
        for i, col in enumerate(use_colors):
             pie.slices[i].fillColor  = col
        return pie


    data = [10,9,8,7,6,5,4,3,2,1]
    labs = ['0000000','1111111','2222222','3333333','4444444',
    '5555555','6666666','7777777','8888888','9999999']
    color = [HexColor("#696969"),HexColor("#A9A9A9"),HexColor("#D8BFD8"),
    HexColor("#DCDCDC"),HexColor('#E6E6FA'),HexColor("#B0C4DE"),
    HexColor("#778899"),HexColor('#B0C4DE'),HexColor("#6495ED"),
    HexColor("#483D8B")
    ]
    z = autoLegender(draw_pie(data,labs,color),labs,color)

    pdf=SimpleDocTemplate('ppff.pdf')
    pdf.multiBuild([z])
     

    6.柱状图

     柱状图需要添加在边框中

    from reportlab.graphics.charts.barcharts import VerticalBarChart
    from reportlab.lib.colors import HexColor
    
    
    def draw_bar_chart(min, max, x_list, data=[()], x_label_angle=0, bar_color=HexColor("#7BB8E7"), height=125, width=280):
        '''
        :param min: 设置y轴的最小值
        :param max: 设置y轴的最大值
        :param x_list: x轴上的标签
        :param data: y轴对应标签的值
        :param x_label_angle: x轴上标签的倾斜角度
        :param bar_color: 柱的颜色  可以是含有多种颜色的列表
        :param height: 柱状图的高度
        :param  柱状图的宽度
        :return: 
        '''
        bc = VerticalBarChart()
        bc.x = 50            # x和y是柱状图在框中的坐标
        bc.y = 50
        bc.height = height  # 柱状图的高度
        bc.width = width    # 柱状图的宽度
        bc.data = data      
        for j in xrange(len(x_list)):
            setattr(bc.bars[j], 'fillColor', bar_color)  # bar_color若含有多种颜色在这里分配bar_color[j]
        # 调整step
        minv = min * 0.5
        maxv = max * 1.5
        maxAxis = int(height/10)
        # 向上取整
        minStep = int((maxv-minv+maxAxis-1)/maxAxis)
    
        bc.valueAxis.valueMin = min * 0.5      #设置y轴的最小值
        bc.valueAxis.valueMax = max * 1.5      #设置y轴的最大值
        bc.valueAxis.valueStep = (max-min)/4   #设置y轴的最小度量单位
        if bc.valueAxis.valueStep < minStep:
            bc.valueAxis.valueStep = minStep
        if bc.valueAxis.valueStep == 0:
            bc.valueAxis.valueStep = 1
        bc.categoryAxis.labels.boxAnchor = 'ne'   # x轴下方标签坐标的开口方向
        bc.categoryAxis.labels.dx = -5           # x和y是x轴下方的标签距离x轴远近的坐标
        bc.categoryAxis.labels.dy = -5
        bc.categoryAxis.labels.angle = x_label_angle   # x轴上描述文字的倾斜角度
        # bc.categoryAxis.labels.fontName = 'song'
        x_real_list = []
        if len(x_list) > 10:
            for i in range(len(x_list)):
                tmp = '' if i%5 != 0 else x_list[i]
                x_real_list.append(tmp)
        else:
            x_real_list = x_list
        bc.categoryAxis.categoryNames = x_real_list
        return bc
    
    
    z = autoLegender(draw_bar_chart(100, 300, ['a', 'b', 'c'], [(100, 200, 120)]))
    
    pdf=SimpleDocTemplate('ppff.pdf')
    pdf.multiBuild([z]) 

    6.累加柱状图

    def draw_2bar_chart(min, max, x_list, data=[()],array=[()], x_label_angle=0,bar_color=[],height=125, width=280):
        '''
        :param min: 设置y轴的最小值
        :param max: 设置y轴的最大值
        :param x_list: x轴上的标签
        :param data: y轴对应标签的值
        :param x_label_angle: x轴上标签的倾斜角度
        :param bar_color: 柱的颜色  可以是含有多种颜色的列表
        :param height: 柱状图的高度
        :param  柱状图的宽度
        :return: 
        '''
        bc = VerticalBarChart()
        bc.x = 50            # x和y是柱状图在框中的坐标
        bc.y = 50
        bc.height = height  # 柱状图的高度
        bc.width = width    # 柱状图的宽度
        bc.data = data
    
        # 图形柱上标注文字
        bc.barLabels.nudge = -5  # 文字在图形柱的上下位置
        bc.barLabelArray = array  # 要添加的文字
        bc.barLabelFormat = 'values'
    
        for j in xrange(len(data)):
            setattr(bc.bars[j], 'fillColor', bar_color[j])  # bar_color若含有多种颜色在这里分配bar_color[j]
        # 调整step
        # minv = min * 0.5
        minv = 0
        maxv = max * 1.5
        maxAxis = int(height/10)
        # 向上取整
        minStep = int((maxv-minv+maxAxis-1)/maxAxis)
    
        bc.valueAxis.valueMin =0      #设置y轴的最小值
        bc.valueAxis.valueMax = max * 1.5      #设置y轴的最大值
        bc.valueAxis.valueStep = (max-min)/4   #设置y轴的最小度量单位
        if bc.valueAxis.valueStep < minStep:
            bc.valueAxis.valueStep = minStep
        if bc.valueAxis.valueStep == 0:
            bc.valueAxis.valueStep = 1
        bc.categoryAxis.labels.boxAnchor = 'ne'   # x轴下方标签坐标的开口方向
        bc.categoryAxis.labels.dx = -5           # x和y是x轴下方的标签距离x轴远近的坐标
        bc.categoryAxis.labels.dy = -5
        bc.categoryAxis.labels.angle = x_label_angle   # x轴上描述文字的倾斜角度
        # bc.categoryAxis.labels.fontName = 'song'
        bc.categoryAxis.style = 'stacked'
        x_real_list = []
        if len(x_list) > 10:
            for i in range(len(x_list)):
                tmp = '' if i%5 != 0 else x_list[i]
                x_real_list.append(tmp)
        else:
            x_real_list = x_list
        bc.categoryAxis.categoryNames = x_real_list
        return bc
    
    
    #    制柱状图
    Style=getSampleStyleSheet()
    n = Style['Normal']
    my_color = [HexColor('#E13C3C'),HexColor('#BE0000')]
    z = autoLegender(draw_2bar_chart(100, 300, ['a', 'b', 'c'],
                                    [(100, 200, 120),(150, 50, 130)],
                                    bar_color=my_color,
                                    array=[['100','200','120'],['150','50','130']] ),
                     categories=['first','last'],
                     use_colors=my_color
                     )
    pdf = MyDocTemplate('ppff.pdf')
    
    pdf.multiBuild([Paragraph('Title',n),z])

    7.添加页眉

    添加页眉需要我们自定义模版

    from reportlab.platypus.doctemplate import BaseDocTemplate, Frame
    from reportlab.lib.units import cm
    from reportlab.platypus import PageTemplate
    from reportlab.lib.styles import getSampleStyleSheet
    import os
    
    def myMainPageFrame(canvas, doc):  # 全局应用
        "The page frame used for all PDF documents."
        canvas.saveState()
        canvas.setFont('Times-Roman', 12)
        pageNumber = canvas.getPageNumber()
        if pageNumber > 0:
            pic_yemei = os.path.join(os.path.dirname(__file__),'yemei01.jpg')   # 页眉图片
            pic_line_file = os.path.join(os.path.dirname(__file__),'line.jpg')  # 页眉线
            canvas.drawImage(pic_yemei, 75, 795, width=100,height=25)
            canvas.drawImage(pic_line_file, 75, 780, width=450, height=15)
            canvas.drawString(10*cm, cm, str(pageNumber))
        canvas.restoreState()
    
    
    class MyDocTemplate(BaseDocTemplate):  # 自定义模版类
        "The document template used for all PDF documents."
        _invalidInitArgs = ('pageTemplates',)
        def __init__(self, filename, **kw):
            frame1 = Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')
            self.allowSplitting = 0
            BaseDocTemplate.__init__(self, filename, **kw)
            template = PageTemplate('normal', [frame1], myMainPageFrame)
            self.addPageTemplates(template)   # 绑定全局应用
    
    
    
    
    Style=getSampleStyleSheet()
    n = Style['Normal']
    z = autoLegender(draw_bar_chart(100, 300, ['a', 'b', 'c'], [(100, 200, 120)]))
    pdf = MyDocTemplate('ppff.pdf')
    
    pdf.multiBuild([Paragraph('Title',n),z])

     

  • 相关阅读:
    http协议学习系列
    git常用命令大全
    git常用命令与常见面试题总结
    MyBatis框架及原理分析
    Mybatis常见面试题总结
    java实现克隆的三种(很最全面)
    java中equals和==之间的区别?clone方法的作用,及其为什么要使用clone方法?如何使用clone复制对象?以及深克隆浅克隆
    ThreadLocal的简单使用及实现的原理
    Java 最常见的 208 道面试题
    TCP流量控制
  • 原文地址:https://www.cnblogs.com/langqi250/p/10733747.html
Copyright © 2011-2022 走看看