Skip to content

Instantly share code, notes, and snippets.

@Mega-JC
Last active January 20, 2024 18:51
Show Gist options
  • Save Mega-JC/d92d9e07506818f3030696844839ce2c to your computer and use it in GitHub Desktop.
Save Mega-JC/d92d9e07506818f3030696844839ce2c to your computer and use it in GitHub Desktop.
ce_logo_overlayer_gui.py
import argparse
import glob
import os
import time
import sys
from gooey import Gooey, GooeyParser
from PIL import Image
def overlay_images(
source_path,
dest_images,
output_dir,
reference_corner,
border_offset_factor_horizontal,
border_offset_factor_vertical,
overlay_width_bounded_scale_factor,
overlay_height_bounded_scale_factor,
):
last_dest_size = None
# Load source image with alpha transparency
source = last_source_resized = Image.open(source_path).convert("RGBA")
# Ensure there are destination images
if not dest_images:
raise ValueError("No destination images provided.")
dest_images_count = len(dest_images)
# Iterate over destination images
for i, dest_path in enumerate(dest_images):
dest_output_path = os.path.join(
output_dir,
f"{os.path.basename(dest_path)}",
)
if os.path.exists(dest_output_path):
print(
f"Skipping '{os.path.basename(dest_path)}' as it was already processed "
f"and saved at '{dest_output_path}' ({i+1}/{dest_images_count} completed)"
)
continue
try:
# Attempt to open the file as an image
dest = Image.open(dest_path).convert("RGBA")
except (IOError, OSError, Image.DecompressionBombError):
# Skip if the file is not a valid image
continue
# Calculate final pasting position after considering border offsets
border_offset_x = border_offset_y = 0
if border_offset_factor_horizontal and border_offset_factor_vertical:
border_offset_x = round(dest.width * border_offset_factor_horizontal)
border_offset_y = round(dest.height * border_offset_factor_vertical)
elif border_offset_factor_horizontal:
border_offset_x = border_offset_y = round(
dest.width * border_offset_factor_horizontal
)
elif border_offset_factor_vertical:
border_offset_y = border_offset_x = round(
dest.height * border_offset_factor_vertical
)
if dest.size == last_dest_size:
source_resized = last_source_resized
elif overlay_width_bounded_scale_factor and overlay_height_bounded_scale_factor:
resized_width = round(dest.width * overlay_width_bounded_scale_factor)
resized_height = round(dest.height * overlay_height_bounded_scale_factor)
source_resized = source.resize(
(resized_width, resized_height),
Image.BICUBIC,
)
elif overlay_width_bounded_scale_factor:
resized_width = round(dest.width * overlay_width_bounded_scale_factor)
source_resized = source.resize(
(resized_width, round(resized_width * (source.height / source.width))),
Image.BICUBIC,
)
elif overlay_height_bounded_scale_factor:
resized_height = round(dest.height * overlay_height_bounded_scale_factor)
source_resized = source.resize(
(
round(resized_height * (source.width / source.height)),
resized_height,
),
Image.BICUBIC,
)
else:
source_resized = source
if reference_corner == "top-left":
final_x = border_offset_x
final_y = border_offset_y
elif reference_corner == "top-right":
final_x = dest.width - source_resized.width - border_offset_x
final_y = border_offset_y
elif reference_corner == "bottom-left":
final_x = border_offset_x
final_y = dest.height - source_resized.height - border_offset_y
elif reference_corner == "bottom-right":
final_x = dest.width - source_resized.width - border_offset_x
final_y = dest.height - source_resized.height - border_offset_y
result = Image.new("RGBA", dest.size)
result.paste(dest, (0, 0))
# Composite source image onto the destination image at specified position
result.alpha_composite(source_resized, (final_x, final_y))
result.convert("RGB").save(
dest_output_path,
)
last_dest_size = dest.size
last_source_resized = source_resized
print(
f"Overlay complete for '{os.path.basename(dest_path)}'. Result saved at "
f"'{dest_output_path}' ({i+1}/{dest_images_count} completed)"
)
time.sleep(0.01)
@Gooey(
program_name="CE Image Overlay Tool v2.0.1",
default_size=(800, 600),
navigation="SIDEBAR",
tabbed_groups=True,
progress_regex=r"^.+\((?P<current>\d+)\/(?P<total>\d+) +completed\)$",
progress_expr="current / total * 100",
)
def main():
parser = GooeyParser(
description="Overlay a source PNG image with alpha transparency on destination images."
)
main_group = parser.add_argument_group("Main")
main_group.add_argument(
"source_image",
widget="FileChooser",
help="The source PNG image to use as an overlay.",
)
main_group.add_argument(
"destination_images_folder",
widget="DirChooser",
help="A folder with the destination images.",
)
main_group.add_argument(
"output_folder",
widget="DirChooser",
help="The output folder where overlay results will be saved.",
)
advanced_group = parser.add_argument_group(
"Advanced",
description="Advanced options. Only change things here if you know what you "
"are doing.\n\n ",
)
advanced_group.add_argument(
"--reference-corner",
type=str,
nargs="?",
default="bottom-right",
choices=["top-left", "top-right", "bottom-left", "bottom-right"],
help="The reference corner for positioning the overlay image.",
)
advanced_group.add_argument(
"--border-offset-factor-horizontal",
type=float,
default=2.7,
help="The factor in percent (%) by which to offset the overlay from the "
"selected reference corner on a destination image horizontally, relative "
"to the size of that destination image's width.",
)
advanced_group.add_argument(
"--border-offset-factor-vertical",
type=float,
help="The factor in percent (%) by which to offset the overlay from the "
"selected reference corner on a destination image vertically, relative "
"to the size of that destination image's height.",
)
advanced_group.add_argument(
"--overlay-width-bounded-scale-factor",
nargs="?",
type=float,
default=10,
help="The factor in percent (%) by which to scale the overlay's width, "
"relative to the width of a destination image's width.",
)
advanced_group.add_argument(
"--overlay-height-bounded-scale-factor",
nargs="?",
type=float,
default=None,
help="The factor in percent (%) by which to scale the overlay's height, "
"relative to the size of a destination image's height.",
)
args = parser.parse_args()
overlay_images(
args.source_image,
glob.glob(os.path.join(args.destination_images_folder, "*")),
args.output_folder,
args.reference_corner,
args.border_offset_factor_horizontal / 100
if args.border_offset_factor_horizontal
else None,
args.border_offset_factor_vertical / 100
if args.border_offset_factor_vertical
else None,
args.overlay_width_bounded_scale_factor / 100
if args.overlay_width_bounded_scale_factor
else None,
args.overlay_height_bounded_scale_factor / 100
if args.overlay_height_bounded_scale_factor
else None,
)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment