|
''' |
|
This code is for generating a banner image with randomly selected and resized images from a directory. |
|
|
|
Usage: |
|
- Run the code in a Python interpreter or an IDE. |
|
- Enter the relative path to the image directory that contains the images you want to use for the banner. |
|
- Enter the desired output width and height of the banner image in pixels. For example, “1400” and “400”. |
|
- The code will create and save the banner image in the same directory as the input images, with a random filename starting with “banner_” |
|
- The code will also show the banner image in a new window. You can close the window when you are done. |
|
''' |
|
|
|
import math |
|
from PIL import Image, ImageDraw, ImageOps |
|
import random |
|
import os |
|
import secrets |
|
|
|
|
|
def put_gradient(im, gradient_magnitude=1.): |
|
if im.mode != 'RGBA': |
|
im = im.convert('RGBA') |
|
width, height = im.size |
|
gradient = Image.new('L', (1, height), color=0xFF) |
|
for y in range(height): |
|
gradient.putpixel((0, y), int(255 * (gradient_magnitude * float(y)/height))) |
|
alpha = gradient.resize(im.size) |
|
black_im = Image.new('RGBA', (width, height), color=0) # i.e. black |
|
black_im.putalpha(alpha) |
|
return Image.alpha_composite(im, black_im) |
|
|
|
# prompt the user for the image directory |
|
image_dir = input("Enter the path to the image directory: ") |
|
|
|
# prompt the user for the output image size |
|
width = int(input("Enter the desired output width: ")) |
|
height = int(input("Enter the desired output height: ")) |
|
|
|
valid_extensions = ['.jpg', '.jpeg', '.png'] |
|
|
|
# get a list of all image files in the directory |
|
image_files = [os.path.join(image_dir, f) for f in os.listdir(image_dir) if f.endswith(tuple(valid_extensions))] |
|
|
|
# define the number of squares |
|
num_squares = len(image_files) |
|
|
|
# calculate the maximum size of the squares |
|
max_size = math.floor(height / 2) |
|
|
|
# calculate the default size of the squares |
|
default_size = math.ceil(width * 0.1) |
|
|
|
# calculate the size of the squares |
|
square_size = min(default_size, max_size) |
|
|
|
# calculate the number of squares that can fit in a row |
|
squares_per_row = math.floor(width / square_size) |
|
|
|
# calculate the number of rows needed to draw all the squares |
|
num_rows = math.ceil(height / squares_per_row) |
|
|
|
if len(image_files) < squares_per_row*num_rows: |
|
image_files = image_files * int(squares_per_row*num_rows) |
|
else: |
|
image_files = image_files[:num_squares] |
|
|
|
# create a new image |
|
image = Image.new('RGBA', (width, height), (255, 255, 255, 255)) |
|
|
|
|
|
for row in range(num_rows): |
|
for i in range(squares_per_row): |
|
# calculate the position of the square |
|
x = i * square_size |
|
y = row * square_size |
|
|
|
tile_image = Image.open(image_files[(row * squares_per_row) + i]) |
|
tile_image_aspect_ratio = tile_image.width / tile_image.height |
|
|
|
if tile_image_aspect_ratio >= 1: |
|
# tile image is wider than or equal to square |
|
tile_image_cropped_width = tile_image.height |
|
tile_image_cropped_height = tile_image.height |
|
tile_image_cropped_x = (tile_image.width - tile_image_cropped_width) // 2 |
|
tile_image_cropped_y = 0 |
|
else: |
|
# tile image is taller than square |
|
tile_image_cropped_width = tile_image.width |
|
tile_image_cropped_height = tile_image.width |
|
tile_image_cropped_x = 0 |
|
tile_image_cropped_y = (tile_image.height - tile_image_cropped_height) // 2 |
|
|
|
tile_image_cropped = tile_image.crop((tile_image_cropped_x, tile_image_cropped_y, tile_image_cropped_x + tile_image_cropped_width, tile_image_cropped_y + tile_image_cropped_height)) |
|
|
|
tile_image_resized = tile_image_cropped.resize((square_size, square_size)) |
|
|
|
image.paste(tile_image_resized, (x, y)) |
|
|
|
output = put_gradient(image) |
|
|
|
# Save output image |
|
filename = 'banner_' + secrets.token_hex(4) + '.jpg' |
|
output.convert('RGB').save(os.path.join(image_dir, filename)) |
|
|
|
# show the image |
|
output.show() |