Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "scrolltext_gif"
version = "0.8.30"
version = "0.9.0"
description = "Module for generating gif-s with scrolling vertical text"
authors = ["Artemii <angap4@gmail.com>"]
license = "MIT"
Expand Down
152 changes: 88 additions & 64 deletions scrolltext_gif/__main__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from PIL import Image, ImageDraw, ImageFont
import json
import argparse as prs
import seaborn as sns
from PIL import Image, ImageDraw, ImageFont, ImageColor
from PIL.ImageFont import FreeTypeFont

from scrolltext_gif.vertical import draw_vertical
Expand Down Expand Up @@ -69,23 +69,36 @@ def is_valid_color(color: str |
Проверка на корректность цвета + его преобразование из float в int.
:param color:
:return: Цвет в корректной форме.
:raises: TypeError
:raises: TypeError, ValueError

"""
if isinstance(color, str):
return color
# TODO: Сделать проверку на корректность str цвета.
# Или же просто не говорить о возможности ввода цвета через str...
if color.startswith("#"):
if len(color[1:]) == 6 and color[1:].isalnum() and all(
char.isdigit() or char.lower() in 'abcdef' for char in color[1:]):
return color
raise ValueError("Неверное HEX значение цвета")
elif color in ImageColor.colormap.keys():
return color
raise TypeError("Неверное наименование цвета в кавычках")

elif isinstance(color, list):
if isinstance(color[0], int) and isinstance(color[1], int) and isinstance(color[2], int):
if all((isinstance(color_element, int) and 0 <= color_element <= 255) for color_element in color[0:3]):
if len(color) == 3:
return tuple(color)

elif len(color) == 4:
if isinstance(color[3], int):
if isinstance(color[3], int) and 0 <= color[3] <= 255:
return tuple(color)
elif isinstance(color[3], float):
elif isinstance(color[3], float) and 0 <= color[3] <= 1:
color[3] = int(color[3] * max_color_val)
return tuple(color)
else:
raise ValueError("У вас сломалось 4-е значение в списке")
raise ValueError("Неверное количество параметров в RGB")

raise TypeError("Неверно набран RGB")

elif color is None:
return None
else:
Expand All @@ -100,28 +113,16 @@ def is_valid_color(color: str |
default="output", help='Название выходного файла')

if __name__ == '__main__':

# Ввод параметров
args = parser.parse_args()

with open(args.config_path) as f:
data = json.load(f)

color_background = data['color_background']
"""Цвет фона"""

color_main_text = data['color_main_text']
"""Цвет текста"""

if color_background == "" or color_background == []:
color_background = (250, 250, 250)
else:
color_background = is_valid_color(color_background)

if color_main_text == "" or color_main_text == []:
color_main_text = (0, 0, 0)
else:
color_main_text = is_valid_color(color_main_text)

# Обработка шрифта
font_size = data['font_size']
"""Размер шрифта"""
if data["font"] == "":
Expand All @@ -131,6 +132,7 @@ def is_valid_color(color: str |
global_font = ImageFont.truetype(data["font"], font_size)
"""Шрифт"""

# Обработка размеров
height, width = data['height'], data['width']

# Старая версия с пропорциями
Expand All @@ -139,46 +141,11 @@ def is_valid_color(color: str |
## TODO: Разобраться с пропорциями.
## Или заставить человека самостоятельно вводить разрешение...

count_colorless = 0
"""Количество людей без цвета"""
name_list: list[
list[str, str | list[int, int, int] | list[int, int, int, float] | list[int, int, int, int] | None]] = []

for human_name in data['people']:
color = data['people'][human_name]
if color == "" or color == []:
count_colorless += 1
color = None
color = is_valid_color(color)
name_list.append([human_name.encode("windows-1251").decode("utf-8"), color])
max_len_name = max([global_font.getlength(human[0]) for human in name_list])
"""Длина самого длинного имени"""

color_palette = "magma"
if data['color_palette'] != "" and data['color_palette'] != []:
color_palette = data['color_palette']
rgb_values = [tuple(int(layer * 255) for layer in color) for color in
sns.color_palette(color_palette, n_colors=count_colorless)]
"""Генерация RGB-значений для людей без указанного цвета"""
# TODO: Сделать более плавную расстановку цвета через "ёлочку"
# Вверх-вниз

people_list: list[Person] = []
"""Список людей"""

border = data['border']
"""Отступ от левой стенки"""
start_pos_x = global_font.getlength(data['first_part'].encode("windows-1251").decode("utf-8")) + border
"""Стартовая позиция для написания имени"""

iter = 0
for human in name_list:
if human[1] is None:
human[1] = rgb_values[iter]
iter += 1
people_list.append(Person(human[0], human[1], global_font, start_pos_x, max_len_name))
# for person in people_list: print(person)

diff_pos_y = font_size + font_size // 16
"""Разница в позициях между строками текста.

Expand All @@ -193,27 +160,84 @@ def is_valid_color(color: str |
# На font_size=150 и 1920x1200 // 4 работает корректно. Ставит в центр Name4.
# На других раскладках ломается

step = 5
"""Сдвиг строк"""

start_pos_y = height - font_size - font_size // 16
"""Нижняя позиция."""

end_pos = start_pos_y - diff_pos_y * (len(name_list) - 1)
end_pos = start_pos_y - diff_pos_y * (len(data['people']) - 1)
"""Верхняя позиция.

В неё переносится текст после выхода за нижнюю часть экрана."""
# ! TODO: При малом количестве имён, спавнится внутри картинки.
# TODO: При малом количестве имён, спавнится внутри картинки.
# Реализовать корректный спавн за границами картинки.
# Вообще, надо сделать размещение не от низа картинки, а от центра

# Обработка основных цветов
if color_background == "" or color_background == []:
color_background = (250, 250, 250)
else:
color_background = is_valid_color(color_background)
if color_main_text == "" or color_main_text == []:
color_main_text = (0, 0, 0)
else:
color_main_text = is_valid_color(color_main_text)

# Обработка цветов людей
count_colorless = 0
"""Количество людей без цвета"""
name_list: list[
list[str, str | list[int, int, int] | list[int, int, int, float] | list[int, int, int, int] | None]] = []
for human_name in data['people']:
color = data['people'][human_name]
if color == "" or color == []:
count_colorless += 1
color = None
color = is_valid_color(color)
name_list.append([human_name.encode("windows-1251").decode("utf-8"), color])
max_len_name = max([global_font.getlength(human[0]) for human in name_list])
"""Длина самого длинного имени"""

# Генерация палитры
color_palette = "magma"
if data['color_palette'] != "" and data['color_palette'] != []:
color_palette = data['color_palette']
rgb_values = [tuple(int(layer * 255) for layer in color) for color in
sns.color_palette(color_palette, n_colors=(
count_colorless // 2 if count_colorless % 2 != 0 else count_colorless // 2 - 1) + 1)]
"""Генерация RGB-значений для людей без указанного цвета"""
# TODO: Сделать возможность вводить "Стандартный цвет". Такой цвет, который будет использован для людей без цвета.
# Если такой параметр включён, не генерировать цвета.

# Создание людей
people_list: list[Person] = []
"""Список людей"""

iter = 0
middle = len(name_list) // 2 if len(name_list) % 2 != 0 else len(name_list) // 2 - 1
"""Последний индекс левой половины"""
if len(rgb_values) != 0:
for human in name_list:
if human[1] is None:
if iter > middle:
human[1] = rgb_values[middle - (iter - middle)]
else:
human[1] = rgb_values[iter]
iter += 1
people_list.append(Person(human[0], human[1], global_font, start_pos_x, max_len_name))
else:
for human in name_list:
people_list.append(Person(human[0], human[1], global_font, start_pos_x, max_len_name))
# for person in people_list: print(person)
# ! DEBUG

for i, item in enumerate(people_list):
item.coords[1] = start_pos_y - diff_pos_y * i

step = 5
"""Сдвиг строк"""

percentile = diff_pos_y // step
"""Вычисление количества шагов, необходимых для того, чтобы текст вышел за нижнюю границу картинки"""
# print(percentile, diff_pos_y / step)
#! Debug
# ! Debug
count_cycles = len(name_list) - 0
"""Количество прокруток.

Expand Down