Added custom image class

This commit is contained in:
Ace 2020-11-29 14:54:00 +01:00
parent 8a82a149af
commit eb806526bd

View File

@ -0,0 +1,246 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Custom image class for Inkycal Project
Takes care of handling images. Made to be used by other modules to handle
images.
Copyright by aceisace
"""
from PIL import Image, ImageOps
import requests
import numpy
import os
import logging
filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename)
class Inkyimage:
"""Inkyimage class
missing documentation, lazy devs :/
"""
def __init__(self, image=None):
"""Initialize Inkyimage module"""
# no image initially
self.image = image
# give an OK message
print(f'{filename} loaded')
def load(self, path):
"""loads an image from a URL or filepath.
Args:
- path:The full path or url of the image file
e.g. `https://sample.com/logo.png` or `/home/pi/Downloads/nice_pic.png`
Raises:
- FileNotFoundError: This Exception is raised when the file could not be
found.
- OSError: A OSError is raised when the URL doesn't point to the correct
file-format, i.e. is not an image
- TypeError: if the URLS doesn't start with htpp
"""
# Try to open the image if it exists and is an image file
try:
if path.startswith('http'):
logger.debug('loading image from URL')
image = Image.open(requests.get(path, stream=True).raw)
else:
logger.info('loading image from local path')
image = Image.open(path)
except FileNotFoundError:
raise ('Your file could not be found. Please check the filepath')
except OSError:
raise ('Please check if the path points to an image file.')
logger.debug(f'width: {image.width}, height: {image.height}')
image.convert(mode='RGBA') #convert to a more suitable format
self.image = image
print('loaded Image')
def clear(self):
"""Removes currently saved image if present"""
if self.image:
self.image = None
print('cleared')
def _preview(self):
"""Preview the image on gpicview (only works on Rapsbian with Desktop)"""
if self._image_loaded():
path = '/home/pi/Desktop/'
self.image.save(path+'temp.png')
os.system("gpicview "+path+'temp.png')
os.system('rm '+path+'temp.png')
@staticmethod
def preview(image):
""""Previews an image on gpicview (only works on Rapsbian with Desktop)
"""
path = '/home/pi/Desktop/'
image.save(path+'temp.png')
os.system("gpicview "+path+'temp.png')
os.system('rm '+path+'temp.png')
def _image_loaded(self):
"""returns True if image was loaded"""
if self.image:
return True
else:
print('image not loaded')
return False
def flip(self, angle):
"""Flips the image by the given angle.
Args:
- angle:->int. A multiple of 90, e.g. 90, 180, 270, 360.
"""
if self._image_loaded():
image = self.image
if not angle % 90 == 0:
print('Angle must be a multiple of 90')
return
image = image.rotate(angle, expand = True)
self.image = image
print(f'flipped image by {angle} degrees')
def autoflip(self, layout):
"""flips the image automatically to the given layout.
Args:
- layout:-> str. Choose `horizontal` or `vertical`.
Checks the image's width and height.
In horizontal mode, the image is flipped if the image height is greater
than the image width.
In vertical mode, the image is flipped if the image width is greater
than the image height.
"""
if self._image_loaded():
image = self.image
if layout == 'horizontal':
if (image.height > image.width):
print('image width greater than image height, flipping')
image = image.rotate(90, expand=True)
elif layout == 'vertical':
if (image.width > image.height):
print('image width greater than image height, flipping')
image = image.rotate(90, expand=True)
else:
print('layout not supported')
return
self.image = image
def remove_alpha(self):
"""Removes transparency if image has transparency.
Checks if an image has an alpha band and replaces the transparency with
white pixels.
"""
if self._image_loaded():
image = self.image
if len(image.getbands()) == 4:
print('has alpha')
logger.debug('removing transparency')
bg = Image.new('RGBA', (image.width, image.height), 'white')
im = Image.alpha_composite(bg, image)
self.image.paste(im, (0,0))
print('removed alpha')
def resize(self, width=None, height=None):
"""Resize an image to desired width or height"""
if self._image_loaded():
if width == None and height == None:
print('no height of width specified')
return
image = self.image
if width:
initial_width = image.width
wpercent = (width/float(image.width))
hsize = int((float(image.height)*float(wpercent)))
image = image.resize((width, hsize), Image.ANTIALIAS)
logger.debug(f"resized image from {initial_width} to {image.width}")
self.image = image
if height:
initial_height = image.height
hpercent = (height / float(image.height))
wsize = int(float(image.width) * float(hpercent))
image = image.resize((wsize, height), Image.ANTIALIAS)
logger.debug(f"resized image from {initial_height} to {image.height}")
self.image = image
def to_mono(self):
"""Converts image to pure balck-white image (1-bit).
retrns 1-bit image
"""
if self._image_loaded():
image = self.image
image = image.convert('1', dither=True)
return image
def to_colour(self):
"""Maps image colours to 3 colours.
"""
if self._image_loaded():
image = self.image.convert('RGB')
# Create a simple palette
pal = [255,255,255, 0,0,0, 255,0,0, 255,255,255]
# Map each pixel of the opened image to the Palette
palette_im = Image.new('P', (3,1))
palette_im.putpalette(pal * 64)
quantized_im = image.quantize(palette=palette_im)
quantized_im.convert('RGB')
# Create a buffer for coloured pixels
buffer1 = numpy.array(quantized_im.convert('RGB'))
r1,g1,b1 = buffer1[:, :, 0], buffer1[:, :, 1], buffer1[:, :, 2]
# Create a buffer for black pixels
buffer2 = numpy.array(quantized_im.convert('RGB'))
r2,g2,b2 = buffer2[:, :, 0], buffer2[:, :, 1], buffer2[:, :, 2]
# re-construct image from coloured-pixels buffer
buffer2[numpy.logical_and(r2 == 0, b2 == 0)] = [255,255,255] # black->white
buffer2[numpy.logical_and(r2 == 255, b2 == 0)] = [0,0,0] #red->black
im_colour = Image.fromarray(buffer2)
# re-construct image from black pixels buffer
buffer1[numpy.logical_and(r1 == 255, b1 == 0)] = [255,255,255]
im_black = Image.fromarray(buffer1)
return im_black, im_colour
if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode')
a = Inkyimage()
a.load('https://pngimg.com/uploads/pokemon/pokemon_PNG148.png')