Skip to content

Commit

Permalink
added new converters and conversion tests
Browse files Browse the repository at this point in the history
  • Loading branch information
prdx23 committed Sep 10, 2021
1 parent 1755ca5 commit 2e4e315
Show file tree
Hide file tree
Showing 7 changed files with 379 additions and 155 deletions.
142 changes: 142 additions & 0 deletions acrylic/Converters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import colorsys

from acrylic.Defaults import SCHEMAS, PRECISION
from acrylic.color_names import color_names, color_names_reverse


def rgb_to_hsl(rgb):
rgb_format, hsl_format = SCHEMAS['rgb'].format, SCHEMAS['hsl'].format

norm = [x / m[1] for x, m in zip(rgb, rgb_format)]
h, l, s = colorsys.rgb_to_hls(*norm)

hsl = [round(x * m[1], PRECISION) for x, m in zip([h, s, l], hsl_format)]
return SCHEMAS['hsl'].output_type(*hsl)


def rgb_to_hsv(rgb):
rgb_format, hsv_format = SCHEMAS['rgb'].format, SCHEMAS['hsv'].format

norm = [x / m[1] for x, m in zip(rgb, rgb_format)]
h, s, v = colorsys.rgb_to_hsv(*norm)

hsl = [round(x * m[1], PRECISION) for x, m in zip([h, s, v], hsv_format)]
return SCHEMAS['hsl'].output_type(*hsl)


def rgb_to_hex(rgb):
return f'#{"".join(f"{x:02X}" for x in rgb)}'.upper()


def rgb_to_name(rgb):
return color_names_reverse[rgb] if rgb in color_names_reverse else '-'


def rgb_to_ryb(rgb):
# Source:
# https://www.jstage.jst.go.jp/article/tievciieej/5/2/5_110/_pdf/-char/en

rgb_format, ryb_format = SCHEMAS['rgb'].format, SCHEMAS['ryb'].format
rgb_r, rgb_g, rgb_b = [x / m[1] for x, m in zip(rgb, rgb_format)]

white = min(rgb_r, rgb_g, rgb_b)
black = min(1 - rgb_r, 1 - rgb_g, 1 - rgb_b)
rgb_r, rgb_g, rgb_b = [x - white for x in (rgb_r, rgb_g, rgb_b)]

yellow = min(rgb_r, rgb_g)
print(yellow, rgb_r, rgb_g)
ryb_r = rgb_r - yellow
ryb_y = (yellow + rgb_g) / 2
ryb_b = (rgb_b + rgb_g - yellow) / 2

norm = 0
if max(rgb_r, rgb_g, rgb_b) != 0:
norm = max(ryb_r, ryb_y, ryb_b) / max(rgb_r, rgb_g, rgb_b)

ryb = [x / norm if norm > 0 else x for x in (ryb_r, ryb_y, ryb_b)]
ryb = [x + black for x in ryb]

result = [round(x * m[1]) for x, m in zip(ryb, ryb_format)]
return SCHEMAS['ryb'].output_type(*result)


# - - - - - - - - - - - - - -


def hsl_to_rgb(hsl):
rgb_format, hsl_format = SCHEMAS['rgb'].format, SCHEMAS['hsl'].format

(h, s, l) = [x / m[1] for x, m in zip(hsl, hsl_format)]
rgb = colorsys.hls_to_rgb(h, l, s)

rgb = [round(x * m[1]) for x, m in zip(rgb, rgb_format)]
return SCHEMAS['rgb'].output_type(*rgb)


def hsv_to_rgb(hsv):
rgb_format, hsv_format = SCHEMAS['rgb'].format, SCHEMAS['hsv'].format

(h, s, v) = [x / m[1] for x, m in zip(hsv, hsv_format)]
rgb = colorsys.hsv_to_rgb(h, s, v)

rgb = [round(x * m[1]) for x, m in zip(rgb, rgb_format)]
return SCHEMAS['rgb'].output_type(*rgb)


def hex_to_rgb(hex_str):
rgb = [int(hex_str[x:x + 2], 16) for x in range(1, 7, 2)]
return SCHEMAS['rgb'].output_type(*rgb)


def name_to_rgb(name):
if name == '-':
return SCHEMAS['rgb'].output_type(0, 0, 0)
return SCHEMAS['rgb'].output_type(*color_names[name])


def ryb_to_rgb(ryb):
# Source:
# https://www.jstage.jst.go.jp/article/tievciieej/5/2/5_110/_pdf/-char/en

rgb_format, ryb_format = SCHEMAS['rgb'].format, SCHEMAS['ryb'].format
ryb_r, ryb_y, ryb_b = [x / m[1] for x, m in zip(ryb, ryb_format)]

