-
Notifications
You must be signed in to change notification settings - Fork 776
/
code.py
executable file
·130 lines (104 loc) · 3.72 KB
/
code.py
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
# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Dotstar POV Display! Can handle up to ~2300 pixel size image (e.g. 36 x 64)
import gc
import time
from adafruit_motorkit import MotorKit
import board
import busio
import digitalio
kit = MotorKit(i2c=board.I2C())
FILENAME = "nyan-xmas.bmp"
IMAGE_DELAY = 0.001
REPEAT = True
BRIGHTNESS = 0.3
PIXEL_DELAY = 0.003
dotstar = busio.SPI(board.SCK, board.MOSI)
while not dotstar.try_lock():
pass
dotstar.configure(baudrate=44000000)
# we'll resize this later
databuf = bytearray(0)
led = digitalio.DigitalInOut(board.D13)
led.switch_to_output()
def read_le(s):
# as of this writting, int.from_bytes does not have LE support, DIY!
result = 0
shift = 0
for byte in bytearray(s):
result += byte << shift
shift += 8
return result
class BMPError(Exception):
pass
try:
with open("/" + FILENAME, "rb") as f:
print("File opened")
if f.read(2) != b'BM': # check signature
raise BMPError("Not BitMap file")
bmpFileSize = read_le(f.read(4))
f.read(4) # Read & ignore creator bytes
bmpImageoffset = read_le(f.read(4)) # Start of image data
headerSize = read_le(f.read(4))
bmpWidth = read_le(f.read(4))
bmpHeight = read_le(f.read(4))
flip = True
print("Size: %d\nImage offset: %d\nHeader size: %d" %
(bmpFileSize, bmpImageoffset, headerSize))
print("Width: %d\nHeight: %d" % (bmpWidth, bmpHeight))
if read_le(f.read(2)) != 1:
raise BMPError("Not singleplane")
bmpDepth = read_le(f.read(2)) # bits per pixel
print("Bit depth: %d" % (bmpDepth))
if bmpDepth != 24:
raise BMPError("Not 24-bit")
if read_le(f.read(2)) != 0:
raise BMPError("Compressed file")
print("Image OK!")
rowSize = (bmpWidth * 3 + 3) & ~3 # 32-bit line boundary
# its huge! but its also fast :)
databuf = bytearray(bmpWidth * bmpHeight * 4)
for row in range(bmpHeight): # For each scanline...
if flip: # Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize
else: # Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize
# print ("seek to %d" % pos)
f.seek(pos)
for col in range(bmpWidth):
b, g, r = bytearray(f.read(3)) # BMP files store RGB in BGR
# front load brightness, gamma and reordering here!
order = [b, g, r]
idx = (col * bmpHeight + (bmpHeight - row - 1)) * 4
databuf[idx] = 0xFF # first byte is 'brightness'
idx += 1
for color in order:
databuf[idx] = int(
pow((color * BRIGHTNESS) / 255, 2.7) * 255 + 0.5)
idx += 1
except BMPError as e:
print("Failed to parse BMP: " + e.args[0])
gc.collect()
print(gc.mem_free())
print("Ready to go!")
kit.motor1.throttle = 1
while True:
print("Draw!")
index = 0
for col in range(bmpWidth):
row = databuf[index:index + bmpHeight * 4]
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
dotstar.write(row)
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
index += bmpHeight * 4
time.sleep(PIXEL_DELAY)
# clear it out
dotstar.write(bytearray([0x00, 0x00, 0x00, 0x00]))
for r in range(bmpHeight * 5):
dotstar.write(bytearray([0xFF, 0x00, 0x00, 0x00]))
dotstar.write(bytearray([0xff, 0xff, 0xff, 0xff]))
gc.collect()
if not REPEAT:
break
time.sleep(IMAGE_DELAY)