Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ Release History

**Fixes**

- None
- Fixes `#73 <https://github.com/dfop02/html4docx/issues/73>`_: Error parsing styles with spaces. | `dfop02 <https://github.com/dfop02>`_
- Fixes `#71 <https://github.com/dfop02/html4docx/issues/71>`_: Error applying color to table cells. | `vvalchev <https://github.com/vvalchev>`_

**New Features**

Expand Down
2 changes: 2 additions & 0 deletions html4docx/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,5 @@ def default_borders():
re.compile(r'page-break-after\s*:\s*always\s*(?:!important)?\s*(?:;|$)'),
re.compile(r'break-after\s*:\s*page\s*(?:!important)?\s*(?:;|$)'),
)

RGB_SPACES_REGEX = re.compile(r'(rgba?\()([^)]+)(\))', re.IGNORECASE)
12 changes: 8 additions & 4 deletions html4docx/h4d.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,10 +352,11 @@ def parse_border_value(value: str):
Parses a border value like:
'1px solid #000000', 'solid 1px red', or '#000000 medium dashed' in any order.
"""
parts = value.split()
value = value.strip()
parts = utils.normalize_rgb_spaces(value).split()

# Return all default if there is only 'none' or empty
if (len(parts) == 1 and parts[0] == "none") or (not value or value.strip() == ""):
if (len(parts) == 1 and parts[0].lower() == "none") or (not value or value.strip() == ""):
return default_size, default_style, default_color

size = None
Expand Down Expand Up @@ -1048,8 +1049,10 @@ def add_text_align_or_margin_to(self, obj, style):
def add_styles_to_table_cell(self, styles, doc_cell, cell_row):
"""Styles that must be applied specifically in a _Cell object"""
# Set background color

if "background-color" in styles:
self.set_cell_background(doc_cell, styles["background-color"])
color = utils.parse_color(styles["background-color"], return_hex=True)
self.set_cell_background(doc_cell, color)

# Set width (approximate, since DOCX uses different units)
if "width" in styles:
Expand Down Expand Up @@ -1733,7 +1736,8 @@ def handle_comment(self, data):

# Style: Green color to mimic HTML comment styling
dark_ish_green = "#008000"
run.font.color.rgb = utils.parse_color(dark_ish_green)
dark_ish_green_color = utils.parse_color(dark_ish_green)
run.font.color.rgb = RGBColor(*dark_ish_green_color)
run.italic = True # makes it feel more like a comment

def ignore_nested_tables(self, tables_soup):
Expand Down
16 changes: 16 additions & 0 deletions html4docx/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,22 @@ def parse_color(original_color: str, return_hex: bool = False):
return rgb_to_hex(colors) if return_hex else colors


def normalize_rgb_spaces(value: str) -> str:
"""
Removes spaces inside rgb()/rgba() so it can be safely split.
Example:
rgb(222, 222, 222) -> rgb(222,222,222)
"""

def _replace(match):
prefix, content, suffix = match.groups()
# remove spaces only inside the function
content = content.replace(" ", "")
return f"{prefix}{content}{suffix}"

return constants.RGB_SPACES_REGEX.sub(_replace, value)


def remove_last_occurence(ls, x):
ls.pop(len(ls) - ls[::-1].index(x) - 1)

Expand Down
10 changes: 5 additions & 5 deletions tests/assets/htmls/tables3.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@
width="641">
<tbody>
<tr style="height:23.75pt;">
<td style="background-color:#3749EF;border-bottom-color:#d95b48;border-left-color:red;border-right-color:darkred;border-style:solid;border-top-color:#d95b48;border-width:1.0pt;height:23.75pt;padding:0in;width:258.35px;"
<td style="background-color:rgb(55, 73, 239);border-bottom-color:#d95b48;border-left-color:red;border-right-color:darkred;border-style:solid;border-top-color:#d95b48;border-width:1.0pt;height:23.75pt;padding:0in;width:258.35px;"
width="344">
<p style="text-align:center;"><span style="color:white;"><strong>CATEGORY</strong></span></p>
</td>
<td style="background-color:#33b32e;border-bottom:1.5px solid
#fac32a;border-left-style:none;border-right:1em solid #fac32a;border-top:1.0pt solid
#fac32a;height:23.75pt;padding:0in;width:222.2pt;" width="296">
rgba(250, 195, 42, 1);border-left-style:none;border-right:1em solid #fac32a;border-top:1.0pt solid
rgb(250, 195, 42);height:23.75pt;padding:0in;width:222.2pt;" width="296">
<p style="margin-left:.7pt;text-align:center;"><span
style="color:white;"><strong>OBSERVATIONS/COMMENTS</strong></span></p>
</td>
</tr>
<tr style="height:15.5pt;">
<td style="background-color:#BFBFBF;border-bottom-style:solid;border-color:#30e667;border-left-style:solid;border-right-style:solid;border-top-style:none;border-width:0.2cm;height:15.5pt;padding:0in;width:258.35in;"
<td style="background-color:#BFBFBF;color:rgba(222, 222, 0, 0);border-bottom-style:solid;border-color:#30e667;border-left-style:solid;border-right-style:solid;border-top-style:none;border-width:0.2cm;height:15.5pt;padding:0in;width:258.35in;"
width="344"><strong>NETHERLANDS COURTS</strong></td>
<td style="background-color:#2eaab3;border-bottom:2px solid
#d948cf;border-left-style:none;border-right:0.2cm solid
#d948cf;border-top-style:none;height:15.5pt;padding:0in;width:6cm;" width="296">&nbsp;</td>
</tr>
<tr>
<td style="background-color:#99fffa;border-bottom-style:solid;border-color:#eaaaa7;border-style:solid;border-width:20%;height:2rem;padding:0in;width:258.35pt;"
<td style="background-color:#99fffa;color:rgba(222, 222, 0, 0);border-bottom-style:solid;border-color:#eaaaa7;border-style:solid;border-width:20%;height:2rem;padding:0in;width:258.35pt;"
width="344"><strong>GERMANY COURTS</strong></td>
<td style="background-color:#2eaab3;border-bottom:0.6em dashed
#acc4aa;border-left-style:none;border-right:0.4rem dotted
Expand Down
Loading