python docx在world中插入表格与图片

在原文档的某段落前面插入标题、表格、以及图片

import logging

from docx import Document
from docx.shared import Pt, Cm
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.table import WD_CELL_VERTICAL_ALIGNMENT
from flask import Flask, jsonify, request, json, app
import logging.handlers as loghandlers

app = Flask(__name__)

######################################################
#   各种类
######################################################

class Response(object):
    SUCCESS = 200
    ERROR = 201

    @staticmethod
    def getResponse(code: int, message: str, data=None):
        return jsonify({
            "code": code,
            "message": message,
            "data": data
        })

class ResultId:
    def __init__(self, title, value):
        self.title = title
        self.value = value

class Table:
    def __init__(self, tableName, columns, rows, columnvalue, rowvalues):
        '''

        :param tableName: 表名
        :param columns: 列数
        :param rows:  行数
        :param columnvalue:  列值数组
        :param rowvalues:  行值数组
        '''
        self.tableName = tableName
        self.columns = columns
        self.rows = rows
        self.columnvalue = columnvalue
        self.rowvalues = rowvalues

class TableParagraph:
    def __init__(self, title, table):
        self.title = title
        self.table = table

class Waveform:
    def __init__(self, title, imags):
        self.title = title
        self.imags = imags


class Report:
    def __init__(self, result, condition_table, waveform, result_table):
        self.result = result
        self.condition = condition_table
        self.imags = waveform
        self.result = result_table
#########################################################################
#
#########################################################################
def buildResultId(document,text, index, resultId):
    specText = text.encode('utf-8').decode('utf-8')
    title = index + '.1' + resultId.title
    content = resultId.value
    addParagraphBefore(document, specText, title)
    for i, p in enumerate(document.paragraphs):
        if(p.text == specText):
            document.paragraphs[i].insert_paragraph_before(text=content)



def buildTableParagraph(document,text, index, tableParagraph):
        specText = text.encode('utf-8').decode('utf-8')
        if(tableParagraph.title == '测试条件'):
            title = index + '.2' + tableParagraph.title
        else:
            title = index + '.4' + tableParagraph.title
        tableName = tableParagraph.table.tableName
        columns = tableParagraph.table.columns
        rows = tableParagraph.table.rows
        columnvalue = tableParagraph.table.columnvalue
        rowvalues = tableParagraph.table.rowvalues
        # 创建表格
        table = createTable(document,rows,columns,rowvalues,columnvalue)
        addParagraphBefore(document, specText, title)
        # 插入段落头,表格名称
        for i, p in enumerate(document.paragraphs):
            if (p.text == specText):
                before = document.paragraphs[i].insert_paragraph_before(text=tableName)
                before.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 设置文档段落对齐
                break
        # 插入表格
        for i, p in enumerate(document.paragraphs):
            if (p.text == specText):
                document.paragraphs[i-1]._p.addnext(table._tbl)
                break


def buildWaveform(document, text, index, waveform):
    specText = text.encode('utf-8').decode('utf-8')
    title = index +'.3'+waveform.title
    imags = waveform.imags
    # 插入段落头
    addParagraphBefore(document, specText, title)
    # 插入图片
    for i, p in enumerate(document.paragraphs):
        if (p.text == specText):
            before = document.paragraphs[i].insert_paragraph_before()
            for a,t in imags:
                before.add_run().add_picture(a, height=Cm(6), width=Cm(10))
                before.add_run().add_break()  # 添加一个折行
                before.add_run().add_text(t)
                before.add_run().add_break()  # 添加一个折行
                before.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 设置文档段落对齐
            break

def buildWaveform2(document, text, index, waveform):
    specText = text.encode('utf-8').decode('utf-8')
    title = index + '.3' + waveform.title
    imags = waveform.imags
    # 插入段落头
    addParagraphBefore(document, specText, title)
    table = document.add_table(rows= len(imags), cols=1)
    table.alignment = WD_TABLE_ALIGNMENT.CENTER   # 表格居中
    for i in range(len(table.rows)):
        table.cell(i, 0).paragraphs[0].add_run().add_picture(imags[i][0], height=Cm(6), width=Cm(10))
        table.cell(i, 0).paragraphs[0].add_run().add_break()
        table.cell(i, 0).paragraphs[0].add_run().add_text(imags[i][1])
        table.cell(i, 0).vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER  # 单元格居中
        table.cell(i, 0).paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 段落居中
    # 插入图片
    for i, p in enumerate(document.paragraphs):
        if (p.text == specText):
            document.paragraphs[i - 1]._p.addnext(table._tbl)
            break


