108 lines
2.9 KiB
Python
Executable File
108 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import argparse
|
|
import requests
|
|
from typing import NamedTuple
|
|
import PIL
|
|
import PIL.Image
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("hostname")
|
|
subparsers = parser.add_subparsers(dest="command")
|
|
clear_parser = subparsers.add_parser("clear")
|
|
draw_parser = subparsers.add_parser("draw")
|
|
draw_parser.add_argument("-c", "--clear", action="store_true")
|
|
draw_parser.add_argument("file")
|
|
info_praser = subparsers.add_parser("info")
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def clear(hostname):
|
|
requests.post(f"http://{hostname}/clear").raise_for_status()
|
|
|
|
|
|
class EpdInfo(NamedTuple):
|
|
width: int
|
|
height: int
|
|
temperature: int
|
|
|
|
@classmethod
|
|
def from_response(cls, resp):
|
|
return cls(
|
|
width=int(resp.headers["width"]),
|
|
height=int(resp.headers["height"]),
|
|
temperature=int(resp.headers["temperature"]),
|
|
)
|
|
|
|
|
|
class Dimensions(NamedTuple):
|
|
width: int
|
|
height: int
|
|
|
|
|
|
def info(hostname):
|
|
resp = requests.get(f"http://{hostname}")
|
|
resp.raise_for_status()
|
|
return EpdInfo.from_response(resp)
|
|
|
|
|
|
def image_refit(image: PIL.Image, bounder: Dimensions) -> PIL.Image:
|
|
bounder_ratio = bounder.width / bounder.height
|
|
image_width, image_height = image.size
|
|
|
|
image_width_by_height = int(image_height * bounder_ratio)
|
|
image_height_by_width = int(image_width / bounder_ratio)
|
|
if image_width > image_width_by_height:
|
|
new_dimensions = Dimensions(image_width_by_height, image_height)
|
|
else:
|
|
new_dimensions = Dimensions(image_width, image_height_by_width)
|
|
return PIL.ImageOps.fit(image, new_dimensions)
|
|
|
|
|
|
def convert_8bit_to_4bit(bytestring):
|
|
fourbit = []
|
|
for i in range(0, len(bytestring), 2):
|
|
first_nibble = int(bytestring[i] / 17)
|
|
second_nibble = int(bytestring[i + 1] / 17)
|
|
fourbit += [first_nibble << 4 | second_nibble]
|
|
fourbit = bytes(fourbit)
|
|
return fourbit
|
|
|
|
|
|
def draw(hostname, filename, clear):
|
|
inf = info(hostname)
|
|
img = PIL.Image.open(filename)
|
|
img = image_refit(img, Dimensions(width=inf.width, height=inf.height))
|
|
img = img.resize((inf.width, inf.height))
|
|
img = img.convert("L")
|
|
img_bytes = convert_8bit_to_4bit(img.tobytes())
|
|
requests.post(
|
|
f"http://{hostname}/draw",
|
|
headers={
|
|
"width": str(inf.width),
|
|
"height": str(inf.height),
|
|
"x": "0",
|
|
"y": "0",
|
|
"clear": "1" if clear else "0",
|
|
},
|
|
data=img_bytes,
|
|
)
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
if args.command == "clear":
|
|
clear(args.hostname)
|
|
elif args.command == "info":
|
|
print(info(args.hostname))
|
|
elif args.command == "draw":
|
|
draw(args.hostname, args.file, args.clear)
|
|
else:
|
|
raise Exception(f"Unknown command {args.command}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|