python-openxml / python-docx

Create and modify Word documents with Python
MIT License
4.53k stars 1.11k forks source link

feature: Run.shading #150

Open microe opened 9 years ago

microe commented 9 years ago

Thanks to version 0.8.3 I am able to read font color of a run. Now I have a separate issue where I have a normal font color (black), but the background color is red (ff, 26, 00) or (ff, 00, 00). Is there a way to read the background color of a run?

scanny commented 9 years ago

Can you inspect the XML for one of the runs in question and post it? opc-diag is handy for that job or you can unzip the .docx file and examine the document.xml part. You'll need to format the XML somehow if you go the latter route as it will all be on one line; (that's why I wrote opc-diag :).

I kind of suspect this must use the same mechanism as highlighting, but haven't dug into what the XML for that looks like yet.

microe commented 9 years ago

Here is the rPr for text that is background highlighted:

<w:rPr>
          <w:shd w:val="clear" w:color="auto" w:fill="FF0000"/>
</w:rPr>

Thanks for tip on opc-diag. I guess it is this w:fill?

scanny commented 9 years ago

Interesting. Here's the XML Schema type for the w:shd element.

<xsd:complexType name="CT_Shd">
  <xsd:attribute name="val"            type="ST_Shd"/>
  <xsd:attribute name="color"          type="ST_HexColor"/>
  <xsd:attribute name="themeColor"     type="ST_ThemeColor"/>
  <xsd:attribute name="themeTint"      type="ST_UcharHexNumber"/>
  <xsd:attribute name="themeShade"     type="ST_UcharHexNumber"/>
  <xsd:attribute name="fill"           type="ST_HexColor"/>
  <xsd:attribute name="themeFill"      type="ST_ThemeColor"/>
  <xsd:attribute name="themeFillTint"  type="ST_UcharHexNumber"/>
  <xsd:attribute name="themeFillShade" type="ST_UcharHexNumber"/>
</xsd:complexType>

According to the spec §17.3.2.32, these attributes are used in various combinations to specify a "background shading", basically the equivalent of highlighting when the color is yellow.

You're right about the main color. The w:fill attribute is used to set it to an RGBColor. w:themeFill can be used to set it to a theme color, and w:themeFillTint and w:themeFillShade to make that theme color some percentage brighter or darker.

The w:color and w:themeColor are used to specify the foreground color when there's a pattern. The w:val attribute specifies one of 38 possible patterns, of which "clear" is one.

I expect <w:shd w:fill="FF0000"/> would accomplish the same thing as the sample you provided, but that would take some experimentation to discover as the spec omits the details on the semantics of the various combinations.

This capability corresponds to a Run.shading property which itself would be a bit complicated, something like this, although it goes a couple additional levels deeper as most of its properties are themselves objects with multiple properties: https://msdn.microsoft.com/en-us/library/office/ff839330.aspx

So the approach would be to work out the expected API well enough that the commonly-used parts could be implemented in the short term, while providing confidence that API wouldn't have to change when the rest was added later.

Short story is, I'll add it to the list here, but it's likely to be a while in coming.

In the meantime, you'll have to access the rPr property of the run and have a look using low-level lxml calls, something factored much more nicely that this rough code to provide an idea of the how-to:

rPr = run._element.rPr
if rPr is None:
    return  # means no w:rPr element is present
results = rPr.xpath('w:shd')
if len(results) == 0:
    return # means no w:shd child element is present
shd = results[0]
from docx.oxml.ns import qn
fill = shd.get(qn(w:fill))
if fill = 'FF0000':
    print('found one')