python-openxml / python-docx

Create and modify Word documents with Python
MIT License
4.63k stars 1.13k forks source link

feature: Font.shading #309

Open ellabebop opened 8 years ago

ellabebop commented 8 years ago

font.highlight_color appears to work fine when applied directly to a run's font, this way.

run=para.add_run("this should have a yellow background, but with no style (!)")
run.font.highlight_color=docx.enum.text.WD_COLOR.YELLOW

When applied using a style, it seems to have no effect.

style=doc.styles.add_style("highlightYellow",docx.enum.style.WD_STYLE_TYPE.CHARACTER)
style.base_style=doc.styles["Normal"]
style.font.highlight_color=docx.enum.text.WD_COLOR.YELLOW

para.add_run("this should have a yellow background, but does not",style)

In Microsoft Word, I can see that the style is being applied to that run, but it's background isn't yellow. If I look at the style using the Modify Style dialog, the sample text snippet shows a yellow background, oddly enough. But in that dialog, Format/Border.../Shading says that Fill is No Color. Selecting yellow there fixes it. Another oddity is that I do get a yellow background opening the same document in LibreOffice, oowriter.

I'm gathering some XML to help isolate this, and will attach it to the issue.

ellabebop commented 8 years ago

I created two docx files, one setting a highlight color using a custom style, the other setting it without a style, by modifying the run's font directly. Both documents contain "Now is the time for all good men to come to the aid of their country", with "good men" highlighted in Microsoft Word and LibreOffice. From opc diff, here's a comparison of those two files, culled down to only what I think might help.

document.xml

--- withStyle/word/document.xml

+++ withoutStyle/word/document.xml

@@ -19,15 +19,15 @@

     mc:Ignorable="w14 w15 wp14"
     >
   <w:body>
-    <w:p w:rsidR="000E0B29" w:rsidRDefault="00666F4F" w:rsidP="00666F4F">
+    <w:p w:rsidR="000E0B29" w:rsidRDefault="007B5FC5">
       <w:r>
         <w:t xml:space="preserve">Now is the time for all </w:t>
       </w:r>
       <w:bookmarkStart w:id="0" w:name="_GoBack"/>
       <w:bookmarkEnd w:id="0"/>
-      <w:r w:rsidRPr="00666F4F">
+      <w:r w:rsidRPr="007B5FC5">
         <w:rPr>
-          <w:rStyle w:val="highlightedChar"/>
+          <w:highlight w:val="yellow"/>
         </w:rPr>
         <w:t>good men</w:t>
       </w:r>

settings.xml

--- withStyle/word/settings.xml

+++ withoutStyle/word/settings.xml

@@ -24,8 +24,8 @@

     <w:compatSetting w:name="differentiateMultirowTableHeaders" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/>
   </w:compat>
   <w:rsids>
-    <w:rsidRoot w:val="00666F4F"/>
-    <w:rsid w:val="00666F4F"/>
+    <w:rsidRoot w:val="007B5FC5"/>
+    <w:rsid w:val="007B5FC5"/>
     <w:rsid w:val="00A9783E"/>
     <w:rsid w:val="00DA7422"/>
   </w:rsids>
@@ -53,5 +53,5 @@

   <w:decimalSymbol w:val="."/>
   <w:listSeparator w:val=","/>
   <w15:chartTrackingRefBased/>
-  <w15:docId w15:val="{BAE80B28-DB1C-463D-A50B-CD0A25BE902D}"/>
+  <w15:docId w15:val="{A78A5ADD-3997-459D-81FF-68474729778E}"/>
 </w:settings>

styles.xml

--- withStyle/word/styles.xml

+++ withoutStyle/word/styles.xml

@@ -426,23 +426,4 @@

     <w:semiHidden/>
     <w:unhideWhenUsed/>
   </w:style>
-  <w:style w:type="paragraph" w:customStyle="1" w:styleId="highlighted">
-    <w:name w:val="highlighted"/>
-    <w:basedOn w:val="Normal"/>
-    <w:link w:val="highlightedChar"/>
-    <w:qFormat/>
-    <w:rsid w:val="00666F4F"/>
-    <w:pPr>
-      <w:shd w:val="clear" w:color="auto" w:fill="FFFF00"/>
-    </w:pPr>
-  </w:style>
-  <w:style w:type="character" w:customStyle="1" w:styleId="highlightedChar">
-    <w:name w:val="highlighted Char"/>
-    <w:basedOn w:val="DefaultParagraphFont"/>
-    <w:link w:val="highlighted"/>
-    <w:rsid w:val="00666F4F"/>
-    <w:rPr>
-      <w:shd w:val="clear" w:color="auto" w:fill="FFFF00"/>
-    </w:rPr>
-  </w:style>
 </w:styles>