def createReport(templateAddress):
    document = Document(templateAddress)
    return document


def buildOneReport(document, text, index, resultId, condition, waveform, resultTable):
    buildResultId(document, text, index, resultId)
    buildTableParagraph(document, text, index, condition)
    buildWaveform2(document, text, index, waveform)
    buildTableParagraph(document, text, index, resultTable)


def saveReport(document,reportAddress):
    document.save(reportAddress)

#############################################################################################
#
############################################################################################


def addParagraphBefore(document, specText, title):
    '''
    在 specText 前面添加 内容为title的段落
    :param document:
    :param specText:
    :param title:
    :return:
    '''
    for i, p in enumerate(document.paragraphs):
        if (p.text == specText):
            document.paragraphs[i].insert_paragraph_before(text=title)

def createTable(document, rows, columns, rowvalues, columnvalue):
    '''
    创建表格
    :param document:
    :param rows:
    :param columns:
    :param rowvalues:
    :param columnvalue:
    :return:
    '''
    table = document.add_table(rows=rows, cols=columns, style='Table Grid')
    table.alignment = WD_TABLE_ALIGNMENT.CENTER   # 表格居中
    for i in range(len(table.rows)):
        for j in range(len(table.columns)):
            if (i == 0):  # 表头赋值
                table.cell(i, j).text = columnvalue[j]
                set_cell_background(table.cell(i, j), '808080')
            else:
                flag = type(rowvalues[i - 1][j]) == str
                if (flag):
                    table.cell(i, j).text = rowvalues[i - 1][j]
                else:
                    table.cell(i, j).text = '%.4f' % rowvalues[i - 1][j]
            table.cell(i, j).vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER  # 单元格居中
            table.cell(i, j).paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 居中
    return table

def set_cell_background(cell, fill, color=None, val=None):
    """
    @fill: Specifies the color to be used for the background
    @color: Specifies the color to be used for any foreground
    pattern specified with the val attribute
    @val: Specifies the pattern to be used to lay the pattern
    color over the background color.
    """
    from docx.oxml.shared import qn  # feel free to move these out
    from docx.oxml.xmlchemy import OxmlElement

    cell_properties = cell._element.tcPr
    try:
        cell_shading = cell_properties.xpath('w:shd')[0]  # in case there's already shading
    except IndexError:
        cell_shading = OxmlElement('w:shd') # add new w:shd element to it
    if fill:
        cell_shading.set(qn('w:fill'), fill)  # set fill property, respecting namespace
    if color:
        pass  # TODO
    if val:
        pass  # TODO
    cell_properties.append(cell_shading)  # finally extend cell props with shading element



##################################################################################################

