DFI/printtext_dfi/FlipdotSender.py

233 lines
7.6 KiB
Python
Raw Normal View History

from PIL import Image, ImageDraw, ImageFont
import socket
import binascii
import io
import time
import re
import numpy as np
import PIL.ImageOps
class FlipdotSender(object):
'''
classdocs
'''
C_BLACK = 0
C_WHITE = 255
global threadrunning
threadrunning=False
lastimgmap = []
def __init__(self, udphost, udpport, img_size=(160,48), font_size=9, font_size_scroll=12,
font_offset1=(0,0), font_offset2=(0,8),
#font_family='/usr/share/fonts/gnu-free/FreeMono.ttf',
#font_family='/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',
font_family='freefont/FreeMono.ttf',
chars_per_line=11):
'''
Constructor
'''
self._udphost = udphost
if not type(udpport) is int or udpport > 65536:
raise TypeError('port has to be int and > 65536 !!')
self._udpport = udpport
self._img_size = img_size
self._font_size = font_size
self._font_size_scroll = font_size_scroll
self._font_offset1 = font_offset1
self._font_offset2 = font_offset2
self._font_family = font_family
self._chars_per_line = chars_per_line
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def stopAnimation(self):
global threadrunning
threadrunning=False #tried to stop a running animation
def _list2byte(self, l):
byte = 0
i = 0
for i in range(8):
byte += 2**(7-i) if l[i] else 0
return byte
def _array2packet(self, a):
return [self._list2byte(a[i*8:i*8+8]) for i in range(int(len(a)/8))]
'''
def _send(self, image): #old function, backup
imgmap = []
for pixel in image.getdata():
r, g, b, a = pixel
if r == FlipdotSender.C_WHITE:
imgmap.append(1)
else:
imgmap.append(0)
lastimgmap=imgmap
packet = self._array2packet(imgmap)
self._sock.sendto(bytes(packet), (self._udphost, self._udpport))'''
def _send(self, image,fadespeed=0,invert=False): #changes slowly 'fadespeed'-pixels at a time
global threadrunning
#if fadespeed=0 -> change instant.
#time to change= 1280/25*0.2
imgmap = []
for pixel in image.getdata():
r, g, b, a = pixel
if r >= 127:
if invert:
imgmap.append(0)
else:
imgmap.append(1)
else:
if invert:
imgmap.append(1)
else:
imgmap.append(0)
imgmaptmp=FlipdotSender.lastimgmap
if fadespeed>0:
threadrunning=True
#diff=np.sum(np.array(imgmaptmp) != np.array(imgmap)) #different pixels
pixelchangeind=np.arange(self._img_size[0]*self._img_size[1])
np.random.shuffle(pixelchangeind)
for _i,ind in enumerate(pixelchangeind):
if threadrunning==False:
break #stop this for
if ind<len(imgmaptmp): #imgmaptmp is not empty (normally at first run)
imgmaptmp[ind]=imgmap[ind]
if _i%fadespeed==0:
packet = self._array2packet(imgmaptmp)
self._sock.sendto(bytes(packet), (self._udphost, self._udpport))
time.sleep(0.2)
if threadrunning==True: #if animation hasnt been cancelled
self.sendPacket(imgmap) #send packet and save last-imagemap
threadrunning=False
else:
self.sendPacket(imgmap) #send packet and save last-imagemap
def sendPacket(self, imgmap):
packet = self._array2packet(imgmap)
self._sock.sendto(bytes(packet), (self._udphost, self._udpport))
FlipdotSender.lastimgmap=imgmap
def send_bytes(self, img):
imgmap = []
for pixel in img:
if pixel == "1":
imgmap.append(1)
else:
imgmap.append(0)
if len(img) < 1280:
imgmap = np.hstack((imgmap, np.zeros(1280-len(img), dtype=int)))
packet = self._array2packet(imgmap)
self._sock.sendto(bytes(packet), (self._udphost, self._udpport))
def send_text(self, text,fadespeed=0):
image = Image.new("RGBA", self._img_size, FlipdotSender.C_BLACK)
draw = ImageDraw.Draw(image)
draw.fontmode = "1" # No AA
font = ImageFont.truetype(self._font_family, self._font_size)
cut = self._chars_per_line
splitted_text = text.split("|")
draw.text(self._font_offset1, splitted_text[0], font=font, fill=FlipdotSender.C_WHITE)
if len(splitted_text)>1:
draw.text(self._font_offset2, splitted_text[1], font=font, fill=FlipdotSender.C_WHITE)
self._send(image,fadespeed)
def send_textFull(self, text,fadespeed=0):
image = Image.new("RGBA", self._img_size, FlipdotSender.C_BLACK)
draw = ImageDraw.Draw(image)
draw.fontmode = "1" # No AA
l=1000 #init very high
splitpoint=40 #very high
currentfontsize=12+1 #init with max font size
font = ImageFont.truetype(self._font_family, currentfontsize)
while(l>80): #while text too long and font not too small
if currentfontsize>8:
currentfontsize=currentfontsize-1 #reduce size and try if fits
else: #if fontsize too small, try cutting sentence (2 lines)
splitpoint=splitpoint-1
font = ImageFont.truetype(self._font_family, currentfontsize)
l=draw.textsize(text[0:splitpoint], font=font)[0]
print("Textlength="+str(l)+" split="+str(splitpoint))
if splitpoint==40: #not splitted
draw.text((0,int((16-currentfontsize)/2) ), text, font=font, fill=FlipdotSender.C_WHITE)
else:
draw.text((0,-1), text[0:splitpoint], font=font, fill=FlipdotSender.C_WHITE)
draw.text((0,-1+currentfontsize), text[splitpoint:], font=font, fill=FlipdotSender.C_WHITE)
self._send(image,fadespeed)
def send_marquee(self, str, speed=3):
global threadrunning
threadrunning=True
offset = self._img_size[0]
font = ImageFont.truetype(self._font_family, self._font_size_scroll)
while offset >= -font.getsize(str)[0]-speed and threadrunning==True:
image = Image.new("RGBA", self._img_size, FlipdotSender.C_BLACK)
draw = ImageDraw.Draw(image)
draw.fontmode = "1" # No AA
draw.text((offset,0), str, font=font, fill=FlipdotSender.C_WHITE)
self._send(image)
offset -= speed
time.sleep(0.15)
threadrunning=False
def send_img_from_filename(self, imgfilename,invert=False):
background = Image.new("RGBA", self._img_size, FlipdotSender.C_BLACK)
image = Image.open(imgfilename)
image = image.convert(mode='RGBA')
image = image.resize(self._img_size)
image.save('/tmp/send2.png', 'PNG')
background.paste(image, box=(0,0), mask=None)
background.save('/tmp/send.png', 'PNG')
self._send(background,0,invert)
def send_img(self, img):
background = Image.new("RGBA", self._img_size, FlipdotSender.C_BLACK)
stream = io.BytesIO(img)
image = Image.open(stream)
image = image.convert(mode='RGBA')
image = image.resize(self._img_size)
image.save('/tmp/send2.jpeg', 'JPEG')
background.paste(image, box=(0,0), mask=None)
background.save('/tmp/send.jpeg', 'JPEG')
self._send(background)