HeyDeC
HeyDeC

Reputation: 11

Python-docx how to set font spacing?

How to set font spacing in python-docx or how to add element to w:rPr? //<w:rPr> <w:spacing w:val="200"/> </w:rPr>

Upvotes: 1

Views: 936

Answers (3)

agdula
agdula

Reputation: 26

This is how I've set the spacing in a new document for 'Normal' text. of course this answer takes advantage of old replies

    # create a new Document
    doc = Document()
    style = doc.styles['Normal']
    spacing = OxmlElement("w:spacing")
    spacing.set(qn('w:val'), str("-12"))
    
    style.font._element.rPr.insert_element_before(
        spacing,
        *("w:w", "w:kern", "w:position", "w:sz", "w:szCs", "w:highlight", "w:u", "w:effect", "w:bdr", "w:shd",
          "w:fitText", "w:vertAlign", "w:rtl", "w:cs", "w:em", "w:lang", "w:eastAsianLayout", "w:specVanish", "w:oMath",
          ),
    )

Upvotes: 0

Delay
Delay

Reputation: 11

I tried the answer by scanny, It did not work. But the output document XML <w:spacing val="200"> is close to the right format. The right format is <w:spacing w:val="200">

Try this

from docx.oxml.ns import qn

spacing.set(qn('w:val'), str(value))

Upvotes: 0

scanny
scanny

Reputation: 28863

There is no API support for this setting in python-docx.

Adding a <w:spacing> element will work if that's what Word does, however the sequence in which child elements appear is, in general, significant in WordprocessingML (the XML schema .docx files adhere to). If you don't get the w:spacing element in the right order among the w:rPr child elements or you add one when one is already there, you'll trigger a repair error.

So you need something like this:

def run_set_spacing(run, value: int):
    """Set the font spacing for `run` to `value` in twips.

    A twip is a "twentieth of an imperial point", so 1/1440 in.
    """

    def get_or_add_spacing(rPr):
        # --- check if `w:spacing` child already exists ---
        spacings = rPr.xpath("./w:spacing")
        # --- return that if so ---
        if spacings:
            return spacings[0]
        # --- otherwise create one ---
        spacing = OxmlElement("w:spacing")
        rPr.insert_element_before(
            spacing,
            *(
                "w:w",
                "w:kern",
                "w:position",
                "w:sz",
                "w:szCs",
                "w:highlight",
                "w:u",
                "w:effect",
                "w:bdr",
                "w:shd",
                "w:fitText",
                "w:vertAlign",
                "w:rtl",
                "w:cs",
                "w:em",
                "w:lang",
                "w:eastAsianLayout",
                "w:specVanish",
                "w:oMath",
            ),
        )
        return spacing

    rPr = run._r.get_or_add_rPr()
    spacing = get_or_add_spacing(rPr)
    spacing.set("val", str(value))

Then you would call this for each run that needs that setting like so:

run_set_spacing(run, 200)

Upvotes: 1

Related Questions