From 47ec4b5521774c74c2515b0d47508985302e58c8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 28 Jun 2021 14:19:48 +0530 Subject: [PATCH] MOBI Output: Fix invalid color specification as plain numbers causing conversion to fail. Fixes #1933797 [ebook-convert fails with TypeError: Argument must be bytes or unicode, got 'float'](https://bugs.launchpad.net/calibre/+bug/1933797) More generally have the conversion pipeline validate values for color just as it does for background-color --- src/calibre/ebooks/mobi/utils.py | 2 +- src/calibre/ebooks/oeb/stylizer.py | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/calibre/ebooks/mobi/utils.py b/src/calibre/ebooks/mobi/utils.py index ff8c51f2cc..2cbadedf8d 100644 --- a/src/calibre/ebooks/mobi/utils.py +++ b/src/calibre/ebooks/mobi/utils.py @@ -640,7 +640,7 @@ def is_guide_ref_start(ref): def convert_color_for_font_tag(val): rgba = parse_color_string(unicode_type(val or '')) if rgba is None or rgba == 'currentColor': - return val + return str(val) clamp = lambda x: min(x, max(0, x), 1) rgb = map(clamp, rgba[:3]) return '#' + ''.join(map(lambda x:'%02x' % int(x * 255), rgb)) diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py index ab330d369b..722193ecf2 100644 --- a/src/calibre/ebooks/oeb/stylizer.py +++ b/src/calibre/ebooks/oeb/stylizer.py @@ -29,6 +29,12 @@ css_parser_log.setLevel(logging.WARN) _html_css_stylesheet = None +def validate_color(col): + return cssprofiles.validateWithProfile('color', + col, + profiles=[profiles.Profiles.CSS_LEVEL_2])[1] + + def html_css_stylesheet(): global _html_css_stylesheet if _html_css_stylesheet is None: @@ -414,6 +420,7 @@ class Style(object): self._height = None self._lineHeight = None self._bgcolor = None + self._fgcolor = None self._pseudo_classes = {} stylizer._styles[element] = self @@ -467,9 +474,7 @@ class Style(object): return self._unit_convert(self._get(name)) def _get(self, name): - result = None - if name in self._style: - result = self._style[name] + result = self._style.get(name, None) if (result == 'inherit' or (result is None and name in INHERITED and self._has_parent())): stylizer = self._stylizer result = stylizer.style(self._element.getparent())._get(name) @@ -491,6 +496,16 @@ class Style(object): def pt_to_px(self, value): return (self._profile.dpi / 72) * value + @property + def color(self): + if self._fgcolor is None: + val = self._get('color') + if val and validate_color(val): + self._fgcolor = val + else: + self._fgcolor = DEFAULTS['color'] + return self._fgcolor + @property def backgroundColor(self): ''' @@ -499,11 +514,6 @@ class Style(object): are not used. None is returned if no background color is set. ''' - def validate_color(col): - return cssprofiles.validateWithProfile('color', - col, - profiles=[profiles.Profiles.CSS_LEVEL_2])[1] - if self._bgcolor is None: col = None val = self._style.get('background-color', None)