Skip to content

Commit bc7549a

Browse files
authored
Merge pull request #3 from soda480/0.1.3
0.1.3
2 parents 05d5bcb + 437aac5 commit bc7549a

File tree

9 files changed

+57
-28
lines changed

9 files changed

+57
-28
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pip install ascii_animator
1717
### Usage
1818
```
1919
ascii-art-animator --help
20-
usage: ascii-art-animator [-h] [-s SPEED] [-f FILE] [-d]
20+
usage: ascii-art-animator [-h] [-s SPEED] [-f FILE] [-d] [-a] [-m MAX_LOOPS]
2121
2222
Ascii Art Animator from GIF
2323
@@ -27,6 +27,9 @@ optional arguments:
2727
speed of the animation: very_slow, slow, normal, fast (default normal)
2828
-f FILE, --file FILE the path to a gif file
2929
-d, --debug display debug messages to stdout
30+
-a, --show_axis display the grid axis
31+
-m MAX_LOOPS, --max_loops MAX_LOOPS
32+
maximum number of loops, set to 0 to loop through image until keyboard interrupt (default 3)
3033
```
3134

3235
### Examples
@@ -39,15 +42,15 @@ Convert the following [GIF image](https://raw.githubusercontent.com/soda480/asci
3942
ascii-art-animator -f docs/images/marcovich.gif
4043
```
4144

42-
![example](https://raw.githubusercontent.com/soda480/ascii-animator/main/docs/images/marcovich-execution.gif)
45+
![example](https://raw.githubusercontent.com/soda480/ascii-animator/main/docs/images/marcovich-exec.gif)
4346

4447
Convert the following [GIF image](https://github.com/soda480/ascii-animator/blob/main/docs/images/afuera.gif?raw=true)
4548

4649
```bash
4750
ascii-art-animator -f docs/images/afuera.gif -s fast
4851
```
4952

50-
![example](https://raw.githubusercontent.com/soda480/ascii-animator/main/docs/images/afuera-execution.gif)
53+
![example](https://raw.githubusercontent.com/soda480/ascii-animator/main/docs/images/afuera-exec.gif)
5154

5255
#### Game-Of-Life
5356

build.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
authors = [Author('Emilio Reyes', 'soda480@gmail.com')]
1616
summary = 'A simple ASCII art animator'
1717
url = 'https://github.com/soda480/ascii-animator'
18-
version = '0.1.2'
18+
version = '0.1.3'
1919
default_task = [
2020
'clean',
2121
'analyze',

docs/images/afuera-exec.gif

5.04 MB
Loading

docs/images/afuera-execution.gif

-6.14 MB
Binary file not shown.

docs/images/marcovich-exec.gif

3.1 MB
Loading
-4.67 MB
Binary file not shown.

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
l2term~=0.1.6
1+
l2term~=0.1.7
22
ascii-magic

src/main/python/ascii_animator/animator.py

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
logger = logging.getLogger(__name__)
1212

1313

14+
class MaxLoopsProcessed(Exception):
15+
pass
16+
17+
1418
class Speed(Enum):
1519
VERY_SLOW = .4
1620
SLOW = .11
@@ -38,36 +42,37 @@ class AsciiAnimation(Animation):
3842
def __init__(self, path):
3943
logger.debug('executing AsciiAnimation constructor')
4044
self._frames = AsciiAnimation.get_ascii_frames_from_image(path)
41-
self.current = None
45+
self.current = 0
4246
self.cycle()
4347

4448
@property
4549
def grid(self):
4650
return self._grid
4751

4852
def cycle(self):
49-
if self.current is None or self.current >= len(self._frames):
53+
cycle_complete = False
54+
if self.current >= len(self._frames):
5055
self.current = 0
56+
cycle_complete = True
5157
self._grid = self._frames[self.current]
5258
self.current += 1
59+
return cycle_complete
5360

5461
@staticmethod
5562
def get_ascii_frames_from_image(path):
5663
logger.debug(f'extracting frames from image "{path}" and converting each frame to ascii art')
57-
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
5864
frames = []
5965
image = Image.open(path)
60-
logger.debug(f'the image "{path}" has {image.n_frames} frames')
66+
logger.debug(f'the image "{path}" has a total of {image.n_frames} frames')
6167
for frame in ImageSequence.Iterator(image):
62-
ascii_art = ascii_magic.from_image(frame, columns=140)
63-
ascii_art_sanitized = ansi_escape.sub('', ascii_art)
64-
frames.append(ascii_art_sanitized.split("\n"))
68+
ascii_art = ascii_magic.from_image(frame, columns=140, mode=ascii_magic.Modes.ASCII)
69+
frames.append(ascii_art.split('\n'))
6570
return frames
6671

6772

6873
class Animator(object):
6974

70-
def __init__(self, animation=None, speed=Speed.NORMAL, show_index=False):
75+
def __init__(self, animation=None, speed=Speed.NORMAL, show_axis=False, max_loops=None):
7176
""" initialize Animator
7277
"""
7378
logger.debug('executing Animator constructor')
@@ -77,21 +82,38 @@ def __init__(self, animation=None, speed=Speed.NORMAL, show_index=False):
7782
raise ValueError("speed must be an instance of Speed Enum")
7883
self.speed = speed
7984
self.animation = animation
80-
self.show_index = show_index
85+
self.show_axis = show_axis
86+
self.max_loops = max_loops
8187
self.start()
8288

89+
def _check_loops(self, cycle_complete):
90+
""" raise exception if maximum number of loops has been processed
91+
"""
92+
if not cycle_complete:
93+
return
94+
if self.max_loops and self.loop == self.max_loops:
95+
raise MaxLoopsProcessed('maximum number of loops processed')
96+
self.loop += 1
97+
8398
def start(self):
8499
""" cycle throught the animation and update the terminal using Lines
85100
"""
86-
with Lines(self.animation.grid, show_index=self.show_index) as lines:
87-
try:
88-
logger.debug('starting ascii art animation')
101+
logger.debug('starting ascii art animation')
102+
try:
103+
logger.debug(f'there are {len(self.animation.grid)} lines in the animation to display')
104+
with Lines(self.animation.grid, show_index=self.show_axis, show_x_axis=self.show_axis) as lines:
105+
self.loop = 1
89106
while True:
90-
# cycle through the animation by updating a grid frame
91-
self.animation.cycle()
92-
# update terminal using the Lines object
107+
# update the grid with the next frame
108+
cycle_complete = self.animation.cycle()
109+
# update terminal via the Lines object
93110
for index in range(len(self.animation.grid)):
94111
lines[index] = self.animation.grid[index]
112+
self._check_loops(cycle_complete)
95113
sleep(self.speed.value)
96-
except KeyboardInterrupt:
97-
pass
114+
115+
except KeyboardInterrupt:
116+
logger.debug('encountered a keyboard interrupt - ending animation')
117+
118+
except MaxLoopsProcessed:
119+
logger.debug(f'maximum loops processed {self.loop} - ending animation')

src/main/python/ascii_animator/cli.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ def get_speed(value):
2222

2323

2424
def main():
25-
parser = argparse.ArgumentParser(description="Ascii Art Animator from GIF")
26-
parser.add_argument("-s", "--speed", type=str, default='normal', help="speed of the animation: very_slow, slow, normal, fast (default normal)")
27-
parser.add_argument("-f", "--file", type=str, help="the path to a gif file")
28-
parser.add_argument("-d", "--debug", action="store_true", help="display debug messages to stdout")
25+
parser = argparse.ArgumentParser(description='Ascii Art Animator from GIF')
26+
parser.add_argument('-s', '--speed', type=str, default='normal', help='speed of the animation: very_slow, slow, normal, fast (default normal)')
27+
parser.add_argument('-f', '--file', type=str, help='the path to a gif file')
28+
parser.add_argument('-d', '--debug', action='store_true', help='display debug messages to stdout')
29+
parser.add_argument('-a', '--show_axis', action='store_true', help='display the grid axis')
30+
parser.add_argument('-m', '--max_loops', type=int, default=3, help='maximum number of loops, set to 0 to loop through image until keyboard interrupt (default 3)')
2931

3032
args = parser.parse_args()
3133

@@ -36,7 +38,9 @@ def main():
3638
speed = get_speed(args.speed)
3739
Animator(
3840
animation=AsciiAnimation(args.file),
39-
speed=speed)
41+
speed=speed,
42+
show_axis=args.show_axis,
43+
max_loops=args.max_loops)
4044

4145
except argparse.ArgumentError:
4246
parser.print_help()
@@ -47,5 +51,5 @@ def main():
4751
sys.exit(2)
4852

4953

50-
if __name__ == "__main__":
54+
if __name__ == '__main__':
5155
main()

0 commit comments

Comments
 (0)