如何更改 python-docx 中的标题字体和大小?
How do I change Heading font face and size in python-docx?
我将此作为 python-docx 问题提交:https://github.com/python-openxml/python-docx/issues/805 但被要求在此处展开讨论。
https://python-docx.readthedocs.io/en/latest/user/styles-using.html 意味着我应该能够像这样更改标题字体样式:
font = doc.styles['Heading 1'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(16)
但这不起作用:生成的文档对所有标题都使用 Calibri。 (它们也是蓝色的,标题 1 有下划线,我也需要以某种方式消除它。)
更改特定标题上的字体或删除标题的 latent_styles 也不起作用。
这是一个尝试所有三种方法的测试程序,但标题 1 和 2 仍然显示为蓝色 Calibri,尽管所有尝试都将它们更改为 Times New Roman:
import docx
doc = docx.Document()
# Deleting heading latent styles seems to do nothing:
latent_styles = doc.styles.latent_styles
latent_styles['Heading 1'].delete()
latent_styles['Heading 2'].delete()
# Setting the Normal font works:
font = doc.styles['Normal'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(12)
# Setting heading styles doesn't do anything:
# they all still end up as blue Calibri.
font = doc.styles['Heading 1'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(16)
font = doc.styles['Heading 2'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(14)
doc.add_heading("Heading 0", 0)
doc.add_paragraph('Here is a paragraph of text.')
doc.add_heading("Heading 1", 1)
doc.add_paragraph('Here is a paragraph of text.')
doc.add_heading("Heading 2", 2)
doc.add_paragraph('Here is a paragraph of text.')
# It also doesn't work to change the style of a specific heading:
heading = doc.add_heading("Another Heading 1", 1)
heading.style.font.name = "Times New Roman"
doc.add_paragraph('Here is a paragraph of text.')
doc.save('test.docx')
Can't change "heading 1" font name using docx 提到这是一个错误,并建议创建一个新样式作为解决方法。一个更简单的解决方法是在普通段落文本中创建运行,然后设置这些运行的样式。但是,如果可以将这些标题设置为蓝色 Calibri 以外的样式,那么使用 "Heading 1" 之类的标准元素似乎会更好……并且文档暗示这是可能的。
如您所见,通常会更改字体 (font.name
) 以获得样式 "just works"。由于我不完全理解的原因,Title
以及 Heading 1
、Heading 2
等样式是一个例外。我希望这与主题指定的字体选择有关。或许与他们形成table-of-contents.
的特殊作用有关
首先,有几点观察:
document.add_heading("0th-level Heading", 0)
应用的样式是Title
。我想这在某种程度上是有道理的,因为 highest-level 标题是整个文档的标题。 Heading 1
、Heading 2
等样式分别在该函数调用中使用 1
和 2
时应用。
如果我们将 font-name "Times New Roman" 应用于 Title
样式,然后检查生成的 XML 我们会看到以下内容:
>>> heading = document.add_heading("Title", 0)
>>> title_style = heading.style
>>> title_style.font.name = "Times New Roman"
>>> title_style.element.xml
<w:style xmlns:w=... w:type="paragraph" w:styleId="Title">
<w:name w:val="Title"/>
<w:basedOn w:val="Normal"/>
<w:next w:val="Normal"/>
<w:link w:val="TitleChar"/>
<w:uiPriority w:val="10"/>
<w:qFormat/>
<w:rsid w:val="00FC693F"/>
<w:pPr>
<w:pBdr>
<w:bottom w:val="single" w:sz="8" w:space="4" w:color="4F81BD" w:themeColor="accent1"/>
</w:pBdr>
<w:spacing w:after="300" w:line="240" w:lineRule="auto"/>
<w:contextualSpacing/>
</w:pPr>
<w:rPr>
<w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia"
w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"
w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
<w:color w:val="17365D" w:themeColor="text2" w:themeShade="BF"/>
<w:spacing w:val="5"/>
<w:kern w:val="28"/>
<w:sz w:val="52"/>
<w:szCs w:val="52"/>
</w:rPr>
</w:style>
- 从这里我们可以看到很多有趣的项目,但我们目前的重点可以限制在
<w:rFonts>
元素上:
>>> title_style.element.rPr.rFonts.xml
<w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia"
w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"
w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
我们可以看到 "Times New Roman" 确实应用了两个字体设置,但标题仍然出现在 Calibri 中,这恰好是 "majorHAnsi" 映射到的内容。
要跳转到解决方案,如果我们将 w:asciiTheme
font-name 设置为 "Times New Roman",标题将按需要显示:
from docx.oxml.ns import qn
rFonts = title_style.element.rPr.rFonts
rFonts.set(qn("w:asciiTheme"), "Times New Roman")
我希望相同类型的过程适用于其他标题样式。
请注意,如果您是从 "scratch" 生成文档而不是编辑现有文档,那么从一个已经具有您想要的样式的空白文档开始可能更容易:
document = Document("my-starting-document.docx")
我将此作为 python-docx 问题提交:https://github.com/python-openxml/python-docx/issues/805 但被要求在此处展开讨论。
https://python-docx.readthedocs.io/en/latest/user/styles-using.html 意味着我应该能够像这样更改标题字体样式:
font = doc.styles['Heading 1'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(16)
但这不起作用:生成的文档对所有标题都使用 Calibri。 (它们也是蓝色的,标题 1 有下划线,我也需要以某种方式消除它。)
更改特定标题上的字体或删除标题的 latent_styles 也不起作用。
这是一个尝试所有三种方法的测试程序,但标题 1 和 2 仍然显示为蓝色 Calibri,尽管所有尝试都将它们更改为 Times New Roman:
import docx
doc = docx.Document()
# Deleting heading latent styles seems to do nothing:
latent_styles = doc.styles.latent_styles
latent_styles['Heading 1'].delete()
latent_styles['Heading 2'].delete()
# Setting the Normal font works:
font = doc.styles['Normal'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(12)
# Setting heading styles doesn't do anything:
# they all still end up as blue Calibri.
font = doc.styles['Heading 1'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(16)
font = doc.styles['Heading 2'].font
font.name = 'Times New Roman'
font.size = docx.shared.Pt(14)
doc.add_heading("Heading 0", 0)
doc.add_paragraph('Here is a paragraph of text.')
doc.add_heading("Heading 1", 1)
doc.add_paragraph('Here is a paragraph of text.')
doc.add_heading("Heading 2", 2)
doc.add_paragraph('Here is a paragraph of text.')
# It also doesn't work to change the style of a specific heading:
heading = doc.add_heading("Another Heading 1", 1)
heading.style.font.name = "Times New Roman"
doc.add_paragraph('Here is a paragraph of text.')
doc.save('test.docx')
Can't change "heading 1" font name using docx 提到这是一个错误,并建议创建一个新样式作为解决方法。一个更简单的解决方法是在普通段落文本中创建运行,然后设置这些运行的样式。但是,如果可以将这些标题设置为蓝色 Calibri 以外的样式,那么使用 "Heading 1" 之类的标准元素似乎会更好……并且文档暗示这是可能的。
如您所见,通常会更改字体 (font.name
) 以获得样式 "just works"。由于我不完全理解的原因,Title
以及 Heading 1
、Heading 2
等样式是一个例外。我希望这与主题指定的字体选择有关。或许与他们形成table-of-contents.
首先,有几点观察:
document.add_heading("0th-level Heading", 0)
应用的样式是Title
。我想这在某种程度上是有道理的,因为 highest-level 标题是整个文档的标题。Heading 1
、Heading 2
等样式分别在该函数调用中使用1
和2
时应用。如果我们将 font-name "Times New Roman" 应用于
Title
样式,然后检查生成的 XML 我们会看到以下内容:
>>> heading = document.add_heading("Title", 0)
>>> title_style = heading.style
>>> title_style.font.name = "Times New Roman"
>>> title_style.element.xml
<w:style xmlns:w=... w:type="paragraph" w:styleId="Title">
<w:name w:val="Title"/>
<w:basedOn w:val="Normal"/>
<w:next w:val="Normal"/>
<w:link w:val="TitleChar"/>
<w:uiPriority w:val="10"/>
<w:qFormat/>
<w:rsid w:val="00FC693F"/>
<w:pPr>
<w:pBdr>
<w:bottom w:val="single" w:sz="8" w:space="4" w:color="4F81BD" w:themeColor="accent1"/>
</w:pBdr>
<w:spacing w:after="300" w:line="240" w:lineRule="auto"/>
<w:contextualSpacing/>
</w:pPr>
<w:rPr>
<w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia"
w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"
w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
<w:color w:val="17365D" w:themeColor="text2" w:themeShade="BF"/>
<w:spacing w:val="5"/>
<w:kern w:val="28"/>
<w:sz w:val="52"/>
<w:szCs w:val="52"/>
</w:rPr>
</w:style>
- 从这里我们可以看到很多有趣的项目,但我们目前的重点可以限制在
<w:rFonts>
元素上:
>>> title_style.element.rPr.rFonts.xml
<w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia"
w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"
w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
我们可以看到 "Times New Roman" 确实应用了两个字体设置,但标题仍然出现在 Calibri 中,这恰好是 "majorHAnsi" 映射到的内容。
要跳转到解决方案,如果我们将 w:asciiTheme
font-name 设置为 "Times New Roman",标题将按需要显示:
from docx.oxml.ns import qn
rFonts = title_style.element.rPr.rFonts
rFonts.set(qn("w:asciiTheme"), "Times New Roman")
我希望相同类型的过程适用于其他标题样式。
请注意,如果您是从 "scratch" 生成文档而不是编辑现有文档,那么从一个已经具有您想要的样式的空白文档开始可能更容易:
document = Document("my-starting-document.docx")