|
- # © 2016 cole
- # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-
- from docxtpl import DocxTemplate
-
- import docx
-
- import jinja2
-
- """
- 使用一个独立的文件来封装需要支持图片等功能,避免污染report_docx.py
- """
-
-
- def calc_length(s):
- """
- 把字符串,数字类型的参数转化为docx的长度对象,如:
- 12 => Pt(12)
- '12' => Pt(12)
- '12pt' => Pt(12) 单位为point
- '12cm' => Cm(12) 单位为厘米
- '12mm' => Mm(12) 单位为毫米
- '12inchs' => Inchs(12) 单位为英寸
- '12emu' => Emu(12)
- '12twips' => Twips(12)
- """
- if not isinstance(s, str):
- # 默认为像素
- return docx.shared.Pt(s)
-
- if s.endswith('cm'):
- return docx.shared.Cm(float(s[:-2]))
- elif s.endswith('mm'):
- return docx.shared.Mm(float(s[:-2]))
- elif s.endswith('inchs'):
- return docx.shared.Inches(float(s[:-5]))
- elif s.endswith('pt') or s.endswith('px'):
- return docx.shared.Pt(float(s[:-2]))
- elif s.endswith('emu'):
- return docx.shared.Emu(float(s[:-3]))
- elif s.endswith('twips'):
- return docx.shared.Twips(float(s[:-5]))
- else:
- # 默认为像素
- return docx.shared.Pt(float(s))
-
-
- def calc_alignment(s):
- """
- 把字符串转换为对齐的常量
- """
- A = docx.enum.text.WD_ALIGN_PARAGRAPH
- if s == 'center':
- return A.CENTER
- elif s == 'left':
- return A.LEFT
- elif s == 'right':
- return A.RIGHT
- else:
- return A.LEFT
-
-
- @jinja2.contextfilter
- def picture(ctx, data, width=None, height=None, align=None):
- """
- 把图片的二进制数据(使用了base64编码)转化为一个docx.Document对象
-
- data:图片的二进制数据(使用了base64编码)
- width:图片的宽度,可以为:'12cm','12mm','12pt' 等,参考前面的 calc_length()
- height:图片的长度,如果没有设置,根据长度自动缩放
- align:图片的位置,'left','center','right'
- """
-
- if not data:
- return None
-
- # 转化为file-like对象
- # 在python2.7中,bytes==str,可以直接使用
- # 在python3.5中,bytes和str是不同的类型,需要使用base64这个库
-
- # data使用了base64编码,所以这里需要解码
- data = data.decode('base64')
-
- import io
- data = io.BytesIO(data)
-
- tpl = ctx['tpl']
- doc = tpl.new_subdoc()
-
- if width:
- width = calc_length(width)
- if height:
- height = calc_length(height)
-
- p = doc.add_paragraph()
- p.alignment = calc_alignment(align)
- p.add_run().add_picture(data, width=width, height=height)
- return doc
-
-
- def get_env():
- """
- 创建一个jinja的enviroment,然后添加一个过滤器
- """
- jinja_env = jinja2.Environment()
- jinja_env.filters['picture'] = picture
- return jinja_env
-
-
- def test():
- """
- 演示了如何使用,可以直接执行该文件,但是需要使用自己写的docx模版,和图片
- """
- tpl = DocxTemplate("tpls/test_tpl.docx")
- # 读取图片的数据且使用base64编码
- data = open('tpls/python_logo.png', 'rb').read().encode('base64')
- obj = {'logo': data}
- # 需要添加模版对象
- ctx = {'obj': obj, 'tpl': tpl}
- jinja_env = get_env()
- tpl.render(ctx, jinja_env)
-
- tpl.save('tpls/test.docx')
-
-
- def main():
- test()
-
-
- if __name__ == '__main__':
- main()
|