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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#!/usr/bin/env python
# -.- coding: utf-8
import socket, time
from PIL import Image, ImageFont, ImageDraw
import sys
import fileinput
import threading
from pathlib import PurePath
UDPHOST="flipdot.lab"
UDPPORT=2323
FPS = 9
STEPS = 1
INVERT=True
DISPLAY_SIZE = (80, 16)
FONT_SIZE = 16
FONT_OFFSET= (1, -1)
C_BLACK = (0, 0, 0)
C_WHITE = (255, 255, 255)
finished = False
framebuffer = []
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def list2byte(l):
byte = 0
i = 0
for i in range(8):
byte += 2**(7-i) if l[i] else 0
return byte
def array2packet(a):
return bytearray([list2byte(a[i*8:i*8+8]) for i in range(int(len(a)/8))])
def str2array(s,font):
# load a pillow font directly
if PurePath(font).suffix == '.pil':
font = ImageFont.load(font)
else:
font = ImageFont.truetype(font=font,size=FONT_SIZE)
img_width = font.getsize(s)[0]
image = Image.new("RGBA", (img_width,DISPLAY_SIZE[1]), C_BLACK)
draw = ImageDraw.Draw(image)
draw.fontmode = "1" # no AA
draw.text(FONT_OFFSET, s, font=font, fill=C_WHITE)
imgmap = []
for pixel in image.getdata():
r, g, b, a = pixel
if r == 255:
imgmap.append(0 if INVERT else 1)
else:
imgmap.append(1 if INVERT else 0)
return imgmap
def render_frames(imgmap):
global framebuffer
global finished
framebuffer = []
finished = False
display_width = DISPLAY_SIZE[0]
display_heigth = DISPLAY_SIZE[1]
imgmap_width = int(len(imgmap) / display_heigth)
scrollimg_width = int(imgmap_width + 2*display_width)
scroll_imgmap = [1 if INVERT else 0] * (scrollimg_width * display_heigth)
# expand imgmap
for row in range(display_heigth):
for col in range(imgmap_width):
scroll_imgmap[display_width-STEPS + row*scrollimg_width + col] = imgmap[col+row*imgmap_width]
# scroll img
curr_frame = [0] * display_width * display_heigth
for offset in range(0, scrollimg_width-display_width, STEPS):
for row in range(display_heigth):
for col in range(display_width):
curr_frame[col+row*display_width] = scroll_imgmap[col+row*scrollimg_width + offset]
framebuffer.append(array2packet(curr_frame))
finished = True
def send_frames(host, port):
global framebuffer
global finished
frame_pos = 0
def frames_left(frame_pos, framebuffer):
return frame_pos < len(framebuffer)
while not finished or frames_left(frame_pos, framebuffer):
if frames_left(frame_pos, framebuffer):
sock.sendto(framebuffer[frame_pos], (host, port))
time.sleep(1.0/FPS)
frame_pos += 1
else:
continue
def scroll_text(host, port, font, text):
text = text.strip()
imgmap = str2array(text,font)
renderer = threading.Thread(target=render_frames,args=(imgmap,))
sender = threading.Thread(target=send_frames,args=(host,port))
renderer.start()
sender.start()
sender.join()
if __name__ == '__main__':
try:
while True:
text = sys.stdin.readline().decode('utf-8').strip()
if text == "":
break
scroll_text(UDPHOST, UDPPORT, "/path/to/font.ttf", text)
except KeyboardInterrupt:
print("Exited due to Ctrl-C")
sys.exit(0)
|