Skip to content

Commit

Permalink
Version 1.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
AntynK committed Apr 6, 2024
1 parent 83bfde3 commit f8869e5
Show file tree
Hide file tree
Showing 49 changed files with 515 additions and 712 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ thumbnails/
__pycache__/
*.py[cod]
*$py.class
logs/

# C extensions
*.so
Expand Down
Binary file removed Art convertor.exe
Binary file not shown.
Binary file removed Colouring art.exe
Binary file not shown.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 AntynK
Copyright (c) 2024 Andrii Karandashov(AntynK)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
45 changes: 27 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,45 @@
# Colouring art
#### [Українська версія](README_UA.md)

It is a simple time killer game, in which you have to paint an image.

## Setup
Firstly you need to download Colouring art.exe(or source code) and assets.bak file, after that run .exe file or source code(file colouring_art.pyw), the game will create some folders.
Firstly you need to download `Colouring art.exe`(or source code) and `assets.bak` file, after that run .exe file or source code(`colouring_art.pyw`), the game will create some folders.

File `assets.bak` must be in the same folder as game. This file constains all fonts and images for game.

In the game by default there are 2 images, but you can add your images.
(They are in the arts folder).

## Adding custom images
You can use the Art convertor.exe(or art_converter.py) utility, it is a simple console program which by default converts images from input folder to output folder. You can change the input folder with flag -i and the output folder with flag -o(output directory will be created automatically if it does not exist).
You can use [pickart](https://pypi.org/project/Pickart/) module to convert PNG files.
Put converted images(.pickart) in categories folder(`arts\<category_name>`).

## About .pickart file
Game uses .pickart files(pick - name of python built-in module [pickle](https://docs.python.org/3.9/library/pickle.html)), files are compressed with [gzip](https://docs.python.org/3.9/library/gzip.html).
## Adding custom categories
By default game has one category `plants` with two images. You can change existing category or add new one.

File structure:
### Category structure
All categories are located in `arts` folder.

```
<category_name>
|-icon.png
|-style.json
|-*.pickart
```
`icon.png` - image that will be displayed on main window. If it is omitted game will use default image.

`style.json` - category style. Configures background colour.

`*.pickart` - [Pickart file](https://pypi.org/project/Pickart/) with any name(with extension `.pickart`). Category can have multiple `*.pickart` files.

### `style.json` file structure
```Python
{
"info":{
"size": (1, 1),
"version": 1
},
"palette":[(int, int, int), ...],
"pixels": [
[(color_index, is_painted), ...]
]
"bg": [red, green, blue, alpha]
}
```
"info" contains the size of image and version of file.

"palette" contains tuples with 3 ints (r, g, b), they must be less or equal 255 and bigger or equal 0.
`bg` - list of integers in range from 0 to 255(including). `alpha` - optional.

"pixels" is a 2d array which contains color_index(int) and painted(bool).

## Security
[Pickle](https://docs.python.org/3.9/library/pickle.html) module has security issues, the game does not use standard pickle.load(), instead it uses [restricted loader](https://docs.python.org/3/library/pickle.html#restricting-globals) which blocks all external classes.
46 changes: 46 additions & 0 deletions README_UA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Colouring art
#### [English version](README.md)

Це гра вбивач часу, де ви маєте розмальовувати зображення.

## Налаштування
Для початку потрібно завантажити файл `Colouring art.exe`(або вихідний код) та файл `assets.bak`, після чого запустіть .exe(або `colouring_art.pyw`).

Файл `assets.bak` має бути в тій самій папці що й гра, бо в цьому файлі містяться всі шрифти та зображення які використовує гра.

У грі за замовчування є 2 зображення, але ви можете додавати свої.

## Додавання своїх зображень
Ви можете використати модуль [pickart](https://pypi.org/project/Pickart/) для конвертації PNG зображень.
Конвертовані зображення потрібно покласти у папку категорії(`arts\<category_name>`)

## Додавання своїх категорій
За замовчуванням у грі є одна категорія `plants` з двома зображеннями дерев. Ви можете змінити існуючу категорію або додати нову.

### Структура категорії
Всі категорії зберігаються у папці `arts`.

```
<назва_категорії>
|-icon.png
|-style.json
|-*.pickart
```

`icon.png` - це зображення яке буде відображаться на головному екрані, якщо його не буде то гра поставить зображення за замовчуванням.

`style.json` - це стиль категорії, налаштовує колір заднього фону категорії.

`*.pickart` - [Pickart файл](https://pypi.org/project/Pickart/) з любою назвою(важливо щоби розширення було `.pickart`) їх може бути довільна кількість.

### Структура файла `style.json`
```Python
{
"bg": [red, green, blue, alpha]
}
```
`bg` - це список з цілих чисел в діапазоні від 0 до 255(включно). `alpha` - не обов'язкова.


## Безпека
Модуль [pickle](https://docs.python.org/3.9/library/pickle.html) має проблеми з безпекою, гра використовує нестандартну версію pickle.load(), a [обмежений завантажувавч](https://docs.python.org/3/library/pickle.html#restricting-globals) який дозволяє зберігати лише базові типи(Неповний перелік: int, str, list, dict, tuple, set).
39 changes: 0 additions & 39 deletions art_converter.py

This file was deleted.

Binary file removed arts/progress.dat
Binary file not shown.
Binary file modified assets.bak
Binary file not shown.
File renamed without changes
2 changes: 1 addition & 1 deletion colouring_art.pyw
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ from engine.game import Game

game = Game()

game.start()
game.start()
21 changes: 0 additions & 21 deletions converter/LICENSE

This file was deleted.

48 changes: 0 additions & 48 deletions converter/convert_to_pickart.py

This file was deleted.

30 changes: 0 additions & 30 deletions converter/convert_to_png.py

This file was deleted.

Empty file added engine/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions engine/assets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .image_cacher import ImageCacher
from .load import load_font, load_image
8 changes: 5 additions & 3 deletions engine/image/cache.py → engine/assets/image_cacher.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from pathlib import Path

import pygame


class ImageCacher:
_cache: dict[str, pygame.surface.Surface] = {}
_cache: dict[Path, pygame.surface.Surface] = {}

@classmethod
def __call__(cls, func):
def wrapper(*args, **kwargs):
key: str = args[0]
key = args[0]
if result := cls._cache.get(key):
return result
result = func(*args, **kwargs)
Expand All @@ -17,5 +19,5 @@ def wrapper(*args, **kwargs):
return wrapper

@classmethod
def delete_cache(cls, key: str):
def delete_cache(cls, key: Path):
del cls._cache[key]
37 changes: 37 additions & 0 deletions engine/assets/load.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import Optional
from pathlib import Path

import pygame

from engine.assets import ImageCacher
from engine.logger import logger
from engine.file_checker import check_assets_file
from engine.static_variables import AssetsFiles


@ImageCacher()
def load_image(
filename: Path, image_size: Optional[int] = None, is_external=False
) -> pygame.surface.Surface:
if not is_external:
check_assets_file(filename)

try:
image: pygame.surface.Surface = pygame.image.load(filename).convert_alpha()
except Exception as e:
logger.error(f"Cannot load image: '{filename}', error: {e}.")
image = load_image(AssetsFiles.DEFAULT_IMG)

if image_size:
image = pygame.transform.scale(image, (image_size, image_size))
return image


def load_font(filename: Path, font_size: int) -> pygame.font.Font:
check_assets_file(filename)
try:
font = pygame.font.Font(filename, font_size)
except Exception as e:
logger.error(f"Cannot load font: '{filename}', error: {e}.")
font = pygame.font.SysFont("Arial", font_size)
return font
35 changes: 35 additions & 0 deletions engine/category_style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import json
from typing import Any
from pathlib import Path

from engine.static_variables import ARTS_DIR
from engine.logger import logger
from engine.colours import CATEGORY_COLOUR, GRAY_COLOUR


class Style:
def __init__(self, category_name: str) -> None:
self.path = Path(ARTS_DIR, category_name, "style.json")
self.category_name = category_name
self._data = {}
self._load()

def _load(self):
CATEGORY_COLOUR.update(GRAY_COLOUR)
try:
self._data: dict[str, Any] = json.loads(self.path.read_text("utf-8"))
self._parse()
except Exception as error:
logger.error(f"Cannot load style: '{self.path}', error: {error}.")

def _parse(self):
if not isinstance(self._data, dict):
raise ValueError("Style config file must start with dict object.")
colour = self._data.get("bg")
if not isinstance(colour, list) or len(colour) not in {3, 4}:
raise ValueError(f"Wrong colour format: {colour}.")

for c in colour:
if c < 0 or c > 255:
raise ValueError(f"Wrong colour format: {colour}.")
CATEGORY_COLOUR.update(colour)
Loading

0 comments on commit f8869e5

Please sign in to comment.