From 4cf6299ac38d637ad2428d7d64916f2b50b157e4 Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Thu, 9 Feb 2017 19:40:46 +0200 Subject: [PATCH 1/3] Add table cell background color --- pydocx/constants.py | 5 +++ pydocx/export/base.py | 4 +++ pydocx/export/html.py | 36 ++++++++++++++++++- .../wordprocessing/table_cell_properties.py | 12 +++++++ pydocx/test/document_builder.py | 3 +- pydocx/util/color.py | 26 ++++++++++++++ tests/export/test_xml.py | 29 +++++++++++++++ tests/fixtures/styled_color.html | 2 +- tests/templates/tc.xml | 2 +- 9 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 pydocx/util/color.py diff --git a/pydocx/constants.py b/pydocx/constants.py index 9f7c1788..6d11673e 100644 --- a/pydocx/constants.py +++ b/pydocx/constants.py @@ -25,6 +25,11 @@ # https://en.wikipedia.org/wiki/Twip TWIPS_PER_POINT = 20 +# According to this: http://alienryderflex.com/hsp.html +BRIGHTNESS_DARK_COLOR = 50 + +COLOR_FOR_DARK_BACKGROUND = 'FFFFFF' + # TODO These alignment values are for traditional conformance. Strict # conformance uses different values JUSTIFY_CENTER = 'center' diff --git a/pydocx/export/base.py b/pydocx/export/base.py index 67b002bc..bee43768 100644 --- a/pydocx/export/base.py +++ b/pydocx/export/base.py @@ -359,6 +359,7 @@ def get_run_styles_to_apply(self, run): (properties.hidden, self.export_run_property_hidden), (properties.vertical_align, self.export_run_property_vertical_align), (properties.color, self.export_run_property_color), + (not properties.color, self.export_run_property_parent_background_color), ] for actual_value, handler in property_rules: if actual_value: @@ -407,6 +408,9 @@ def export_run_property_vertical_align(self, run, results): def export_run_property_color(self, run, results): return results + def export_run_property_parent_background_color(self, run, results): + return results + def export_hyperlink(self, hyperlink): return self.yield_nested(hyperlink.children, self.export_node) diff --git a/pydocx/export/html.py b/pydocx/export/html.py index 18e3ea53..a1fd1b00 100644 --- a/pydocx/export/html.py +++ b/pydocx/export/html.py @@ -17,11 +17,16 @@ POINTS_PER_EM, PYDOCX_STYLES, TWIPS_PER_POINT, - EMUS_PER_PIXEL + EMUS_PER_PIXEL, + BRIGHTNESS_DARK_COLOR, + COLOR_FOR_DARK_BACKGROUND ) from pydocx.export.base import PyDocXExporter from pydocx.export.numbering_span import NumberingItem from pydocx.openxml import wordprocessing +from pydocx.openxml.wordprocessing.paragraph import Paragraph +from pydocx.openxml.wordprocessing.table_cell import TableCell +from pydocx.util import color from pydocx.util.uri import uri_is_external from pydocx.util.xml import ( convert_dictionary_to_html_attributes, @@ -572,6 +577,29 @@ def export_run_property_color(self, run, results): tag = HtmlTag('span', **attrs) return self.export_run_property(tag, run, results) + def export_run_property_parent_background_color(self, run, results): + background_color = None + + if isinstance(run.parent, (Paragraph,)): + paragraph = run.parent + if isinstance(paragraph.parent, (TableCell,)) and paragraph.parent.properties: + table_cell_prop = paragraph.parent.properties + background_color = table_cell_prop.background_color + + if background_color: + brightness = color.brightness(background_color) + # We need to change the text color if background color is dark + # and text run does not have custom color. + # Office Word does this automatically. + if brightness < BRIGHTNESS_DARK_COLOR: + attrs = { + 'style': 'color: #%s' % COLOR_FOR_DARK_BACKGROUND + } + tag = HtmlTag('span', **attrs) + results = self.export_run_property(tag, run, results) + + return results + def export_text(self, text): results = super(PyDocXHTMLExporter, self).export_text(text) for result in results: @@ -668,6 +696,12 @@ def export_table_cell(self, table_cell): attrs['colspan'] = colspan if rowspan > 1: attrs['rowspan'] = rowspan + + if table_cell.properties: + background_color = table_cell.properties.background_color + if background_color: + attrs['style'] = 'background-color: #%s' % background_color + tag = HtmlTag('td', **attrs) numbering_spans = self.yield_numbering_spans(table_cell.children) diff --git a/pydocx/openxml/wordprocessing/table_cell_properties.py b/pydocx/openxml/wordprocessing/table_cell_properties.py index 2a94c9b0..b04e18e0 100644 --- a/pydocx/openxml/wordprocessing/table_cell_properties.py +++ b/pydocx/openxml/wordprocessing/table_cell_properties.py @@ -13,6 +13,8 @@ class TableCellProperties(XmlModel): grid_span = XmlChild(name='gridSpan', attrname='val') + background_fill = XmlChild(name='shd', attrname='fill') + vertical_merge = XmlChild(name='vMerge', type=lambda el: dict(el.attrib)) # noqa def should_close_previous_vertical_merge(self): @@ -25,3 +27,13 @@ def should_close_previous_vertical_merge(self): if merge != 'continue': return True return False + + @property + def background_color(self): + background_fill = getattr(self, 'background_fill', None) + + # There is no need to set white background color + if background_fill not in ('auto', 'FFFFFF'): + return background_fill + + return None diff --git a/pydocx/test/document_builder.py b/pydocx/test/document_builder.py index 589fec16..082c8e86 100644 --- a/pydocx/test/document_builder.py +++ b/pydocx/test/document_builder.py @@ -206,13 +206,14 @@ def li(self, text, ilvl, numId, bold=False): ) @classmethod - def table_cell(self, paragraph, merge=False, merge_continue=False): + def table_cell(self, paragraph, merge=False, merge_continue=False, fill_color='auto'): template = env.get_template(templates['tc']) return template_render( template, paragraph=paragraph, merge=merge, merge_continue=merge_continue, + fill_color=fill_color ) @classmethod diff --git a/pydocx/util/color.py b/pydocx/util/color.py new file mode 100644 index 00000000..0c712f97 --- /dev/null +++ b/pydocx/util/color.py @@ -0,0 +1,26 @@ +# coding: utf-8 +from __future__ import ( + absolute_import, + print_function, + unicode_literals, +) + +import math + + +def hex_to_rgb(value): + """Return (red, green, blue) for the color given as #rrggbb.""" + + value = value.lstrip('#') + lv = len(value) + return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) + + +def brightness(hex_color): + """A trick to determine the brightness of the color. + More info about this here: http://alienryderflex.com/hsp.html + """ + + r, g, b = hex_to_rgb(hex_color) + + return math.sqrt(math.pow(r, 2) * .241 + math.pow(g, 2) * .691 + math.pow(b, 2) * .068) diff --git a/tests/export/test_xml.py b/tests/export/test_xml.py index 2ad17a88..38b5a306 100644 --- a/tests/export/test_xml.py +++ b/tests/export/test_xml.py @@ -296,6 +296,35 @@ def get_xml(self): return xml +class TableWithCellBackgroundColor(TranslationTestCase): + expected_output = ''' + + + + + + + + + +
AAABBB
CCC + DDD +
+ ''' + + def get_xml(self): + cell1 = DXB.table_cell(paragraph=DXB.p_tag('AAA'), fill_color='FF00FF') + cell2 = DXB.table_cell(paragraph=DXB.p_tag('BBB'), fill_color='FFFFFF') + cell3 = DXB.table_cell(paragraph=DXB.p_tag('CCC'), fill_color='auto') + # for dark color we get white text color + cell4 = DXB.table_cell(paragraph=DXB.p_tag('DDD'), fill_color='000000') + rows = [DXB.table_row([cell1, cell2]), DXB.table_row([cell3, cell4])] + table = DXB.table(rows) + body = table + xml = DXB.xml(body) + return xml + + class SimpleListTestCase(TranslationTestCase): expected_output = '''
    diff --git a/tests/fixtures/styled_color.html b/tests/fixtures/styled_color.html index c9873ce3..b7ab76fe 100644 --- a/tests/fixtures/styled_color.html +++ b/tests/fixtures/styled_color.html @@ -2,7 +2,7 @@

    BBB

    - +
    CCCCCC

    DDD

    diff --git a/tests/templates/tc.xml b/tests/templates/tc.xml index eff9ce0d..b60b7e4e 100644 --- a/tests/templates/tc.xml +++ b/tests/templates/tc.xml @@ -14,7 +14,7 @@ - + From 900e880be4619cb12f5a7f64096342baa94fc87c Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Thu, 23 Feb 2017 17:17:29 +0200 Subject: [PATCH 2/3] Skip setting white backgournd color --- pydocx/openxml/wordprocessing/table_cell_properties.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pydocx/openxml/wordprocessing/table_cell_properties.py b/pydocx/openxml/wordprocessing/table_cell_properties.py index b04e18e0..19f7abd2 100644 --- a/pydocx/openxml/wordprocessing/table_cell_properties.py +++ b/pydocx/openxml/wordprocessing/table_cell_properties.py @@ -6,6 +6,7 @@ ) from pydocx.models import XmlModel, XmlChild +from pydocx.constants import COLOR_FOR_DARK_BACKGROUND class TableCellProperties(XmlModel): @@ -30,10 +31,8 @@ def should_close_previous_vertical_merge(self): @property def background_color(self): - background_fill = getattr(self, 'background_fill', None) - # There is no need to set white background color - if background_fill not in ('auto', 'FFFFFF'): - return background_fill + if self.background_fill not in ('auto', COLOR_FOR_DARK_BACKGROUND): + return self.background_fill return None From fd31f4db63060f8dfd077f57907e76ed55afef94 Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Thu, 2 Mar 2017 12:37:01 +0200 Subject: [PATCH 3/3] Add support for paragraph highlight color --- .gitignore | 2 ++ pydocx/export/base.py | 4 ++++ pydocx/export/html.py | 11 +++++++++++ .../openxml/wordprocessing/run_properties.py | 11 +++++++++-- tests/fixtures/styled_color.docx | Bin 14048 -> 12604 bytes tests/fixtures/styled_color.html | 16 ++++++++++++++-- 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 83b2da20..50299015 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ main.py docs/_build tests/failures/*.html + +~$*.docx diff --git a/pydocx/export/base.py b/pydocx/export/base.py index bee43768..31adfa8d 100644 --- a/pydocx/export/base.py +++ b/pydocx/export/base.py @@ -359,6 +359,7 @@ def get_run_styles_to_apply(self, run): (properties.hidden, self.export_run_property_hidden), (properties.vertical_align, self.export_run_property_vertical_align), (properties.color, self.export_run_property_color), + (properties.highlight_color, self.export_run_property_highlight_color), (not properties.color, self.export_run_property_parent_background_color), ] for actual_value, handler in property_rules: @@ -408,6 +409,9 @@ def export_run_property_vertical_align(self, run, results): def export_run_property_color(self, run, results): return results + def export_run_property_highlight_color(self, run, results): + return results + def export_run_property_parent_background_color(self, run, results): return results diff --git a/pydocx/export/html.py b/pydocx/export/html.py index a1fd1b00..c75ab5de 100644 --- a/pydocx/export/html.py +++ b/pydocx/export/html.py @@ -577,6 +577,17 @@ def export_run_property_color(self, run, results): tag = HtmlTag('span', **attrs) return self.export_run_property(tag, run, results) + def export_run_property_highlight_color(self, run, results): + if run.properties is None or run.properties.highlight_color is None: + return results + + attrs = { + 'style': 'background-color: %s' % run.properties.highlight_color + } + tag = HtmlTag('span', **attrs) + + return self.export_run_property(tag, run, results) + def export_run_property_parent_background_color(self, run, results): background_color = None diff --git a/pydocx/openxml/wordprocessing/run_properties.py b/pydocx/openxml/wordprocessing/run_properties.py index 63587a57..3682b6e4 100644 --- a/pydocx/openxml/wordprocessing/run_properties.py +++ b/pydocx/openxml/wordprocessing/run_properties.py @@ -28,17 +28,24 @@ class RunProperties(XmlModel): sz = XmlChild(name='sz', attrname='val') clr = XmlChild(name='color', attrname='val') r_fonts = XmlChild(type=RFonts) + highlight_clr = XmlChild(name='highlight', attrname='val') @property def color(self): if self.clr is None: return - # TODO: When we support background colors, remove FFFFFF check - if self.clr == '000000' or self.clr == 'FFFFFF': + if self.clr == '000000': return return self.clr + @property + def highlight_color(self): + if self.highlight_clr is None: + return + + return self.highlight_clr + @property def position(self): if self.pos is None: diff --git a/tests/fixtures/styled_color.docx b/tests/fixtures/styled_color.docx index b7d22abfdaefb3146eff5955d0c9716ee39de39c..ae9b055b0b81fb2d827b6543d6ef049b9685e315 100644 GIT binary patch literal 12604 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

    - +
    CCC + CCC +
    -

    DDD

    +

    + + DDD + +

    +

    + AAA + BBB + CCC + DDD +