diff --git a/CHANGELOG.md b/CHANGELOG.md index e28e673..952cd75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * All `AuthSrc()` derivatives, deprecated and never used, have been removed. * New module `mat` adds a shallow reimplementation of `Matrix()` in order to implement matrix multiplication * Removed obsolete `configparse` implementation that has been around since 0.3 and shelved since 0.4. -* `color`: added support for conversion from RGB to sRGB +* `color`: added support for conversion from RGB to sRGB, XYZ ## 0.11.2 diff --git a/docs/color.rst b/docs/color.rst new file mode 100644 index 0000000..189a063 --- /dev/null +++ b/docs/color.rst @@ -0,0 +1,19 @@ + +Color +===== + +.. currentmodule:: suou.color + +... + +Web colors +---------- + +.. autoclass:: RGBColor + + +.. autoclass:: WebColor + + +.. autoclass:: XYZColor + diff --git a/docs/generated/suou.codecs.rst b/docs/generated/suou.codecs.rst index 0112a23..0e76eff 100644 --- a/docs/generated/suou.codecs.rst +++ b/docs/generated/suou.codecs.rst @@ -1,4 +1,4 @@ -suou.codecs +suou.codecs =========== .. automodule:: suou.codecs @@ -16,6 +16,7 @@ suou.codecs b64encode cb32decode cb32encode + cb32lencode jsonencode quote_css_string rb64decode diff --git a/docs/generated/suou.color.rst b/docs/generated/suou.color.rst index 03365c4..339e4ed 100644 --- a/docs/generated/suou.color.rst +++ b/docs/generated/suou.color.rst @@ -1,4 +1,4 @@ -suou.color +suou.color ========== .. automodule:: suou.color @@ -9,5 +9,7 @@ suou.color .. autosummary:: Chalk + RGBColor + SRGBColor WebColor \ No newline at end of file diff --git a/docs/generated/suou.flask_sqlalchemy.rst b/docs/generated/suou.flask_sqlalchemy.rst index 458fa6f..dd6a455 100644 --- a/docs/generated/suou.flask_sqlalchemy.rst +++ b/docs/generated/suou.flask_sqlalchemy.rst @@ -1,18 +1,6 @@ -suou.flask\_sqlalchemy +suou.flask\_sqlalchemy ====================== .. automodule:: suou.flask_sqlalchemy - - .. rubric:: Functions - - .. autosummary:: - - require_auth - - .. rubric:: Classes - - .. autosummary:: - - FlaskAuthSrc \ No newline at end of file diff --git a/docs/generated/suou.legal.rst b/docs/generated/suou.legal.rst index f19f6f0..2598387 100644 --- a/docs/generated/suou.legal.rst +++ b/docs/generated/suou.legal.rst @@ -1,6 +1,12 @@ -suou.legal +suou.legal ========== .. automodule:: suou.legal + + .. rubric:: Classes + + .. autosummary:: + + Lawyer \ No newline at end of file diff --git a/docs/generated/suou.peewee.rst b/docs/generated/suou.peewee.rst new file mode 100644 index 0000000..f2c339e --- /dev/null +++ b/docs/generated/suou.peewee.rst @@ -0,0 +1,23 @@ +suou.peewee +=========== + +.. automodule:: suou.peewee + + + .. rubric:: Functions + + .. autosummary:: + + connect_reconnect + + .. rubric:: Classes + + .. autosummary:: + + ConnectToDatabase + PeeweeConnectionState + ReconnectMysqlDatabase + RegexCharField + SiqField + SnowflakeField + \ No newline at end of file diff --git a/docs/generated/suou.strtools.rst b/docs/generated/suou.strtools.rst index 1bc81a1..5ae2742 100644 --- a/docs/generated/suou.strtools.rst +++ b/docs/generated/suou.strtools.rst @@ -1,4 +1,4 @@ -suou.strtools +suou.strtools ============= .. automodule:: suou.strtools @@ -9,4 +9,5 @@ suou.strtools .. autosummary:: PrefixIdentifier + SpitText \ No newline at end of file diff --git a/docs/generated/suou.validators.rst b/docs/generated/suou.validators.rst index b7974a0..4c10573 100644 --- a/docs/generated/suou.validators.rst +++ b/docs/generated/suou.validators.rst @@ -1,4 +1,4 @@ -suou.validators +suou.validators =============== .. automodule:: suou.validators @@ -12,4 +12,5 @@ suou.validators must_be not_greater_than not_less_than + yesno \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 9c3d855..69ab767 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,4 +16,5 @@ ease programmer's QoL and write shorter and cleaner code that works. sqlalchemy iding validators + color api \ No newline at end of file diff --git a/src/suou/__init__.py b/src/suou/__init__.py index 06f5698..2753744 100644 --- a/src/suou/__init__.py +++ b/src/suou/__init__.py @@ -38,13 +38,14 @@ from .http import WantsContentType from .color import chalk, WebColor from .mat import Matrix -__version__ = "0.12.0a3" +__version__ = "0.12.0a4" __all__ = ( 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', 'DictConfigSource', 'EnvConfigSource', 'I18n', 'Incomplete', 'JsonI18n', 'Matrix', 'MissingConfigError', 'MissingConfigWarning', 'PrefixIdentifier', + 'RGBColor', 'SRGBColor', 'Siq', 'SiqCache', 'SiqGen', 'SiqType', 'Snowflake', 'SnowflakeGen', 'StringCase', 'TimedDict', 'TomlI18n', 'UserSigner', 'Wanted', 'WantsContentType', 'WebColor', diff --git a/src/suou/color.py b/src/suou/color.py index dfd2a6d..e8383fb 100644 --- a/src/suou/color.py +++ b/src/suou/color.py @@ -22,6 +22,8 @@ from __future__ import annotations from collections import namedtuple from functools import lru_cache +from suou.mat import Matrix + class Chalk: """ @@ -143,15 +145,26 @@ class RGBColor(namedtuple('_WebColor', 'red green blue')): *New in 0.12.0* """ return SRGBColor(*( - (i / 12.92 if abs(c) <= 0.04045 else - (-1 if i < 0 else 1) * (((abs(c) + 0.55)) / 1.055) ** 2.4) for i in self + (i / 12.92 if abs(i) <= 0.04045 else + (-1 if i < 0 else 1) * (((abs(i) + 0.55)) / 1.055) ** 2.4) for i in self )) + + __add__ = blend_with def __str__(self): return f"rgb({self.red}, {self.green}, {self.blue})" + RGB_TO_XYZ = Matrix([ + [0.41239079926595934, 0.357584339383878, 0.1804807884018343], + [0.21263900587151027, 0.715168678767756, 0.07219231536073371], + [0.01933081871559182, 0.11919477979462598, 0.9505321522496607] + ]) + + def to_xyz(self): + return XYZColor(*(self.RGB_TO_XYZ @ Matrix.as_column(self)).get_column()) + WebColor = RGBColor @@ -160,15 +173,43 @@ WebColor = RGBColor class SRGBColor(namedtuple('_SRGBColor', 'red green blue')): """ - Represent a color in the sRGB-Linear space. + Represent a color in the sRGB space. *New in 0.12.0* - """ + """ + red: float + green: float + blue: float + + def __str__(self): + return f"srgb({self.red}, {self.green}, {self.blue})" + def to_rgb(self): return RGBColor(*( ((-1 if i < 0 else 1) * (1.055 * (abs(i) ** (1/2.4)) - 0.055) if abs(i) > 0.0031308 else 12.92 * i) for i in self)) + def to_xyz(self): + return self.to_rgb().to_xyz() -__all__ = ('chalk', 'WebColor') + + +class XYZColor(namedtuple('_XYZColor', 'x y z')): + """ + Represent a color in the XYZ color space. + """ + + XYZ_TO_RGB = Matrix([ + [ 3.2409699419045226, -1.537383177570094, -0.4986107602930034], + [-0.9692436362808796, 1.8759675015077202, 0.04155505740717559], + [ 0.05563007969699366, -0.20397695888897652, 1.0569715142428786] + ]) + + def to_rgb(self): + return RGBColor(*(self.XYZ_TO_RGB @ Matrix.as_column(self)).get_column()) + + + + +__all__ = ('chalk', 'WebColor', "RGBColor", 'SRGBColor') diff --git a/src/suou/functools.py b/src/suou/functools.py index c68c6b6..e72b689 100644 --- a/src/suou/functools.py +++ b/src/suou/functools.py @@ -341,4 +341,4 @@ def none_pass(func: Callable[_T, _U], *args, **kwargs) -> Callable[_T, _U]: __all__ = ( 'deprecated', 'not_implemented', 'timed_cache', 'none_pass', 'alru_cache' -) \ No newline at end of file +) diff --git a/src/suou/glue.py b/src/suou/glue.py index 6368deb..2ead20b 100644 --- a/src/suou/glue.py +++ b/src/suou/glue.py @@ -66,4 +66,4 @@ def glue(*modules): return decorator # This module is experimental and therefore not re-exported into __init__ -__all__ = ('glue', 'FakeModule') \ No newline at end of file +__all__ = ('glue', 'FakeModule') diff --git a/src/suou/legal.py b/src/suou/legal.py index 8046435..91d9c8b 100644 --- a/src/suou/legal.py +++ b/src/suou/legal.py @@ -95,4 +95,4 @@ class Lawyer(SpitText): return self.format(COMPLETENESS, 'app_name') # This module is experimental and therefore not re-exported into __init__ -__all__ = ('Lawyer',) \ No newline at end of file +__all__ = ('Lawyer',) diff --git a/src/suou/mat.py b/src/suou/mat.py index 4f8f2b9..b0b201b 100644 --- a/src/suou/mat.py +++ b/src/suou/mat.py @@ -116,6 +116,25 @@ class Matrix(Collection[_T]): [self[j, i] for j in range(sx)] for i in range(sy) ) + @classmethod + def as_row(cls, iterable: Iterable): + return cls([[*iterable]]) + + @classmethod + def as_column(cls, iterable: Iterable): + return cls([[x] for x in iterable]) + + def get_column(self, idx = 0): + sx, _ = self.shape() + return [ + self[j, idx] for j in range(sx) + ] + + def get_row(self, idx = 0): + _, sy = self.shape() + return [ + self[idx, j] for j in range(sy) + ] __all__ = ('Matrix', ) diff --git a/src/suou/migrate.py b/src/suou/migrate.py index 357dc03..5cb199c 100644 --- a/src/suou/migrate.py +++ b/src/suou/migrate.py @@ -135,4 +135,4 @@ class UlidSiqMigrator(SiqMigrator): __all__ = ( 'SnowflakeSiqMigrator', 'UlidSiqMigrator' -) \ No newline at end of file +)