ellabebop commented 8 years ago

Oops. Mistakenly closed it.

scanny commented 8 years ago

A couple preliminary observations:

document.xml

--- withStyle/word/document.xml

+++ withoutStyle/word/document.xml

@@ -19,15 +19,15 @@

     mc:Ignorable="w14 w15 wp14"
     >
   <w:body>
     <w:p>
       <w:r>
         <w:t xml:space="preserve">Now is the time for all </w:t>
       </w:r>
       <w:r>
         <w:rPr>
-          <w:rStyle w:val="highlightedChar"/>
+          <w:highlight w:val="yellow"/>
         </w:rPr>
         <w:t>good men</w:t>
       </w:r>

What this is telling us is that the character style was removed when you applied the highlight_color.

styles.xml

--- withStyle/word/styles.xml

+++ withoutStyle/word/styles.xml

@@ -426,23 +426,4 @@

     <w:semiHidden/>
     <w:unhideWhenUsed/>
   </w:style>
-  <w:style w:type="paragraph" w:customStyle="1" w:styleId="highlighted">
-    <w:name w:val="highlighted"/>
-    <w:basedOn w:val="Normal"/>
-    <w:link w:val="highlightedChar"/>
-    <w:qFormat/>
-    <w:rsid w:val="00666F4F"/>
-    <w:pPr>
-      <w:shd w:val="clear" w:color="auto" w:fill="FFFF00"/>
-    </w:pPr>
-  </w:style>
-  <w:style w:type="character" w:customStyle="1" w:styleId="highlightedChar">
-    <w:name w:val="highlighted Char"/>
-    <w:basedOn w:val="DefaultParagraphFont"/>
-    <w:link w:val="highlighted"/>
-    <w:rsid w:val="00666F4F"/>
-    <w:rPr>
-      <w:shd w:val="clear" w:color="auto" w:fill="FFFF00"/>
-    </w:rPr>
-  </w:style>
 </w:styles>

This part is inconclusive, just showing that two styles have been removed. I think what we need is a comparison of one that is created by python-docx and works in LibreOffice, and one that's created using the Word UI and works in Word. Just a clip of the style element itself will do the trick, something like this:

<w:style w:type="character" w:customStyle="1" w:styleId="highlightedChar">
  <w:name w:val="highlighted Char"/>
  <w:rPr>
    <w:shd w:val="clear" w:color="auto" w:fill="FFFF00"/>
  </w:rPr>
</w:style>

I'm thinking it's probably best to focus on the behavior of an independent character style for the moment, as it being linked to a paragraph style complicates things. It's definitely plausible that highlighting works in a character style, but not when that character style is linked to a paragraph style, perhaps because Microsoft thought it unlikely anyone would want to highlight a whole paragraph or something.

ellabebop commented 8 years ago

I used python-docx to create an equivalent document, setting the highlight color using a style.

import docx

doc=docx.Document()
para=doc.add_paragraph()

style=doc.styles.add_style("my yellow highlight",docx.enum.style.WD_STYLE_TYPE.CHARACTER)
style.base_style=doc.styles["Normal"]
style.font.highlight_color=docx.enum.text.WD_COLOR.YELLOW

para.add_run("Now is the time for all ")
para.add_run("good men",style)
para.add_run(" to come to the aid of their country.")

doc.save("worksInLibre.docx")

I confirmed that the highlighting works in LibreOffice but not in Microsoft Word. I also used Microsoft Word to create the same document, but using a non-linked, character style, and confirmed it works both there and in LibreOffice. Here some output from an opc diff comparison of those two documents.

document.xml

--- fromWord/word/document.xml

+++ fromPython/word/document.xml

@@ -2,12 +2,13 @@

 <w:document
     xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main"
+    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:v="urn:schemas-microsoft-com:vml"
     xmlns:w10="urn:schemas-microsoft-com:office:word"
     xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
-    xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
     xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
     xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
     xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
