Added rendering capabilites

Removed dummy settings.json file
This commit is contained in:
Ace 2020-05-29 04:00:39 +02:00
parent e7cb176530
commit 6efc1ffc71

View File

@ -1,7 +1,7 @@
from config import Settings, Layout
from inkycal import Settings, Layout
from inkycal.custom import *
import os.path.exists
from os.path import exists
import traceback
import logging
import arrow
@ -20,27 +20,50 @@ except ImportError:
print('pip3 install numpy')
logger = logging.getLogger('inkycal')
logger.setLevel(level=logging.DEBUG)
logger.setLevel(level=logging.ERROR)
class inkycal:
class Inkycal:
"""Main class"""
def __init__(self, settings_path, render=False):
def __init__(self, settings_path, render=True):
"""initialise class
settings_path = str -> location/folder of settings file
render = bool -> show something on the ePaper?
"""
self._release = '2.0.0beta'
# Check if render is boolean
if not isinstance(render, bool):
raise Exception('render must be True or False, not "{}"'.format(render))
self.render = render
# load+validate settings file. Import and setup specified modules
# Init settings class
self.Settings = Settings(settings_path)
# Check if display support colour
self.supports_colour = self.Settings.Layout.supports_colour
# Option to flip image upside down
self.upside_down = False
# Option to use epaper image optimisation
self.optimize = True
# Load drivers if image should be rendered
if self.render == True:
# Get model and check if colour can be rendered
model= self.Settings.model
# Init Display class
from inkycal.display import Display
self.Display = Display(model)
# load+validate settings file. Import and setup specified modules
self.active_modules = self.Settings.active_modules()
for module in self.active_modules:
try:
loader = 'from modules import {0}'.format(module)
loader = 'from inkycal.modules import {0}'.format(module)
module_data = self.Settings.get_config(module)
size, conf = module_data['size'], module_data['config']
setup = 'self.{} = {}(size, conf)'.format(module, module)
@ -95,7 +118,12 @@ class inkycal:
return remaining_time
def test(self):
"""Test if inkycal can be run correctly"""
"""Inkycal test run"""
print('You are running inkycal v{}'.format(self._release))
print('Running inkyal test-run for {} ePaper'.format(
self.Settings.model))
for module in self.active_modules:
generate_im = 'self.{0}.generate_image()'.format(module)
@ -107,17 +135,20 @@ class inkycal:
print('Error!')
print(traceback.format_exc())
def run(self, render = True):
def run(self):
"""Runs the main inykcal program nonstop (cannot be stopped anymore!)
Set render to True to show something on the display"""
# TODO: rendering
# TODO: printing traceback on display (or at least a smaller message?)
# Upside down
# Calibration
# Stitch images together ,merge black&colour if required
Will show something on the display if render was set to True"""
# Count the number of times without any crashs
# TODO: printing traceback on display (or at least a smaller message?)
# Calibration
# Get the time of initial run
runtime = arrow.now()
# Function to flip images upside down
upside_down = lambda image: image.rotate(180, expand=True)
# Count the number of times without any errors
counter = 1
while True:
@ -133,57 +164,169 @@ class inkycal:
counter = 0
print('OK')
if render == True:
print('rendering....')
## if upside_down == True:
## image = image.rotate(180, expand=True)
## if three_colour_support == True:
## image_col = image_col.rotate(180, expand=True)
# Assemble image from each module
self._assemble()
# Check if image should be rendered
if self.render == True:
Display = self.Display
if self.supports_colour == True:
im_black = Image.open(images+'canvas.png')
im_colour = Image.open(images+'canvas_colour.png')
# Flip the image by 180° if required
if self.upside_down == True:
upside_down(im_black)
upside_down(im_colour)
# render the image on the display
Display.render(im_black, im_colour)
# Part for black-white ePapers
elif self.supports_colour == False:
im_black = self._merge_bands()
# Flip the image by 180° if required
if self.upside_down == True:
upside_down(im_black)
Display.render(im_black)
print('\ninkycal has been running without any errors for', end = ' ')
print('{} display_updates'.format(counter))
print('{} display updates'.format(counter))
print('That was {}'.format(runtime.humanize()))
counter += 1
sleep_time = self.countdown(10) #####
sleep_time = self.countdown()
time.sleep(sleep_time)
def _merge_bands():
"""Merges black and coloured bands for black-white ePapers
returns the merged image
"""
def _merge()
"""Stitches images from each module a single one (for each colour)
Merges black and colour band for black-white epaper
"""
im_path = images
image = Image.new('RGB',
im_location = images
# Check if both files exist
# Center sub images
im1_path, im2_path = images+'canvas.png', images+'canvas_colour.png'
# If there is an image for black and colour, merge them
if exists(im1_path) and exists(im2_path):
im1 = Image.open(im1_name).convert('RGBA')
im2 = Image.open(im2_name).convert('RGBA')
def clear_white(img):
"""Replace all white pixels from image with transparent pixels
"""
x = numpy.asarray(img.convert('RGBA')).copy()
x[:, :, 3] = (255 * (x[:, :, :3] != 255).any(axis=2)).astype(numpy.uint8)
return Image.fromarray(x)
im2 = clear_white(im2)
im1.paste(im2, (0,0), im2)
# If there is no image for the coloured-band, return the bw-image
elif exists(im1_path) and not exists(im2_path):
im1 = Image.open(im1_name).convert('RGBA')
return im1
for module in self.active_modules:
im1_name, im2_name = module+'.png', module+'_colour.png'
def _assemble(self):
"""Assmebles all sub-images to a single image"""
# Check if display can only show black-white
if self.Settings.supports_colour == False:
if exists(im1_name) and exists(im2_name):
im1 = Image.open(images+im1_name).convert('RGBA')
im2 = Image.open(images+im2_name).convert('RGBA')
# Create an empty canvas with the size of the display
width, height = self.Settings.Layout.display_size
height, width = width, height
# White to transparent pixels
def clear_white(img):
"""Replace all white pixels from image with transparent pixels
"""
x = numpy.asarray(img.convert('RGBA')).copy()
x[:, :, 3] = (255 * (x[:, :, :3] != 255).any(axis=2)).astype(numpy.uint8)
return Image.fromarray(x)
im_black = Image.new('RGB', (width, height), color = 'white')
im_colour = Image.new('RGB', (width ,height), color = 'white')
# Paste black pixels of im2 on im1
im2 = clear_white(im2)
im1.paste(im2, (0,0), im2)
im1.save(module+'_comb.png', 'PNG')
# Set cursor for y-axis
im1_cursor = 0
im2_cursor = 0
# Check if display can support colour
elif self.Settings.supports_colour == True:
for module in self.active_modules:
im1_path = images+module+'.png'
im2_path = images+module+'_colour.png'
# Check if there is an image for the black band
if exists(im1_path):
# Get actual size of image
im1 = Image.open(im1_path).convert('RGBA')
im1_size = im1.size
# Get the size of the section
section_size = self.Settings.get_config(module)['size']
# Calculate coordinates to center the image
x = int( (section_size[0]-im1_size[0]) /2)
# If this is the first module, use the y-offset
if im1_cursor == 0:
y = int( (section_size[1]-im1_size[1]) /2)
else:
y = im1_cursor
# center the image in the section space
im_black.paste(im1, (x,y), im1)
# Shift the y-axis cursor at the beginning of next section
im1_cursor += section_size[1] - y
# Check if there is an image for the coloured band
if exists(im2_path):
# Get actual size of image
im2 = Image.open(im2_path).convert('RGBA')
im2_size = im2.size
# Get the size of the section
section_size = self.Settings.get_config(module)['size']
# Calculate coordinates to center the image
x = int( (section_size[0]-im2_size[0]) /2)
# If this is the first module, use the y-offset
if im2_cursor == 0:
y = int( (section_size[1]-im2_size[1]) /2)
else:
y = im2_cursor
# center the image in the section space
im_colour.paste(im2, (x,y), im2)
# Shift the y-axis cursor at the beginning of next section
im2_cursor += section_size[1] - y
if self.optimize == True:
self._optimize_im(im_black).save(images+'canvas.png', 'PNG')
self._optimize_im(im_colour).save(images+'canvas_colour.png', 'PNG')
else:
im_black.save(images+'canvas.png', 'PNG')
im_colour.save(images+'canvas_colour.png', 'PNG')
def _optimize_im(self, image, threshold=220):
"""Optimize the image for rendering on ePaper displays"""
buffer = numpy.array(image.convert('RGB'))
red, green = buffer[:, :, 0], buffer[:, :, 1]
buffer[numpy.logical_and(red <= threshold, green <= threshold)] = [0,0,0] #grey->black
image = Image.fromarray(buffer)
return image
def calibrate(self):
"""Calibrate the ePaper display to prevent burn-ins (ghosting)
Currently has to be run manually"""
self.Display.calibrate()
def _check_for_updates(self):
"""Check if a new update is available for inkycal"""
raise NotImplementedError('Tha developer were too lazy to implement this..')