black = min(ryb_r, ryb_y, ryb_b)
white = min(1 - ryb_r, 1 - ryb_y, 1 - ryb_b)
(ryb_r, ryb_y, ryb_b) = (x - black for x in (ryb_r, ryb_y, ryb_b))

green = min(ryb_y, ryb_b)
rgb_r = ryb_r + ryb_y - green
rgb_g = ryb_y + green
rgb_b = 2 * (ryb_b - green)

norm = 0
if max(ryb_r, ryb_y, ryb_b) != 0:
norm = max(rgb_r, rgb_g, rgb_b) / max(ryb_r, ryb_y, ryb_b)

rgb = [x / norm if norm > 0 else x for x in (rgb_r, rgb_g, rgb_b)]
rgb = [x + white for x in rgb]

result = [round(x * m[1]) for x, m in zip(rgb, rgb_format)]
return SCHEMAS['rgb'].output_type(*result)


# - - - - - - - - - - - - - -


rgb_to = {
'hsl': rgb_to_hsl,
'hsv': rgb_to_hsv,
'hex': rgb_to_hex,
'name': rgb_to_name,
'ryb': rgb_to_ryb,
}


rgb_from = {
'hsl': hsl_to_rgb,
'hsv': hsv_to_rgb,
'hex': hex_to_rgb,
'name': name_to_rgb,
'ryb': ryb_to_rgb,
}
10 changes: 8 additions & 2 deletions acrylic/Defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
Ryb = namedtuple('Ryb', 'r y b')

Schema = namedtuple(
'Schema', 'format names length rng input_type output_type'
'Schema', 'format names length rng input_type output_type validation_type'
)

RANDOM = -1
PRECISION = 3
PRECISION = 2


SCHEMAS = {
Expand All @@ -26,6 +26,7 @@
rng=lambda a, b: randint(a, b),
input_type=int,
output_type=Rgb,
validation_type='values',
),
'hsl': Schema(
format=Hsl((0, 360.0), (0, 100.0), (0, 100.0)),
Expand All @@ -34,6 +35,7 @@
rng=lambda a, b: round(uniform(a, b), PRECISION),
input_type=float,
output_type=Hsl,
validation_type='values',
),
'hsv': Schema(
format=Hsv((0, 360.0), (0, 100.0), (0, 100.0)),
Expand All @@ -42,6 +44,7 @@
rng=lambda a, b: round(uniform(a, b), PRECISION),
input_type=float,
output_type=Hsv,
validation_type='values',
),
'ryb': Schema(
format=Ryb((0, 255), (0, 255), (0, 255)),
Expand All @@ -50,6 +53,7 @@
rng=lambda a, b: randint(a, b),
input_type=int,
output_type=Ryb,
validation_type='values',
),
'hex': Schema(
format=re.compile(r''.join([
Expand All @@ -64,6 +68,7 @@
rng='#' + ''.join(choice('0123456789ABCDEF') for _ in range(6)),
input_type=str,
output_type=lambda x: f'#{x.upper()}',
validation_type='string',
),
'name': Schema(
format=color_names,
Expand All @@ -72,5 +77,6 @@
rng=choice(list(color_names.keys())),
input_type=str,
output_type=str,
validation_type='string',
),
}
16 changes: 11 additions & 5 deletions acrylic/Validator.py → acrylic/Validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
from acrylic.Defaults import RANDOM, PRECISION, SCHEMAS


def validate(value, colorspace):
if SCHEMAS[colorspace].validation_type == 'values':
return validate_values(value, colorspace)
if SCHEMAS[colorspace].validation_type == 'string':
return validate_string(value, colorspace)


def in_range(x, a, b, p):
if x < a or x > b:
raise ValueError(f'{p!r} should be in range {a} - {b}')
Expand Down Expand Up @@ -106,18 +113,17 @@ def validate_string(value, colorspace):
value = check_datatype(schema.input_type, value, colorspace)

if colorspace == 'hex':
match = schema.format.match(value)
if match and match.group('hex'):
match = schema.format.match(value, 0, 10)
if match and match.lastgroup == 'hex':
return schema.output_type(match.group('hex'))
elif match and match.group('hex_alpha'):
elif match and match.lastgroup == 'hex_alpha':
return schema.output_type(match.group('hex_alpha'))
elif match and match.group('hex_short'):
elif match and match.lastgroup == 'hex_short':
extended = ''.join(f'{x}{x}' for x in match.group('hex_short'))
return schema.output_type(extended)

if colorspace == 'name':
value = ''.join(value.strip().lower().split())
print(value)
if value in schema.format:
return schema.output_type(value)

Expand Down
Loading

0 comments on commit 2e4e315

Please sign in to comment.