Allow usage without display and SPI when setting render->False
Generated images will be available in the images folder
This commit is contained in:
		| @@ -10,210 +10,210 @@ from PIL import Image | ||||
| from inkycal.custom import top_level | ||||
| import glob | ||||
|  | ||||
|  | ||||
| class Display: | ||||
|   """Display class for inkycal | ||||
|     """Display class for inkycal | ||||
|  | ||||
|   Creates an instance of the driver for the selected E-Paper model and allows | ||||
|   rendering images and calibrating the E-Paper display | ||||
|     Creates an instance of the driver for the selected E-Paper model and allows | ||||
|     rendering images and calibrating the E-Paper display | ||||
|  | ||||
|   args: | ||||
|     - epaper_model: The name of your E-Paper model. | ||||
|     args: | ||||
|       - epaper_model: The name of your E-Paper model. | ||||
|  | ||||
|  | ||||
|   """ | ||||
|  | ||||
|   def __init__(self, epaper_model): | ||||
|     """Load the drivers for this epaper model""" | ||||
|  | ||||
|     if 'colour' in epaper_model: | ||||
|       self.supports_colour = True | ||||
|     else: | ||||
|       self.supports_colour = False | ||||
|  | ||||
|     try: | ||||
|       driver_path = f'inkycal.display.drivers.{epaper_model}' | ||||
|       driver = import_module(driver_path) | ||||
|       self._epaper = driver.EPD() | ||||
|       self.model_name = epaper_model | ||||
|  | ||||
|     except ImportError: | ||||
|       raise Exception('This module is not supported. Check your spellings?') | ||||
|  | ||||
|     except FileNotFoundError: | ||||
|       raise Exception('SPI could not be found. Please check if SPI is enabled') | ||||
|  | ||||
|   def render(self, im_black, im_colour = None): | ||||
|     """Renders an image on the selected E-Paper display. | ||||
|  | ||||
|     Initlializes the E-Paper display, sends image data and executes command | ||||
|     to update the display. | ||||
|  | ||||
|     Args: | ||||
|       - im_black: The image for the black-pixels. Anything in this image that is | ||||
|         black is rendered as black on the display. This is required and ideally | ||||
|         should be a black-white image. | ||||
|  | ||||
|       - im_colour: For E-Paper displays supporting colour, a separate image, | ||||
|         ideally black-white is required for the coloured pixels. Anything that is | ||||
|         black in this image will show up as either red/yellow. | ||||
|  | ||||
|     Rendering an image for black-white E-Paper displays: | ||||
|  | ||||
|     >>> sample_image = PIL.Image.open('path/to/file.png') | ||||
|     >>> display = Display('my_black_white_display') | ||||
|     >>> display.render(sample_image) | ||||
|  | ||||
|  | ||||
|     Rendering black-white on coloured E-Paper displays: | ||||
|  | ||||
|     >>> sample_image = PIL.Image.open('path/to/file.png') | ||||
|     >>> display = Display('my_coloured_display') | ||||
|     >>> display.render(sample_image, sample_image) | ||||
|  | ||||
|  | ||||
|     Rendering coloured image where 2 images are available: | ||||
|  | ||||
|     >>> black_image = PIL.Image.open('path/to/file.png') # black pixels | ||||
|     >>> colour_image = PIL.Image.open('path/to/file.png') # coloured pixels | ||||
|     >>> display = Display('my_coloured_display') | ||||
|     >>> display.render(black_image, colour_image) | ||||
|     """ | ||||
|  | ||||
|     epaper = self._epaper | ||||
|     def __init__(self, epaper_model): | ||||
|         """Load the drivers for this epaper model""" | ||||
|  | ||||
|     if self.supports_colour == False: | ||||
|       print('Initialising..', end = '') | ||||
|       epaper.init() | ||||
|       print('Updating display......', end = '') | ||||
|       epaper.display(epaper.getbuffer(im_black)) | ||||
|       print('Done') | ||||
|         if 'colour' in epaper_model: | ||||
|             self.supports_colour = True | ||||
|         else: | ||||
|             self.supports_colour = False | ||||
|  | ||||
|     elif self.supports_colour == True: | ||||
|       if not im_colour: | ||||
|         raise Exception('im_colour is required for coloured epaper displays') | ||||
|       print('Initialising..', end = '') | ||||
|       epaper.init() | ||||
|       print('Updating display......', end = '') | ||||
|       epaper.display(epaper.getbuffer(im_black), epaper.getbuffer(im_colour)) | ||||
|       print('Done') | ||||
|         try: | ||||
|             driver_path = f'inkycal.display.drivers.{epaper_model}' | ||||
|             driver = import_module(driver_path) | ||||
|             self._epaper = driver.EPD() | ||||
|             self.model_name = epaper_model | ||||
|  | ||||
|     print('Sending E-Paper to deep sleep...', end = '') | ||||
|     epaper.sleep() | ||||
|     print('Done') | ||||
|         except ImportError: | ||||
|             raise Exception('This module is not supported. Check your spellings?') | ||||
|  | ||||
|   def calibrate(self, cycles=3): | ||||
|     """Calibrates the display to retain crisp colours | ||||
|         except FileNotFoundError: | ||||
|             raise Exception('SPI could not be found. Please check if SPI is enabled') | ||||
|  | ||||
|     Flushes the selected display several times with it's supported colours, | ||||
|     removing any previous effects of ghosting. | ||||
|     def render(self, im_black, im_colour=None): | ||||
|         """Renders an image on the selected E-Paper display. | ||||
|  | ||||
|     Args: | ||||
|       - cycles: -> int. The number of times to flush the display with it's | ||||
|         supported colours. | ||||
|         Initlializes the E-Paper display, sends image data and executes command | ||||
|         to update the display. | ||||
|  | ||||
|     It's recommended to calibrate the display after every 6 display updates | ||||
|     for best results. For black-white only displays, calibration is less | ||||
|     critical, but not calibrating regularly results in grey-ish text. | ||||
|         Args: | ||||
|           - im_black: The image for the black-pixels. Anything in this image that is | ||||
|             black is rendered as black on the display. This is required and ideally | ||||
|             should be a black-white image. | ||||
|  | ||||
|     Please note that calibration takes a while to complete. 3 cycles may | ||||
|     take 10 mins on black-white E-Papers while it takes 20 minutes on coloured | ||||
|     E-Paper displays. | ||||
|     """ | ||||
|           - im_colour: For E-Paper displays supporting colour, a separate image, | ||||
|             ideally black-white is required for the coloured pixels. Anything that is | ||||
|             black in this image will show up as either red/yellow. | ||||
|  | ||||
|     epaper = self._epaper | ||||
|     epaper.init() | ||||
|         Rendering an image for black-white E-Paper displays: | ||||
|  | ||||
|     display_size = self.get_display_size(self.model_name) | ||||
|  | ||||
|     white = Image.new('1', display_size, 'white') | ||||
|     black = Image.new('1', display_size, 'black') | ||||
|  | ||||
|     print('----------Started calibration of ePaper display----------') | ||||
|     if self.supports_colour == True: | ||||
|       for _ in range(cycles): | ||||
|         print('Calibrating...', end= ' ') | ||||
|         print('black...', end= ' ') | ||||
|         epaper.display(epaper.getbuffer(black), epaper.getbuffer(white)) | ||||
|         print('colour...', end = ' ') | ||||
|         epaper.display(epaper.getbuffer(white), epaper.getbuffer(black)) | ||||
|         print('white...') | ||||
|         epaper.display(epaper.getbuffer(white), epaper.getbuffer(white)) | ||||
|         print(f'Cycle {_+1} of {cycles} complete') | ||||
|  | ||||
|     if self.supports_colour == False: | ||||
|       for _ in range(cycles): | ||||
|         print('Calibrating...', end= ' ') | ||||
|         print('black...', end = ' ') | ||||
|         epaper.display(epaper.getbuffer(black)) | ||||
|         print('white...') | ||||
|         epaper.display(epaper.getbuffer(white)), | ||||
|         print(f'Cycle {_+1} of {cycles} complete') | ||||
|  | ||||
|       print('-----------Calibration complete----------') | ||||
|       epaper.sleep() | ||||
|         >>> sample_image = PIL.Image.open('path/to/file.png') | ||||
|         >>> display = Display('my_black_white_display') | ||||
|         >>> display.render(sample_image) | ||||
|  | ||||
|  | ||||
|   @classmethod | ||||
|   def get_display_size(cls, model_name): | ||||
|     """Returns the size of the display as a tuple -> (width, height) | ||||
|         Rendering black-white on coloured E-Paper displays: | ||||
|  | ||||
|     Looks inside drivers folder for the given model name, then returns it's | ||||
|     size. | ||||
|         >>> sample_image = PIL.Image.open('path/to/file.png') | ||||
|         >>> display = Display('my_coloured_display') | ||||
|         >>> display.render(sample_image, sample_image) | ||||
|  | ||||
|     Args: | ||||
|       - model_name: str -> The name of the E-Paper display to get it's size. | ||||
|  | ||||
|     Returns: | ||||
|       (width, height) ->tuple, showing the size of the display | ||||
|         Rendering coloured image where 2 images are available: | ||||
|  | ||||
|     You can use this function directly without creating the Display class: | ||||
|         >>> black_image = PIL.Image.open('path/to/file.png') # black pixels | ||||
|         >>> colour_image = PIL.Image.open('path/to/file.png') # coloured pixels | ||||
|         >>> display = Display('my_coloured_display') | ||||
|         >>> display.render(black_image, colour_image) | ||||
|         """ | ||||
|  | ||||
|     >>> Display.get_display_size('model_name') | ||||
|     """ | ||||
|     if not isinstance(model_name, str): | ||||
|       print('model_name should be a string') | ||||
|       return | ||||
|     else: | ||||
|       driver_files = top_level+'/inkycal/display/drivers/*.py' | ||||
|       drivers = glob.glob(driver_files) | ||||
|       drivers = [i.split('/')[-1].split('.')[0] for i in drivers] | ||||
|       drivers.remove('__init__') | ||||
|       drivers.remove('epdconfig') | ||||
|       if model_name not in drivers: | ||||
|         print('This model name was not found. Please double check your spellings') | ||||
|         return | ||||
|       else: | ||||
|         with open(top_level+'/inkycal/display/drivers/'+model_name+'.py') as file: | ||||
|           for line in file: | ||||
|             if 'EPD_WIDTH=' in line.replace(" ", ""): | ||||
|               width = int(line.rstrip().replace(" ", "").split('=')[-1]) | ||||
|             if 'EPD_HEIGHT=' in line.replace(" ", ""): | ||||
|               height = int(line.rstrip().replace(" ", "").split('=')[-1]) | ||||
|         return width, height | ||||
|         epaper = self._epaper | ||||
|  | ||||
|   @classmethod | ||||
|   def get_display_names(cls): | ||||
|     """Prints all supported E-Paper models. | ||||
|         if not self.supports_colour: | ||||
|             print('Initialising..', end='') | ||||
|             epaper.init() | ||||
|             print('Updating display......', end='') | ||||
|             epaper.display(epaper.getbuffer(im_black)) | ||||
|             print('Done') | ||||
|  | ||||
|     Fetches all filenames in driver folder and prints them on the console. | ||||
|         elif self.supports_colour: | ||||
|             if not im_colour: | ||||
|                 raise Exception('im_colour is required for coloured epaper displays') | ||||
|             print('Initialising..', end='') | ||||
|             epaper.init() | ||||
|             print('Updating display......', end='') | ||||
|             epaper.display(epaper.getbuffer(im_black), epaper.getbuffer(im_colour)) | ||||
|             print('Done') | ||||
|  | ||||
|     Returns: | ||||
|       Printed version of all supported Displays. | ||||
|         print('Sending E-Paper to deep sleep...', end='') | ||||
|         epaper.sleep() | ||||
|         print('Done') | ||||
|  | ||||
|     Use one of the models to intilialize the Display class in order to gain | ||||
|     access to the E-Paper. | ||||
|     def calibrate(self, cycles=3): | ||||
|         """Calibrates the display to retain crisp colours | ||||
|  | ||||
|     You can use this function directly without creating the Display class: | ||||
|         Flushes the selected display several times with it's supported colours, | ||||
|         removing any previous effects of ghosting. | ||||
|  | ||||
|         Args: | ||||
|           - cycles: -> int. The number of times to flush the display with it's | ||||
|             supported colours. | ||||
|  | ||||
|         It's recommended to calibrate the display after every 6 display updates | ||||
|         for best results. For black-white only displays, calibration is less | ||||
|         critical, but not calibrating regularly results in grey-ish text. | ||||
|  | ||||
|         Please note that calibration takes a while to complete. 3 cycles may | ||||
|         take 10 minutes on black-white E-Papers while it takes 20 minutes on coloured | ||||
|         E-Paper displays. | ||||
|         """ | ||||
|  | ||||
|         epaper = self._epaper | ||||
|         epaper.init() | ||||
|  | ||||
|         display_size = self.get_display_size(self.model_name) | ||||
|  | ||||
|         white = Image.new('1', display_size, 'white') | ||||
|         black = Image.new('1', display_size, 'black') | ||||
|  | ||||
|         print('----------Started calibration of ePaper display----------') | ||||
|         if self.supports_colour: | ||||
|             for _ in range(cycles): | ||||
|                 print('Calibrating...', end=' ') | ||||
|                 print('black...', end=' ') | ||||
|                 epaper.display(epaper.getbuffer(black), epaper.getbuffer(white)) | ||||
|                 print('colour...', end=' ') | ||||
|                 epaper.display(epaper.getbuffer(white), epaper.getbuffer(black)) | ||||
|                 print('white...') | ||||
|                 epaper.display(epaper.getbuffer(white), epaper.getbuffer(white)) | ||||
|                 print(f'Cycle {_ + 1} of {cycles} complete') | ||||
|  | ||||
|         if not self.supports_colour: | ||||
|             for _ in range(cycles): | ||||
|                 print('Calibrating...', end=' ') | ||||
|                 print('black...', end=' ') | ||||
|                 epaper.display(epaper.getbuffer(black)) | ||||
|                 print('white...') | ||||
|                 epaper.display(epaper.getbuffer(white)), | ||||
|                 print(f'Cycle {_ + 1} of {cycles} complete') | ||||
|  | ||||
|             print('-----------Calibration complete----------') | ||||
|             epaper.sleep() | ||||
|  | ||||
|     @classmethod | ||||
|     def get_display_size(cls, model_name): | ||||
|         """Returns the size of the display as a tuple -> (width, height) | ||||
|  | ||||
|         Looks inside "drivers" folder for the given model name, then returns it's | ||||
|         size. | ||||
|  | ||||
|         Args: | ||||
|           - model_name: str -> The name of the E-Paper display to get it's size. | ||||
|  | ||||
|         Returns: | ||||
|           (width, height) ->tuple, showing the size of the display | ||||
|  | ||||
|         You can use this function directly without creating the Display class: | ||||
|  | ||||
|         >>> Display.get_display_size('model_name') | ||||
|         """ | ||||
|         if not isinstance(model_name, str): | ||||
|             print('model_name should be a string') | ||||
|             return | ||||
|         else: | ||||
|             driver_files = top_level + '/inkycal/display/drivers/*.py' | ||||
|             drivers = glob.glob(driver_files) | ||||
|             drivers = [i.split('/')[-1].split('.')[0] for i in drivers] | ||||
|             drivers.remove('__init__') | ||||
|             drivers.remove('epdconfig') | ||||
|             if model_name not in drivers: | ||||
|                 print('This model name was not found. Please double check your spellings') | ||||
|                 return | ||||
|             else: | ||||
|                 with open(top_level + '/inkycal/display/drivers/' + model_name + '.py') as file: | ||||
|                     for line in file: | ||||
|                         if 'EPD_WIDTH=' in line.replace(" ", ""): | ||||
|                             width = int(line.rstrip().replace(" ", "").split('=')[-1]) | ||||
|                         if 'EPD_HEIGHT=' in line.replace(" ", ""): | ||||
|                             height = int(line.rstrip().replace(" ", "").split('=')[-1]) | ||||
|                 return width, height | ||||
|  | ||||
|     @classmethod | ||||
|     def get_display_names(cls): | ||||
|         """Prints all supported E-Paper models. | ||||
|  | ||||
|         Fetches all filenames in driver folder and prints them on the console. | ||||
|  | ||||
|         Returns: | ||||
|           Printed version of all supported Displays. | ||||
|  | ||||
|         Use one of the models to intilialize the Display class in order to gain | ||||
|         access to the E-Paper. | ||||
|  | ||||
|         You can use this function directly without creating the Display class: | ||||
|  | ||||
|         >>> Display.get_display_names() | ||||
|         """ | ||||
|         driver_files = top_level + '/inkycal/display/drivers/*.py' | ||||
|         drivers = glob.glob(driver_files) | ||||
|         drivers = [i.split('/')[-1].split('.')[0] for i in drivers] | ||||
|         drivers.remove('__init__') | ||||
|         drivers.remove('epdconfig') | ||||
|         print(*drivers, sep='\n') | ||||
|  | ||||
|     >>> Display.get_display_names() | ||||
|     """ | ||||
|     driver_files = top_level+'/inkycal/display/drivers/*.py' | ||||
|     drivers = glob.glob(driver_files) | ||||
|     drivers = [i.split('/')[-1].split('.')[0] for i in drivers] | ||||
|     drivers.remove('__init__') | ||||
|     drivers.remove('epdconfig') | ||||
|     print(*drivers, sep='\n') | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|   print("Running Display class in standalone mode") | ||||
|  | ||||
|     print("Running Display class in standalone mode") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user