diff --git a/client_sw/__pycache__/matrixSender.cpython-35.pyc b/client_sw/__pycache__/matrixSender.cpython-35.pyc new file mode 100644 index 0000000..67ba09e Binary files /dev/null and b/client_sw/__pycache__/matrixSender.cpython-35.pyc differ diff --git a/client_sw/images.py b/client_sw/images.py new file mode 100644 index 0000000..f6ab70e --- /dev/null +++ b/client_sw/images.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import time +from PIL import Image, ImageDraw, ImageFont +from matrixSender import MatrixSender +import time +import sys +from random import randint + +matrix = MatrixSender(udphost="localhost", udpport=2323, img_size=(160,24*6), bitsperpixel=2) + + +def send_img_from_filename(imgfilename,invert=False): + background = Image.new("RGBA", matrix._img_size, MatrixSender.C_BLACK) + image = Image.open(imgfilename) + image = image.convert(mode='RGBA') + image = image.resize(matrix._img_size) + image.save('/tmp/send2.png', 'PNG') + background.paste(image, box=(0,0), mask=None) + background.save('/tmp/send.png', 'PNG') + + matrix.send(background,invert) + +def send_img(img): + background = Image.new("RGBA", matrix._img_size, MatrixSender.C_BLACK) + stream = io.BytesIO(img) + image = Image.open(stream) + image = image.convert(mode='RGBA') + image = image.resize(matrix._img_size) + image.save('/tmp/send2.jpeg', 'JPEG') + background.paste(image, box=(0,0), mask=None) + background.save('/tmp/send.jpeg', 'JPEG') + + matrix.send(background) + +if __name__ == '__main__': + if len(sys.argv)>1: + send_img_from_filename(sys.argv[1]) diff --git a/client_sw/images/160_144/grauverlauf.png b/client_sw/images/160_144/grauverlauf.png new file mode 100644 index 0000000..4e84818 Binary files /dev/null and b/client_sw/images/160_144/grauverlauf.png differ diff --git a/client_sw/images/160_144/pokemon1.png b/client_sw/images/160_144/pokemon1.png new file mode 100644 index 0000000..9c8d1b9 Binary files /dev/null and b/client_sw/images/160_144/pokemon1.png differ diff --git a/client_sw/images/160_48/Spaceinvaders.png b/client_sw/images/160_48/Spaceinvaders.png new file mode 100644 index 0000000..958e512 Binary files /dev/null and b/client_sw/images/160_48/Spaceinvaders.png differ diff --git a/client_sw/images/160_48/black.png b/client_sw/images/160_48/black.png new file mode 100644 index 0000000..e07e41a Binary files /dev/null and b/client_sw/images/160_48/black.png differ diff --git a/client_sw/images/160_48/chaoswest.png b/client_sw/images/160_48/chaoswest.png new file mode 100644 index 0000000..4dd523e Binary files /dev/null and b/client_sw/images/160_48/chaoswest.png differ diff --git a/client_sw/images/160_48/ctdo_logo.png b/client_sw/images/160_48/ctdo_logo.png new file mode 100644 index 0000000..0542ce8 Binary files /dev/null and b/client_sw/images/160_48/ctdo_logo.png differ diff --git a/client_sw/images/160_48/kirby.png b/client_sw/images/160_48/kirby.png new file mode 100644 index 0000000..286f961 Binary files /dev/null and b/client_sw/images/160_48/kirby.png differ diff --git a/client_sw/images/160_48/kirbyboss.png b/client_sw/images/160_48/kirbyboss.png new file mode 100644 index 0000000..96f914b Binary files /dev/null and b/client_sw/images/160_48/kirbyboss.png differ diff --git a/client_sw/images/160_48/mario.png b/client_sw/images/160_48/mario.png new file mode 100644 index 0000000..2e9e200 Binary files /dev/null and b/client_sw/images/160_48/mario.png differ diff --git a/client_sw/images/160_48/nyancat.png b/client_sw/images/160_48/nyancat.png new file mode 100644 index 0000000..dca7c51 Binary files /dev/null and b/client_sw/images/160_48/nyancat.png differ diff --git a/client_sw/images/160_48/pokemon_wildpidgey.png b/client_sw/images/160_48/pokemon_wildpidgey.png new file mode 100644 index 0000000..8e2f7af Binary files /dev/null and b/client_sw/images/160_48/pokemon_wildpidgey.png differ diff --git a/client_sw/images/160_48/schlange.png b/client_sw/images/160_48/schlange.png new file mode 100644 index 0000000..cb820bf Binary files /dev/null and b/client_sw/images/160_48/schlange.png differ diff --git a/client_sw/images/160_48/tetris.png b/client_sw/images/160_48/tetris.png new file mode 100644 index 0000000..1ecc545 Binary files /dev/null and b/client_sw/images/160_48/tetris.png differ diff --git a/client_sw/images/160_48/troll.png b/client_sw/images/160_48/troll.png new file mode 100644 index 0000000..5d6b723 Binary files /dev/null and b/client_sw/images/160_48/troll.png differ diff --git a/client_sw/images/160_48/tuwat.png b/client_sw/images/160_48/tuwat.png new file mode 100644 index 0000000..8f1f878 Binary files /dev/null and b/client_sw/images/160_48/tuwat.png differ diff --git a/client_sw/images/160_48/white.png b/client_sw/images/160_48/white.png new file mode 100644 index 0000000..64a4803 Binary files /dev/null and b/client_sw/images/160_48/white.png differ diff --git a/client_sw/images/160_48/zelda.png b/client_sw/images/160_48/zelda.png new file mode 100644 index 0000000..036a21b Binary files /dev/null and b/client_sw/images/160_48/zelda.png differ diff --git a/client_sw/matrixSender.py b/client_sw/matrixSender.py new file mode 100644 index 0000000..6ff413c --- /dev/null +++ b/client_sw/matrixSender.py @@ -0,0 +1,93 @@ +from PIL import Image, ImageDraw, ImageFont +import socket +import binascii +import io +import time +import re +import numpy as np + +import PIL.ImageOps + + + +class MatrixSender(object): + + C_BLACK = 0 + C_WHITE = 255 + + global threadrunning + threadrunning=False + + + def __init__(self, udphost, udpport, img_size=(160,48), bitsperpixel=1): + + 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.bitsperpixel=bitsperpixel + + self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + + + 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 _intToBitlist(self,number): #convert integer number to list of bits, exampe: 1-> [0,1], 2->[1,0] + bitlistvaryinglength=[x for x in "{0:b}".format(number)] + bitlist=np.zeros(self.bitsperpixel,dtype=int) + bitlist[self.bitsperpixel-len(bitlistvaryinglength):]=bitlistvaryinglength + return bitlist + + + def send(self, image,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 + + pixelbrightness=int( (r+g+b)/3 *(pow(2,self.bitsperpixel)-1) /255 +0.5) + + + if invert: + pixelbrightness=pow(2,self.bitsperpixel)-1-pixelbrightness + + for b in self._intToBitlist(pixelbrightness): + imgmap.append(b) + + + + 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)) + + + 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)) diff --git a/client_sw/matrixsimulator.py b/client_sw/matrixsimulator.py new file mode 100644 index 0000000..cb11b15 --- /dev/null +++ b/client_sw/matrixsimulator.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import _thread +import socket +import pygame +import math +import random +import numpy as np +from pygame.locals import * +import time + +WIDTH=160 +HEIGHT=24*6 +PIXELSIZE=4 #For Simulator Display +UDPPORT=2323 +DEBUG=True +BITSPERPIXEL=2 + + +class FlipdotSim(): + def __init__(self, + imageSize = (160,48), #80,16 + pixelSize = 10, + udpPort = 2323, + bitsperpixel=1): + self.imageSize=imageSize + self.udpPort = udpPort + self.bitsperpixel=bitsperpixel + self.flipdotMatrixSimulatorWidget = FlipdotMatrixSimulatorWidget(imageSize, pixelSize, bitsperpixel) #comment out if no simulator needed + self.udpHostSocket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + self.udpHostSocket.bind(("", self.udpPort)) + + self.timesincelastpacket=time.time() + + def run(self): + self.RunServer() + + def bitlistToInt(self,bitlist): #lsb last, [1,0]=2, [0,1]=1 + number=0 + for bitindex,bitvalue in enumerate(reversed(bitlist)): + number+=bitvalue*pow(2,bitindex) + return number + + def RunServer(self): + try: + while True: + #rawData = self.udpHostSocket.recv(4096) + rawData = self.udpHostSocket.recv(4096*2) + + imageArray = ImageArrayAdapter().convertPacketToImageArray(rawData) + if DEBUG: + print("Received Data. Time since last message: "+str( round( time.time()-self.timesincelastpacket,2))+"s ("+str( round( (1/ (time.time()-self.timesincelastpacket) ) ,2) ) +" FPS)") + self.timesincelastpacket=time.time() + _bitsneeded=self.imageSize[0]*self.imageSize[1]*self.bitsperpixel + if len(imageArray) < _bitsneeded: + if DEBUG: + print("WARNING: Not enough data received. Got "+str(len(imageArray))+" bits, needs "+str(_bitsneeded)+" bits") + emptyArray=np.zeros(_bitsneeded,dtype=int) + emptyArray[0:len(imageArray)]=imageArray + imageArray=emptyArray + elif len(imageArray) > _bitsneeded: + if DEBUG: + print("WARNING: Too much data received. Got "+str(len(imageArray))+" bits, needs "+str(_bitsneeded)+" bits") + imageArray=imageArray[0:_bitsneeded] + + imageArray=[self.bitlistToInt(x) for x in np.array(imageArray).reshape((int(len(imageArray)/self.bitsperpixel),self.bitsperpixel))] + + self.flipdotMatrixSimulatorWidget.show(imageArray) #send to simulator display + + finally: + self.udpHostSocket.close() + +class ImageArrayAdapter(): + def __init__(self): + self.arrayOfBinaryInts = [] + + def convertPacketToImageArray(self, udpPacketStr): + self.arrayOfBinaryInts = [] + byteArray = bytearray(udpPacketStr) + + #Fix for other format. Not Used + #byteArray = udpPacketStr.translate(None, b'\r\n').decode().replace('[','').replace(']','').replace(' ','').split(',') + #byteArray = [int(x) for x in byteArray] + #print("rawtype="+str(type(byteArray))) + + #print(byteArray) + for byte in byteArray: + #print("byte:"+str(byte)) + self.__appendByteToArrayOfBinaryInts(byte) + return self.arrayOfBinaryInts + + def __appendByteToArrayOfBinaryInts(self, byte): + byteValue = int(byte) + for i in range(8): + if math.floor(byteValue/(2**(7-i))) > 0: + self.arrayOfBinaryInts.append(1) + #print("append 1") + else: + self.arrayOfBinaryInts.append(0) + #print("append 0") + byteValue = byteValue%(2**(7-i)) + + + + +class FlipdotMatrixSimulatorWidget(): + BLACKCOLOR = 0 + WHITECOLOR = 1 + + def __init__(self, + imageSize = (160,48), + pixelSize = 4, + bitsperpixel = 1): + self.imageSize = imageSize + self.pixelSize = pixelSize + + pygame.init() + self.screen = pygame.display.set_mode((imageSize[0]*pixelSize, imageSize[1]*pixelSize)) + self.screen.fill((255,255,255)) + _thread.start_new_thread(self.watchCloseThread, ()) + + self.bitsperpixel=bitsperpixel + + + + def watchCloseThread(self): + while True: + for event in pygame.event.get(): + if event.type in (QUIT, QUIT): + import os + os.kill(os.getpid(), 9) + pygame.time.delay(500) + + def show(self, imageArray): + for yValue in range(self.imageSize[1]): + for xValue in range(self.imageSize[0]): + i = self.imageSize[0]*yValue + xValue + color = imageArray[i] / (pow(2,self.bitsperpixel)-1) #gives a number between 0 and 1 inclusive. Example for bitsperpixel=2: [1,0]-> 2/ (2^2-1)=2/3 + self.updatePixel(xValue, yValue, color) + pygame.display.update() + + def clearPixels(self): + for xValue in range(self.imageSize[0]): + for yValue in range(self.imageSize[1]): + self.updatePixel(xValue, yValue, self.BLACKCOLOR) + + def updatePixel(self, xValue, yValue, brightness): + surface = pygame.Surface((self.pixelSize, self.pixelSize)) + minimumbrightness=32 + rectcolor = ( (255-minimumbrightness)*brightness+minimumbrightness,127*brightness+ minimumbrightness/2, minimumbrightness/4) + + #surface.fill(rectcolor) + pygame.draw.circle(surface, rectcolor, (int(self.pixelSize/2), int(self.pixelSize/2)), int(self.pixelSize/2)) #Draw LED as filled circles + self.screen.blit(surface, (xValue*self.pixelSize, yValue*self.pixelSize)) + + + +if __name__ == '__main__': + FlipdotSim(imageSize=(WIDTH,HEIGHT), pixelSize = PIXELSIZE, udpPort=UDPPORT, bitsperpixel=BITSPERPIXEL).run()