Making a splash with Watermark Creator
To build this app, we will need the following modules: tkinter and PIL.
Let's start by setting up the GUI. We will create a window with two frames, one for displaying images and the other for displaying controls. We will also create a placeholder for the image to be displayed.
from tkinter import *
from tkinter import filedialog, Text
import PIL.Image
import PIL.ImageTk
import PIL.ImageFont
import PIL.ImageDraw
# Initialize main window
window = Tk()
window.geometry("1400x1000")
window.config(padx=15, pady=15)
# Left side of main window. Contains text, images, input files
left_frame = Frame(window)
left_frame.grid(column=0, row=0, pady=80)
# Right side of main windows. Display images and text which we want to
# put as watermark.
right_frame = Frame(window)
right_frame.grid(column=1, row=0)
# Creates placeholder for images to display on right_frame.
canvas = Canvas(right_frame, width=350, height=350, bg="white")
image_container = canvas.create_image(0, 0, anchor=NW)
canvas.grid(
padx=50,
)
# Frame within left_frame. Displays text instructions.
text_frame = Frame(left_frame)
text_frame.grid(column=0)
# Global TEXT variable input field.
watermark_text = Text(text_frame, width=40, height=1)
watermark_text.grid(column=0, columnspan=2)
# Frame for buttons in left_frame. They are used to get data from input
# and display text on image place.
text_buttons_frame = Frame(left_frame)
text_buttons_frame.grid(padx=10, pady=10)
Then we will retrieve_input() of an user and save it in our global variable.
def retrieve_input():
""" Retrieves a text which is input by user in Text field."""
global TEXT
TEXT = watermark_text.get("1.0", END)
Next we will define a show_text() which will create a text in our previously created placeholder image. We will also create a button with callback to it.
def show_text(opacity=255, x=0, y=0):
"""
Shows and updates watermark text. Takes opacity, x axis and y axis
as arguments.
"""
global MYIMG, IM2
if TEXT != "":
# Defines font which will be used.
font = PIL.ImageFont.truetype("arial.ttf", 48)
# Creates and displays TEXT we given earlier with parameters
# opacity, x and y we set on sliders. Text area size
text_bg = PIL.Image.new(
"RGBA", CURRENTLY_OPEN_IMAGE.size, (0, 0, 0, 0))
draw_text_bg = PIL.ImageDraw.Draw(text_bg)
draw_text_bg.text(
(0, 0), TEXT, (255, 255, 255, int(opacity_slider.get())), font=font
)
IM2 = PIL.Image.new("RGBA", CURRENTLY_OPEN_IMAGE.size, (0, 0, 0, 0))
IM2.paste(
text_bg,
(x_axis_location.get(), y_axis_location.get()),
mask=text_bg.convert("RGBA"),
)
MYIMG = PIL.ImageTk.PhotoImage(IM2)
canvas.create_image(0, 0, image=MYIMG, anchor="nw")
Button(text_buttons_frame, text="Convert", command=show_text).grid(
column=1, row=1, padx=10
)
After that we create an frame in left_frame in which we will create our opacity, x axis and y axis sliders.
sliders_frame = Frame(left_frame)
sliders_frame.grid(column=0)
def update_opacity(opacity):
""" Updates opacity with value given in Scale opacity_slider"""
show_text(opacity=opacity)
opacity_slider = Scale(
sliders_frame,
label="Opacity",
from_=0,
to=255,
command=update_opacity,
orient=HORIZONTAL,
)
opacity_slider.grid(column=1, row=0)
def update_x_axis(x):
""" Updates watermark text location in X axis with value given
in Scale x_axis_location"""
show_text(x=x)
x_axis_location = Scale(
sliders_frame,
label="X Axis",
from_=0,
to=350,
command=update_x_axis,
orient=HORIZONTAL,
)
x_axis_location.grid(column=0, row=1)
def update_y_axis(y):
""" Updates watermark text location in Y axis with value given
in Scale y_axis_location"""
show_text(y=y)
y_axis_location = Scale(
sliders_frame,
label="Y Axis",
from_=0,
to=350,
command=update_y_axis,
orient=HORIZONTAL,
)
y_axis_location.grid(column=3, row=1)
Now we also need to create a textbox where we can see our images which we chosen to edit.
files_frame = Frame(left_frame)
files_frame.grid()
FILE_PATH = []
def get_local_file():
""" Opens file/s from chosen folder. """
global FILE_PATH
FILE_PATH = filedialog.askopenfilename(multiple=True)
# Takes chosen files path and formats it to, so only filename is left.
for file in FILE_PATH:
file_name = file.split("/")[-1::]
files.append(file_name)
# Inputs these names in a listbox which displays them for user.
# They can be accesed by a click.
for file_name in files:
images_listbox.insert("end", file_name)
for file_image in files:
for path in FILE_PATH:
if file_image[0] in path:
open_images.append(
PIL.ImageTk.PhotoImage(PIL.Image.open(path)))
# open_images.append(PIL.ImageTk.PhotoImage(
# PIL.Image.open(f"images/{file_image[0]}")))
def print_filename(event):
""" Displays chosen image from listbox in canvas. """
global CURRENTLY_OPEN_IMAGE
# Defines which image is chosen.
image_index = images_listbox.curselection()[0]
# Opens image.
CURRENTLY_OPEN_IMAGE = PIL.Image.open(FILE_PATH[image_index])
# Setup canvas size to a size of opened image.
canvas_size = CURRENTLY_OPEN_IMAGE.size
x_axis_location.configure(to=canvas_size[0])
y_axis_location.configure(to=canvas_size[1])
canvas.config(width=canvas_size[0], height=canvas_size[1])
canvas.itemconfig(image_container, image=open_images[image_index])
canvas.update()
# Create listbox where images will be listed.
images_listbox = Listbox(files_frame, width=90, height=10)
images_listbox.grid(column=1, row=1, sticky=(N, W, E, S))
# Add scrollbar on the left of images_listbox.
images_listbox_scrollbar = Scrollbar(
files_frame, orient=VERTICAL, command=images_listbox.yview
)
images_listbox_scrollbar.grid(column=0, row=1, stick=NS)
images_listbox["yscrollcommand"] = images_listbox_scrollbar.set
images_listbox.bind("<<ListboxSelect>>", print_filename)
Button(files_frame, text="Chose your file", command=get_local_file).grid(
column=1, pady=10
)
Also a Quit button
Button(files_frame, text="Quit", command=window.destroy).grid(column=1)
And last one which will save our edited image
def save_image():
""" Saves image with watermark we have currently
displaying in canvas"""
final_image = PIL.Image.new("RGBA", CURRENTLY_OPEN_IMAGE.size)
final_image.paste(CURRENTLY_OPEN_IMAGE)
final_image.paste(IM2, (0, 0), mask=IM2.convert("RGBA"))
final_image.save("final.png")
Button(files_frame, text="Save results", command=save_image).grid(column=1)
Using tkinter we need to make it to run in mainloop()
window.mainloop()