shades.canvas

canvas

contains functions/classes relating to Shades' canvas object

 1"""
 2canvas
 3
 4contains functions/classes relating to Shades' canvas object
 5"""
 6from random import randint, shuffle
 7from typing import List, Callable
 8
 9import numpy as np
10
11from PIL import Image
12
13from .utils import color_clamp
14
15
16def Canvas(
17        height: int = 700,
18        width: int = 700,
19        color: List[int] = (240, 240, 240),
20        color_mode: str = 'RGB',
21    ) -> Image:
22    """
23    Returns an blank image to draw on.
24    A function due to PIL library restrictions
25    Although in effect used as class so follows naming conventions
26    for color_mode 'RGB' and 'HSB' supported
27    ('RGBA' and 'HSBA' accepted, but may produce unexpected results)
28    """
29    image = Image.new(color_mode, (int(width), int(height)),
30                      color_clamp(color))
31    # adding methods or state is pretty restricted by PIL design
32    # but a couple of QOL object variables
33    image.x_center = int(image.width/2)
34    image.y_center = int(image.height/2)
35    image.center = (image.x_center, image.y_center)
36    image.random_point = lambda: (
37        randint(0, image.width), randint(0, image.height)
38    )
39    return image
40
41
42def pixel_sort(canvas: Image, key: Callable = sum, interval: int = None) -> Image:
43    """
44    Returns a color sorted version of canvas.
45    Accepts a custom function for sorting color tuples in key
46    """
47    if interval is None:
48        interval = canvas.height * canvas.width
49    canvas_array = np.array(canvas)
50    pixels = canvas_array.reshape(
51        canvas.width * canvas.height,
52        len(canvas_array[0][0])
53        )
54    splits = int(len(pixels) / interval)
55    intervals = np.array_split(pixels, splits)
56    intervals = np.array([sorted(i, key=key) for i in intervals])
57    pixels = intervals.reshape(
58        canvas.height,
59        canvas.width,
60        len(canvas_array[0][0]),
61    )
62    return Image.fromarray(pixels)
63
64
65def grid_shuffle(canvas: Image, x_grids: int, y_grids: int):
66    """
67    Returns and image, with grid sections shuffled
68    """
69    # first off, we need to find some basics like the grid size
70    x_size = int(canvas.width / x_grids)
71    y_size = int(canvas.height / y_grids)
72    # and maybe let's make a list of all the grid corners?
73    corners = []
74    for x_coord in range(0, canvas.width - x_size + 1, x_size):
75        for y_coord in range(0, canvas.height - y_size + 1, y_size):
76            corners.append((x_coord, y_coord))
77    # now shuffle
78    shuffle(corners)
79    # now iterate through in pairs swapping pixels
80    # at the moment the below will error if there's an odd number
81    for i in range(0, len(corners), 2):
82        corner_a = corners[i]
83        try:
84            corner_b = corners[i+1]
85        except IndexError:
86            corner_b = corners[0]
87
88        for x_coord in range(x_size):
89            for y_coord in range(y_size):
90                a_coords = (corner_a[0] + x_coord, corner_a[1] + y_coord)
91                b_coords = (corner_b[0] + x_coord, corner_b[1] + y_coord)
92                # now swap the pixels
93                a_val = canvas.getpixel(a_coords)
94                canvas.putpixel(a_coords, canvas.getpixel(b_coords))
95                canvas.putpixel(b_coords, a_val)
96
97    return canvas
def Canvas( height: int = 700, width: int = 700, color: List[int] = (240, 240, 240), color_mode: str = 'RGB') -> <module 'PIL.Image' from '/usr/lib/python3/dist-packages/PIL/Image.py'>:
17def Canvas(
18        height: int = 700,
19        width: int = 700,
20        color: List[int] = (240, 240, 240),
21        color_mode: str = 'RGB',
22    ) -> Image:
23    """
24    Returns an blank image to draw on.
25    A function due to PIL library restrictions
26    Although in effect used as class so follows naming conventions
27    for color_mode 'RGB' and 'HSB' supported
28    ('RGBA' and 'HSBA' accepted, but may produce unexpected results)
29    """
30    image = Image.new(color_mode, (int(width), int(height)),
31                      color_clamp(color))
32    # adding methods or state is pretty restricted by PIL design
33    # but a couple of QOL object variables
34    image.x_center = int(image.width/2)
35    image.y_center = int(image.height/2)
36    image.center = (image.x_center, image.y_center)
37    image.random_point = lambda: (
38        randint(0, image.width), randint(0, image.height)
39    )
40    return image

Returns an blank image to draw on. A function due to PIL library restrictions Although in effect used as class so follows naming conventions for color_mode 'RGB' and 'HSB' supported ('RGBA' and 'HSBA' accepted, but may produce unexpected results)

def pixel_sort( canvas: <module 'PIL.Image' from '/usr/lib/python3/dist-packages/PIL/Image.py'>, key: Callable = <built-in function sum>, interval: int = None) -> <module 'PIL.Image' from '/usr/lib/python3/dist-packages/PIL/Image.py'>:
43def pixel_sort(canvas: Image, key: Callable = sum, interval: int = None) -> Image:
44    """
45    Returns a color sorted version of canvas.
46    Accepts a custom function for sorting color tuples in key
47    """
48    if interval is None:
49        interval = canvas.height * canvas.width
50    canvas_array = np.array(canvas)
51    pixels = canvas_array.reshape(
52        canvas.width * canvas.height,
53        len(canvas_array[0][0])
54        )
55    splits = int(len(pixels) / interval)
56    intervals = np.array_split(pixels, splits)
57    intervals = np.array([sorted(i, key=key) for i in intervals])
58    pixels = intervals.reshape(
59        canvas.height,
60        canvas.width,
61        len(canvas_array[0][0]),
62    )
63    return Image.fromarray(pixels)

Returns a color sorted version of canvas. Accepts a custom function for sorting color tuples in key

def grid_shuffle( canvas: <module 'PIL.Image' from '/usr/lib/python3/dist-packages/PIL/Image.py'>, x_grids: int, y_grids: int):
66def grid_shuffle(canvas: Image, x_grids: int, y_grids: int):
67    """
68    Returns and image, with grid sections shuffled
69    """
70    # first off, we need to find some basics like the grid size
71    x_size = int(canvas.width / x_grids)
72    y_size = int(canvas.height / y_grids)
73    # and maybe let's make a list of all the grid corners?
74    corners = []
75    for x_coord in range(0, canvas.width - x_size + 1, x_size):
76        for y_coord in range(0, canvas.height - y_size + 1, y_size):
77            corners.append((x_coord, y_coord))
78    # now shuffle
79    shuffle(corners)
80    # now iterate through in pairs swapping pixels
81    # at the moment the below will error if there's an odd number
82    for i in range(0, len(corners), 2):
83        corner_a = corners[i]
84        try:
85            corner_b = corners[i+1]
86        except IndexError:
87            corner_b = corners[0]
88
89        for x_coord in range(x_size):
90            for y_coord in range(y_size):
91                a_coords = (corner_a[0] + x_coord, corner_a[1] + y_coord)
92                b_coords = (corner_b[0] + x_coord, corner_b[1] + y_coord)
93                # now swap the pixels
94                a_val = canvas.getpixel(a_coords)
95                canvas.putpixel(a_coords, canvas.getpixel(b_coords))
96                canvas.putpixel(b_coords, a_val)
97
98    return canvas

Returns and image, with grid sections shuffled