summary refs log tree commit diff
path: root/third_party/flipdots/scripts/scroll_text.py
blob: 68a5cf89bcec8cea10d3df66028b8338096578a8 (plain) (blame)
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
#!/usr/bin/env python
# -.- coding: utf-8

import socket, time
from PIL import Image, ImageFont, ImageDraw
import sys
import fileinput
import threading

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):
    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)