Font management is a recurring challenge when working with Word documents. Whether you need to audit which fonts are used across a file or consistently replace one font with another, manual handling is not only time‑consuming but also error‑prone. By using the Spire.Doc for Python library, you can programmatically inspect and selectively modify font information inside Word documents with just a few lines of code, greatly streamlining the process. This article walks through two concrete examples, explaining the underlying principles and practical tips in detail.
1. Why Choose Spire.Doc for Python
Spire.Doc for Python is a professional‑grade library for Word document manipulation that requires no Microsoft Office installation. It lets you create, modify, convert, and extract content entirely within Python. Its object model closely mirrors Word’s internal structure: a Documentcontains multipleSectionobjects; eachSectionhas aBody; each BodyholdsParagraphelements; and each paragraph consists of child objects such asTextRange, images, and tables. Font attributes—name (FontName), size (FontSize), color (TextColor), and more—are stored in the CharacterFormatproperty of eachTextRange. This hierarchical design provides a clear and logical path for traversing and updating font settings.
2. Scenario 1: Extracting All Font Information from a Document
The first example scans an entire Word document, extracts the font name, size, and color for every text fragment, deduplicates the results, and writes them to a text file. This is especially useful for document consistency reviews and font compliance audits.
from spire.doc import *
from spire.doc.common import *
# Helper to write a list of strings to a text file
def WriteAllText(fname:str, text:List[str]):
fp = open(fname, "w", encoding="utf-8")
for s in text:
fp.write(s)
# Custom class to represent a font identity (name + size)
class FontInfo:
def __init__(self):
self._m_name = ''
self._m_size = None
def __eq__(self, other):
if isinstance(other, FontInfo):
return self._m_name == other.get_name() and self._m_size == other.get_size()
return False
def get_name(self):
return self._m_name
def set_name(self, value):
self._m_name = value
def get_size(self):
return self._m_size
def set_size(self, value):
self._m_size = value
# Prepare variables
fontInformations = ""
font_infos = []
# Load the document
document = Document()
document.LoadFromFile("/sample.docx")
# Iterate over sections, paragraphs, and child objects
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
for j in range(section.Body.Paragraphs.Count):
paragraph = section.Body.Paragraphs.get_Item(j)
for k in range(paragraph.ChildObjects.Count):
obj = paragraph.ChildObjects.get_Item(k)
# Only process text ranges
if isinstance(obj, TextRange):
txtRange = obj if isinstance(obj, TextRange) else None
fontName = txtRange.CharacterFormat.FontName
fontSize = txtRange.CharacterFormat.FontSize
textColor = txtRange.CharacterFormat.TextColor.Name
# Deduplicate by name+size (color is not a distinguishing factor for the font itself)
fontInfo = FontInfo()
fontInfo.set_name(fontName)
fontInfo.set_size(fontSize)
if fontInfo not in font_infos:
font_infos.append(fontInfo)
line = "Font name: {0:s}, Size: {1:f}, Color: {2:s}".format(
fontInfo.get_name(), fontInfo.get_size(), textColor
)
fontInformations += line + '\r'
# Save the results
WriteAllText("/retrieved_fonts.txt", fontInformations)
document.Dispose()
Key Implementation Steps
-
Load and initialise –
document.LoadFromFile("/sample.docx"). -
Three‑level traversal – loop through
Sections, thenParagraphs, thenChildObjects. -
Filter for text ranges – use
isinstance(obj, TextRange)to isolate elements that carry font formatting. -
Extract attributes – from
txtRange.CharacterFormat, readFontName(string),FontSize(float, in points), andTextColor.Name(colour name). -
Custom deduplication – the
FontInfoclass overrides__eq__to treat a combination of name and size as unique. Only new entries are appended to the output string. -
Write to file – the
WriteAllTexthelper saves the accumulated string.
Design Considerations
- Why deduplicate by name and size only? Colour is not an inherent font property; the same font can appear in multiple colours. Including colour would inflate the results unnecessarily. This approach focuses on the font’s core identity.
-
Error handling – though not shown, it is wise to guard against
FontSizebeingNone(e.g., with WordArt or special styles). - Performance – the nested loops are efficient for typical documents. For files with tables or text boxes, you would need to extend the traversal to those containers as well.
A sample output might look like:
Font name: SimSun, Size: 12.000000, Color: Black
Font name: Arial, Size: 10.500000, Color: Red
...
3. Scenario 2: Targeted Replacement of a Specific Font
The second example is more focused: it replaces every occurrence of “FangSong” (Imitation Song) with “LiSu” (Clerical Script) throughout the document. This is a common task when unifying brand styles or adapting to local typographic conventions.
from spire.doc import *
from spire.doc.common import *
document = Document()
document.LoadFromFile("/sample.docx")
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
for j in range(section.Body.Paragraphs.Count):
paragraph = section.Body.Paragraphs.get_Item(j)
for k in range(paragraph.ChildObjects.Count):
obj = paragraph.ChildObjects.get_Item(k)
if isinstance(obj, TextRange):
txtRange = obj if isinstance(obj, TextRange) else None
fontName = txtRange.CharacterFormat.FontName
if fontName == "FangSong":
txtRange.CharacterFormat.FontName = "LiSu"
document.SaveToFile("/replaced_font.docx", FileFormat.Docx)
document.Dispose()
How It Works
- Traverse the document in the same three‑level manner.
-
Identify each
TextRangeand retrieve its current font name. -
Conditional replacement – if the font name equals
"FangSong", assign"LiSu"toFontName. - Save the modified document under a new name.
Extensions and Precautions
- Partial replacement – if you only want to replace fonts in certain paragraphs or styles, add extra filters (e.g., by paragraph style or section) inside the loop.
- Font availability – the target font (“LiSu”) must be installed on the system or embedded in the document; otherwise, Word will substitute a fallback. For production use, prefer common fonts like “SimSun” or “Times New Roman”, or embed the fonts beforehand.
-
Format retention – replacing the font does not affect other formatting such as bold, italic, or colour, because the
CharacterFormatproperties are independent.
4. Comparison and Combined Workflow
| Aspect | Retrieving Fonts | Replacing Fonts |
|---|---|---|
| Primary goal | Auditing and analysis | Standardisation and conversion |
| Data flow | Document → external text file | Document → new document |
| Implementation complexity | Requires custom deduplication logic | Simple conditional update |
| Performance overhead | List membership checks (can be optimised with a set) | Negligible |
These two scripts complement each other. You can run the retrieval first to get an overview of current font usage, decide which fonts to replace, and then apply the replacement. For finer control—say, replacing only a specific font at a certain size—you can merge the logic and check both FontName and FontSize during replacement.
5. Optimisation and Best Practices
-
Use a set for deduplication – if you don’t need colour, you can store
(fontName, fontSize)tuples in a set, eliminating the custom class. -
Add exception handling – wrap
LoadFromFileandSaveToFileintry...exceptblocks to handle file permission or format issues gracefully. - Batch processing – encapsulate the core logic in a function and call it for a list of file paths.
-
Dispose of resources – always call
document.Dispose(), especially when processing many documents in a loop, to avoid memory leaks.
6. Conclusion
With Spire.Doc for Python, we have built two essential font‑management tools in under a hundred lines of code. The library’s clear object model and straightforward API make it an excellent fit for automated workflows. Whether you are checking font compliance in financial reports or updating templates across a large corpus, this approach significantly reduces manual effort and improves accuracy. Readers are encouraged to extend the code to handle additional scenarios—such as table cells, headers, footers, or specific paragraph styles—to build even more powerful document governance solutions. Ultimately, the value of these techniques lies in solving real‑world problems, and the combination of Python and Spire.Doc delivers that promise effectively.
Top comments (0)