diff --git a/README.md b/README.md
index 53d228f..776222f 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,7 @@
Генерирует SVG халфтоновый эффект из изображения с анимацией мерцания точек.
Например:
-
-
+
## Что делает
@@ -48,4 +47,4 @@ poetry run python main.py img/img_2.jpg
или наоборот ""распустить")
- `fill:#80000090` -- цвет точек (с прозрачностью)
-
+
diff --git a/img/cc.svg b/img/cc.svg
new file mode 100644
index 0000000..4a7ed92
--- /dev/null
+++ b/img/cc.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/img/img_2.jpg b/img/img_2.jpg
deleted file mode 100644
index 9efaeab..0000000
Binary files a/img/img_2.jpg and /dev/null differ
diff --git a/img/img_2j.svg b/img/img_2j.svg
deleted file mode 100644
index b3a1841..0000000
--- a/img/img_2j.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/img/lp.svg b/img/lp.svg
new file mode 100644
index 0000000..278e2e0
--- /dev/null
+++ b/img/lp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/img/lp_8j.svg b/img/lp_8j.svg
deleted file mode 100644
index dc96562..0000000
--- a/img/lp_8j.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/main.py b/main.py
index 0874ab4..382b8a9 100644
--- a/main.py
+++ b/main.py
@@ -8,7 +8,7 @@ def encode_to_base36(num):
if num < 0:
raise ValueError("Number must be non-negative")
- charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
if num < len(charset):
return charset[num]
@@ -19,8 +19,9 @@ def encode_to_base36(num):
return ''.join(reversed(result))
-def generate_halftone_svg(image_path, output_path, cols=80, max_radius=6, animation_variants=12):
+def generate_halftone_svg(image_path, output_path, cols=80, max_radius=8, animation_variants=12):
import random
+ from collections import defaultdict
img = Image.open(image_path).convert('L')
aspect_ratio = img.height / img.width
@@ -31,14 +32,21 @@ def generate_halftone_svg(image_path, output_path, cols=80, max_radius=6, animat
width = cols * step
height = rows * step
- svg_elements = []
-
# Генерируем CSS-классы для разных задержек
animation_classes = []
for i in range(animation_variants):
delay = (i / animation_variants) * 3
encoded_i = encode_to_base36(i)
- animation_classes.append(f".a{encoded_i}{{--d:{delay:.2f}s}}")
+ # Убрать .0 для целых чисел: 1.0s → 1s
+ if delay == int(delay):
+ delay_str = f"{int(delay)}"
+ else:
+ delay_str = f"{delay:.1f}".lstrip('0')
+ animation_classes.append(f".{encoded_i}{{--d:{delay_str}s}}")
+
+ # Собираем элементы группируя по классам: {class: [(radius, cx, cy), ...]}
+ elements_by_class = defaultdict(list)
+ unique_radii = set()
for y in range(rows):
for x in range(cols):
@@ -48,20 +56,41 @@ def generate_halftone_svg(image_path, output_path, cols=80, max_radius=6, animat
if factor < 0.15:
continue
- radius = factor * max_radius
+ radius = int(factor * max_radius)
+ if radius == 0:
+ continue
+
cx = x * step + step // 2
cy = y * step + step // 2
- # Каждой точке свой класс с уникальной задержкой
anim_class = random.randint(0, animation_variants - 1)
encoded_class = encode_to_base36(anim_class)
- svg_elements.append(
- f''
- )
+
+ elements_by_class[encoded_class].append((radius, cx, cy))
+ unique_radii.add(radius)
+
+ # Создаем с определениями кружков для каждого радиуса
+ defs = ''
+ for radius in sorted(unique_radii):
+ encoded_radius = encode_to_base36(radius)
+ defs += f''
+ defs += ''
+
+ # Создаем группы по классам
+ groups = []
+ for anim_class in sorted(elements_by_class.keys()):
+ group_elements = elements_by_class[anim_class]
+ uses = ''.join(
+ f''
+ for radius, cx, cy in group_elements
+ )
+ if uses:
+ groups.append(f'{uses}')
animation_css = "".join(animation_classes)
+ groups_html = "".join(groups)
- svg_template = f""""""
+ svg_template = f''''''
with open(output_path, 'w') as f:
f.write(svg_template)
@@ -69,4 +98,4 @@ def generate_halftone_svg(image_path, output_path, cols=80, max_radius=6, animat
if __name__ == '__main__':
file_name_in = sys.argv[-1]
- generate_halftone_svg(file_name_in, f'{file_name_in.split(".")[0]}j.svg', cols=90, max_radius=5)
+ generate_halftone_svg(file_name_in, f'{file_name_in.split(".")[0]}j.svg', cols=63, max_radius=7)