Merge pull request 'feature/event-customization-2024' (#2) from feature/event-customization-2024 into master
Reviewed-on: https://git.jojo.party/Maxelweb/personal-badger/pulls/2
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
# Badger2040 System II
|
# Badger2040 System II
|
||||||
|
|
||||||
|
> Forked from https://github.com/oneearedrabbit/badger-system-ii
|
||||||
|
|
||||||
Tired of boring badges that just blend in with the crowd? You want to show off your quirky personality and love of retro technology? You are looking for a fun project to bond with your engineering team? Look no further than the programmable e-ink badge!
|
Tired of boring badges that just blend in with the crowd? You want to show off your quirky personality and love of retro technology? You are looking for a fun project to bond with your engineering team? Look no further than the programmable e-ink badge!
|
||||||
|
|
||||||
https://kruzenshtern.org/the-e-ink-badge-the-coolest-badge-you-didnt-know-you-needed/
|
https://kruzenshtern.org/the-e-ink-badge-the-coolest-badge-you-didnt-know-you-needed/
|
||||||
|
|||||||
3
scripts/.gitignore
vendored
Normal file
3
scripts/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
*.bin
|
||||||
|
*.png
|
||||||
|
*.jpeg
|
||||||
136
scripts/convert.py
Normal file
136
scripts/convert.py
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Converts images into a format suitable for display on Badger 2040.
|
||||||
|
|
||||||
|
Optionally resizes images to 296x128 to fit the display.
|
||||||
|
|
||||||
|
Crunches images down to dithered, 1bit colour depth.
|
||||||
|
|
||||||
|
Outputs either in raw binary format or as a .py file for embedding into MicroPython.
|
||||||
|
|
||||||
|
Output to py functionality is borrwed from data_to_py.py, Copyright (c) 2016 Peter Hinch
|
||||||
|
"""
|
||||||
|
|
||||||
|
import io
|
||||||
|
import argparse
|
||||||
|
from PIL import Image, ImageEnhance
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
PY_HEADER = """# Code generated by convert.py.
|
||||||
|
"""
|
||||||
|
|
||||||
|
PY_FOOTER = """_mvdata = memoryview(_data)
|
||||||
|
|
||||||
|
def data():
|
||||||
|
return _mvdata
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Converts images into the format used by Badger2040.')
|
||||||
|
parser.add_argument('file', nargs="+", help='input files to convert')
|
||||||
|
parser.add_argument('--out_dir', type=Path, default=None, help='output directory')
|
||||||
|
parser.add_argument('--binary', action="store_true", help='output binary file for MicroPython')
|
||||||
|
parser.add_argument('--py', action="store_true", help='output .py file for MicroPython embedding')
|
||||||
|
parser.add_argument('--resize', action="store_true", help='force images to 296x128 pixels')
|
||||||
|
|
||||||
|
options = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
class ByteWriter(object):
|
||||||
|
bytes_per_line = 16
|
||||||
|
|
||||||
|
def __init__(self, stream, varname):
|
||||||
|
self.stream = stream
|
||||||
|
self.stream.write('{} =\\\n'.format(varname))
|
||||||
|
self.bytecount = 0 # For line breaks
|
||||||
|
|
||||||
|
def _eol(self):
|
||||||
|
self.stream.write("'\\\n")
|
||||||
|
|
||||||
|
def _eot(self):
|
||||||
|
self.stream.write("'\n")
|
||||||
|
|
||||||
|
def _bol(self):
|
||||||
|
self.stream.write("b'")
|
||||||
|
|
||||||
|
# Output a single byte
|
||||||
|
def obyte(self, data):
|
||||||
|
if not self.bytecount:
|
||||||
|
self._bol()
|
||||||
|
self.stream.write('\\x{:02x}'.format(data))
|
||||||
|
self.bytecount += 1
|
||||||
|
self.bytecount %= self.bytes_per_line
|
||||||
|
if not self.bytecount:
|
||||||
|
self._eol()
|
||||||
|
|
||||||
|
# Output from a sequence
|
||||||
|
def odata(self, bytelist):
|
||||||
|
for byt in bytelist:
|
||||||
|
self.obyte(byt)
|
||||||
|
|
||||||
|
# ensure a correct final line
|
||||||
|
def eot(self): # User force EOL if one hasn't occurred
|
||||||
|
if self.bytecount:
|
||||||
|
self._eot()
|
||||||
|
self.stream.write('\n')
|
||||||
|
|
||||||
|
|
||||||
|
def convert_image(img):
|
||||||
|
if options.resize:
|
||||||
|
img = img.resize((296, 128)) # resize
|
||||||
|
try:
|
||||||
|
enhancer = ImageEnhance.Contrast(img)
|
||||||
|
img = enhancer.enhance(2.0)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
img = img.convert("1") # convert to black and white
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
def write_stream(header, footer, ip_stream, op_stream):
|
||||||
|
op_stream.write(header)
|
||||||
|
op_stream.write('\n')
|
||||||
|
data = ip_stream.read()
|
||||||
|
bw_data = ByteWriter(op_stream, '_data')
|
||||||
|
bw_data.odata(data)
|
||||||
|
bw_data.eot()
|
||||||
|
op_stream.write(footer)
|
||||||
|
|
||||||
|
|
||||||
|
# create map of images based on input filenames
|
||||||
|
for input_filename in options.file:
|
||||||
|
with Image.open(input_filename) as img:
|
||||||
|
img = convert_image(img)
|
||||||
|
|
||||||
|
image_name = Path(input_filename).stem
|
||||||
|
|
||||||
|
w, h = img.size
|
||||||
|
|
||||||
|
output_data = [~b & 0xff for b in list(img.tobytes())]
|
||||||
|
|
||||||
|
if options.binary:
|
||||||
|
if options.out_dir is not None:
|
||||||
|
output_filename = (options.out_dir / image_name).with_suffix(".bin")
|
||||||
|
else:
|
||||||
|
output_filename = Path(input_filename).with_suffix(".bin")
|
||||||
|
print(f"Saving to {output_filename}, {w}x{h}")
|
||||||
|
with open(output_filename, "wb") as out:
|
||||||
|
out.write(bytearray(output_data))
|
||||||
|
elif options.py:
|
||||||
|
if options.out_dir is not None:
|
||||||
|
output_filename = (options.out_dir / image_name).with_suffix(".py")
|
||||||
|
else:
|
||||||
|
output_filename = Path(input_filename).with_suffix(".py")
|
||||||
|
print(f"Saving to {output_filename}, {w}x{h}")
|
||||||
|
with open(output_filename, "w") as out:
|
||||||
|
write_stream(PY_HEADER, PY_FOOTER, io.BytesIO(bytes(output_data)), out)
|
||||||
|
else:
|
||||||
|
image_code = '''\
|
||||||
|
static const uint8_t {image_name}[{count}] = {{
|
||||||
|
{byte_data}
|
||||||
|
}};
|
||||||
|
'''.format(image_name=image_name, count=len(output_data), byte_data=", ".join(str(b) for b in output_data))
|
||||||
|
|
||||||
|
print(image_code)
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,5 +1,5 @@
|
|||||||
Kirill Timofeev
|
Mariano Sciacco
|
||||||
Engineering Team
|
IoT & Cloud Engineer
|
||||||
Census
|
Vimar S.p.A.
|
||||||
oneearedrabbit
|
git.marianosciacco.it
|
||||||
badge.bin
|
badgem.bin
|
||||||
BIN
src/badges/badgem.bin
Normal file
BIN
src/badges/badgem.bin
Normal file
Binary file not shown.
BIN
src/badges/badgem.png
Normal file
BIN
src/badges/badgem.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,9 @@ import badger_os
|
|||||||
from widgets import draw_window, pprint, ptitle, plength, ppara, button, draw_ui
|
from widgets import draw_window, pprint, ptitle, plength, ppara, button, draw_ui
|
||||||
from random import random
|
from random import random
|
||||||
|
|
||||||
IMAGE_WIDTH = 96
|
# IMAGE_WIDTH = 96
|
||||||
IMAGE_HEIGHT = 96
|
# IMAGE_HEIGHT = 96
|
||||||
DELTA = 0
|
# DELTA = 0
|
||||||
|
|
||||||
# Check that the fortune directory exists, if not, make it
|
# Check that the fortune directory exists, if not, make it
|
||||||
try:
|
try:
|
||||||
@@ -25,8 +25,8 @@ state = {
|
|||||||
"running": "badge_app",
|
"running": "badge_app",
|
||||||
}
|
}
|
||||||
|
|
||||||
IMAGE_WIDTH = 64
|
IMAGE_WIDTH = 29
|
||||||
IMAGE_HEIGHT = 64
|
IMAGE_HEIGHT = 32
|
||||||
|
|
||||||
def render():
|
def render():
|
||||||
display.pen(15)
|
display.pen(15)
|
||||||
@@ -47,11 +47,11 @@ def draw_clippy():
|
|||||||
y = 21
|
y = 21
|
||||||
width = 294
|
width = 294
|
||||||
height = 106
|
height = 106
|
||||||
draw_window(display, x, y, width, height, " Special ")
|
draw_window(display, x, y, width, height, " Information ")
|
||||||
|
|
||||||
clippy_dat = bytearray(int(IMAGE_WIDTH * IMAGE_HEIGHT / 8))
|
# clippy_dat = bytearray(int(IMAGE_WIDTH * IMAGE_HEIGHT / 8))
|
||||||
open(f"images/clippy.bin", "rb").readinto(clippy_dat)
|
# open(f"images/logo.bin", "rb").readinto(clippy_dat)
|
||||||
display.image(clippy_dat, IMAGE_WIDTH, IMAGE_HEIGHT, 212, 56)
|
# display.image(clippy_dat, IMAGE_WIDTH, IMAGE_HEIGHT, 212, 56)
|
||||||
|
|
||||||
# scrollbars
|
# scrollbars
|
||||||
display.pen(0)
|
display.pen(0)
|
||||||
@@ -92,7 +92,7 @@ def draw_elements():
|
|||||||
display.pen(15)
|
display.pen(15)
|
||||||
display.clear()
|
display.clear()
|
||||||
|
|
||||||
draw_ui(display, "Special")
|
draw_ui(display, "About")
|
||||||
|
|
||||||
draw_clippy()
|
draw_clippy()
|
||||||
|
|
||||||
|
|||||||
BIN
src/images/loghetto.bin
Normal file
BIN
src/images/loghetto.bin
Normal file
Binary file not shown.
BIN
src/images/loghetto.png
Normal file
BIN
src/images/loghetto.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
src/images/logo.bin
Normal file
BIN
src/images/logo.bin
Normal file
Binary file not shown.
BIN
src/images/logo.png
Normal file
BIN
src/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 767 B |
@@ -34,19 +34,19 @@ def draw_about():
|
|||||||
|
|
||||||
# logo
|
# logo
|
||||||
image = bytearray(int(32 * 32 / 8))
|
image = bytearray(int(32 * 32 / 8))
|
||||||
open("images/{}".format("census.bin"), "r").readinto(image)
|
open("images/{}".format("logo.bin"), "r").readinto(image)
|
||||||
display.image(image, 32, 32, 86, 56)
|
display.image(image, 32, 32, 86, 56)
|
||||||
|
|
||||||
pprint(display, "Engineering", 125, 56, 0)
|
pprint(display, "AWS Summit", 125, 56, 0)
|
||||||
pprint(display, "Offsite", 125, 66, 0)
|
# pprint(display, "---", 125, 66, 0)
|
||||||
pprint(display, "Brooklyn", 125, 76, 0)
|
pprint(display, "Milan (Italy)", 125, 66, 0)
|
||||||
pprint(display, "2022", 125, 86, 0)
|
pprint(display, "2024", 125, 76, 0)
|
||||||
|
|
||||||
def render():
|
def render():
|
||||||
display.pen(15)
|
display.pen(15)
|
||||||
display.clear()
|
display.clear()
|
||||||
|
|
||||||
draw_ui(display, "About")
|
draw_ui(display, "Event")
|
||||||
|
|
||||||
draw_about()
|
draw_about()
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ def draw_qr_code(ox, oy, size, code):
|
|||||||
|
|
||||||
|
|
||||||
def draw_qr_file(n):
|
def draw_qr_file(n):
|
||||||
draw_window(display, 6, 26, 282, 94, " About us ")
|
draw_window(display, 6, 26, 282, 94, " About me ")
|
||||||
|
|
||||||
file = CODES[n]
|
file = CODES[n]
|
||||||
codetext = open("qrcodes/{}".format(file), "r")
|
codetext = open("qrcodes/{}".format(file), "r")
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
https://getcensus.com/
|
https://marianosciacco.it/publications/qrfuzz-paper/
|
||||||
Census
|
Mariano Sciacco
|
||||||
* the leading reverse ETL
|
* IoT & Cloud Engineer
|
||||||
* no more CSV files
|
* Vimar S.p.A.
|
||||||
* sync data in real-time
|
* (AWS Summit 2024)
|
||||||
|
|
||||||
Scan this code to learn
|
If You Are Scanning This,
|
||||||
more about Census.
|
It Is Too Late!
|
||||||
@@ -187,23 +187,28 @@ def draw_background(display):
|
|||||||
# display.image(image, 296, 128, 0, 0)
|
# display.image(image, 296, 128, 0, 0)
|
||||||
|
|
||||||
def draw_menu(display, selected):
|
def draw_menu(display, selected):
|
||||||
menu = "Badge QR Special About"
|
menu = "Badge QR About Event"
|
||||||
|
|
||||||
# logo
|
# logo
|
||||||
display.pen(0)
|
display.pen(0)
|
||||||
display.thickness(1)
|
display.thickness(1)
|
||||||
|
|
||||||
x = 12
|
loghetto = bytearray(int(16 * 18 / 8))
|
||||||
y = 6
|
open("images/{}".format("loghetto.bin"), "r").readinto(loghetto)
|
||||||
display.line(x + 2, y, x + 8, y)
|
display.image(loghetto, 16, 18, 10, 2)
|
||||||
display.line(x + 6, y + 1, x + 9, y + 1)
|
|
||||||
display.line(x + 1, y + 2, x + 10, y + 2)
|
# old logo
|
||||||
display.line(x + 5, y + 3, x + 10, y + 3)
|
# x = 12
|
||||||
display.line(x, y + 4, x + 10, y + 4)
|
# y = 6
|
||||||
display.line(x + 5, y + 5, x + 10, y + 5)
|
# display.line(x + 2, y, x + 8, y)
|
||||||
display.line(x + 1, y + 6, x + 10, y + 6)
|
# display.line(x + 6, y + 1, x + 9, y + 1)
|
||||||
display.line(x + 6, y + 7, x + 9, y + 7)
|
# display.line(x + 1, y + 2, x + 10, y + 2)
|
||||||
display.line(x + 2, y + 8, x + 8, y + 8)
|
# display.line(x + 5, y + 3, x + 10, y + 3)
|
||||||
|
# display.line(x, y + 4, x + 10, y + 4)
|
||||||
|
# display.line(x + 5, y + 5, x + 10, y + 5)
|
||||||
|
# display.line(x + 1, y + 6, x + 10, y + 6)
|
||||||
|
# display.line(x + 6, y + 7, x + 9, y + 7)
|
||||||
|
# display.line(x + 2, y + 8, x + 8, y + 8)
|
||||||
|
|
||||||
x = 40
|
x = 40
|
||||||
pprint(display, menu, x, 6, 0)
|
pprint(display, menu, x, 6, 0)
|
||||||
@@ -226,6 +231,7 @@ def draw_border(display):
|
|||||||
display.line(1, 1, 1, 127)
|
display.line(1, 1, 1, 127)
|
||||||
display.line(1, 127, 295, 127)
|
display.line(1, 127, 295, 127)
|
||||||
display.line(295, 1, 295, 127)
|
display.line(295, 1, 295, 127)
|
||||||
|
|
||||||
display.image(bytearray((0xff, 0xff, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0xc0)), 8, 8, 0, 0)
|
display.image(bytearray((0xff, 0xff, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0xc0)), 8, 8, 0, 0)
|
||||||
display.image(bytearray((0xff, 0xff, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x03)), 8, 8, 288, 0)
|
display.image(bytearray((0xff, 0xff, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x03)), 8, 8, 288, 0)
|
||||||
display.image(bytearray((0x03, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0xff, 0xff)), 8, 8, 288, 120)
|
display.image(bytearray((0x03, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0xff, 0xff)), 8, 8, 288, 120)
|
||||||
|
|||||||
Reference in New Issue
Block a user