Skip to content

Commit d443682

Browse files
authored
Added code.py
Fixing pylint issues
1 parent 1b40859 commit d443682

1 file changed

Lines changed: 354 additions & 0 deletions

File tree

EInk_Autostereograms/code.py

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
import os
2+
import time
3+
import json
4+
import digitalio
5+
import busio
6+
import board
7+
import displayio
8+
import adafruit_imageload
9+
from analogio import AnalogIn
10+
from adafruit_epd.epd import Adafruit_EPD
11+
from adafruit_epd.il91874 import Adafruit_IL91874
12+
13+
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
14+
ecs = digitalio.DigitalInOut(board.D10)
15+
dc = digitalio.DigitalInOut(board.D9)
16+
srcs = digitalio.DigitalInOut(board.D8) # can be None to use internal memory
17+
led = digitalio.DigitalInOut(board.D13)
18+
led.direction = digitalio.Direction.OUTPUT
19+
20+
print("Creating display")
21+
display = Adafruit_IL91874(
22+
176,
23+
264,
24+
spi, # 2.7" Tri-color display
25+
cs_pin=ecs,
26+
dc_pin=dc,
27+
sramcs_pin=srcs,
28+
rst_pin=None,
29+
busy_pin=None,
30+
)
31+
32+
# read buttons from ePaper shield
33+
def read_buttons():
34+
with AnalogIn(board.A3) as ain:
35+
reading = ain.value / 65535
36+
if reading > 0.75:
37+
return None
38+
if reading > 0.4:
39+
return 4
40+
if reading > 0.25:
41+
return 3
42+
if reading > 0.13:
43+
return 2
44+
return 1
45+
46+
# display bitmap file
47+
def display_bitmap(epd, filename):
48+
try:
49+
f = open("/" + filename, "rb")
50+
except OSError:
51+
display_message("Error: Couldn't open file " + filename)
52+
53+
print("File opened")
54+
try:
55+
if f.read(2) != b"BM": # check signature
56+
raise BMPError("Not BitMap file")
57+
bmpFileSize = read_le(f.read(4))
58+
f.read(4) # Read & ignore creator bytes
59+
bmpImageoffset = read_le(f.read(4)) # Start of image data
60+
headerSize = read_le(f.read(4))
61+
bmpWidth = read_le(f.read(4))
62+
# convert width to 8 pixels per byte width
63+
bmpWidth = (bmpWidth + 7) // 8
64+
bmpHeight = read_le(f.read(4))
65+
# convert unsigned int to signed int in case there is a negative height
66+
if bmpHeight > 0x7FFFFFFF:
67+
bmpHeight = bmpHeight - 4294967296
68+
flip = True
69+
if bmpHeight < 0:
70+
bmpHeight = abs(bmpHeight)
71+
flip = False
72+
print(
73+
"Size: %d\nImage offset: %d\nHeader size: %d"
74+
% (bmpFileSize, bmpImageoffset, headerSize)
75+
)
76+
print("Width: %d\nHeight: %d" % (bmpWidth, bmpHeight))
77+
if read_le(f.read(2)) != 1:
78+
raise BMPError("Not singleplane")
79+
bmpDepth = read_le(f.read(2)) # bits per pixel
80+
print("Bit depth: %d" % (bmpDepth))
81+
if bmpDepth != 1:
82+
raise BMPError("Not 1-bit")
83+
if read_le(f.read(4)) != 0:
84+
raise BMPError("Compressed file not supported")
85+
read_le(4) # SizeImage
86+
read_le(4) # biXPelsPerMeter
87+
read_le(4) # biYPelsPerMeter
88+
read_le(4) # biClrUsed
89+
read_le(4) # biClrImportant
90+
blkpixel = 1
91+
if read_le(4) != 0:
92+
blkpixel = 0
93+
print("black pixel is ", blkpixel)
94+
print("Image OK! Drawing...")
95+
rowSize = (bmpWidth + 3) & ~3 # 32-bit line boundary
96+
for row in range(bmpHeight): # For each scanline...
97+
# blink the LED
98+
if row % 2 == 0:
99+
led.value = False
100+
else:
101+
led.value = True
102+
if flip: # Bitmap is stored bottom-to-top order (normal BMP)
103+
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize
104+
else: # Bitmap is stored top-to-bottom
105+
pos = bmpImageoffset + row * rowSize
106+
f.seek(pos)
107+
rowdata = f.read(bmpWidth)
108+
for col in range(bmpWidth):
109+
for b in range(8):
110+
if (rowdata[col] & (0x80 >> b) != 0 and blkpixel == 0) or (
111+
rowdata[col] & (0x80 >> b) == 0 and blkpixel == 1
112+
):
113+
epd.pixel(col * 8 + b, row, Adafruit_EPD.BLACK)
114+
except OSError:
115+
display_message("Error: couldn't read file " + filename)
116+
except BMPError:
117+
display_message("Error: unsupported BMP file " + filename)
118+
finally:
119+
f.close()
120+
print("Finished drawing")
121+
return
122+
123+
124+
def read_le(s):
125+
result = 0
126+
shift = 0
127+
for byte in bytearray(s):
128+
result += byte << shift
129+
shift += 8
130+
return result
131+
132+
133+
class BMPError(Exception):
134+
pass
135+
136+
137+
# alternate bitmap display method using imageload library
138+
def display_bitmap_alternate(epd, filename):
139+
image, _ = adafruit_imageload.load(
140+
filename, bitmap=displayio.Bitmap, palette=displayio.Palette
141+
)
142+
for y in range(display.height):
143+
# blink the LED
144+
if y % 2 == 0:
145+
led.value = True
146+
else:
147+
led.value = False
148+
for x in range(display.width):
149+
if image[x, y] == 0:
150+
epd.pixel(x, y, Adafruit_EPD.BLACK)
151+
return
152+
153+
154+
# display message both on the screen and the serial port
155+
def display_message(message):
156+
print(message)
157+
display.rotation = 1
158+
display.fill_rect(0, 10, 264, 20, Adafruit_EPD.WHITE)
159+
display.text(message, 10, 10, Adafruit_EPD.BLACK)
160+
display.display()
161+
return
162+
163+
164+
# slide show routine
165+
def show_files():
166+
try:
167+
filelist = os.listdir(config["slidefolder"])
168+
display.rotation = 1
169+
led.value = True
170+
while True:
171+
for file in filelist:
172+
starttime = time.monotonic()
173+
display.fill(Adafruit_EPD.WHITE)
174+
print("displaying file", config["slidefolder"] + "/" + file)
175+
display_bitmap(display, config["slidefolder"] + "/" + file)
176+
endtime = time.monotonic()
177+
minutes = (endtime - starttime) // 60
178+
seconds = int(endtime - starttime) - minutes * 60
179+
print("update time:", minutes, "minutes", seconds, "seconds")
180+
print("updating display")
181+
display.display()
182+
print("done")
183+
time.sleep(5)
184+
except (ValueError, Exception) as e:
185+
display_message("Error: " + file + " " + e.args[0])
186+
led.value = False
187+
return
188+
189+
# run specified job
190+
def run_job(jobfile):
191+
try:
192+
print("running job " + jobfile)
193+
fpr = open(config["jobfolder"] + "/" + jobfile, mode="r")
194+
job = json.load(fpr)
195+
fpr.close()
196+
print("image: ", job["image"])
197+
starttime = time.monotonic()
198+
pixelsize = job["bkpixelsize"]
199+
whitepct = job["bkratio"]
200+
panelcount = 6
201+
led.value = True
202+
203+
display.rotation = 1
204+
display.fill(Adafruit_EPD.WHITE)
205+
print("ePaper display size:", display.width, display.height)
206+
print(config["imagefolder"] + "/" + job["image"])
207+
image, _ = adafruit_imageload.load(
208+
config["imagefolder"] + "/" + job["image"],
209+
bitmap=displayio.Bitmap,
210+
palette=displayio.Palette,
211+
)
212+
inv = False
213+
print("image size:", image.width, image.height)
214+
if image[0] == 1:
215+
inv = True
216+
print("using inv image")
217+
panelwidth = display.width // panelcount
218+
createfile = True
219+
try:
220+
out = open(config["asgfolder"] + "/asg" + job["image"], mode="wb")
221+
print("writing to file asg" + job["image"])
222+
except (OSError, Exception):
223+
# readonly filesystem, do not create file
224+
createfile = False
225+
if createfile: # == True
226+
# BMP files are all the same dimensions, just different bitmaps,
227+
# writing hardcoded headers here
228+
# write file header (14 bytes)
229+
out.write(
230+
bytearray(
231+
[
232+
0x42, 0x4D, 0xFE, 0x18, 0, 0, 0, 0, 0, 0, 0x3E, 0, 0, 0
233+
]
234+
)
235+
)
236+
# write image header (40 bytes)
237+
out.write(
238+
bytearray(
239+
[
240+
0x28, 0, 0, 0, 0x8, 0x1, 0, 0, 0x50, 0xFF,
241+
0xFF, 0xFF, 0x1, 0, 0x1, 0, 0, 0, 0, 0,
242+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
243+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
244+
]
245+
)
246+
)
247+
# write 2 item color table (8 bytes)
248+
out.write(bytearray([0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0]))
249+
with open(
250+
config["bkfolder"] + "/background-" + str(whitepct)
251+
+ "-" + str(pixelsize) + ".dat", "rb") as fp:
252+
bkdata = fp.read()
253+
canvas = list(bkdata)
254+
for y in range(0, display.height):
255+
# blink the LED
256+
if y % 2 == 0:
257+
led.value = True
258+
else:
259+
led.value = False
260+
tcanvas = [0 for i in range(display.width + panelwidth)]
261+
tpanel = [0 for i in range(panelwidth)]
262+
for x in range(panelwidth):
263+
bytepos = ((x % panelwidth) // 8) + (
264+
y // pixelsize * (panelwidth + 7) // 8
265+
)
266+
bitpos = x % 8
267+
pixel = canvas[bytepos] & 1 << (bitpos)
268+
if pixel != 0:
269+
tpanel[x] = 1
270+
for x in range(display.width + panelwidth):
271+
pixel = tpanel[x % panelwidth]
272+
if pixel != 0:
273+
tcanvas[x] = 1
274+
for x in range(0, display.width):
275+
if (x % panelwidth) == 0 and x > 0:
276+
for x2 in range(x, x + panelwidth):
277+
tcanvas[x2] = tcanvas[x2 - panelwidth]
278+
for x2 in range(panelwidth):
279+
tpanel[x2] = tcanvas[x + x2 - panelwidth]
280+
offset = 0
281+
print("debug")
282+
if x >= 22 and (
283+
x < (image.width + panelwidth // 2)
284+
and y < image.height
285+
and (
286+
(image[x - panelwidth // 2, y] != 0 and not inv)
287+
or (image[x - panelwidth // 2, y] == 0 and inv)
288+
)
289+
):
290+
# offset = 4
291+
if job["imagegrayscale"] == 0:
292+
offset = job["imageheight"]
293+
else:
294+
offset = (
295+
image[x - panelwidth // 2, y]
296+
* job["grayscalecolors"]
297+
// 255
298+
)
299+
if offset != 0:
300+
for x2 in range(x, display.width, panelwidth):
301+
tcanvas[x2] = tcanvas[x2 + offset]
302+
for x in range(0, display.width):
303+
# write line to eink display
304+
if tcanvas[x] != 0:
305+
display.pixel(x, y, Adafruit_EPD.BLACK)
306+
# else:
307+
# display.pixel(x,y,Adafruit_EPD.WHITE)
308+
if createfile:
309+
count = 0
310+
for x in range(0, display.width + 7, 8):
311+
value = 0
312+
for b in range(8):
313+
value |= (tcanvas[x + b] << 7) >> b
314+
out.write(bytes([value]))
315+
count += 1
316+
# add padding to end of line
317+
padding = (4 - (count % 4)) % 4
318+
for x in range(padding):
319+
out.write(bytes([0]))
320+
if createfile:
321+
out.close()
322+
endtime = time.monotonic()
323+
minutes = (endtime - starttime) // 60
324+
seconds = int(endtime - starttime) - minutes * 60
325+
print("completion time:", minutes, "minutes", seconds, "seconds")
326+
print("updating display")
327+
display.display()
328+
print("done")
329+
except (ValueError, Exception) as e:
330+
display_message("Error: " + e.args[0])
331+
led.value = False
332+
return
333+
334+
# main routine
335+
display.fill(Adafruit_EPD.WHITE)
336+
with open("/config.json") as fpx:
337+
config = json.load(fpx)
338+
fpx.close()
339+
print("waiting for button press")
340+
while True:
341+
button = read_buttons()
342+
if button:
343+
# button pressed, waiting for button release
344+
while read_buttons():
345+
time.sleep(0.1)
346+
if not button:
347+
continue
348+
print("Button #%d pressed" % button)
349+
if button == 1:
350+
for jobfile in config["jobs"]:
351+
run_job(jobfile)
352+
if button == 2:
353+
show_files()
354+
time.sleep(0.01)

0 commit comments

Comments
 (0)