added palette and dithering support in custom image class

This commit is contained in:
Ace 2020-12-02 00:57:36 +01:00
parent 80199dffc7
commit f6de947096

View File

@ -9,7 +9,7 @@ images.
Copyright by aceisace Copyright by aceisace
""" """
from PIL import Image, ImageOps from PIL import Image, ImageOps, ImageColor
import requests import requests
import numpy import numpy
import os import os
@ -19,9 +19,7 @@ filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Inkyimage: class Inkyimage:
"""Inkyimage class """Custom Imge class written for commonly used image operations.
missing documentation, lazy devs :/
""" """
def __init__(self, image=None): def __init__(self, image=None):
@ -168,7 +166,7 @@ class Inkyimage:
def resize(self, width=None, height=None): def resize(self, width=None, height=None):
"""Resize an image to desired width or height""" """Resize an image to desired width or height"""
if self._image_loaded(): if self._image_loaded():
if width == None and height == None: if width == None and height == None:
print('no height of width specified') print('no height of width specified')
return return
@ -191,53 +189,115 @@ class Inkyimage:
logger.debug(f"resized image from {initial_height} to {image.height}") logger.debug(f"resized image from {initial_height} to {image.height}")
self.image = image self.image = image
def to_mono(self): def to_palette(self, palette, dither=True):
"""Converts image to pure balck-white image (1-bit). """Maps an image to a given colour palette.
retrns 1-bit image Maps each pixel from the image to a colour from the palette.
Args:
- palette: A supported token. (see below)
- dither:->bool. Use dithering? Set to `False` for solid colour fills.
Returns:
- two images: one for the coloured band and one for the black band.
Raises:
- ValueError if palette token is not supported
Supported palette tokens:
>>> 'bwr' # black-white-red
>>> 'bwy' # black-white-yellow
>>> 'bw' # black-white
""" """
if self._image_loaded(): # Check if an image is 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(): if self._image_loaded():
image = self.image.convert('RGB') image = self.image.convert('RGB')
else:
print('No image loaded')
# Create a simple palette if palette == 'bwr':
pal = [255,255,255, 0,0,0, 255,0,0, 255,255,255] # black-white-red palette
pal = [255,255,255, 0,0,0, 255,0,0]
# Map each pixel of the opened image to the Palette elif palette == 'bwy':
palette_im = Image.new('P', (3,1)) # black-white-yellow palette
palette_im.putpalette(pal * 64) pal = [255,255,255, 0,0,0, 255,255,0]
quantized_im = image.quantize(palette=palette_im)
quantized_im.convert('RGB')
# Create a buffer for coloured pixels elif palette == 'bw':
buffer1 = numpy.array(quantized_im.convert('RGB')) pal = None
r1,g1,b1 = buffer1[:, :, 0], buffer1[:, :, 1], buffer1[:, :, 2]
# Create a buffer for black pixels else:
buffer2 = numpy.array(quantized_im.convert('RGB')) raise ValueError('The given palette is not supported.')
r2,g2,b2 = buffer2[:, :, 0], buffer2[:, :, 1], buffer2[:, :, 2]
# re-construct image from coloured-pixels buffer if pal:
buffer2[numpy.logical_and(r2 == 0, b2 == 0)] = [255,255,255] # black->white # The palette needs to have 256 colors, for this, the black-colour
buffer2[numpy.logical_and(r2 == 255, b2 == 0)] = [0,0,0] #red->black # is added until the
im_colour = Image.fromarray(buffer2) colours = len(pal) // 3
#print(f'The palette has {colours} colours')
# re-construct image from black pixels buffer if 256 % colours != 0:
buffer1[numpy.logical_and(r1 == 255, b1 == 0)] = [255,255,255] #print('Filling palette with black')
pal += (256 % colours) * [0,0,0]
#print(pal)
colours = len(pal) // 3
#print(f'The palette now has {colours} colours')
# Create a dummy image to be used as a palette
palette_im = Image.new('P', (1,1))
# Attach the created palette. The palette should have 256 colours
# equivalent to 768 integers
palette_im.putpalette(pal* (256//colours))
# Quantize the image to given palette
quantized_im = image.quantize(palette=palette_im, dither=dither)
quantized_im = quantized_im.convert('RGB')
# get rgb of the non-black-white colour from the palette
rgb = [pal[x:x+3] for x in range(0, len(pal),3)]
rgb = [col for col in rgb if col != [0,0,0] and col != [255,255,255]][0]
r_col, g_col, b_col = rgb
#print(f'r:{r_col} g:{g_col} b:{b_col}')
# Create an image buffer for black pixels
buffer1 = numpy.array(quantized_im)
# Get RGB values of each pixel
r,g,b = buffer1[:, :, 0], buffer1[:, :, 1], buffer1[:, :, 2]
# convert coloured pixels to white
buffer1[numpy.logical_and(r==r_col, g==g_col)] = [255,255,255]
# reconstruct image for black-band
im_black = Image.fromarray(buffer1) im_black = Image.fromarray(buffer1)
return im_black, im_colour # Create a buffer for coloured pixels
buffer2 = numpy.array(quantized_im)
# Get RGB values of each pixel
r,g,b = buffer2[:, :, 0], buffer2[:, :, 1], buffer2[:, :, 2]
# convert black pixels to white
buffer2[numpy.logical_and(r==0, g==0)] = [255,255,255]
# convert non-white pixels to black
buffer2[numpy.logical_and(g==g_col, b==0)] = [0,0,0]
# reconstruct image for colour-band
im_colour = Image.fromarray(buffer2)
#self.preview(im_black)
#self.preview(im_colour)
else:
im_black = image.convert('1', dither=dither)
im_colour = Image.new(mode='RGB', size=im_black.size, color='white')
return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode') print(f'running {filename} in standalone/debug mode')