@app.route("/listen/buildreport", methods=["POST"])
def close_driver_v():
    # 三个常量
    templateAddress = r'C:\test\报告模板.docx'
    reportAddress = r"C:\test\report.docx"
    text = '附件1 硬件测试精度指标'
    # 创建报告
    doc = createReport(templateAddress)
    # 获取参数值
    data_list = json.loads(request.get_data(as_text=True))
    logger.info('收到请求: %s', data_list)
    if len(data_list) == 0:
        return Response.getResponse(Response.ERROR, '参数为空')
    i = 1
    for data in data_list:
        try:
            idvalue = data['idkey']
            doublePulseTestcondition = data['doublePulseTestcondition']
            doublePulseTestWaveform = data['doublePulseTestWaveform']
            doublePulseTestResult = data['doublePulseTestResult']
            # 构建参数
            resultId = ResultId('测试ID', idvalue)
            condition_table = Table(doublePulseTestcondition['tableName'], doublePulseTestcondition['columns'],
                                    doublePulseTestcondition['rows'], doublePulseTestcondition['columnvalue'],
                                    doublePulseTestcondition['rowvalues'])
            result_table = Table(doublePulseTestResult['tableName'], doublePulseTestResult['columns'],
                                 doublePulseTestResult['rows'], doublePulseTestResult['columnvalue'],
                                 doublePulseTestResult['rowvalues'])
            condition = TableParagraph(doublePulseTestcondition['title'], condition_table)
            resultTable = TableParagraph(doublePulseTestResult['title'], result_table)
            waveform = Waveform(doublePulseTestWaveform['title'], doublePulseTestWaveform['images'])
            index = '3.' + str(i)
            # 写入报告
            buildOneReport(doc, text, index, resultId, condition, waveform, resultTable)
            i = i + 1
        except Exception as e:
            logger.info('发生异常', e)
            return Response.getResponse(Response.ERROR, e)

    # 保存报告
    saveReport(doc, reportAddress)
    return Response.getResponse(Response.SUCCESS, '操作成功')

def start_listen():
    app.config['JSON_AS_ASCII'] = False
    app.run(host='0.0.0.0', port=5000, debug=False)


def loginit(logname, logpath):
    logger = logging.getLogger(logname)
    logger.setLevel(logging.INFO)
    # 创建处理器
    # loghandler = logging.StreamHandler()    # 日志信息输出到终端
    # loghandler = logging.FileHandler(logpath) # 日志信息输出到文件
    # loghandler = loghandlers.RotatingFileHandler(logpath,maxBytes=1024*1,backupCount=5) # 根据文件大小轮换日志文件
    loghandler = loghandlers.TimedRotatingFileHandler(logpath, when='M', interval=1, backupCount=5, encoding='utf-8') # 根据时间轮换日志文件
    loghandler.setLevel(logging.INFO)
    # 创建格式器(打印日志的时间-打印日志级别的名称-打印当前执行程序名-打印日志的当前函数-打印日志的当前行号: 日志信息)
    logformatter = logging.Formatter('%(asctime)s-%(levelname)s-%(filename)s-%(funcName)s-%(lineno)d: %(message)s')
    # 将格式器添加到处理器中
    loghandler.setFormatter(logformatter)
    # 将处理器添加到记录器中
    logger.addHandler(loghandler)
    return logger


if __name__ == '__main__':
    # templateAddress = r'C:\test\IGBT-HPD-LU-450V-800A【报告模板】---20230323(3) - 副本.docx'
    # reportAddress = r"C:\test\report.docx"
    # text = '附件1 硬件测试精度指标'
    # resultId = ResultId('测试ID', '2023-03-17-11-29-10-469.0-800.0-DP-LU-Ron-2.4-Roff-5.1-Vgs_p-15.2-Vgs_n-8.4-heat-22.0-phase-s-phase-h')
    # table = table('表1', 3, 4, ['参数', '参数值', '单位'], [['T0', 0.0000, 'us'], ['T1d', 46.5400, 'us'], ['T2d', 5.0000, 'us']])
    # condition = tableParagraph('测试条件',table)
    # resultTable = tableParagraph('测试结果',table)
    # waveform = Waveform('测试波形', [['C:\\Users\\Pictures\\Saved Pictures\\tupian\\图片1.png','第一张图'],
    #                                  ['C:\\Users\\Pictures\\Saved Pictures\\tupian\\图片2.png','第二张图'],
    #                                  ['C:\\Users\\Pictures\\Saved Pictures\\tupian\\图片3.png','第三张图'],
    #                                  ['C:\\Users\\Pictures\\Saved Pictures\\tupian\\图片4.png','第四张图']])
    # document = Document(templateAddress)
    # buildResultId(document, text, resultId)
    # buildTableParagraph(document, text, condition)
    # buildWaveform2(document, text, waveform)
    # buildTableParagraph(document, text, resultTable)
    # document.save(reportAddress)
    # LOG_FORMAT = "%(asctime)s - %(levelname)s - %(user)s[%(ip)s] - %(message)s"
    logger = loginit('test', 'report.log')
    start_listen()






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值