forked from LiveCarta/BookConverter
epub converter: prettify css_reader.py
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import cssutils
|
import cssutils
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
@@ -18,9 +20,8 @@ sizes_pr = [-1, 0.5, 0.56, 0.63, 0.69, 0.75, 0.81, 0.88, 0.94, 1.0, 1.06, 1.13,
|
|||||||
|
|
||||||
sizes_px = ['10px', '10px', '11px', '12px', '13px', '14px', '15px', '16px', '17px', '18px', '19px', '20px', '21px',
|
sizes_px = ['10px', '10px', '11px', '12px', '13px', '14px', '15px', '16px', '17px', '18px', '19px', '20px', '21px',
|
||||||
'22px', '23px', '24px', '25px', '26px', '27px', '28px', '29px', '30px', '31px', '32px', '33px', '34px',
|
'22px', '23px', '24px', '25px', '26px', '27px', '28px', '29px', '30px', '31px', '32px', '33px', '34px',
|
||||||
'35px',
|
'35px', '36px', '37px', '38px', '39px', '40px', '41px', '42px', '43px', '44px', '45px', '46px', '47px',
|
||||||
'36px', '37px', '38px', '39px', '40px', '41px', '42px', '43px', '44px', '45px', '46px', '47px', '48px',
|
'48px', '49px', '50px', '64px', '72px']
|
||||||
'49px', '50px', '64px', '72px']
|
|
||||||
|
|
||||||
|
|
||||||
def convert_font_size(value):
|
def convert_font_size(value):
|
||||||
@@ -52,6 +53,13 @@ def convert_font_size(value):
|
|||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
LIVECARTA_STYLE_ATTRS = { css property: value }
|
||||||
|
|
||||||
|
Style properties that can be used to fit livecarta css style convention.
|
||||||
|
If property has empty list, it means that any value can be converted.
|
||||||
|
If property has not empty list, it means that only certain property-value combinations can be transformed.
|
||||||
|
"""
|
||||||
LIVECARTA_STYLE_ATTRS = {
|
LIVECARTA_STYLE_ATTRS = {
|
||||||
'text-indent': [],
|
'text-indent': [],
|
||||||
'font-variant': ['small-caps'],
|
'font-variant': ['small-caps'],
|
||||||
@@ -69,6 +77,13 @@ LIVECARTA_STYLE_ATTRS = {
|
|||||||
'color': [],
|
'color': [],
|
||||||
'background-color': [],
|
'background-color': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
LIVECARTA_STYLE_ATTRS_MAPPING = { property: mapping function }
|
||||||
|
|
||||||
|
Warning, if LIVECARTA_STYLE_ATTRS is changed, LIVECARTA_STYLE_ATTRS_MAPPING should be updated
|
||||||
|
to suit livecarta style convention.
|
||||||
|
"""
|
||||||
LIVECARTA_STYLE_ATTRS_MAPPING = {
|
LIVECARTA_STYLE_ATTRS_MAPPING = {
|
||||||
'text-indent': lambda x: LawCartaConfig.INDENT,
|
'text-indent': lambda x: LawCartaConfig.INDENT,
|
||||||
'font-variant': lambda x: x,
|
'font-variant': lambda x: x,
|
||||||
@@ -80,6 +95,9 @@ LIVECARTA_STYLE_ATTRS_MAPPING = {
|
|||||||
'background-color': lambda x: LawCartaConfig.HTML42LIVECARTA_COLORS.get(str2color_name(x), ''),
|
'background-color': lambda x: LawCartaConfig.HTML42LIVECARTA_COLORS.get(str2color_name(x), ''),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
LIVECARTA_STYLE_ATTRS_SHOULD_BE_TAG = { (property, value): tag }
|
||||||
|
"""
|
||||||
LIVECARTA_STYLE_ATTRS_SHOULD_BE_TAG = {
|
LIVECARTA_STYLE_ATTRS_SHOULD_BE_TAG = {
|
||||||
('font-weight', 'bold'): 'strong',
|
('font-weight', 'bold'): 'strong',
|
||||||
('font-weight', '600'): 'strong',
|
('font-weight', '600'): 'strong',
|
||||||
@@ -95,7 +113,9 @@ LIVECARTA_STYLE_ATTRS_SHOULD_BE_TAG = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def check_style_to_be_tag(style):
|
def check_style_to_be_tag(style) -> List[tuple]:
|
||||||
|
""" Some css style properties converts to tags.
|
||||||
|
Search for them and prepare list of properties to be removed from style string"""
|
||||||
to_remove = []
|
to_remove = []
|
||||||
for k in LIVECARTA_STYLE_ATTRS_SHOULD_BE_TAG:
|
for k in LIVECARTA_STYLE_ATTRS_SHOULD_BE_TAG:
|
||||||
if f'{k[0]}:{k[1]}' in style:
|
if f'{k[0]}:{k[1]}' in style:
|
||||||
@@ -103,6 +123,29 @@ def check_style_to_be_tag(style):
|
|||||||
return to_remove
|
return to_remove
|
||||||
|
|
||||||
|
|
||||||
|
def update_property_to_livecarta_convention(rule, property_):
|
||||||
|
if property_.name not in LIVECARTA_STYLE_ATTRS:
|
||||||
|
# property not in LIVECARTA_STYLE_ATTRS, remove from css file
|
||||||
|
rule.style[property_.name] = ''
|
||||||
|
|
||||||
|
elif LIVECARTA_STYLE_ATTRS.get(property_.name):
|
||||||
|
# check property value to decide weather to remove or not the property_
|
||||||
|
cleaned_property = property_.value.replace('\"', '')
|
||||||
|
if cleaned_property in LIVECARTA_STYLE_ATTRS[property_.name]:
|
||||||
|
|
||||||
|
if property_.name in LIVECARTA_STYLE_ATTRS_MAPPING:
|
||||||
|
# apply transformation
|
||||||
|
func = LIVECARTA_STYLE_ATTRS_MAPPING[property_.name]
|
||||||
|
rule.style[property_.name] = func(cleaned_property)
|
||||||
|
else:
|
||||||
|
# property + value not in LIVECARTA_STYLE_ATTRS, remove from css file
|
||||||
|
rule.style[property_.name] = ''
|
||||||
|
else:
|
||||||
|
# property can have any value
|
||||||
|
if property_.name in LIVECARTA_STYLE_ATTRS_MAPPING:
|
||||||
|
func = LIVECARTA_STYLE_ATTRS_MAPPING[property_.name]
|
||||||
|
cleaned_property = property_.value.replace('\"', '')
|
||||||
|
rule.style[property_.name] = func(cleaned_property)
|
||||||
|
|
||||||
|
|
||||||
def clean_css(css):
|
def clean_css(css):
|
||||||
@@ -110,35 +153,18 @@ def clean_css(css):
|
|||||||
for rule in sheet:
|
for rule in sheet:
|
||||||
if rule.type == rule.STYLE_RULE:
|
if rule.type == rule.STYLE_RULE:
|
||||||
for property_ in rule.style:
|
for property_ in rule.style:
|
||||||
|
update_property_to_livecarta_convention(rule, property_)
|
||||||
if property_.name not in LIVECARTA_STYLE_ATTRS:
|
|
||||||
rule.style[property_.name] = ''
|
|
||||||
# not remove based on property value
|
|
||||||
elif LIVECARTA_STYLE_ATTRS.get(property_.name):
|
|
||||||
tmp = property_.value.replace('\"', '')
|
|
||||||
if tmp in LIVECARTA_STYLE_ATTRS[property_.name]:
|
|
||||||
if property_.name in LIVECARTA_STYLE_ATTRS_MAPPING:
|
|
||||||
func = LIVECARTA_STYLE_ATTRS_MAPPING[property_.name]
|
|
||||||
tmp = property_.value.replace('\"', '')
|
|
||||||
rule.style[property_.name] = func(tmp)
|
|
||||||
else:
|
|
||||||
rule.style[property_.name] = ''
|
|
||||||
else:
|
|
||||||
if property_.name in LIVECARTA_STYLE_ATTRS_MAPPING:
|
|
||||||
func = LIVECARTA_STYLE_ATTRS_MAPPING[property_.name]
|
|
||||||
tmp = property_.value.replace('\"', '')
|
|
||||||
rule.style[property_.name] = func(tmp)
|
|
||||||
|
|
||||||
css_text = sheet._getCssText().decode()
|
css_text = sheet._getCssText().decode()
|
||||||
return css_text
|
return css_text
|
||||||
|
|
||||||
|
|
||||||
def add_inline_style_to_html_soup(soup1, css_text):
|
def add_inline_style_to_html_soup(soup1, css_text):
|
||||||
livecarta_p_ids = []
|
livecarta_tmp_ids = []
|
||||||
h_regex = f'(^h[{LawCartaConfig.SUPPORTED_LEVELS + 1}-9]$)'
|
h_regex = f'(^h[{LawCartaConfig.SUPPORTED_LEVELS + 1}-9]$)'
|
||||||
for i, x in enumerate(soup1.find_all(re.compile('(^p$)|(^span$)|(^li$)|(^ul$)' + h_regex))):
|
for i, x in enumerate(soup1.find_all(re.compile('(^p$)|(^span$)|(^li$)|(^ul$)|(^ol$)' + h_regex))):
|
||||||
x.attrs['livecarta_id'] = i
|
x.attrs['livecarta_id'] = i
|
||||||
livecarta_p_ids.append(i)
|
livecarta_tmp_ids.append(i)
|
||||||
|
|
||||||
html_with_inline_style = transform(str(soup1), css_text=css_text,
|
html_with_inline_style = transform(str(soup1), css_text=css_text,
|
||||||
remove_classes=False,
|
remove_classes=False,
|
||||||
@@ -146,7 +172,7 @@ def add_inline_style_to_html_soup(soup1, css_text):
|
|||||||
disable_validation=True)
|
disable_validation=True)
|
||||||
soup2 = BeautifulSoup(html_with_inline_style, features='lxml')
|
soup2 = BeautifulSoup(html_with_inline_style, features='lxml')
|
||||||
|
|
||||||
for i in livecarta_p_ids:
|
for i in livecarta_tmp_ids:
|
||||||
tag = soup1.find(attrs={'livecarta_id': i})
|
tag = soup1.find(attrs={'livecarta_id': i})
|
||||||
tag_initial_name = tag.name
|
tag_initial_name = tag.name
|
||||||
tag_with_style = soup2.find(attrs={'livecarta_id': i})
|
tag_with_style = soup2.find(attrs={'livecarta_id': i})
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
from webcolors import html4_hex_to_names, hex_to_rgb, rgb_to_name
|
from webcolors import html4_hex_to_names, hex_to_rgb, rgb_to_name
|
||||||
|
|
||||||
|
|
||||||
def closest_colour_rgb(requested_colour):
|
def closest_colour_rgb(requested_color):
|
||||||
min_colours = {}
|
min_colours = {}
|
||||||
for key, name in html4_hex_to_names.items():
|
for key, name in html4_hex_to_names.items():
|
||||||
r_c, g_c, b_c = hex_to_rgb(key)
|
r_c, g_c, b_c = hex_to_rgb(key)
|
||||||
rd = (r_c - requested_colour[0]) ** 2
|
rd = (r_c - requested_color[0]) ** 2
|
||||||
gd = (g_c - requested_colour[1]) ** 2
|
gd = (g_c - requested_color[1]) ** 2
|
||||||
bd = (b_c - requested_colour[2]) ** 2
|
bd = (b_c - requested_color[2]) ** 2
|
||||||
min_colours[(rd + gd + bd)] = name
|
min_colours[(rd + gd + bd)] = name
|
||||||
|
|
||||||
return min_colours[min(min_colours.keys())]
|
return min_colours[min(min_colours.keys())]
|
||||||
|
|||||||
Reference in New Issue
Block a user