-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathsample2
More file actions
116 lines (96 loc) · 3.63 KB
/
sample2
File metadata and controls
116 lines (96 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
!pip install apng
import os, IPython
import math
from PIL import Image, ImageDraw, ImageFont
from apng import APNG
class AStudio(object):
bodies: list
frame: int
def __init__(self, width=400, height=300, background='skyblue'):
self.width = width
self.height = height
self.background = background
self.bodies = []
self.files = []
self.frame = 0
def append(self, shape):
self.bodies.append(shape) # 被写体を追加する
return shape
def render(self, caption=''):
# 新しいキャンバスを作る
canvas = ACanvas(self.width, self.height, self.background)
# リスト上の形状を順番に描画する
for body in self.bodies:
body.render(canvas, self.frame)
# PNG画像に保存する
filename = f'frame{self.frame}.png'
canvas.image.save(filename)
self.files.append(filename)
self.frame += 1
def create_anime(self, filename='anime.png', delay=50):
APNG.from_files(self.files, delay=int(delay)).save(filename)
for image in self.files:
os.remove(image) # 不要なファイルは消す
self.files = []
return filename
class ACanvas(object):
width:int #横幅
height:int #高さ
background: any #背景色
image: Image
draw: ImageDraw
def __init__(self, width=400, height=300, background='skyblue'):
self.width = width
self.height = height
self.background = background
self.image = Image.new('RGBA', (self.width, self.height), self.background)
self.draw = ImageDraw.Draw(self.image, 'RGBA')
class AShape(object):
width:int #幅
height:int #高さ
cx:int #中心点のx
cy:int #中心点のy
scale:float # スケール
def __init__(self, width, height=None, cx=None, cy=None):
self.width = width
self.height = width if height is None else height
self.cx = self.width / 2 if cx is None else cx
self.cy = self.height / 2 if cy is None else cy
self.scale = 1.0
def bounds(self): # 左上の座標と幅,高さを計算する
w = self.width * self.scale
h = self.height * self.scale
ox = self.cx - w/2
oy = self.cy - h/2
return ox, oy, w, h
def render(self, canvas: ACanvas, tick: int):
ox, oy, w, h = self.bounds()
canvas.draw.rectangle((ox, oy, ox+w, oy+h), fill=(127,127,127))
def test_shape(shape, A=100, B=100, a=5, b=4, delta=-math.pi/4):
# スタジオを用意
studio = AStudio(300,300)
# スタジオに被写体を一つ追加する
studio.append(shape)
frames = 60
for t in range(frames):
x = 150 + A*math.cos(a*(2*math.pi*t/frames))
y = 150 - B*math.sin(b*(2*math.pi*t/frames) + delta)
# 被写体の中心を移動させる
shape.cx = x
shape.cy = y
# 全ての移動が終わったら、撮影
studio.render()
# 動画を編集して表示する
return studio.create_anime(delay=1/100000000000)
class AImage(AShape):
color: any
def __init__(self, width=100, height=None, cx=None, cy=None, image='furo_ducky.png'):
AShape.__init__(self, width, height, cx, cy)
if image.startswith('http'):
self.pic = Image.open(io.BytesIO(requests.get(image).content))
else:
self.pic = Image.open(image)
def render(self, canvas: ACanvas, frame: int):
ox, oy, w, h = self.bounds()
pic = self.pic.resize((int(w), int(h)))
canvas.image.paste(pic, (int(ox), int(oy)), pic)