Skip to content

Commit

Permalink
replace absl by python argparse from stdlib (#7)
Browse files Browse the repository at this point in the history
Check if output file have gif extension.
Improve main and output.
Also remove unused import (os).
  • Loading branch information
4383 authored and sergey48k committed Aug 10, 2018
1 parent e05fccd commit 6521ec3
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 97 deletions.
74 changes: 37 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,43 @@ $ pip install anishot

## Usage
```
$ anishot
Usage:
anishot.__main__:
--h: Window height
(default: '0')
(an integer)
--inp: Input screenshot image
--maxspeed: Max speed on scroll px/frame
(default: '200')
(an integer)
--out: Output antimated GIF
--pad: Padding on sides
(default: '0')
(an integer)
--rgb_bg: Background color
(default: '#ffffff')
--rgb_outline: Screenshot outline color
(default: '#e1e4e8')
--rgb_shadow: Screenshot shadow color
(default: '#999999')
--rgb_window: Window outline color
(default: '#e1e4e8')
--shadow_size: Shadow size
(default: '0')
(an integer)
--start_scale: Start scale
(default: '0.5')
(a number)
--stops: List of stops for scrolling
(default: '')
(a comma separated list)
--zoom_steps: Number of steps on initial zoom in
(default: '7')
(an integer)
--zoom_to: Point to zoom to
(default: '0')
(an integer)
$ anishot --help
usage: anishot [-h] [-p PAD] [-m MAXSPEED] [-s [STOPS [STOPS ...]]]
[--zoom-steps ZOOM_STEPS] [--start-scale START_SCALE]
[--zoom-to ZOOM_TO] [--shadow-size SHADOW_SIZE]
[--rgb-outline RGB_OUTLINE] [--rgb-background RGB_BACKGROUND]
[--rgb-shadow RGB_SHADOW] [--rgb-window RGB_WINDOW]
input output height
Animates a long screenshot into a GIF
positional arguments:
input Input screenshot image
output Output animated GIF
height Window height
optional arguments:
-h, --help show this help message and exit
-p PAD, --pad PAD Padding on sides
-m MAXSPEED, --maxspeed MAXSPEED
Max speed on scroll px/frame
-s [STOPS [STOPS ...]], --stops [STOPS [STOPS ...]]
Max speed on scroll px/frame
--zoom-steps ZOOM_STEPS
Number of steps on initial zoom in
--start-scale START_SCALE
Start scale
--zoom-to ZOOM_TO Point to zoom to
--shadow-size SHADOW_SIZE
Shadow size
--rgb-outline RGB_OUTLINE
Screenshot outline color
--rgb-background RGB_BACKGROUND
Background color
--rgb-shadow RGB_SHADOW
Screenshot shadow color
--rgb-window RGB_WINDOW
Window outline color
```

The anishot at the top of this README was generated by:
Expand Down
144 changes: 86 additions & 58 deletions anishot/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,57 @@
__copyright__ = 'Copyright 2018 Sourcerer'
__author__ = 'Sergey Surkov'

import os
import argparse
import sys

from absl import flags as gflags
import imageio
import numpy

from PIL import Image
from PIL.ImageDraw import Draw

gflags.DEFINE_string('inp', None, 'Input screenshot image')
gflags.DEFINE_string('out', None, 'Output antimated GIF')

gflags.DEFINE_integer('h', 0, 'Window height')
gflags.DEFINE_integer('pad', 0, 'Padding on sides')
gflags.DEFINE_integer('maxspeed', 200, 'Max speed on scroll px/frame')
gflags.DEFINE_list('stops', [], 'List of stops for scrolling')
gflags.DEFINE_integer('zoom_steps', 7, 'Number of steps on initial zoom in')
gflags.DEFINE_float('start_scale', .5, 'Start scale')
gflags.DEFINE_integer('zoom_to', 0, 'Point to zoom to')

gflags.DEFINE_integer('shadow_size', 0, 'Shadow size')
gflags.DEFINE_string('rgb_outline', '#e1e4e8', 'Screenshot outline color')
gflags.DEFINE_string('rgb_bg', '#ffffff', 'Background color')
gflags.DEFINE_string('rgb_shadow', '#999999', 'Screenshot shadow color')
gflags.DEFINE_string('rgb_window', '#e1e4e8', 'Window outline color')

gflags.register_validator('inp', os.path.exists, 'Input screenshot required')
gflags.register_validator('h', lambda v: v > 0, 'Window height required')

F = gflags.FLAGS
ARGS = None


def argparser():
parser = argparse.ArgumentParser(
description='Animates a long screenshot into a GIF')
parser.add_argument('input', type=argparse.FileType(),
help='Input screenshot image')
parser.add_argument('output', type=str,
help='Output animated GIF')
parser.add_argument('height', type=int,
help='Window height')
parser.add_argument('-p', '--pad', default=0, type=int,
help='Padding on sides')
parser.add_argument('-m', '--maxspeed', default=200, type=int,
help='Max speed on scroll px/frame')
parser.add_argument('-s', '--stops', nargs='*', default=[],
help='Max speed on scroll px/frame')
parser.add_argument('--zoom-steps', default=7, type=int,
help='Number of steps on initial zoom in')
parser.add_argument('--start-scale', default=5, type=int,
help='Start scale')
parser.add_argument('--zoom-to', default=0, type=int,
help='Point to zoom to')
parser.add_argument('--shadow-size', default=0, type=int,
help='Shadow size')
parser.add_argument('--rgb-outline', default='#e1e4e8', type=str,
help='Screenshot outline color')
parser.add_argument('--rgb-background', default='#ffffff', type=str,
help='Background color')
parser.add_argument('--rgb-shadow', default='#999999', type=str,
help='Screenshot shadow color')
parser.add_argument('--rgb-window', default='#e1e4e8', type=str,
help='Window outline color')
global ARGS
ARGS = parser.parse_args()


def make_blank_frame(width):
return Image.new('RGB', (width + F.pad * 2, F.h), F.rgb_bg)
return Image.new('RGB',
(width + ARGS.pad * 2, ARGS.height), ARGS.rgb_background)


def scale_image(image, scale):
Expand All @@ -53,13 +69,14 @@ def render_frame(image, y, frame):
draw = Draw(frame)

# Draw shadow and image.
off = F.shadow_size
draw.rectangle([x + off, y + off, x + off + w, y + off + h], F.rgb_shadow)
off = ARGS.shadow_size
draw.rectangle(
[x + off, y + off, x + off + w, y + off + h], ARGS.rgb_shadow)
frame.paste(image, (x, y))
draw.rectangle([x, y, x + w, y + h], outline=F.rgb_outline)
draw.rectangle([x, y, x + w, y + h], outline=ARGS.rgb_outline)

# Draw a frame border.
draw.rectangle([0, 0, fw - 1, fh - 1], outline=F.rgb_window)
draw.rectangle([0, 0, fw - 1, fh - 1], outline=ARGS.rgb_window)


def add_frame(frame, duration, frames):
Expand All @@ -68,19 +85,20 @@ def add_frame(frame, duration, frames):

def make_zoomin(image, frames):
w, h = image.size
scale = F.start_scale
step = (1 - scale) / (F.zoom_steps + 1)
start_y = -F.h / 10 / scale
for i in range(F.zoom_steps):
scale = ARGS.start_scale
step = (1 - scale) / (ARGS.zoom_steps + 1)
start_y = -ARGS.height / 10 / scale
for i in range(ARGS.zoom_steps):
scaled = scale_image(image, scale)
if not scaled:
continue
frame = make_blank_frame(w)

progress = (F.zoom_steps - i - 1) / (F.zoom_steps - 1)
y = -int(
(progress * start_y + (1 - progress) * F.zoom_to) * scale + .5)
progress = (ARGS.zoom_steps - i - 1) / (ARGS.zoom_steps - 1)
y = -int((progress * start_y + (1 - progress) * ARGS.zoom_to) *
scale + .5)
render_frame(scaled, y, frame)
add_frame(frame, .1 if i > 0 else 1.5, frames)

scale += step


Expand All @@ -93,7 +111,8 @@ def add_scroll_frame(image, y, duration, frames):
def make_scroll(image, frames):
w, h = image.size

stops = [F.zoom_to] + list(map(int, F.stops)) + [h - F.h + F.pad]
stops = [ARGS.zoom_to] + \
list(map(int, ARGS.stops)) + [h - ARGS.height + ARGS.pad]
add_scroll_frame(image, stops[0], 2, frames)
for i in range(len(stops) - 1):
s0, s1 = stops[i:i + 2]
Expand All @@ -103,34 +122,43 @@ def make_scroll(image, frames):
while y < s1:
add_scroll_frame(image, y, .01, frames)
y += speed
speed = min(speed * 2, F.maxspeed)
speed = min(speed * 2, ARGS.maxspeed)

add_scroll_frame(image, s1, 2, frames)


def process():
image = Image.fromarray(imageio.imread(ARGS.input.name))
frames = []

if ARGS.zoom_steps:
make_zoomin(image, frames)
make_scroll(image, frames)

imageio.mimwrite(ARGS.output,
map(lambda f: numpy.array(f[0]), frames),
duration=list(map(lambda f: f[1], frames)))


def check():
if ARGS.output[-4:] != '.gif':
raise ValueError("output must be a gif file")


def finish():
msg = "Done! Generated file will be available at {}".format(ARGS.output)
print(msg)


def main():
argv = sys.argv
try:
F(argv)

image = Image.fromarray(imageio.imread(F.inp))
frames = []

if F.zoom_steps:
make_zoomin(image, frames)
make_scroll(image, frames)

imageio.mimwrite(F.out,
map(lambda f: numpy.array(f[0]), frames),
duration=list(map(lambda f: f[1], frames)))
except TypeError as e:
print('e: ', e)
print('Usage: %s' % F)
return 1
except gflags.Error as e:
print('e: ', e)
print('Usage: %s' % F)
return 1
argparser()
check()
process()
finish()
except ValueError:
print("Invalid output filename")
return 127


if __name__ == '__main__':
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
absl-py=0.2.2
imageio==2.3.0
Pillow==5.2.0
Pillow==5.2.0

0 comments on commit 6521ec3

Please sign in to comment.