diff --git a/fonts/DejaVuSans.ttf b/fonts/DejaVuSans.ttf new file mode 100644 index 0000000..e5f7eec Binary files /dev/null and b/fonts/DejaVuSans.ttf differ diff --git a/fonts/DejaVuSansCondensed.ttf b/fonts/DejaVuSansCondensed.ttf new file mode 100644 index 0000000..3259bc2 Binary files /dev/null and b/fonts/DejaVuSansCondensed.ttf differ diff --git a/fonts/DejaVuSansMono.ttf b/fonts/DejaVuSansMono.ttf new file mode 100644 index 0000000..f578602 Binary files /dev/null and b/fonts/DejaVuSansMono.ttf differ diff --git a/fonts/NotoMono-Regular.ttf b/fonts/NotoMono-Regular.ttf new file mode 100644 index 0000000..3560a3a Binary files /dev/null and b/fonts/NotoMono-Regular.ttf differ diff --git a/fonts/VeraMono.ttf b/fonts/VeraMono.ttf new file mode 100644 index 0000000..139f0b4 Binary files /dev/null and b/fonts/VeraMono.ttf differ diff --git a/fonts/unifont-10.0.07.ttf b/fonts/unifont-10.0.07.ttf new file mode 100644 index 0000000..4ce5a2e Binary files /dev/null and b/fonts/unifont-10.0.07.ttf differ diff --git a/printer.py b/printer.py index b7733c2..8333548 100755 --- a/printer.py +++ b/printer.py @@ -17,11 +17,12 @@ import textwrap import toml import tweepy +from PIL import Image, ImageDraw, ImageFont logging.basicConfig(level=logging.INFO) logger = logging.getLogger("tweet-printer") -printer_line_width = 48 +printer_line_width = 52 def load_config(): fn = "config.toml" @@ -124,10 +125,82 @@ class Printer: 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): 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): def __init__(self, title, ignore_rt=False, printer=None): super().__init__() @@ -137,7 +210,7 @@ class StreamListener(tweepy.StreamListener): self.printer = printer @classmethod - def split_and_encode_text(cls, text, extra_lines=[]): + def split(cls, text, extra_lines=[]): lines = extra_lines for line in text.splitlines(True): stripped = line.strip() @@ -145,7 +218,11 @@ class StreamListener(tweepy.StreamListener): lines += textwrap.wrap(stripped, printer_line_width) else: 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): try: @@ -179,6 +256,9 @@ class StreamListener(tweepy.StreamListener): header = format_header(status.user.screen_name, status.user.name, status.created_at) print(header) print(text) + r = ImageRenderer("fonts/DejaVuSansMono.ttf") + r.render([header]+self.split(text)).show() + return True if self.printer: self.print_tweet(text, [header]) else: @@ -280,6 +360,10 @@ def main(): except KeyboardInterrupt: pass +def test(): + r = ImageRenderer("fonts/DejaVuSans.ttf", font_size=20) + r.render_header("trilader", "Daniel 🙏", datetime.datetime.now()).show() if __name__ == "__main__": - main() + #main() + test() diff --git a/rendertest.py b/rendertest.py new file mode 100644 index 0000000..781b495 --- /dev/null +++ b/rendertest.py @@ -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() diff --git a/test.py b/test.py new file mode 100755 index 0000000..06cc2df --- /dev/null +++ b/test.py @@ -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() diff --git a/test2.py b/test2.py new file mode 100644 index 0000000..ed9e538 --- /dev/null +++ b/test2.py @@ -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()