備忘錄_20160105(定位) 修改 回首頁

程式 2025-04-24 11:11:36 1745464296 100
用 python 來產生 word 檔案

用 python 來產生 word 檔案

# pip install python-docx
from docx import Document
from docx.shared import Pt
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Cm
from docx.enum.section import WD_ORIENT
from docx.enum.text import WD_ALIGN_PARAGRAPH

def set_table_border(table):
    tbl = table._tbl
    tblPr = tbl.tblPr

    # 建立 <w:tblBorders> 元素
    tblBorders = OxmlElement('w:tblBorders')

    for border_name in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'):
        border = OxmlElement(f'w:{border_name}')
        border.set(qn('w:val'), 'single')       # 實線 single
        border.set(qn('w:sz'), '1')             # 線條寬度,單位為 1/8 pt,1pt=>8,目前用1,等於就是1/8pt
        border.set(qn('w:space'), '0')          # 線與內容之間距離
        border.set(qn('w:color'), '000000')     # 黑色
        tblBorders.append(border)

    # 加入到 <w:tblPr> 中
    tblPr.append(tblBorders)

def cm_to_twips(cm):
    return int(cm * 567)  # 1 cm ≈ 567 twips

def set_table_width(table, width_cm):
    table.autofit = False
    tbl = table._tbl
    tblPr = tbl.tblPr
    width_twips = cm_to_twips(width_cm)

    tblW = tblPr.xpath('./w:tblW')
    if tblW:
        tblW[0].set(qn('w:w'), str(width_twips))
        tblW[0].set(qn('w:type'), 'dxa')
    else:
        tblW = OxmlElement('w:tblW')
        tblW.set(qn('w:w'), str(width_twips))
        tblW.set(qn('w:type'), 'dxa')
        tblPr.append(tblW)

def set_table_alignment(table, alignment='center'):
    """
    alignment: 'left', 'center', or 'right'
    """
    tbl = table._tbl
    tblPr = tbl.tblPr
    jc = OxmlElement('w:jc')
    jc.set(qn('w:val'), alignment)
    tblPr.append(jc)

# 插入欄位函式(頁碼、總頁數用)
def insert_field(run, field_code):
    fldChar1 = OxmlElement('w:fldChar')
    fldChar1.set(qn('w:fldCharType'), 'begin')

    instrText = OxmlElement('w:instrText')
    instrText.set(qn('xml:space'), 'preserve')
    instrText.text = field_code

    fldChar2 = OxmlElement('w:fldChar')
    fldChar2.set(qn('w:fldCharType'), 'separate')

    fldChar3 = OxmlElement('w:fldChar')
    fldChar3.set(qn('w:fldCharType'), 'end')

    r_element = run._r
    r_element.append(fldChar1)
    r_element.append(instrText)
    r_element.append(fldChar2)
    r_element.append(fldChar3)

def set_cell_padding(cell, top=0, left=0, bottom=0, right=0):
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()

    # 建立 <w:tcMar>(儲存格內距)元素
    tcMar = OxmlElement('w:tcMar')

    for name, value in (('top', top), ('left', left), ('bottom', bottom), ('right', right)):
        mar = OxmlElement(f'w:{name}')
        mar.set(qn('w:w'), str(value))   # TWIPS 單位:1 pt = 20,1 cm ≈ 567
        mar.set(qn('w:type'), 'dxa')
        tcMar.append(mar)

    tcPr.append(tcMar)
    
def set_table_cell_margins(table, margin=0):
    """
    設定整張表格的儲存格內距為指定值(預設 0)
    """
    tbl = table._tbl
    tblPr = tbl.tblPr

    tblCellMar = OxmlElement('w:tblCellMar')
    for side in ('top', 'start', 'bottom', 'end'):
        elem = OxmlElement(f'w:{side}')
        elem.set(qn('w:w'), str(margin))
        elem.set(qn('w:type'), 'dxa')  # dxa = 1/20 pt
        tblCellMar.append(elem)
    tblPr.append(tblCellMar)

def set_paragraph_background(paragraph, color_hex):
    """
    設定段落背景色,例如 color_hex = "FFFF00"(黃色)
    """
    p = paragraph._p  # 取得底層 <w:p> 元素
    pPr = p.get_or_add_pPr()  # 取得段落屬性 <w:pPr>
    
    shd = OxmlElement('w:shd')  # 建立 <w:shd> 元素
    shd.set(qn('w:val'), 'clear')         # 填滿方式,clear 表示實心
    shd.set(qn('w:color'), 'auto')        # 字體顏色(不設定)
    shd.set(qn('w:fill'), color_hex)      # 背景填滿色

    pPr.append(shd)  # 加到段落屬性中

def set_cell_background(cell, color_hex):
    """
    設定儲存格背景色,例如 color_hex = "FFFF00"(黃色)
    """
    tc = cell._tc                      # 取得底層 <w:tc> 元素
    tcPr = tc.get_or_add_tcPr()       # 取得 <w:tcPr> 儲存格屬性元素

    shd = OxmlElement('w:shd')        # 建立 <w:shd> 元素
    shd.set(qn('w:val'), 'clear')     # 填滿方式
    shd.set(qn('w:color'), 'auto')    # 不指定字體顏色
    shd.set(qn('w:fill'), color_hex)  # 背景填滿色

    tcPr.append(shd)                  # 加到儲存格屬性中

