123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- from reportlab.pdfbase import pdfmetrics # 注册字体
- from reportlab.pdfbase.ttfonts import TTFont # 字体类
- from reportlab.platypus import Table, SimpleDocTemplate, Paragraph, Image, Frame, PageTemplate, Spacer # 报告内容相关类
- from reportlab.lib.pagesizes import A4 # 页面的标志尺寸(8.5*inch, 11*inch)
- from reportlab.lib.styles import getSampleStyleSheet # 文本样式
- from reportlab.lib import colors # 颜色模块
- from reportlab.graphics.charts.barcharts import VerticalBarChart # 图表类
- from reportlab.graphics.charts.legends import Legend # 图例类
- from reportlab.graphics.shapes import Drawing # 绘图工具
- from reportlab.lib.units import cm # 单位:cm
- import argparse
- import re
- pdfmetrics.registerFont(TTFont('SimSun', './py/SimSun.ttf'))
- class Graphs:
- # 绘制标题
- @staticmethod
- def draw_title(title: str, linespace=50, fontsize=18):
- # 获取所有样式表
- style = getSampleStyleSheet()
- # 拿到标题样式
- ct = style['Heading2']
- # 单独设置样式相关属性
- ct.fontName = 'SimSun' # 字体名
- ct.fontSize = fontsize # 字体大小
- ct.leading = linespace # 行间距
- ct.textColor = colors.green # 字体颜色
- ct.alignment = 1 # 居中
- ct.bold = True
- # 创建标题对应的段落,并且返回
- return Paragraph(title, ct)
- # 绘制小标题
- @staticmethod
- def draw_little_title(title: str):
- # 获取所有样式表
- style = getSampleStyleSheet()
- # 拿到标题样式
- ct = style['Normal']
- # 单独设置样式相关属性
- ct.fontName = 'SimSun' # 字体名
- ct.fontSize = 15 # 字体大小
- ct.leading = 30 # 行间距
- ct.textColor = colors.red # 字体颜色
- # 创建标题对应的段落,并且返回
- return Paragraph(title, ct)
- # 绘制普通段落内容
- @staticmethod
- def draw_text(text: str,alignment=0,firstLineIndent=32):
- # 获取所有样式表
- style = getSampleStyleSheet()
- # 获取普通样式
- ct = style['Normal']
- ct.fontName = 'SimSun'
- ct.fontSize = 12
- ct.wordWrap = 'CJK' # 设置自动换行
- ct.alignment = alignment # 左对齐
- ct.firstLineIndent = firstLineIndent # 第一行开头空格
- ct.leading = 25
- return Paragraph(text, ct)
- # 绘制表格
- @staticmethod
- def draw_info_table(*args, col_width=120):
- # 列宽度
- col_width = col_width
- style = [
- ('FONTNAME', (0, 0), (-1, -1), 'SimSun'), # 字体
- ('FONTSIZE', (0, 0), (-1, 0), 12), # 第一行的字体大小
- ('FONTSIZE', (0, 1), (-1, -1), 12), # 第二行到最后一行的字体大小
- ('BACKGROUND', (0, 0), (-1, 0), '#d5dae6'), # 设置第一行背景颜色
- ('ALIGN', (0, 0), (-1, -1), 'CENTER'), # 第一行水平居中
- ('ALIGN', (0, 1), (-1, -1), 'CENTER'), # 第二行到最后一行左右左对齐
- ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), # 所有表格上下居中对齐
- ('TEXTCOLOR', (0, 0), (-1, -1), colors.darkslategray), # 设置表格内文字颜色
- ('GRID', (0, 0), (-1, -1), 0.5, colors.black), # 设置表格框线为grey色,线宽为0.5
- # ('SPAN', (0, 1), (0, 2)), # 合并第一列二三行
- # ('SPAN', (0, 3), (0, 4)), # 合并第一列三四行
- # ('SPAN', (0, 5), (0, 6)), # 合并第一列五六行
- # ('SPAN', (0, 7), (0, 8)), # 合并第一列五六行
- ]
- table = Table(args, colWidths=col_width, rowHeights=(1*cm, 1*cm),style=style)
- return table
- # 绘制表格
- @staticmethod
- def draw_result_table(*args, col_width=120):
- # 列宽度
- col_width = col_width
- style = [
- ('FONTNAME', (0, 0), (-1, -1), 'SimSun'), # 字体
- ('FONTSIZE', (0, 0), (-1, 0), 12), # 第一行的字体大小
- ('FONTSIZE', (0, 1), (-1, -1), 12), # 第二行到最后一行的字体大小
- ('BACKGROUND', (0, 0), (-1, 0), '#d5dae6'), # 设置第一行背景颜色
- ('ALIGN', (0, 0), (-1, -1), 'CENTER'), # 第一行水平居中
- ('ALIGN', (0, 1), (-1, -1), 'CENTER'), # 第二行到最后一行左右左对齐
- ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), # 所有表格上下居中对齐
- ('TEXTCOLOR', (0, 0), (-1, -1), colors.darkslategray), # 设置表格内文字颜色
- ('GRID', (0, 0), (-1, -1), 0.5, colors.black), # 设置表格框线为grey色,线宽为0.5
- # ('SPAN', (0, 1), (0, 2)), # 合并第一列二三行
- # ('SPAN', (0, 3), (0, 4)), # 合并第一列三四行
- # ('SPAN', (0, 5), (0, 6)), # 合并第一列五六行
- # ('SPAN', (0, 7), (0, 8)), # 合并第一列五六行
- ]
- table = Table(args, colWidths=col_width, style=style)
- return table
- @staticmethod
- def draw_explanation_table(*args, col_width=120):
- # 列宽度
- col_width = col_width
- style = [
- ('FONTNAME', (0, 0), (-1, -1), 'SimSun'), # 字体
- ('FONTSIZE', (0, 0), (-1, 0), 12), # 第一行的字体大小
- ('FONTSIZE', (0, 1), (-1, -1), 12), # 第二行到最后一行的字体大小
- ('BACKGROUND', (0, 0), (-1, 0), '#d5dae6'), # 设置第一行背景颜色
- ('ALIGN', (0, 0), (-1, -1), 'CENTER'), # 第一行水平居中
- ('ALIGN', (0, 1), (-1, -1), 'CENTER'), # 第二行到最后一行左右左对齐
- ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), # 所有表格上下居中对齐
- ('TEXTCOLOR', (0, 0), (-1, -1), colors.darkslategray), # 设置表格内文字颜色
- ('GRID', (0, 0), (-1, -1), 0.5, colors.black), # 设置表格框线为grey色,线宽为0.5
- # ('SPAN', (0, 1), (0, 2)), # 合并第一列二三行
- # ('SPAN', (0, 3), (0, 4)), # 合并第一列三四行
- # ('SPAN', (0, 5), (0, 6)), # 合并第一列五六行
- # ('SPAN', (0, 7), (0, 8)), # 合并第一列五六行
- ]
- table = Table(args, colWidths=(100,350), style=style)
- return table
- # 创建图表
- @staticmethod
- def draw_bar(bar_data: list, ax: list, items: list):
- drawing = Drawing(500, 250)
- bc = VerticalBarChart()
- bc.x = 45 # 整个图表的x坐标
- bc.y = 45 # 整个图表的y坐标
- bc.height = 200 # 图表的高度
- bc.width = 350 # 图表的宽度
- bc.data = bar_data
- bc.strokeColor = colors.black # 顶部和右边轴线的颜色
- bc.valueAxis.valueMin = 5000 # 设置y坐标的最小值
- bc.valueAxis.valueMax = 26000 # 设置y坐标的最大值
- bc.valueAxis.valueStep = 2000 # 设置y坐标的步长
- bc.categoryAxis.labels.dx = 2
- bc.categoryAxis.labels.dy = -8
- bc.categoryAxis.labels.angle = 20
- bc.categoryAxis.categoryNames = ax
- # 图示
- leg = Legend()
- leg.fontName = 'SimSun'
- leg.alignment = 'right'
- leg.boxAnchor = 'ne'
- leg.x = 475 # 图例的x坐标
- leg.y = 240
- leg.dxTextSpace = 10
- leg.columnMaximum = 3
- leg.colorNamePairs = items
- drawing.add(leg)
- drawing.add(bc)
- return drawing
- # 绘制图片
- @staticmethod
- def draw_img(path):
- img = Image(path) # 读取指定路径下的图片
- img.drawWidth = 12*cm # 设置图片的宽度
- img.drawHeight = 6*cm # 设置图片的高度
- return img
- def footer(canvas, doc):
- canvas.saveState()
- canvas.setFont('SimSun', 12)
- canvas.line(cm, cm * 1.2, A4[0] - cm, cm * 1.2)
- canvas.drawCentredString(A4[0]/2, cm * 0.7, "本报告仅供临床参考,不做诊断证明之用")
- canvas.restoreState()
- def header(canvas, doc):
- canvas.saveState()
- canvas.drawImage(logo, 50, doc.height + 50,2*cm,2*cm)
- canvas.setFont('SimSun', 12)
- canvas.line(cm, cm * 1.2, A4[0] - cm, cm * 1.2)
- canvas.drawCentredString(A4[0]/2, cm * 0.7, "本报告仅供临床参考,不做诊断证明之用")
- canvas.restoreState()
- if __name__ == '__main__':
- parse = argparse.ArgumentParser()
- parse.add_argument('filename', type=str)
- parse.add_argument('logo', type=str)
- parse.add_argument('output', type=str)
- args = parse.parse_args()
- with open(args.filename, 'rb') as fp:
- data = fp.readlines()
- d = eval(data[0])
- global logo, output_path
- logo = args.logo
- output_path = args.output
- gender = ['男','女']
- # 创建内容对应的空列表
- content = list()
- # 添加标题
- content.append(Graphs.draw_title(d['userEntity']['institutionName'],linespace=20,fontsize=14))
- content.append(Graphs.draw_title(d['name']))
- # 基本信息
- content.append(Graphs.draw_text('【基本信息】',firstLineIndent=0))
- data = [
- ('姓 名', '性 别', '出生日期'),
- (d['userEntity']['petName'],gender[int(d['userEntity']['gender'])],d['userEntity']['birthday'])
- ]
- content.append(Graphs.draw_info_table(*data, col_width=150))
- # 添加段落文字
- s = Spacer(width=0, height=1*cm)
- content.append(s)
- content.append(Graphs.draw_text('【测试结果】',firstLineIndent=0))
- # 添加图片
- # content.append(Graphs.draw_img('1.png'))
- data = [('项目', '结果','常模参考值')]
- for i in d['result']:
- data.append((i['name'],i['score'], i['reference']))
- content.append(Graphs.draw_result_table(*data,col_width=150))
- s = Spacer(width=0, height=1*cm)
- content.append(s)
- content.append(Graphs.draw_text('【结果说明】',firstLineIndent=0))
- # 添加表格
- styles = getSampleStyleSheet()
- styleC = styles["BodyText"]
- styleC.fontName = 'SimSun'
- styleC.fontSize = 12 # 字体大小
- styleC.alignment = 1 # 居中
- styleC.textColor = colors.darkslategray
- styles = getSampleStyleSheet()
- styleL = styles["BodyText"]
- styleL.fontName = 'SimSun'
- styleL.fontSize = 12 # 字体大小
- styleL.alignment = 0 # 左对齐
- styleL.textColor = colors.darkslategray
- for i in d['result']:
- if len(i['nameExplain'])>1:
- explanation = Paragraph(i['nameExplain'], styleL)
- else:
- explanation = Paragraph(i['nameExplain'], styleC)
- if len(i['suggestion'])>1:
- suggestion = Paragraph(i['suggestion'], styleL)
- else:
- suggestion = Paragraph(i['suggestion'], styleC)
- data = [
- ('维度名称', i['name']),
- ('得 分', i['score']),
- ('结 论', i['symptom']),
- ('维度说明', explanation),
- ('建 议',suggestion)
- ]
- content.append(Graphs.draw_explanation_table(*data))
- s = Spacer(width=0, height=2*cm)
- content.append(s)
- content.append(Graphs.draw_text(f'医生签名:__________________ 测评日期:{d["reportTime"]}',2))
- # 生成pdf文件
- output_name = f"{output_path}"
- doc = SimpleDocTemplate(output_name, pagesize=A4)
- frame = Frame(36, 36, A4[0] - 72, A4[1] - 72)
- header_frame = Frame(36, 36, A4[0] - 72, A4[1] - 72)
- footer_template = PageTemplate(id='footer', frames=[frame], onPage=footer)
- header_template = PageTemplate(id='header', frames=[header_frame], onPage=header)
- doc.addPageTemplates([header_template, footer_template])
- doc.build(content,onFirstPage=footer, onLaterPages=footer)
|