3
votes

There are plenty of SO threads for setting background color in tables, but I'd like to change color for a piece of normal text in a paragraph.

I'm able to set the highlight color, but then I can only select 1 of 17 available colors.

In Word, the background color is referred to as "shading" and is done by clicking the paint bucket icon.

While highlighting only changes the color behind the text, shading paints the color of the whole line - either way is fine by me.

Is it possible to set any RGB value behind text which is not in a table by using python-docx?

formatting example

1
Maybe include an example image. I'm not sure what "color of the whole like" means. Are you talking about the outline of the text?scanny

1 Answers

4
votes

I had the same problem, but I found a trick to do what you are asking.

First, you need to import these three modules:

from docx.shared import Pt
from docx.oxml.ns import qn
from docx.oxml.shared import OxmlElement

Those modules are essential because you need to access the "XML version" of the run object, and add a <w:shd> element, which will set the shading, under <w:rPr>.

# Create a template
doc = Document()

# Add a paragraph
p = doc.add_paragraph()

# Add text to paragraph reference
txt = 'Custom background colour (a.k.a shading, done with the paint bucket tool)'
run = p.add_run(txt)
    
# Get the XML tag
tag = run._r
print(run.element.xml) # print XML

# Create XML element
shd = OxmlElement('w:shd')

# Add attributes to the element
shd.set(qn('w:val'), 'clear')
shd.set(qn('w:color'), 'auto')
shd.set(qn('w:fill'), 'FFAAAA')

In the print out command, it will output:

<w:r xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
    <w:t>Custom background colour (a.k.a shading, done with the paint bucket tool)</w:t>
</w:r>

But there is still no <w:rPr> element. At this point, you can create another XML element for that like above, but I did the following:

# This is the tricky part
run.font.size = Pt(14)
print(run.element.xml)

After the second print out command, it will output:

<w:r xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
    <w:rPr>
        <w:sz w:val="28"/>
    </w:rPr>
    <w:t>Custom background colour (a.k.a shading, done with the paint bucket tool)</w:t>
</w:r>

Finally, you need to append the element to <w:rPr>

tag.rPr.append(shd)
print(run.element.xml)

Here is the final print out command:

<w:r xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
    <w:rPr>
        <w:sz w:val="28"/>
        <w:shd w:val="clear" w:color="auto" w:fill="FFAAAA"/>
    </w:rPr>
    <w:t>Custom background colour (a.k.a shading, done with the paint bucket tool)</w:t>
</w:r>

Of course, you need to save the output to a file:

# Save document
doc.save('d.docx')

Put every thing together:

from docx import Document
from docx.shared import Pt
from docx.oxml.ns import qn
from docx.oxml.shared import OxmlElement

# Create a template
doc = Document()

# Add a paragraph
p = doc.add_paragraph()

# Add text to paragraph reference
txt = 'Custom background colour (a.k.a shading, done with the paint bucket tool)'
run = p.add_run(txt)

# Get the XML tag
tag = run._r
print(run.element.xml)

# Create XML element
shd = OxmlElement('w:shd')

# Add attributes to the element
shd.set(qn('w:val'), 'clear')
shd.set(qn('w:color'), 'auto')
shd.set(qn('w:fill'), 'FFAAAA')

# Set the font size - this is important! Without this step the
# tag.rPr value below will be None.
run.font.size = Pt(14)
print(run.element.xml)

tag.rPr.append(shd)
print(run.element.xml)

# Save document
doc.save('d.docx')

I don't know if this method works for you, hope this helps. If you want to change to other styles rather than shading, I think that should do the trick, too. But you do need to know what the elements are. Also, you can find the documentation about style, which provides an XML example to show what a word document would look like in XML format as well.