Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Daniel Schulte | f6a73c00d2 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
92
printer.py
92
printer.py
|
@ -17,11 +17,12 @@ import textwrap
|
||||||
|
|
||||||
import toml
|
import toml
|
||||||
import tweepy
|
import tweepy
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger("tweet-printer")
|
logger = logging.getLogger("tweet-printer")
|
||||||
|
|
||||||
printer_line_width = 48
|
printer_line_width = 52
|
||||||
|
|
||||||
def load_config():
|
def load_config():
|
||||||
fn = "config.toml"
|
fn = "config.toml"
|
||||||
|
@ -124,10 +125,82 @@ class Printer:
|
||||||
10 # extra*Y Unit exta space
|
10 # extra*Y Unit exta space
|
||||||
]))
|
]))
|
||||||
|
|
||||||
|
def write_image(self, img):
|
||||||
|
def size_for_printer(w,h):
|
||||||
|
return [math.ceil(w/8), (w//8)//256, h%256, h//256]
|
||||||
|
|
||||||
|
w, h = img.size
|
||||||
|
if w!=576:
|
||||||
|
logger.error("Currently images with width other than 576 can't be printed")
|
||||||
|
return
|
||||||
|
|
||||||
|
data = [0x1d, 0x76, 0x30, 0x00] + size_for_printer(*img.size)
|
||||||
|
for y in range(img.height):
|
||||||
|
current_byte = 0
|
||||||
|
current_bit = 0
|
||||||
|
for x in range(img.width):
|
||||||
|
l = img.getpixel((x, y))
|
||||||
|
to_add = 1<<(7-current_bit)
|
||||||
|
current_byte += to_add if l<127 else 0
|
||||||
|
current_bit += 1
|
||||||
|
if current_bit>7:
|
||||||
|
data.append(current_byte)
|
||||||
|
current_bit = 0
|
||||||
|
current_byte = 0
|
||||||
|
if current_bit != 0:
|
||||||
|
data.append(current_byte)
|
||||||
|
self.printer.write(bytes(data))
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
self.printer.flush()
|
self.printer.flush()
|
||||||
|
|
||||||
|
|
||||||
|
class ImageRenderer:
|
||||||
|
def __init__(self, font_file, font_size=None):
|
||||||
|
self.font = ImageFont.truetype(font_file, font_size or 18)
|
||||||
|
self.line_height = self.font.getsize("x")[1]
|
||||||
|
self.line_spacing = 4
|
||||||
|
|
||||||
|
def render_header(self, handle, name, dt, is_rt=None):
|
||||||
|
h = self.font.getsize("0@"+handle+name)[1] # Figure out, how high this line will be
|
||||||
|
w = 576
|
||||||
|
if is_rt is None:
|
||||||
|
is_rt = False
|
||||||
|
handle_text = f"@{handle} "
|
||||||
|
if is_rt:
|
||||||
|
handle_text = "RT by "+handle_text
|
||||||
|
name_text = f"({name})"
|
||||||
|
dt_text = dt.strftime(" %Y-%m-%d %H:%M:%S")
|
||||||
|
space_for_dt = self.font.getsize(dt_text)
|
||||||
|
space_for_handle = self.font.getsize(handle_text)
|
||||||
|
space_for_name = self.font.getsize(name_text)
|
||||||
|
|
||||||
|
print(space_for_handle, space_for_name, space_for_dt)
|
||||||
|
|
||||||
|
w_left_for_name = w-space_for_handle[0]-space_for_dt[0]
|
||||||
|
while len(name_text) and space_for_name[0]>w_left_for_name:
|
||||||
|
name_text = name_text[-2]+"\u2026)"
|
||||||
|
space_for_name = self.font.getsize(name_text)
|
||||||
|
|
||||||
|
print(handle_text, name_text, dt_text, sep="")
|
||||||
|
img = Image.new("1", (576, h), 0)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw.text((0,0), handle_text, font=self.font, fill=1)
|
||||||
|
draw.text((space_for_handle[0], 0), name_text, font=self.font, fill=1)
|
||||||
|
draw.text((w-space_for_dt[0], 0), dt_text, font=self.font, fill=1)
|
||||||
|
return img
|
||||||
|
|
||||||
|
def render(self, lines):
|
||||||
|
spacing = self.line_height + self.line_spacing
|
||||||
|
img = Image.new("1", (576, len(lines)*spacing), 0)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
for i,line in enumerate(lines):
|
||||||
|
draw.text((0, i*spacing), line, font=self.font, fill=1)
|
||||||
|
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
class StreamListener(tweepy.StreamListener):
|
class StreamListener(tweepy.StreamListener):
|
||||||
def __init__(self, title, ignore_rt=False, printer=None):
|
def __init__(self, title, ignore_rt=False, printer=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -137,7 +210,7 @@ class StreamListener(tweepy.StreamListener):
|
||||||
self.printer = printer
|
self.printer = printer
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def split_and_encode_text(cls, text, extra_lines=[]):
|
def split(cls, text, extra_lines=[]):
|
||||||
lines = extra_lines
|
lines = extra_lines
|
||||||
for line in text.splitlines(True):
|
for line in text.splitlines(True):
|
||||||
stripped = line.strip()
|
stripped = line.strip()
|
||||||
|
@ -145,7 +218,11 @@ class StreamListener(tweepy.StreamListener):
|
||||||
lines += textwrap.wrap(stripped, printer_line_width)
|
lines += textwrap.wrap(stripped, printer_line_width)
|
||||||
else:
|
else:
|
||||||
lines.append(stripped)
|
lines.append(stripped)
|
||||||
return [line.encode("latin-1") for line in lines]
|
return lines
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def split_and_encode_text(cls, text, extra_lines=[]):
|
||||||
|
return [line.encode("latin-1") for line in split(text, extra_lines)]
|
||||||
|
|
||||||
def print_tweet(self, text, headers):
|
def print_tweet(self, text, headers):
|
||||||
try:
|
try:
|
||||||
|
@ -179,6 +256,9 @@ class StreamListener(tweepy.StreamListener):
|
||||||
header = format_header(status.user.screen_name, status.user.name, status.created_at)
|
header = format_header(status.user.screen_name, status.user.name, status.created_at)
|
||||||
print(header)
|
print(header)
|
||||||
print(text)
|
print(text)
|
||||||
|
r = ImageRenderer("fonts/DejaVuSansMono.ttf")
|
||||||
|
r.render([header]+self.split(text)).show()
|
||||||
|
return True
|
||||||
if self.printer:
|
if self.printer:
|
||||||
self.print_tweet(text, [header])
|
self.print_tweet(text, [header])
|
||||||
else:
|
else:
|
||||||
|
@ -280,6 +360,10 @@ def main():
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def test():
|
||||||
|
r = ImageRenderer("fonts/DejaVuSans.ttf", font_size=20)
|
||||||
|
r.render_header("trilader", "Daniel 🙏", datetime.datetime.now()).show()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
#main()
|
||||||
|
test()
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
img = Image.new("RGB", (100, 100), (47,47,47))
|
||||||
|
font = ImageFont.truetype("fonts/unifont-10.0.07.ttf", 20)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw.text((0,25), "A🙏B", font=font, fill=(255,255,255))
|
||||||
|
img.show()
|
|
@ -0,0 +1,85 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import math
|
||||||
|
import PIL
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
def line(w, h=1):
|
||||||
|
out = [0x1d, 0x76, 0x30, 0x00]
|
||||||
|
out += [math.ceil(w/8), (w//8)//256]
|
||||||
|
out += [h%256, h//256]
|
||||||
|
print(w,h,out)
|
||||||
|
|
||||||
|
data = [0xFF]*(w//8)
|
||||||
|
last = 0
|
||||||
|
for i in range(w%8):
|
||||||
|
last += 2**(7-i)
|
||||||
|
if last != 0:
|
||||||
|
data.append(last)
|
||||||
|
|
||||||
|
print(len(data))
|
||||||
|
|
||||||
|
for i in range(h):
|
||||||
|
out += data
|
||||||
|
|
||||||
|
print(len(out))
|
||||||
|
|
||||||
|
return bytes(out)
|
||||||
|
|
||||||
|
def size_for_printer(w,h):
|
||||||
|
return [math.ceil(w/8), (w//8)//256, h%256, h//256]
|
||||||
|
|
||||||
|
def print_image(filename):
|
||||||
|
img = Image.open(filename)
|
||||||
|
w, h = img.size
|
||||||
|
needs_resize = False
|
||||||
|
if w>576:
|
||||||
|
f = 576/w
|
||||||
|
nw = int(w*f)
|
||||||
|
nh = int(h*f)
|
||||||
|
needs_resize=True
|
||||||
|
|
||||||
|
img = img.convert("1")
|
||||||
|
if needs_resize:
|
||||||
|
img = img.resize((nw, nh), PIL.Image.NEAREST)
|
||||||
|
|
||||||
|
data = [0x1d, 0x76, 0x30, 0x00] + size_for_printer(*img.size)
|
||||||
|
for y in range(img.height):
|
||||||
|
current_byte = 0
|
||||||
|
current_bit = 0
|
||||||
|
for x in range(img.width):
|
||||||
|
l = img.getpixel((x, y))
|
||||||
|
to_add = 1<<(7-current_bit)
|
||||||
|
current_byte += to_add if l<127 else 0
|
||||||
|
current_bit += 1
|
||||||
|
if current_bit>7:
|
||||||
|
data.append(current_byte)
|
||||||
|
current_bit = 0
|
||||||
|
current_byte = 0
|
||||||
|
if current_bit != 0:
|
||||||
|
data.append(current_byte)
|
||||||
|
return bytes(data)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open("/dev/usb/lp1", "wb") as lp:
|
||||||
|
lp.write(bytes([0x1b, 0x40]))
|
||||||
|
lp.write(bytes([0x1b, 0x74, 0x06]))
|
||||||
|
lp.write(" 0123456789ABCDEF0123456789ABCDEF".encode("latin-1"))
|
||||||
|
lp.write(bytes([13,10]))
|
||||||
|
for offs in range(7):
|
||||||
|
lp.write((hex(2+2*offs)[-1]+" ").encode("latin-1"))
|
||||||
|
for c in range(32):
|
||||||
|
lp.write(bytes([(1+offs)*0x20+c]))
|
||||||
|
lp.write(bytes([13,10]))
|
||||||
|
#lp.write("Hier kommt ein ".encode("latin-1"))
|
||||||
|
#lp.write(print_image("inline.bmp"))
|
||||||
|
#lp.write("-Emoji".encode("latin-1"))
|
||||||
|
#lp.write(bytes([0x0d, 0x0a]))
|
||||||
|
|
||||||
|
#lp.write(print_image("test6.bmp"))
|
||||||
|
#lp.write(bytes([0x0d, 0x0a]))
|
||||||
|
lp.write(bytes([0x1d, 0x56, 0x42, 25]))
|
||||||
|
lp.flush();
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
def main():
|
||||||
|
out = Image.new("1", (576, 400), 0)
|
||||||
|
d = ImageDraw.Draw(out)
|
||||||
|
|
||||||
|
font1 = ImageFont.truetype("fonts/DejaVuSansMono.ttf", 18)
|
||||||
|
font2 = ImageFont.truetype("fonts/NotoMono-Regular.ttf", 18)
|
||||||
|
font3 = ImageFont.truetype("fonts/VeraMono.ttf", 18)
|
||||||
|
|
||||||
|
font = font3
|
||||||
|
|
||||||
|
line_height = d.textsize("-", font=font)[1]
|
||||||
|
line_spacing = 4 + line_height
|
||||||
|
|
||||||
|
lines = ["Test",
|
||||||
|
"1234567890123456789012345678901234567890123456789012",
|
||||||
|
"---------+---------+---------+---------+---------+--",
|
||||||
|
"Hallo, das hier ist ein Test mit Sonderzeichen!",
|
||||||
|
"äöüßÄÖܵ¹²³¼€¬{[]}\\",
|
||||||
|
"/\\/\\/\\/\\/\\/\\/\\~~~+++---___^^^°°°%%$$§§"]
|
||||||
|
|
||||||
|
for i,line in enumerate(lines):
|
||||||
|
d.text((0, i*line_spacing), line, font=font, fill=1)
|
||||||
|
|
||||||
|
out.show()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue