Added (plain) text to display module

This commit is contained in:
aceisace 2022-10-03 02:58:07 +02:00
parent 560d73a87c
commit 3460aabd7b
3 changed files with 245 additions and 1 deletions

View File

@ -6,4 +6,5 @@ from .inkycal_todoist import Todoist
from .inkycal_image import Inkyimage
from .inkycal_jokes import Jokes
from .inkycal_stocks import Stocks
from .inkycal_slideshow import Slideshow
from .inkycal_slideshow import Slideshow
from .inkycal_textfile_to_display import TextToDisplay

View File

@ -0,0 +1,117 @@
#!python3
"""
Textfile module for InkyCal Project
Reads data from a plain .txt file and renders it on the display.
If the content is too long, it will be truncated from the back until it fits
Copyright by aceisace
"""
from inkycal.modules.template import inkycal_module
from inkycal.custom import *
from urllib.request import urlopen
logger = logging.getLogger(__name__)
class TextToDisplay(inkycal_module):
"""TextToDisplay module
"""
name = "Text module - Display text from a local file on the display"
requires = {
"filepath": {
"label": "Please enter a filepath or URL pointing to a .txt file",
},
}
def __init__(self, config):
"""Initialize inkycal_textfile_to_display module"""
super().__init__(config)
config = config['config']
# Check if all required parameters are present
for param in self.requires:
if param not in config:
raise Exception(f'config is missing {param}')
# required parameters
self.filepath = config["filepath"]
self.make_request = True if self.filepath.startswith("https://") else False
# give an OK message
print(f'{__name__} loaded')
def _validate(self):
"""Validate module-specific parameters"""
# ensure we only use a single file
assert (self.filepath and len(self.filepath) == 1)
def generate_image(self):
"""Generate image for this module"""
# Define new image size with respect to padding
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size=im_size, color='white')
# Check if internet is available
if internet_available():
logger.info('Connection test passed')
else:
raise NetworkNotReachableError
# Set some parameters for formatting feeds
line_spacing = 1
line_height = self.font.getsize('hg')[1] + line_spacing
line_width = im_width
max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing))
# Calculate padding from top so the lines look centralised
spacing_top = int(im_height % line_height / 2)
# Calculate line_positions
line_positions = [
(0, spacing_top + _ * line_height) for _ in range(max_lines)]
if self.make_request:
logger.info("Detected http path, making request")
file_content = urlopen(self.filepath).read().decode('utf-8')
else:
# Create list containing all lines
with open(self.filepath, 'r') as file:
file_content = file.read()
fitted_content = text_wrap(file_content, font=self.font, max_width=im_width)
# Trim down the list to the max number of lines
del fitted_content[max_lines:]
# Write feeds on image
for index, line in enumerate(fitted_content):
write(
im_black,
line_positions[index],
(line_width, line_height),
line,
font=self.font,
alignment='left'
)
# return images
return im_black, im_colour
if __name__ == '__main__':
print(f'running {__name__} in standalone/debug mode')

View File

@ -0,0 +1,126 @@
#!python3
import os
import unittest
from inkycal.modules import TextToDisplay as Module
from helper_functions import *
environment = get_environment()
# Set to True to preview images. Only works on Raspberry Pi OS with Desktop
use_preview = False
file_path = None
dummy_data = [
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', ' Donec feugiat facilisis neque vel blandit.',
'Integer viverra dolor risus.', ' Etiam neque tellus, sollicitudin at nisi a, mollis ornare enim.',
'Quisque sed ante eu leo dictum sagittis quis nec nisi.',
'Suspendisse id nulla dictum, sollicitudin urna id, iaculis elit.',
'Nulla luctus pellentesque diam, ac consequat urna molestie vitae.',
'Donec elementum turpis eget augue laoreet, nec maximus lacus malesuada.', '\n\nEtiam eu nunc mauris.',
'Nullam aliquam tristique leo, at dignissim turpis sodales vitae.',
'Aenean cursus laoreet neque, sit amet semper orci tincidunt et.',
'Proin orci urna, efficitur malesuada mattis at, pretium commodo odio.',
'Maecenas in ante id eros aliquam porttitor quis eget est.',
'Duis ex urna, porta nec semper nec, dignissim eu urna.', ' Quisque eleifend non magna at rutrum.',
'\nSed at eros blandit, tempor quam et, mollis ante.', ' Etiam fringilla euismod gravida.',
'Curabitur facilisis consectetur luctus.',
'Integer lectus augue, convallis a consequat id, sollicitudin eget lorem.',
'Curabitur tincidunt suscipit nibh quis mollis.',
'Fusce cursus, orci ut maximus fringilla, velit mauris dictum est, sed ultricies ante orci viverra erat.',
'Quisque pellentesque, mauris nec vulputate commodo, risus libero volutpat nibh, vel tristique mi neque id quam.',
'\nVivamus blandit, dolor ut interdum sagittis, arcu tortor finibus nibh, ornare convallis dui velit quis nunc.',
'Sed turpis justo, pellentesque eu risus scelerisque, vestibulum vulputate magna.',
'Vivamus tincidunt sollicitudin nisl, feugiat euismod nulla consequat ut.',
'Praesent bibendum, sapien sit amet aliquet posuere, tellus purus porta lectus, ut volutpat purus tellus tempus est.',
'Maecenas condimentum lobortis erat nec dignissim', ' Nulla molestie posuere est',
'Proin ultrices, nisl id luctus lacinia, augue ipsum pharetra leo, quis commodo augue dui varius urna.',
'Morbi ultrices turpis malesuada tellus fermentum vulputate.',
'Aliquam viverra nulla aliquam viverra gravida.', ' Pellentesque eu viverra massa.',
'Vestibulum id nisl vehicula, aliquet dui sed, venenatis eros.',
'Nunc iaculis, neque vitae euismod viverra, nisl mauris luctus velit, a aliquam turpis erat fringilla libero.',
'Ut ligula elit, lacinia convallis tempus interdum, finibus ut ex.',
'Nulla efficitur ac ligula sit amet dignissim.', ' Donec sed mi et justo venenatis faucibus.',
'Sed tincidunt nibh erat, in vestibulum purus consequat eget.',
'\nNulla iaculis volutpat orci id efficitur.', ' Vivamus vehicula sit amet augue tristique dignissim.',
'Praesent eget nulla est.', ' Integer nec diam fermentum, convallis metus lacinia, lobortis mauris.',
'Nulla venenatis metus fringilla, lacinia sem nec, pharetra sapien.',
'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.',
'Duis facilisis sapien est, a elementum lorem maximus ut.'
]
tests = [
{
"position": 1,
"name": "TextToFile",
"config": {
"size": [500, 100],
"filepath": file_path,
"padding_x": 10,
"padding_y": 10,
"fontsize": 12,
"language": "en"
}
},
{
"position": 1,
"name": "TextToFile",
"config": {
"size": [500, 400],
"filepath": file_path,
"padding_x": 10,
"padding_y": 10,
"fontsize": 12,
"language": "en"
}
},
]
class TestTextToDisplay(unittest.TestCase):
def test_get_config(self):
print('getting data for web-ui...', end="")
Module.get_config()
print('OK')
def test_generate_image(self):
delete_file_after_parse = False
if not file_path:
delete_file_after_parse = True
print("Filepath does not exist. Creating dummy file")
tmp_path = "tmp.txt"
with open(tmp_path, mode="w") as file:
file.writelines(dummy_data)
# update tests with new temp path
for test in tests:
test["config"]["filepath"] = tmp_path
else:
make_request = True if file_path.startswith("https://") else False
if not make_request and not os.path.exists(file_path):
raise FileNotFoundError("Your text file could not be found")
for test in tests:
print(f'test {tests.index(test) + 1} generating image..')
module = Module(test)
im_black, im_colour = module.generate_image()
print('OK')
if use_preview and environment == 'Raspberry':
preview(merge(im_black, im_colour))
im = merge(im_black, im_colour)
im.show()
if delete_file_after_parse:
print("cleaning up temp file")
os.remove("tmp.txt")
if __name__ == '__main__':
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
unittest.main()