# https://python-docx.readthedocs.io/en/latest/
oDoc=Document()
oSection=oDoc.sections[0]
oSection.orientation = WD_ORIENT.PORTRAIT
oSection.page_width = Cm(21)
oSection.page_height = Cm(29.7)
oSection.top_margin = Cm(1)
oSection.bottom_margin = Cm(1)
oSection.left_margin = Cm(1)
oSection.right_margin = Cm(1)

oFooter=oSection.footer
oP=oFooter.paragraphs[0]
oP.alignment = WD_ALIGN_PARAGRAPH.CENTER
oP.text="2025-04-24 大乘起信論勝異方便 "
oRun=oP.add_run()
insert_field(oRun, 'PAGE')
oP.add_run(" / ")
oRun=oP.add_run()
insert_field(oRun, 'NUMPAGES')

oP=oDoc.add_paragraph('')
oP.paragraph_format.space_before = Pt(0)
oP.paragraph_format.space_after = Pt(0)

oTable=oDoc.add_table(rows=0, cols=1)

oTable.autofit=False
oTable.allow_autofit=False
set_table_alignment(oTable, 'center')
set_table_width(oTable, 18)
set_table_border(oTable)

oP=oDoc.add_paragraph('')
oP.paragraph_format.space_before = Pt(0)
oP.paragraph_format.space_after = Pt(0)

# 第一個儲存格
if 1==1:
  
  oCell=oTable.add_row().cells[0]
  oCell.width=Cm(18)
  set_cell_padding(oCell)
  set_cell_background(oCell, 'e7e1fa')
  
  # oP=oCell.paragraphs[0]
  # oP=oCell.add_paragraph()
  oP=oCell.paragraphs[0]
  oP.paragraph_format.space_before = Pt(0)
  oP.paragraph_format.space_after = Pt(0)
  oRun=oP.add_run('大乘起信論勝異方便')
  oRun.font.name='標楷體'
  oRun._element.rPr.rFonts.set(qn('w:eastAsia'), '標楷體')
  oRun.font.size=Pt(12)
  oRun.font.bold=True

# 第二個儲存格
if 1==1:
  
  oCell=oTable.add_row().cells[0]
  oCell.width=Cm(18)
  set_cell_padding(oCell)
  set_cell_background(oCell, 'ffffff')

  # oP=oCell.paragraphs[0]
  # oP=oCell.add_paragraph()
  oP=oCell.paragraphs[0]
  oP.paragraph_format.space_before = Pt(0)
  oP.paragraph_format.space_after = Pt(0)
  oRun=oP.add_run('[開場白]')
  oRun.font.name='標楷體'
  oRun._element.rPr.rFonts.set(qn('w:eastAsia'), '標楷體')
  oRun.font.size=Pt(24)
  oRun.font.bold=True

# 第三個儲存格
if 1==1:
  
  oCell=oTable.add_row().cells[0]
  oCell.width=Cm(18)
  set_cell_padding(oCell)
  set_cell_background(oCell, 'cbeef7')

  # oP=oCell.paragraphs[0]
  # oP=oCell.add_paragraph()
  oP=oCell.paragraphs[0]
  oP.paragraph_format.space_before = Pt(0)
  oP.paragraph_format.space_after = Pt(0)
  oRun=oP.add_run('講稿與辭典')
  oRun.font.name='標楷體'
  oRun._element.rPr.rFonts.set(qn('w:eastAsia'), '標楷體')
  oRun.font.size=Pt(12)
  oRun.font.bold=True

# 第四個儲存格
if 1==1:
  
  oCell=oTable.add_row().cells[0]
  oCell.width=Cm(18)
  set_cell_padding(oCell)
  set_cell_background(oCell, 'ffffff')

  # oP=oCell.paragraphs[0]
  # oP=oCell.add_paragraph()
  oP=oCell.paragraphs[0]
  set_paragraph_background(oP, 'dddddd')
  oP.paragraph_format.space_before = Pt(0)
  oP.paragraph_format.space_after = Pt(0)
  oRun=oP.add_run("諸位老師學長早安,\r\n阿彌陀佛。")
  oRun.font.name='標楷體'
  oRun._element.rPr.rFonts.set(qn('w:eastAsia'), '標楷體')
  oRun.font.size=Pt(16)
  oRun.font.bold=False

  # oP=oCell.paragraphs[0]
  # oP=oCell.add_paragraph()
  oP=oCell.add_paragraph()
  oP.paragraph_format.space_before = Pt(0)
  oP.paragraph_format.space_after = Pt(0)
  oRun=oP.add_run("這裡是辭典文字......")
  oRun.font.name='標楷體'
  oRun._element.rPr.rFonts.set(qn('w:eastAsia'), '標楷體')
  oRun.font.size=Pt(12)
  oRun.font.bold=False

######set_table_cell_margins(oTable, 0)
#nmomtf

oDoc.save('20250424.docx')