project / July 31st, 2021
This is a desktop app in which users can upload an image and choose to add an image watermark or a text watermark to the bottom-right corner of the image. The newly watermarked image is then displayed to the user in a separate window and saved in the same directory where the original image is located.
This is a professional portfolio project that was created after completing the 100 Days of Code Python Bootcamp.
After completing the 100 Days of Code Python Bootcamp, this project was offered as a suggested project idea to apply my knowledge of the Python Tkinter Iibrary from the course. In addition to Tkinter, this project would also test my ability to learn about a new library, the Pillow library for manipulating image files in Python. Just like other professional portfolio projects, developing skills in planning and executing a project from scratch without guidance was the most valuable lesson. Planning the Watermarker GUI layout and app functionality served as excellent tests for applying these skills.
Python
Tkinter
Pillow
Initially, my plan for this project was to have a GUI with two buttons. Clicking the first button would utilize Tkinter's filedialog module to enable the user to select an image to be watermarked, and a pre-selected picture (the Chikorita image) would be watermarked onto the image using the Pillow library. The second button would simply close the GUI window and end the program.
However, as I did more research into watermarking with Python, I learned that watermarking text onto images was also a viable option. I also wanted to provide more choice for the user by enabling them to select the watermark image in addition to the base image, or type out text if they wanted to watermark text onto the base image.
Eventually, I devised a solution that would use five (later six) functions:
A function called open_base_image to enable the user to select the base image (the image to be watermarked) using the Pillow library. The location path to the base image is then inserted into an input box that will display the base image path for the user.
A function called open_watermark_image that is similar to open_base_image, except the user is selecting the image that will be watermarked onto the base image. The location path to the watermark image is displayed in another input box below the base image input box.
A function called add_image_watermark that uses Pillow to take the base image and watermark image paths, resizes the watermark image to an appropriate watermark size before positioning it in the bottom-right corner of the base image, saves the newly watermarked image, and displays it in a separate pop-up window.
A function called add_text_watermark where Pillow is used to take the base image path, and text is taken from a watermark text input box and drawn onto the bottom-right corner of the base image. Once finished, the newly watermarked image is saved and displayed in a separate window.
A function called close_window that closes the window after a button labeled "Exit" is clicked. The program is subsequently shut down.
Additionally, I added another function called choose_colour after completing the majority of the project. This function will display a colour picker and enable the user to select a font colour for their text watermark after a button is clicked.
Once I had a general idea of the Watermarker's functionalities, I used Tkinter to create a GUI layout. To start, I added a canvas widget that contains the logo I selected for this app. Next, I added various labels, buttons, and text input boxes in rows positioned below the logo. The labels inform the user of the data that each text input box should contain. The buttons are labeled to describe the action each of them would take, and each button is connected to each of the respective functions described above. Additionally, I added an additional text box to allow the user to specify an amount they want to scale the text watermark by. Because I chose a picture of the Pokemon Chikorita as the logo, this helped guide my colour choices for the buttons and labels.
The next step was to implement each of the functions described above. For the open_base_image and open_watermark_image functions, the askopenfilename method from the Tkinter.filedialog module is used to open a window that enables the user to select a base or watermark image. Once selected, the image path is inserted into their respective text input boxes.
The add_image_watermark function extracts the paths in each of these textboxes and the Pillow Image open method is used to read each image and convert them into RGBA format. The watermark image is then resized to a tenth of the base image and positioned to the bottom-right corner of the base image by subtracting the dimensions of the resized watermarked image from the base image. The base image and final image watermark are then pasted onto a new blank image and converted to RGB format (suitable for JPEG or PNG) to form the newly watermarked image, which is displayed in a new pop-up window and saved in the same directory as the base image under a new name. Once completed, the GUI will display a success message at the bottom of the window and specify the location of the new image.
The add_text_watermark function follows a similar process as add_image_watermark, except that it extracts the base image path from its textbox and the inputs written for the watermark text, font colour, and font scaling. The base image is converted to RGBA format, and the Pillow ImageDraw text method is used to draw the inputted watermark text at the bottom-right corner of the base image. To calculate the position of the watermark text, the ImageDraw textsize method is first used to acquire the dimensions of the watermark text, which is then subtracted from the base image dimensions. Pillow's ImageFont truetype method is used to specify the font family and font size of the text. I chose the default font size to be the specified font scale (default is 1) multiplied by the square root of the sum of the width and height of the base image. Once completed, the newly watermarked image is displayed in a separate pop-up window and saved in the same directory as the base image under a different name. Like the add_image_watermark function, the GUI will display a success message at the bottom with the location of the new image.
The colour_picker will assign the chosen font colour to a global variable that can be accessed by the add_text_watermark function to change the watermark text colour. The font colour button is also changed to the chosen colour to remind the user of what colour the watermark text will be. The close_window function will close the window and end the program when the Exit button is clicked.
Throughout the process, I added extra lines of code to each function to disable or enable buttons depending on what was clicked. For example, all buttons except those to select the base image, watermark text colour, and exit the program are disabled at the start of the program, and have a grey colour. Once a base image is selected, the remaining buttons to select a watermark image and add an image or text watermark will change colour to the default green and become clickable.
I also added Exception handling to add_image_watermark and add_text_watermark to handle errors in cases where these functions are called, but there are empty text box inputs or wrong file paths specified for the base or watermark image. A message will be displayed at the bottom of the GUI to inform the user of an error in these cases.
Finishing touches are made by adding padding around each button and label to make the GUI less cluttered, and extra lines of code are added to clear certain textboxes after a function is completed.
Building the Watermarker was a valuable experience in creating a desktop GUI app that applied my existing knowledge of Tkinter, while also learning to incorporate a new library in Pillow and planning out a project from scratch. Although I reached points where I felt lost or stuck, it was personally satisfying to be able to push through these points and create an app that is both practical and creative!
There are endless improvements that can be made to the Watermarker. The Watermarker can be further elevated by providing more user options to customize their watermark like image size, positioning, and angles. It would also help to display a preview of the final watermarked image to assist users in making adjustments quicker and more easily.