@@ -16,34 +17,26 @@

     xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
     xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
     xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
-    mc:Ignorable="w14 w15 wp14"
+    mc:Ignorable="w14 wp14"
     >
   <w:body>
-    <w:p w:rsidR="000E0B29" w:rsidRDefault="001B2ADB">
+    <w:p>
       <w:r>
         <w:t xml:space="preserve">Now is the time for all </w:t>
       </w:r>
-      <w:r w:rsidRPr="001B2ADB">
+      <w:r>
         <w:rPr>
           <w:rStyle w:val="myyellowhighlight"/>
         </w:rPr>
-        <w:t>good m</w:t>
-      </w:r>
-      <w:bookmarkStart w:id="0" w:name="_GoBack"/>
-      <w:bookmarkEnd w:id="0"/>
-      <w:r w:rsidRPr="001B2ADB">
-        <w:rPr>
-          <w:rStyle w:val="myyellowhighlight"/>
-        </w:rPr>
-        <w:t>en</w:t>
+        <w:t>good men</w:t>
       </w:r>
       <w:r>
         <w:t xml:space="preserve"> to come to the aid of their country.</w:t>
       </w:r>
     </w:p>
-    <w:sectPr w:rsidR="000E0B29">
+    <w:sectPr w:rsidR="00FC693F" w:rsidRPr="0006063C" w:rsidSect="00034616">
       <w:pgSz w:w="12240" w:h="15840"/>
-      <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/>
+      <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="720" w:footer="720" w:gutter="0"/>
       <w:cols w:space="720"/>
       <w:docGrid w:linePitch="360"/>
     </w:sectPr>

styles.xml

...
   <w:style w:type="character" w:customStyle="1" w:styleId="myyellowhighlight">
     <w:name w:val="my yellow highlight"/>
-    <w:basedOn w:val="DefaultParagraphFont"/>
-    <w:uiPriority w:val="1"/>
-    <w:qFormat/>
-    <w:rsid w:val="001B2ADB"/>
+    <w:basedOn w:val="Normal"/>
     <w:rPr>
-      <w:bdr w:val="none" w:sz="0" w:space="0" w:color="auto"/>
-      <w:shd w:val="clear" w:color="auto" w:fill="FFFF00"/>
+      <w:highlight w:val="yellow"/>
     </w:rPr>
   </w:style>
...
scanny commented 8 years ago

@ellabebop - How are you adding a highlight color to a character style in the Word UI? I don't see a button for that, either on my Mac (Word 2011) or on Windows (Word 2010).

scanny commented 8 years ago

Ok, looks like highlighting is actually not supported in styles: http://answers.microsoft.com/en-us/office/forum/office_2010-word/can-one-have-highlighted-as-part-of-a-character/326b835a-f1da-4441-9b99-a1192b28c1fe

I had a vague recollection of that from somewhere.

So I think the feature you're after is actually Font.shading.

DKWoods commented 8 years ago

@ellabebop https://github.com/ellabebop - How are you adding a highlight color to a character style in the Word UI? I don't see a button for that, either on my Mac (Word 2011) or on Windows (Word 2010).

In Word 2010 on Windows, there's a button on the Home ribbon just to the right of the font formatting (bold, italics, etc.) buttons. It's between Text Effects and Font Color. The icon shows letters with a pale yellow highlight and what is supposed to be a highlighter pen. It has a drop-down with about 15 colors to choose from.

David

scanny commented 8 years ago

So that's the one to apply it directly, but my question is how do you do that to a style. That familiar "yellow highlighter" button doesn't appear in the New Style dialog.

ellabebop commented 8 years ago

After some digging, I concluded it's what I described at the beginning of this thread. In the Modify Style dialog, use Format/Border.../Shading. It's buried, but achieves the same effect as the button David mentions.

Jim

scanny commented 8 years ago

@ellabebop Ah, got it now, apologies I didn't catch it from the original post.

So the implementation of this would actually be Font.shading, which would return a Shading object (best first guess anyway) that supported colors and possibly patterns and so forth.

We wouldn't change the behavior of Font.highlight_color when it happened to belong to a character style. Folks would have to use shading for the job, just like in the UI.

I'll change the title of this issue to reflect this and we'll leave it open and see if anyone wants to pick it up.

ellabebop commented 8 years ago

That makes sense, and I came to the same realization. Thanks.