|
import os |
|
import numpy as np |
|
from PIL import Image |
|
from concurrent.futures import ThreadPoolExecutor |
|
|
|
def create_gray_checkerboard(shape: tuple, square_size: int): |
|
""" |
|
Create a gray-scale checkerboard pattern array with the given shape. |
|
The pattern alternates between 0.8 and 1.0 values in a square_size grid. |
|
""" |
|
|
|
x, y = np.meshgrid(np.arange(shape[1]), np.arange(shape[0])) |
|
|
|
|
|
board = ((x // square_size + y // square_size) % 2) * 0.2 + 0.8 |
|
return board |
|
|
|
def add_checkered_background_to_image(image_path, output_path, square_size=20): |
|
""" |
|
Add a gray checkerboard background to an image and save it as PNG. |
|
""" |
|
with Image.open(image_path) as img: |
|
img = img.convert("RGBA") |
|
|
|
|
|
|
|
checkerboard_array = create_gray_checkerboard((img.height, img.width), square_size) |
|
|
|
|
|
|
|
|
|
checkerboard_gray = (checkerboard_array * 255).astype(np.uint8) |
|
checkerboard_gray = np.expand_dims(checkerboard_gray, axis=2) |
|
|
|
|
|
alpha_channel = np.full_like(checkerboard_gray, 255) |
|
checkerboard_rgba = np.concatenate([checkerboard_gray]*3 + [alpha_channel], axis=2) |
|
|
|
background = Image.fromarray(checkerboard_rgba, mode="RGBA") |
|
|
|
|
|
combined = Image.alpha_composite(background, img) |
|
combined.save(output_path, "PNG") |
|
|
|
def process_image_file(input_path, output_path, square_size): |
|
""" |
|
Process a single image file to add a checkerboard background. |
|
""" |
|
if not os.path.exists(output_path): |
|
add_checkered_background_to_image(input_path, output_path, square_size) |
|
print(f"Processed (checkerboard): {input_path} -> {output_path}") |
|
else: |
|
print(f"Skipped (checkerboard): {output_path} already exists") |
|
|
|
def process_directory(input_dir, output_dir, square_size=20): |
|
""" |
|
Recursively process a directory to add a checkerboard background to all images and convert them to PNG. |
|
""" |
|
if not os.path.exists(output_dir): |
|
os.makedirs(output_dir) |
|
|
|
tasks = [] |
|
with ThreadPoolExecutor() as executor: |
|
for root, _, files in os.walk(input_dir): |
|
for file in files: |
|
if file.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')): |
|
input_path = os.path.join(root, file) |
|
relative_path = os.path.relpath(input_path, input_dir) |
|
output_path = os.path.join(output_dir, os.path.splitext(relative_path)[0] + '.png') |
|
|
|
|
|
os.makedirs(os.path.dirname(output_path), exist_ok=True) |
|
|
|
|
|
tasks.append(executor.submit(process_image_file, input_path, output_path, square_size)) |
|
|
|
|
|
for task in tasks: |
|
task.result() |