python TK interface for adding borders under pictures

Python adds borders and logo textures to images, obtains image exif parameters, and fills in image text content – CSDN Blog

import tkinter as tk
from tkinter import ttk
import os
import glob
import json
import tkinter.messagebox as messagebox # Pop up prompt box
from PIL import Image, ImageDraw, ImageFont
import exifread

def photo_exif(image_path):

    f = open(image_path, 'rb')

    tags = exifread.process_file(f)

    # Print all photo information and save it as key-value pairs
    # for tag in tags.keys():
    # print("Key: {0}, value {1}".format(tag, tags[tag]))
    # print(str(tags['EXIF FocalLength']) + 'mm', tags['EXIF ExposureTime'], 'ISO' + str(tags['EXIF ISOSpeedRatings']) )
    return tags



def add_logo_with_text(image_path, logo_path, logo_size, text1, text2, text3, font_path, font_size, font_color, border_size,
                       border_color, output_path):
    #Open the original image
    image = Image.open(image_path).convert("RGB")
    width, height = image.size

    # Calculate the size and position of the border area
    font = ImageFont.truetype(font_path, font_size)
    text1_width, text1_height = font.getsize(text1)
    text2_width, text2_height = font.getsize(text2)
    text3_width, text3_height = font.getsize(text3)
    text_width = max(text1_width, text2_width, text3_width)
    text_height = text1_height + text2_height + text3_height
    border_width = logo_size[0] + text_width + border_size * 3
    border_height = max(logo_size[1], text_height) + border_size * 2
    border_position = ((width - border_width) // 2, height)

    # Open the logo image and resize it
    logo = Image.open(logo_path).resize(logo_size, Image.ANTIALIAS)

    #Create new image
    new_width = width
    new_height = height + border_height
    new_image = Image.new("RGB", (new_width, new_height), "white")

    # Copy the original image to the top of the new image
    new_image.paste(image, (0, 0, width, height))

    # Draw a border on the new image
    draw = ImageDraw.Draw(new_image)
    border_rect = (border_position[0], height, border_position[0] + border_width, height + border_height)
    draw.rectangle(border_rect, fill=None, outline=border_color, width=border_size)

    # Draw the logo image in the border area
    logo_position = (border_position[0] + border_size, height + (border_height - logo_size[1]) // 2)
    new_image.paste(logo, logo_position)

    # Draw text within the border area
    text1_position = (border_position[0] + border_size * 2 + logo_size[0], height + (border_height - text_height) // 2)
    text2_position = (border_position[0] + border_size * 2 + logo_size[0], text1_position[1] + text1_height)
    text3_position = (border_position[0] + border_size * 2 + logo_size[0], text2_position[1] + text2_height)
    draw.text(text1_position, text1, font=font, fill=font_color)
    draw.text(text2_position, text2, font=font, fill=font_color)
    draw.text(text3_position, text3, font=font, fill=font_color)

    # Save the synthesized image
    new_image.save(output_path)

def generate_callback():
    # Get the selected value of the drop-down list
    param1 = combo1.get()
    param2 = combo2.get()
    param3 = combo3.get()
    param4 = combo4.get()
    param5 = combo5.get()
    param6 = combo6.get()
    param66 = combo66.get()
    param7 = combo7.get()

    # Determine whether the input is empty and pop up a prompt box
    if not param1:
        messagebox.showerror("Error", "The image path cannot be empty!")
        return
    if not param2:
        messagebox.showerror("Error", "Logo path cannot be empty!")
        return
    if not param3:
        messagebox.showerror("Error", "Parameter 1 cannot be empty!")
        return
    if not param4:
        messagebox.showerror("Error", "Parameter 2 cannot be empty!")
        return
    if not param5:
        messagebox.showerror("Error", "Parameter 3 cannot be empty!")
        return
    if not param6:
        messagebox.showerror("Error", "Font path cannot be empty!")
        return
    if not param66:
        messagebox.showerror("Error", "Font size cannot be empty!")
        return
    if not param7:
        messagebox.showerror("Error", "The output path cannot be empty!")
        return

    # Call the backend processing function and pass parameters
    # print(param1, param2, param22, param3, param4, param5, param6, param66, param7)

    # Example usage
    # photo path
    image_path = param1
    # logo image path
    logo_path = param2
    # Logo image size
    logo_size = (255, 255)
    # image information
    tags = photo_exif(image_path)
    text1 = param3
    text2 = param4
    text3 = param5
    # Font path
    font_path = param6
    font_size = 55
    font_color = (0, 0, 0) # black
    border_size = 55
    border_color = (255, 255, 255) # white
    # Output photos. The suffix is png for lossless images and jpg for compressed images.
    output_path = str(image_path) + str(param7)

    add_logo_with_text(image_path, logo_path, logo_size, text1, text2, text3, font_path, font_size, font_color, border_size,
                       border_color, output_path)
    print("The picture has been saved to:", output_path)
    messagebox.showinfo("Prompt", "The picture has been saved to: \\
" + output_path)


def on_file_list_double_click(event):
    selected_index = event.widget.curselection()
    if selected_index:
        selected_file = event.widget.get(selected_index)
        combo1.set(selected_file)

def on_logo_list_double_click(event):
    selected_index = event.widget.curselection()
    if selected_index:
        selected_file = event.widget.get(selected_index)
        combo2.set(selected_file)

def on_font_list_double_click(event):
    selected_index = event.widget.curselection()
    if selected_index:
        selected_file = event.widget.get(selected_index)
        combo6.set(selected_file)

#Create the main window
root = tk.Tk()


#Read json file parameters
f = open('config.json', 'r', encoding='utf-8')
content = f.read()
a = json.loads(content)

# Create components with parameter names and drop-down lists
label1 = tk.Label(root, text="Picture path:")
combo1 = ttk.Combobox(root, state="normal", values=a["param1"])
label2 = tk.Label(root, text="logo path:")
combo2 = ttk.Combobox(root, state="normal", values=a["param2"])
label3 = tk.Label(root, text="Parameter 1:")
combo3 = ttk.Combobox(root, state="normal", values=a["param3"])
label4 = tk.Label(root, text="Parameter 2:")
combo4 = ttk.Combobox(root, state="normal", values=a["param4"])
label5 = tk.Label(root, text="Parameter 3:")
combo5 = ttk.Combobox(root, state="normal", values=a["param5"])
label6 = tk.Label(root, text="Font path:")
combo6 = ttk.Combobox(root, state="normal", values=a["param6"])
label66 = tk.Label(root, text="Font size:")
combo66 = ttk.Combobox(root, state="normal", values=a["param66"])
label7 = tk.Label(root, text="Output path:")
combo7 = ttk.Combobox(root, state="normal", values=a["param7"])

# label7 = tk.Label(root, text="Output path:")
# combo7 = ttk.Combobox(root, state="normal", values=["Option 1", "Option 2", "Option 3"])

#Set the height and width of the drop-down box
combo1.configure(width=68)
combo2.configure(width=68)
combo3.configure(width=68)
combo4.configure(width=68)
combo5.configure(width=68)
combo6.configure(width=68)
combo66.configure(width=68)
combo7.configure(width=68)



#Create a generate button and bind a callback function
generate_btn = tk.Button(text="Generate", command=generate_callback, width=79, height=2)

# Use grid layout to place each component
label1.grid(row=0, column=0)
combo1.grid(row=0, column=1)
label2.grid(row=1, column=0)
combo2.grid(row=1, column=1)
label3.grid(row=2, column=0)
combo3.grid(row=2, column=1)
label4.grid(row=3, column=0)
combo4.grid(row=3, column=1)
label5.grid(row=4, column=0)
combo5.grid(row=4, column=1)
label6.grid(row=5, column=0)
combo6.grid(row=5, column=1)
label66.grid(row=6, column=0)
combo66.grid(row=6, column=1)
label7.grid(row=7, column=0)
combo7.grid(row=7, column=1)
generate_btn.grid(row=8, columnspan=2) # Use columnspan to set the button to span two columns

#Set the default selected value
combo1.current(0)
combo2.current(0)
combo3.current(0)
combo4.current(0)
combo5.current(0)
combo6.current(0)
combo66.current(0)
combo7.current(0)

#Add title
title_label = tk.Label(root, text="File path:")
title_label.grid(row=0, column=2, sticky="w")

#Add title
logo_title_label = tk.Label(root, text="Logo path:")
logo_title_label.grid(row=0, column=4, sticky="w")

font_title_label = tk.Label(root, text="Font path:")
font_title_label.grid(row=0, column=6, sticky="w")

# Get all file paths in the current py file directory
file_paths = glob.glob('*')

#Create file path list box component
file_listbox_var = tk.StringVar(value=file_paths)
file_listbox = tk.Listbox(root, listvariable=file_listbox_var)
file_listbox.grid(row=1, column=2, rowspan=7, padx=10, pady=10, sticky="nsew")

# Bind the double-click event handler function
file_listbox.bind('<Double-Button-1>', on_file_list_double_click)

# Set the list box to automatically fill the parent container
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)

#Create scrollbar
file_scrollbar = tk.Scrollbar(root, orient="vertical", command=file_listbox.yview)
file_scrollbar.grid(row=1, column=3, rowspan=7, sticky="ns")

#Associate the scroll bar with the file path list box
file_listbox.configure(yscrollcommand=file_scrollbar.set)

#Create the logo path list box component
logo_listbox_var = tk.StringVar(value=file_paths)
logo_listbox = tk.Listbox(root, listvariable=logo_listbox_var)
logo_listbox.grid(row=1, column=4, rowspan=7, padx=10, pady=10, sticky="nsew")

# Bind the double-click event handler function
logo_listbox.bind('<Double-Button-1>', on_logo_list_double_click)

#Create scrollbar
logo_scrollbar = tk.Scrollbar(root, orient="vertical", command=logo_listbox.yview)
logo_scrollbar.grid(row=1, column=5, rowspan=7, sticky="ns")

#Associate the scroll bar with the logo path list box
logo_listbox.configure(yscrollcommand=logo_scrollbar.set)

#Create font path list box component
font_listbox_var = tk.StringVar(value=file_paths)
font_listbox = tk.Listbox(root, listvariable=font_listbox_var)
font_listbox.grid(row=1, column=6, rowspan=7, padx=10, pady=10, sticky="nsew")

# Bind the double-click event handler function
font_listbox.bind('<Double-Button-1>', on_font_list_double_click)

#Create scrollbar
font_scrollbar = tk.Scrollbar(root, orient="vertical", command=font_listbox.yview)
font_scrollbar.grid(row=1, column=7, rowspan=7, sticky="ns")

#Associate the scroll bar with the font path list box
font_listbox.configure(yscrollcommand=font_scrollbar.set)

#
# root.geometry("900x400") # Set the width of the window to 600 pixels and the height to 400 pixels

#Run the main loop
root.mainloop()