From 09d9e46a899add1f2e6eabad7094051b56b74781 Mon Sep 17 00:00:00 2001 From: themanyfaceddemon Date: Sun, 28 Jul 2024 23:50:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B5=D0=B1=D0=BE=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=B0=D1=8F=20=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D1=83=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 ++- Code/systems/texture_system/__init__.py | 3 + Code/systems/texture_system/color.py | 58 +++++++++++++++++++ Code/systems/texture_system/texture_system.py | 54 +++++------------ Tests/Texture/TextureSystem.py | 20 +------ 5 files changed, 82 insertions(+), 60 deletions(-) create mode 100644 Code/systems/texture_system/color.py diff --git a/.gitignore b/.gitignore index 06ec1a8..3590828 100644 --- a/.gitignore +++ b/.gitignore @@ -19,12 +19,13 @@ venv.bak/ .vs/* .vscode/* -# Data -[Dd]ata/* +# Server data Content/Servers/* # Texture -Sprites/ +Content/Compiled/* +*_compiled*.gif +*_compiled*.png # PyQT6 *_ui.py diff --git a/Code/systems/texture_system/__init__.py b/Code/systems/texture_system/__init__.py index 76df2f1..ff1c5e5 100644 --- a/Code/systems/texture_system/__init__.py +++ b/Code/systems/texture_system/__init__.py @@ -1 +1,4 @@ +from systems.texture_system.color import Color from systems.texture_system.texture_system import TextureSystem + +__all__ = ['Color', 'TextureSystem'] diff --git a/Code/systems/texture_system/color.py b/Code/systems/texture_system/color.py new file mode 100644 index 0000000..24e7e74 --- /dev/null +++ b/Code/systems/texture_system/color.py @@ -0,0 +1,58 @@ +class Color: + __slots__ = ['_r', '_g', '_b', '_a'] + + def __init__(self, r: int, g: int, b: int, a: int) -> None: + self.r = r + self.g = g + self.b = b + self.a = a + + @property + def r(self) -> int: + return self._r + + @r.setter + def r(self, value: int) -> None: + if not (0 <= value <= 255): + raise ValueError("Invalid value for r. It must be between 0 and 255") + + self._r = value + + @property + def g(self) -> int: + return self._g + + @g.setter + def g(self, value: int) -> None: + if not (0 <= value <= 255): + raise ValueError("Invalid value for g. It must be between 0 and 255") + + self._g = value + + @property + def b(self) -> int: + return self._b + + @b.setter + def b(self, value: int) -> None: + if not (0 <= value <= 255): + raise ValueError("Invalid value for b. It must be between 0 and 255") + + self._b = value + + @property + def a(self) -> int: + return self._a + + @a.setter + def a(self, value: int) -> None: + if not (0 <= value <= 255): + raise ValueError("Invalid value for a. It must be between 0 and 255") + + self._a = value + + def __str__(self) -> str: + return f"{self.r}_{self.g}_{self.b}_{self.a}" + + def __repr__(self) -> str: + return f"Color(r={self.r}, g={self.g}, b={self.b}, a={self.a})" diff --git a/Code/systems/texture_system/texture_system.py b/Code/systems/texture_system/texture_system.py index 0b101e0..d95888e 100644 --- a/Code/systems/texture_system/texture_system.py +++ b/Code/systems/texture_system/texture_system.py @@ -5,6 +5,8 @@ import yaml from PIL import Image, ImageSequence +from root_path import ROOT_PATH +from systems.texture_system.color import Color class TextureSystem: @@ -12,7 +14,7 @@ class TextureSystem: """ __slots__ = [] DEFAULT_FPS: int = 24 - DEFAULT_COLOR: Tuple[int, int, int, int] = (255, 255, 255, 255) + DEFAULT_COLOR: Color = Color(255, 255, 255, 255) @staticmethod def _get_hash_list(layers: List[Dict[str, Any]]) -> str: @@ -54,32 +56,6 @@ def _slice_image(image: Image.Image, frame_width: int, frame_height: int, num_fr return frames - @staticmethod - def _get_color_str(color: Tuple[int, int, int, int]) -> str: - """Возвращает строковое представление цвета. - - Args: - color (Tuple[int, int, int, int]): Цвет в формате RGBA. - - Returns: - str: Строковое представление цвета. - """ - TextureSystem._validate_color(color) - return '_'.join(map(str, color)) - - @staticmethod - def _validate_color(color: Tuple[int, int, int, int]) -> None: - """Проверяет, что цвет в формате RGBA имеет корректные значения. - - Args: - color (Tuple[int, int, int, int]): Цвет в формате RGBA. - - Raises: - ValueError: Если значения цвета находятся вне диапазона 0-255. - """ - if not all(0 <= c <= 255 for c in color): - raise ValueError("Invalid RGBA color format for texture. All values must be between 0 и 255") - @staticmethod def get_textures(path: str) -> List[Dict[str, Any]]: """Загружает текстуры из указанного пути. @@ -93,7 +69,7 @@ def get_textures(path: str) -> List[Dict[str, Any]]: with open(f"{path}/info.yml", 'r') as file: info = yaml.safe_load(file) - return info.get('Sprites', []) + return info.get('Texture', []) @staticmethod def get_state_info(path: str, state: str) -> Tuple[int, int, int, bool]: @@ -112,7 +88,7 @@ def get_state_info(path: str, state: str) -> Tuple[int, int, int, bool]: with open(f"{path}/info.yml", 'r') as file: info = yaml.safe_load(file) - info = info.get('Sprites', []) + info = info.get('Texture', []) sprite_info = next((sprite for sprite in info if sprite['name'] == state), None) if not sprite_info: @@ -126,13 +102,13 @@ def get_state_info(path: str, state: str) -> Tuple[int, int, int, bool]: return frame_width, frame_height, num_frames, is_mask @staticmethod - def _get_compiled(path: str, state: str, color: Optional[Tuple[int, int, int, int]] = None, is_gif: bool = False) -> Union[Image.Image, List[Image.Image], None]: + def _get_compiled(path: str, state: str, color: Optional[Color] = None, is_gif: bool = False) -> Union[Image.Image, List[Image.Image], None]: """Проверяет наличие компилированного изображения или GIF. Args: path (str): Путь к файлу. state (str): Имя состояния. - color (Optional[Tuple[int, int, int, int]], optional): Цвет в формате RGBA. По умолчанию None. + color (Optional[Color], optional): Цвет в формате RGBA. По умолчанию None. is_gif (bool, optional): Указывает, является ли изображение GIF. По умолчанию False. Returns: @@ -140,7 +116,7 @@ def _get_compiled(path: str, state: str, color: Optional[Tuple[int, int, int, in """ image_path: str = f"{path}/{state}" if color: - image_path += f"_compiled_{TextureSystem._get_color_str(color)}" + image_path += f"_compiled_{color}" image_path += ".gif" if is_gif else ".png" @@ -155,13 +131,13 @@ def _get_compiled(path: str, state: str, color: Optional[Tuple[int, int, int, in return None @staticmethod - def get_image_recolor(path: str, state: str, color: Tuple[int, int, int, int] = DEFAULT_COLOR) -> Image.Image: + def get_image_recolor(path: str, state: str, color: Color = DEFAULT_COLOR) -> Image.Image: """Возвращает перекрашенное изображение указанного состояния. Args: path (str): Путь к файлу. state (str): Имя состояния. - color (Tuple[int, int, int, int], optional): Цвет в формате RGBA. По умолчанию DEFAULT_COLOR. + color (Color, optional): Цвет в формате RGBA. По умолчанию DEFAULT_COLOR. Returns: Image.Image: Перекрашенное изображение. @@ -183,7 +159,7 @@ def get_image_recolor(path: str, state: str, color: Tuple[int, int, int, int] = ] image.putdata(new_colored_image) - image.save(f"{path}/{state}_compiled_{TextureSystem._get_color_str(color)}.png") + image.save(f"{path}/{state}_compiled_{color}.png") return image @staticmethod @@ -207,13 +183,13 @@ def get_image(path: str, state: str) -> Image.Image: raise FileNotFoundError(f"Image file for state '{state}' not found in path '{path}'.") @staticmethod - def get_gif_recolor(path: str, state: str, color: Tuple[int, int, int, int] = DEFAULT_COLOR, fps: int = DEFAULT_FPS) -> List[Image.Image]: + def get_gif_recolor(path: str, state: str, color: Color = DEFAULT_COLOR, fps: int = DEFAULT_FPS) -> List[Image.Image]: """Возвращает перекрашенный GIF указанного состояния. Args: path (str): Путь к файлу. state (str): Имя состояния. - color (Tuple[int, int, int, int], optional): Цвет в формате RGBA. По умолчанию DEFAULT_COLOR. + color (Color, optional): Цвет в формате RGBA. По умолчанию DEFAULT_COLOR. fps (int, optional): Частота кадров. По умолчанию DEFAULT_FPS. Returns: @@ -229,7 +205,7 @@ def get_gif_recolor(path: str, state: str, color: Tuple[int, int, int, int] = DE frames = TextureSystem._slice_image(image, frame_width, frame_height, num_frames) - output_path = f"{path}/{state}_compiled_{TextureSystem._get_color_str(color)}.gif" + output_path = f"{path}/{state}_compiled_{color}.gif" frames[0].save(output_path, save_all=True, append_images=frames[1:], duration=1000//fps, loop=0) return frames @@ -289,7 +265,7 @@ def merge_layers(layers: List[Dict[str, Any]], fps: int = DEFAULT_FPS) -> Union[ Returns: Union[Image.Image, List[Image.Image]]: Объединенное изображение или список кадров GIF. """ - base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'Sprites', 'compiled')) + base_path = os.path.join(ROOT_PATH, 'Content', 'Compiled') if not os.path.exists(base_path): os.makedirs(base_path) diff --git a/Tests/Texture/TextureSystem.py b/Tests/Texture/TextureSystem.py index 62751e4..9d71949 100644 --- a/Tests/Texture/TextureSystem.py +++ b/Tests/Texture/TextureSystem.py @@ -12,13 +12,13 @@ class TestTextureSystem(unittest.TestCase): def setUp(self): - self.test_dir = 'test_sprites' + self.test_dir = 'test_texture' os.makedirs(self.test_dir, exist_ok=True) self.compiled_dir = os.path.abspath(os.path.join(self.test_dir, 'compiled')) os.makedirs(self.compiled_dir, exist_ok=True) info_data = { - 'Sprites': [ + 'Texture': [ { 'name': 'state1', 'size': {'x': 100, 'y': 100}, @@ -68,22 +68,6 @@ def test_get_hash_list(self): expected_hash = hashlib.sha256(pickle.dumps(layers)).hexdigest() self.assertEqual(TextureSystem._get_hash_list(layers), expected_hash) - def test_get_color_str(self): - color = (255, 128, 64, 32) - expected_str = '255_128_64_32' - self.assertEqual(TextureSystem._get_color_str(color), expected_str) - - def test_validate_color(self): - valid_color = (255, 128, 64, 32) - try: - TextureSystem._validate_color(valid_color) - except ValueError: - self.fail("_validate_color raised ValueError unexpectedly!") - - invalid_color = (256, 128, 64, 32) - with self.assertRaises(ValueError): - TextureSystem._validate_color(invalid_color) - def test_slice_image(self): image = Image.new('RGBA', (450, 150), 'white') frames = TextureSystem._slice_image(image, 150, 150, 3)