diff --git a/gfxlcd/abstract/chip.py b/gfxlcd/abstract/chip.py index 36eb407..03bf3c0 100644 --- a/gfxlcd/abstract/chip.py +++ b/gfxlcd/abstract/chip.py @@ -99,3 +99,8 @@ class Chip(metaclass=abc.ABCMeta): def fill_rect(self, pos_x1, pos_y1, pos_x2, pos_y2): """draw a filled rectangle""" pass + + @abc.abstractmethod + def draw_image(self, pos_x, pos_y, image): + """draw a PIL image""" + pass diff --git a/gfxlcd/demos/assets/dsp2017_101_64.png b/gfxlcd/demos/assets/dsp2017_101_64.png new file mode 100644 index 0000000..1f9beb1 Binary files /dev/null and b/gfxlcd/demos/assets/dsp2017_101_64.png differ diff --git a/gfxlcd/demos/assets/dsp2017_122_29.png b/gfxlcd/demos/assets/dsp2017_122_29.png new file mode 100644 index 0000000..298425f Binary files /dev/null and b/gfxlcd/demos/assets/dsp2017_122_29.png differ diff --git a/gfxlcd/demos/assets/japan_temple_240x320.jpg b/gfxlcd/demos/assets/japan_temple_240x320.jpg new file mode 100644 index 0000000..0946e24 Binary files /dev/null and b/gfxlcd/demos/assets/japan_temple_240x320.jpg differ diff --git a/gfxlcd/demos/assets/numbers.jpg b/gfxlcd/demos/assets/numbers.jpg new file mode 100644 index 0000000..f8904ad Binary files /dev/null and b/gfxlcd/demos/assets/numbers.jpg differ diff --git a/gfxlcd/demos/ili_image.py b/gfxlcd/demos/ili_image.py new file mode 100644 index 0000000..93afdc0 --- /dev/null +++ b/gfxlcd/demos/ili_image.py @@ -0,0 +1,23 @@ +import RPi.GPIO +import sys +from PIL import Image +sys.path.append("../../") +from gfxlcd.driver.ili9325.gpio import GPIO as ILIGPIO +from gfxlcd.driver.ili9325.ili9325 import ILI9325 +RPi.GPIO.setmode(RPi.GPIO.BCM) + + +lcd_tft = ILI9325(240, 320, ILIGPIO()) +lcd_tft.init() + +# bypass of missing +3v line to power backlight +LED = 6 +RPi.GPIO.setup(LED, RPi.GPIO.OUT) +RPi.GPIO.output(LED, 1) + +image_file = Image.open("assets/japan_temple_240x320.jpg") +lcd_tft.draw_image(0, 0, image_file) + +numbers_image = Image.open("assets/dsp2017_101_64.png") +lcd_tft.transparency_color = (0, 0, 0) +lcd_tft.draw_image(10, 10, numbers_image) diff --git a/gfxlcd/demos/nju_image.py b/gfxlcd/demos/nju_image.py new file mode 100644 index 0000000..fb348aa --- /dev/null +++ b/gfxlcd/demos/nju_image.py @@ -0,0 +1,20 @@ +import RPi.GPIO +import sys +import random +from PIL import Image +sys.path.append("../../") +from gfxlcd.driver.nju6450.gpio import GPIO +from gfxlcd.driver.nju6450.nju6450 import NJU6450 +RPi.GPIO.setmode(RPi.GPIO.BCM) + + +lcd_nju = NJU6450(122, 32, GPIO()) +lcd_nju.init() +lcd_nju.auto_flush = False + +image_file = Image.open("assets/dsp2017_122_29.png") +# lcd_nju.threshold = 50 +# lcd_nju.transparency_color = [110, 57] +lcd_nju.draw_image(0, 0, image_file) + +lcd_nju.flush(True) diff --git a/gfxlcd/demos/ssd_image.py b/gfxlcd/demos/ssd_image.py new file mode 100644 index 0000000..011aff0 --- /dev/null +++ b/gfxlcd/demos/ssd_image.py @@ -0,0 +1,23 @@ +import RPi.GPIO +import sys +from PIL import Image +sys.path.append("../../") +from gfxlcd.driver.ssd1306.spi import SPI +from gfxlcd.driver.ssd1306.ssd1306 import SSD1306 +RPi.GPIO.setmode(RPi.GPIO.BCM) + +lcd_oled = SSD1306(128, 64, SPI()) +lcd_oled.init() +lcd_oled.auto_flush = False + +image_file = Image.open("assets/dsp2017_101_64.png") + +lcd_oled.threshold = 50 + +lcd_oled.threshold = 0 +# lcd_oled.transparency_color = [110, 57] #110 #[110, 57] +# lcd_oled.threshold = 255 + +lcd_oled.draw_image(10, 0, image_file) + +lcd_oled.flush(True) diff --git a/gfxlcd/drawing/area.py b/gfxlcd/drawing/area.py index 8fc1d19..7c2daac 100644 --- a/gfxlcd/drawing/area.py +++ b/gfxlcd/drawing/area.py @@ -121,3 +121,59 @@ class Area(Pixel): color = self._converted_background_color() for _ in range(0, size): self.driver.data(color, None) + + def draw_image(self, pos_x, pos_y, image): + """draw a PIL image""" + image_file = image.convert('RGB') + width, height = image_file.size + self._set_area( + pos_x, + pos_y, + pos_x + width - 1, + pos_y + height - 1 + ) + row = 0 + col = 0 + area = None + temporary_area = None + for red, green, blue in list(image_file.getdata()): + if self._is_transparent((red, green, blue)): + area = ( + pos_x, + pos_y + row + 1, + pos_x + width - 1, + pos_y + height - 1 + ) + temporary_area = ( + pos_x + col + 1, + pos_y + row, + pos_x + width - 1, + pos_y + row + ) + else: + if temporary_area is not None: + self._set_area(*temporary_area) + temporary_area = None + self.color = (red, green, blue) + self.driver.data(self._converted_color(), None) + + col += 1 + if col > width - 1: + col = 0 + row += 1 + if area is not None: + self._set_area(*area) + area = None + + def _is_transparent(self, color): + """check if color is a transparency color""" + if self.options['transparency_color'] is None: + return False + elif type(self.options['transparency_color'][0]) == int \ + and color == self.options['transparency_color']: + return True + elif type(self.options['transparency_color'][0]) == list \ + and color in self.options['transparency_color']: + return True + + return False diff --git a/gfxlcd/drawing/page.py b/gfxlcd/drawing/page.py index 6e6ca58..d9c899c 100644 --- a/gfxlcd/drawing/page.py +++ b/gfxlcd/drawing/page.py @@ -113,3 +113,29 @@ class Page(Pixel, metaclass=abc.ABCMeta): def flush(self, force=None): """flush buffer to the screen""" pass + + def draw_image(self, pos_x, pos_y, image): + """draw a PIL image""" + image_file = image.convert('L') + width, height = image_file.size + offset_x = 0 + offset_y = 0 + for stream in list(image_file.getdata()): + if stream > self.options['threshold'] \ + and not self._is_transparent(stream): + self.draw_pixel(pos_x + offset_x, pos_y + offset_y) + offset_x += 1 + if offset_x > width - 1: + offset_x = 0 + offset_y += 1 + + def _is_transparent(self, color): + """check if color is a transparency color""" + if type(self.options['transparency_color']) == int \ + and color == self.options['transparency_color']: + return True + elif type(self.options['transparency_color']) == list \ + and color in self.options['transparency_color']: + return True + + return False diff --git a/gfxlcd/drawing/pixel.py b/gfxlcd/drawing/pixel.py index c2c22ac..a3a7339 100644 --- a/gfxlcd/drawing/pixel.py +++ b/gfxlcd/drawing/pixel.py @@ -12,6 +12,28 @@ class Pixel(object): self.options['background_color'] = { 'R': 0, 'G': 0, 'B': 0, } + self.options['threshold'] = 50 + self.options['transparency_color'] = None + + @property + def threshold(self): + """get threshold for B&W conversion""" + return self.options['threshold'] + + @threshold.setter + def threshold(self, threshold): + """set B&W threshold for conversion """ + self.options['threshold'] = threshold + + @property + def transparency_color(self): + """get transparency color""" + return self.options['transparency_color'] + + @transparency_color.setter + def transparency_color(self, transparency_color): + """set transparency color """ + self.options['transparency_color'] = transparency_color def draw_pixel(self, pos_x, pos_y): """dummy fuction""" diff --git a/gfxlcd/driver/ssd1306/__init__.py b/gfxlcd/driver/ssd1306/__init__.py index 31c4620..a9428b5 100644 --- a/gfxlcd/driver/ssd1306/__init__.py +++ b/gfxlcd/driver/ssd1306/__init__.py @@ -1,2 +1,2 @@ """driver/ssd1306 module""" -__author__ = 'Bartosz Kosciow' \ No newline at end of file +__author__ = 'Bartosz Kosciow' diff --git a/readme.md b/readme.md index f260d85..84373ac 100644 --- a/readme.md +++ b/readme.md @@ -13,6 +13,7 @@ On NJU and SSD uses buffer to keep current content as help for page operations. Wiring is below +Demos are in demos directory Initialization === @@ -111,12 +112,18 @@ draw_arc(x1, y1, radius, from_angle, to_angle fill_rect(x1, y1, x2, y2) +draw_image(x, y, PIL.Image) Colours === lcd.color = (r, g, b) + lcd.background_color = (r, g ,b) +lcd.threshold = 255 - for images a threshold between black and white (on monochrome) + +lcd.transparency_color = [110, 57] #110 - color(s) that are skipped during drawing an image + Wiring === diff --git a/setup.py b/setup.py index d2016fa..d2bb2cb 100644 --- a/setup.py +++ b/setup.py @@ -13,11 +13,11 @@ def read(*paths): setup( name='gfxlcd', - version='0.1.0', + version='0.1.2', description='gfxlcd is a handler for grpahical lcds: ILI9328, SSD1306, NJU6450 @ Raspberry Pi.', keywords=['gfxlcd', 'raspberry pi' ,'ili9328' ,'ssd1306', 'nju6450', 'lcd', 'graphical lcd'], long_description=(read('readme.md')), - url='https://bitbucket.org/kosci/charlcd.git', + url='https://github.com/bkosciow/gfxlcd', license='MIT', author='Bartosz Kościów', author_email='kosci1@gmail.com', diff --git a/tox.ini b/tox.ini index 41710dd..0ad5206 100644 --- a/tox.ini +++ b/tox.ini @@ -16,5 +16,5 @@ commands= nosetests --with-xunit --xunit-file=junit-{envname}.xml gfxlcd/tests /bin/bash -c "pylint gfxlcd > pylint-{envname}.log || :" [flake8] show-source = True -exclude = .git,.venv,.tox,dist,doc,build,*egg,*/tests/* +exclude = .git,.venv,.tox,dist,doc,build,*egg,*/tests/*,*/demos/*