Image Manipulation in Python using Pillow

Mahathir Muhammad
15 min readAug 9, 2023

--

Introducing: PIL (Python Imaging Library) or Pillow

Hello, welcome to my writing experience with the medium platform, at this time I will try to do a little bit of image manipulation in Python using the Pillow library. I am excited to leverage Pillow’s power to perform a variety of image processing tasks, create stunning visual effects, and bring imaginations to life through digital imagery.

PIL is an additional open-source library for Python whose main function is to manipulate image files. PIL was created by Fredrik Lundh in 1995, and development was discontinued in 2011. PIL was forked and continued by the Pillow library.

Pillow supports many popular file formats, such as PNG, JPG/JPEG, TIFF and BMP. If necessary, Pillow and Python support additional decoder libraries. Types of manipulation include masking, filtering, enhancement, adding text, per pixel manipulation and others.

Pillow is a powerful and user-friendly Python imaging library that allows me to open, manipulate and save images in various formats. I have extensive experience in utilizing Pillow’s rich set of functionalities to perform image transformations, filters, enhancements and more.

Environment Preparation: Install Pillow Library

python3 -m pip install --upgrade Pillow

According to an article from Abiola Farounbi said:

Pillow offers the Image object, which has inbuilt functions and properties on which manipulation operations can be carried out.

For next warming up, first import an Image object to the Python file:

from PIL import Image

Then load the image by calling the Image.open() function, which returns a value of the Image object data type

image = Image.open(‘sample.jpeg’)

For our examples, we’ll use a sample image from Unsplash.

Also worth noting, the images are in the same directory as the Python script file being run.

Here are some basic operations to modify the appearance or structure of an image:

  1. Image Enhancement and Filters
    We will be adjusting brightness, contrast or applying filters like gaussian blur, enhance edge and emboss filter:
  • Brightness and Contrast Adjustment
    In Pillow (PIL), we can adjust the brightness and contrast of an image using theImageEnhance module. In this code, we use the ImageEnhance.Brightness and ImageEnhance.Contrast classes from Pillow to adjust the brightness and contrast of the image, respectively. Here’s how we can do it:
  1. Import another necessary module called ImageEnhance:
from PIL import Image, ImageEnhance

2. Adjust the brightness:

brightness_factor = 1.5  # Increase brightness by 50%
enhancer = ImageEnhance.Brightness(image)
brightened_image = enhancer.enhance(brightness_factor)

For brightness adjustment, we create an ImageEnhance.Brightness object and specify the enhancement factor. A factor of 1.0 means no change, less than 1.0 darkens the image, and greater than 1.0 brightens it. In the example, we increase the brightness by 50% (factor = 1.5).

3. Adjust the contrast:

contrast_factor = 1.2  # Increase contrast by 20%
enhancer = ImageEnhance.Contrast(image)
contrasted_image = enhancer.enhance(contrast_factor)

For contrast adjustment, we create an ImageEnhance.Contrast object and specify the enhancement factor. A factor of 1.0 means no change, less than 1.0 decreases contrast, and greater than 1.0 increases contrast. In the example, we increase the contrast by 20% (factor = 1.2).

We then use the enhance() method of both ImageEnhance objects to apply the adjustments to the input image, creating the brighter and high-contrast versions.

If we want to save the adjusted images, using save() and display all three images using show():

# Save the adjusted images
brightened_image.save("path/to/save/brightened_image.jpeg")
contrasted_image.save("path/to/save/contrasted_image.jpeg")
  • Applying Filters

To apply filters using Pillow in Python, we can use the ImageFilter module. Here’s an example of how to apply various filters to an image:

  1. Import another necessary module called ImageFilter:
from PIL import Image, ImageFilter

2. Apply EMBOSS, GaussianBlur, and EDGE_ENHANCE filters:

# Apply the emboss filter
embossed_image = image.filter(ImageFilter.EMBOSS)

# Apply the Gaussian blur filter
gaussian_blur_image = image.filter(ImageFilter.GaussianBlur(radius=5))

# Apply the edge enhancement filter
edge_enhanced_image = image.filter(ImageFilter.EDGE_ENHANCE)
  • To apply an emboss filter, we use the ImageFilter.EMBOSS filter.
  • To apply a Gaussian blur filter, we use the filter() method with ImageEnhance.GaussianBlur and specify the radius parameter to control the blurriness. A larger radius value will result in a more pronounced blur effect.
  • To apply an edge enhancement filter, we use the ImageFilter.EDGE_ENHANCE filter.

We can experiment with other filters available in the ImageFilter module to achieve different visual effects on your images.

2. Image Cropping and Resizing

With Pillow, we can crop images to specific dimensions or aspect ratios and resize them to fit various platforms or create thumbnails without losing image quality:

  • Cropping an image

Crop the image by specifying a box (left, upper, right, lower) that defines the region we want to keep. Anyway, we don’t have to import any modules except Image, so let’s jump to:

  1. Define the cropping region:
left = 100
upper = 100
right = 300
lower = 300

2. Crop the image:

cropped_image = image.crop((left, upper, right, lower))
  • Resizing an image

We can resize an image to a specific size or scale it proportionally by specifying one dimension.

  1. Define the new size (width and height):
new_width = 800
new_height = 600

2. Resize the image:

resized_image = image.resize((new_width, new_height))

By specifying the new width and height, you can resize the image to your desired dimensions while maintaining the original aspect ratio. Keep in mind that resizing may affect the image’s appearance, so it’s a good idea to use a size proportional to the original image to avoid distortion.

3. Image Composition and Overlay

I have experience overlaying images on top of each other, combining them seamlessly to create composite images and applying transparency effects to achieve stunning visual results:

  • Import the required modules from the Pillow library, including Image and new module calledImageDraw:
from PIL import Image, ImageDraw
  • Compose the images There are various ways to compose images, depending on your desired effect. Here are a few examples:
  1. Pasting one image onto another Use the paste() method to paste the overlay image onto the background image at a specified position:
position = (100, 100)  # (x, y) coordinates where you want to place the overlay image
background_image.paste(overlay_image, position, overlay_image)

2. Blending images with transparency If your overlay image has an alpha channel (transparency), you can use the blend() method to blend it with the background image:

alpha = 0.5  # Set the alpha value (0.0 for fully transparent, 1.0 for fully opaque)
blended_image = Image.blend(background_image, overlay_image, alpha)

4. Text and Graphic Annotation

Using Pillow, we can add text, shapes and graphical elements to images for creating informative and visually appealing visual content:

  • First, we have to import the two other necessary modules, here is the code:
from PIL import Image, ImageDraw, ImageFont
  • Create a drawing object and font object Create a drawing object using the ImageDraw.Draw() method, and load a font using the ImageFont.truetype() method. You need to specify the path to the font file and the desired font size:
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("path/to/your/font.ttf", size=40) # Replace "path/to/your/font.ttf" with the path to your preferred font file
  • Add text annotation to the image Use the draw.text() method to add text annotation to the image. You can specify the text content, position (x, y coordinates), text color (as an RGB tuple), and the font:
text = "Hello, Pillow!"
text_position = (50, 50) # (x, y) coordinates for the text
text_color = (255, 255, 255) # RGB color for the text (white in this example)
draw.text(text_position, text, fill=text_color, font=font)
  • Add graphic annotation to the image You can add various graphic annotations like rectangles, lines, circles, polygons, etc. In this example, we’ll draw a rectangle using the draw.rectangle() method. Specify the coordinates of the top-left and bottom-right corners of the rectangle and the outline color (as an RGB tuple):
rectangle_position = [(100, 100), (200, 200)]  # Top-left and bottom-right coordinates of the rectangle
rectangle_color = (0, 255, 0) # RGB color for the rectangle (green in this example)
draw.rectangle(rectangle_position, outline=rectangle_color)

5. Geometric Transforms

Pillow provides various geometric transformations, such as shear and affine transformations:

  • Rotation, which to perform rotation, use the rotate() method. Provide the angle of rotation as an argument. Positive angles rotate the image counter-clockwise, and negative angles rotate it clockwise:
rotated_image = image.rotate(45)  # Rotate the image by 45 degrees counter-clockwise
  • Scaling the image use the resize() method. Provide the new dimensions as a tuple (width, height):
scaled_image = image.resize((image.width // 2, image.height // 2))  # Scale the image to half of its original size
  • Shearing use the transform() method with an affine transformation matrix. The matrix is represented as a tuple (a, b, c, d, e, f). For horizontal shearing, set b and e to the shear factor:
sheared_image = image.transform((image.width + 100, image.height), Image.AFFINE, (1, 0.2, -100, 0, 1, 0))
# Apply horizontal shearing with a shear factor of 0.2
  • Flip the image, use the transpose() method with the appropriate option. For horizontal flipping, use Image.FLIP_LEFT_RIGHT:
flipped_image = image.transpose(Image.FLIP_LEFT_RIGHT)  # Flip the image horizontally

We’ve now applied geometric transforms to your image using Pillow in Python. We can experiment with different rotation angles, scaling factors, shear factors, and flip options to achieve different effects on your images. So we’ve done with those things some of basic operations using Pillow!

Let me take your body & mind further with Pillow

1. Instagram-like Filter Application

In this project, I developed a Python application that allows users to apply Instagram-like filters to their images using Pillow. Users can choose from a variety of filters, adjust their intensity and see real-time previews of the filtered images. Now, let’s build the Python application:

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk, ImageFilter, ImageEnhance

class InstagramFilterApp:
def __init__(self, root):
self.root = root
self.root.title("Instagram-like Filters")

self.original_image = None
self.filtered_image = None
self.filter_intensity = 1.0

self.canvas = tk.Canvas(root, width=500, height=500)
self.canvas.pack()

self.load_button = tk.Button(root, text="Load Image", command=self.load_image)
self.load_button.pack()

self.filter_options = {
"Normal": None,
"Grayscale": ImageFilter.GaussianBlur(2),
"Blur": ImageFilter.GaussianBlur(5),
"Sharpness": ImageFilter.SHARPEN,
"Brightness": "Brightness",
"Contrast": "Contrast"
}

self.filter_var = tk.StringVar()
self.filter_var.set("Normal")

self.filter_dropdown = tk.OptionMenu(root, self.filter_var, *self.filter_options.keys())
self.filter_dropdown.pack()

self.intensity_label = tk.Label(root, text="Intensity:")
self.intensity_label.pack()

self.intensity_scale = tk.Scale(root, from_=0.1, to=2.0, resolution=0.1, orient=tk.HORIZONTAL)
self.intensity_scale.set(1.0)
self.intensity_scale.pack()

self.apply_button = tk.Button(root, text="Apply Filter", command=self.apply_filter)
self.apply_button.pack()

def load_image(self):
file_path = filedialog.askopenfilename(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif")])
if file_path:
self.original_image = Image.open(file_path)
self.filtered_image = self.original_image.copy()
self.show_image()

def show_image(self):
self.filtered_image.thumbnail((500, 500))
photo = ImageTk.PhotoImage(self.filtered_image)
self.canvas.create_image(0, 0, anchor=tk.NW, image=photo)
self.canvas.image = photo

def apply_filter(self):
selected_filter = self.filter_var.get()
filter_option = self.filter_options[selected_filter]

if filter_option is None:
self.filtered_image = self.original_image.copy()
elif filter_option == "Brightness":
self.apply_brightness()
elif filter_option == "Contrast":
self.apply_contrast()
else:
self.apply_pillow_filter(filter_option)

self.show_image()

def apply_brightness(self):
brightness_factor = self.intensity_scale.get()
enhancer = ImageEnhance.Brightness(self.original_image)
self.filtered_image = enhancer.enhance(brightness_factor)

def apply_contrast(self):
contrast_factor = self.intensity_scale.get()
enhancer = ImageEnhance.Contrast(self.original_image)
self.filtered_image = enhancer.enhance(contrast_factor)

def apply_pillow_filter(self, filter_option):
self.filtered_image = self.original_image.filter(filter_option)
self.apply_intensity()

def apply_intensity(self):
intensity = self.intensity_scale.get()
enhancer = ImageEnhance.Brightness(self.filtered_image)
self.filtered_image = enhancer.enhance(intensity)

if __name__ == "__main__":
root = tk.Tk()
app = InstagramFilterApp(root)
root.mainloop()
  1. Import Libraries: Import the required libraries: tkinter for GUI, filedialog for file selection, and PIL (Pillow) for image processing.
  2. Create Main Application Class: Define the InstagramFilterApp class, which will manage the application's functionality.
  3. Initialize UI Components: In the __init__ method of the class, create UI components using tkinter, such as buttons, dropdowns, and scales.
  4. Load Image: Implement the load_image method to open a file dialog, load the selected image, and display it on the canvas.
  5. Display Images: Define the show_image method to display the filtered image on the canvas.
  6. Apply Filters: Implement the apply_filter method to apply the selected filter to the image and display the result. Depending on the filter option, either apply a Pillow filter or adjust brightness/contrast.
  7. Apply Brightness and Contrast: Implement methods apply_brightness and apply_contrast to adjust image brightness and contrast using ImageEnhance.
  8. Apply Pillow Filter: Implement the apply_pillow_filter method to apply Pillow's image filters to the image.
  9. Apply Filter Intensity: Implement the apply_intensity method to adjust the intensity of the applied filter using ImageEnhance.
  10. Main Block: Initialize the Tkinter root window, create an instance of the InstagramFilterApp class, and start the Tkinter event loop.

This complete code creates a Python application that enables users to apply various Instagram-like filters to their images. Users can select filters, adjust intensity, and see real-time previews of the filtered images. The ImageFilter module from Pillow is used for basic filters, while the ImageEnhance module is used for adjusting brightness and contrast. The code provides a solid foundation, and we can expand it by adding more filters and customization options.

2. Image Collage Generator

Using Pillow’s image composition capabilities, I created a script that generates a collage of images based on user input. The users can specify the arrangement, spacing and size of the images in the collage, resulting in a visually pleasing layout.

import os
import tkinter as tk
from tkinter import filedialog
from PIL import Image

class ImageCollageGenerator:
def __init__(self):
self.images = []
self.collage = None
self.output_folder = "./output_collage/"

if not os.path.exists(self.output_folder):
os.makedirs(self.output_folder)

def load_images(self):
file_paths = filedialog.askopenfilenames(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif")])
if file_paths:
self.images = [Image.open(path) for path in file_paths]

def generate_collage(self, rows, cols, spacing, width, height):
total_images = rows * cols

if total_images < len(self.images):
self.images = self.images[:total_images]
elif total_images > len(self.images):
self.images.extend([Image.new("RGB", (1, 1), (255, 255, 255))] * (total_images - len(self.images)))

collage_width = cols * width + (cols - 1) * spacing
collage_height = rows * height + (rows - 1) * spacing

self.collage = Image.new("RGB", (collage_width, collage_height), (255, 255, 255))

x_offset, y_offset = 0, 0
for i, img in enumerate(self.images):
img = img.resize((width, height), Image.ANTIALIAS)
self.collage.paste(img, (x_offset, y_offset))

x_offset += width + spacing
if (i + 1) % cols == 0:
x_offset = 0
y_offset += height + spacing

def save_collage(self):
if self.collage:
file_path = filedialog.asksaveasfilename(defaultextension=".png", filetypes=[("PNG", "*.png")])
if file_path:
self.collage.save(file_path)

if __name__ == "__main__":
app = tk.Tk()
app.title("Image Collage Generator")

collage_generator = ImageCollageGenerator()

btn_load = tk.Button(app, text="Load Images", command=collage_generator.load_images)
btn_load.pack(pady=5)

frame_options = tk.Frame(app)
frame_options.pack()

label_rows = tk.Label(frame_options, text="Rows:")
label_rows.pack(side=tk.LEFT)
entry_rows = tk.Entry(frame_options)
entry_rows.pack(side=tk.LEFT)

label_cols = tk.Label(frame_options, text="Columns:")
label_cols.pack(side=tk.LEFT)
entry_cols = tk.Entry(frame_options)
entry_cols.pack(side=tk.LEFT)

label_spacing = tk.Label(frame_options, text="Spacing:")
label_spacing.pack(side=tk.LEFT)
entry_spacing = tk.Entry(frame_options)
entry_spacing.pack(side=tk.LEFT)

label_width = tk.Label(frame_options, text="Width:")
label_width.pack(side=tk.LEFT)
entry_width = tk.Entry(frame_options)
entry_width.pack(side=tk.LEFT)

label_height = tk.Label(frame_options, text="Height:")
label_height.pack(side=tk.LEFT)
entry_height = tk.Entry(frame_options)
entry_height.pack(side=tk.LEFT)

def generate_collage():
rows = int(entry_rows.get())
cols = int(entry_cols.get())
spacing = int(entry_spacing.get())
width = int(entry_width.get())
height = int(entry_height.get())

collage_generator.generate_collage(rows, cols, spacing, width, height)
collage_generator.save_collage()

btn_generate = tk.Button(app, text="Generate Collage", command=generate_collage)
btn_generate.pack(pady=5)

app.mainloop()
  1. import os and import tkinter as tk: Import the required libraries for file and folder operations, as well as for the GUI framework.
  2. from tkinter import filedialog: Import the filedialog module from tkinter to enable opening and saving files.
  3. from PIL import Image: Import the Image module from the Pillow library to handle image manipulation.
  4. class ImageCollageGenerator:: Define a class to encapsulate the image collage generation functionality.
  5. def __init__(self):: Constructor method that initializes class attributes like the list of images and the output folder.
  6. self.output_folder = "./output_collage/": Sets the default folder for saving generated collages.
  7. if not os.path.exists(self.output_folder):: Checks if the output folder exists. If not, it's created using os.makedirs.
  8. def load_images(self):: Method to load multiple images using the filedialog.askopenfilenames dialog.
  9. def generate_collage(self, rows, cols, spacing, width, height):: Method to generate the collage based on specified parameters.
  10. if total_images < len(self.images):: Truncate the list of images if there are more images than required for the specified arrangement.
  11. elif total_images > len(self.images):: If there are fewer images than required, add blank images to fulfill the arrangement.
  12. self.collage = Image.new("RGB", (collage_width, collage_height), (255, 255, 255)): Create a blank image with specified dimensions.
  13. for i, img in enumerate(self.images):: Loop through images, resize, and paste them onto the collage.
  14. def save_collage(self):: Save the generated collage using filedialog.asksaveasfilename.
  15. if __name__ == "__main__":: Entry point of the script, where the GUI is defined and the application runs.
  16. app = tk.Tk(): Create the main application window.
  17. app.title("Image Collage Generator"): Set the title of the application window.
  18. collage_generator = ImageCollageGenerator(): Create an instance of the ImageCollageGenerator class.
  19. btn_load = tk.Button(app, text="Load Images", command=collage_generator.load_images): Create a button to load images, linked to load_images method.
  20. frame_options = tk.Frame(app): Create a frame to group collage options.
  21. Labels and Entry widgets for specifying collage parameters (rows, columns, spacing, width, and height) are created and packed in the frame.
  22. def generate_collage():: Define a function to generate the collage based on user-specified parameters.
  23. The user-specified parameters are obtained from the Entry widgets and converted to integers.
  24. collage_generator.generate_collage(rows, cols, spacing, width, height): Call the generate_collage method of the ImageCollageGenerator instance.
  25. collage_generator.save_collage(): Call the save_collage method to save the generated collage.
  26. btn_generate = tk.Button(app, text="Generate Collage", command=generate_collage): Create a button to trigger the collage generation.
  27. The application enters the main event loop using app.mainloop(). This loop keeps the GUI running and responsive to user interactions.

This script creates a simple GUI application that allows users to load images, specify collage parameters, generate a collage, and save the collage. The user input is collected through the GUI widgets, and the ImageCollageGenerator class handles the collage creation logic using the Pillow library.

3. Comic Book Style Image Generator

Inspired by comic book art, I designed an image generator that converts ordinary images into comic book-style images using Pillow’s image filtering and text overlay features.

Creating a Comic Book Style Image Generator involves applying various image filters to give images a comic book appearance and adding text overlays to create a narrative or dialogue effect. In this example, we’ll implement a simple version using Pillow. Let’s go through the script step by step with explanations for each part:

from PIL import Image, ImageFilter, ImageDraw, ImageFont

def apply_comic_filters(image):
# Apply a series of filters to achieve the comic book style
cartoon_image = image.copy()
cartoon_image = cartoon_image.convert("L").point(lambda p: p < 128 and 0 or 255)
cartoon_image = cartoon_image.filter(ImageFilter.CONTOUR)
cartoon_image = cartoon_image.filter(ImageFilter.SMOOTH_MORE)
return cartoon_image

def add_text_overlay(image, text):
# Add text overlay to the image
draw = ImageDraw.Draw(image)
font = ImageFont.load_default() # You can also load custom fonts
text_position = (20, 20) # Position of the text overlay
text_color = (255, 255, 255) # White color for the text
draw.text(text_position, text, font=font, fill=text_color)
return image

if __name__ == "__main__":
input_image_path = "sample.jpg" # Replace with your input image path
output_image_path = "output_comic.png"

# Open the input image
input_image = Image.open(input_image_path)

# Apply comic book filters
comic_image = apply_comic_filters(input_image)

# Add text overlay
text = "This is a comic book style image!"
comic_image_with_text = add_text_overlay(comic_image, text)

# Save the output image
comic_image_with_text.save(output_image_path)
  1. from PIL import Image, ImageFilter, ImageDraw, ImageFont: Import the required modules from the Pillow library for image manipulation, filtering, drawing, and font handling.
  2. def apply_comic_filters(image):: Define a function to apply comic book style filters to the image.
  3. Convert the image to grayscale using .convert("L") and apply thresholding to create a black and white image with clear edges.
  4. Apply the contour filter using .filter(ImageFilter.CONTOUR) to emphasize edges and create a comic book-like outline effect.
  5. Apply the SMOOTH_MORE filter using .filter(ImageFilter.SMOOTH_MORE) to smooth out any remaining noise and create a clean look.
  6. def add_text_overlay(image, text):: Define a function to add text overlay to the image.
  7. Create a drawing object using ImageDraw.Draw(image).
  8. Specify the font to be used for the text overlay. In this case, the default font is loaded using ImageFont.load_default().
  9. Set the position and color of the text overlay.
  10. Use draw.text() to add the text overlay to the image.
  11. if __name__ == "__main__":: Entry point of the script where the actual processing happens.
  12. input_image_path = "input.jpg": Specify the path of the input image. Replace "input.jpg" with the path of your input image.
  13. output_image_path = "output_comic.png": Specify the path where the generated comic book-style image will be saved.
  14. input_image = Image.open(input_image_path): Open the input image using the Pillow library.
  15. Apply comic book filters to the input image using the apply_comic_filters() function.
  16. Add the text overlay to the filtered image using the add_text_overlay() function.
  17. Save the resulting image with comic book style and text overlay to the specified output path.

Please note that this example provides a simple way to achieve a comic book style effect using basic filtering and text overlay. For more advanced effects, you might want to explore other filters, color adjustments, and image processing techniques.

4. Batch Image Resizer and Watermarker

To simplify image processing tasks, I developed a batch image processing script using Pillow. It can resize a collection of images to predefined dimensions and overlay a watermark or logo on each image, making it ideal for photographers and content creators.

This script will resize a collection of images to predefined dimensions and overlay a watermark or logo on each image:

import os
from PIL import Image, ImageDraw, ImageFont

def resize_and_watermark(input_folder, output_folder, target_size, watermark_path):
if not os.path.exists(output_folder):
os.makedirs(output_folder)

watermark = Image.open(watermark_path).convert("RGBA")

for filename in os.listdir(input_folder):
if filename.endswith((".png", ".jpg", ".jpeg")):
input_path = os.path.join(input_folder, filename)
output_path = os.path.join(output_folder, filename)

img = Image.open(input_path)
img = img.resize(target_size, Image.ANTIALIAS)

watermark_position = (img.width - watermark.width, img.height - watermark.height)
img.paste(watermark, watermark_position, watermark)

img.save(output_path)

if __name__ == "__main__":
input_folder = "input_images" # Replace with the path to your input images folder
output_folder = "output_images" # Replace with the path to your output images folder
target_size = (800, 600) # Desired width and height of the resized images
watermark_path = "watermark.png" # Replace with the path to your watermark image

resize_and_watermark(input_folder, output_folder, target_size, watermark_path)
  1. import os and from PIL import Image, ImageDraw, ImageFont: Import the required modules from the Pillow library for image manipulation and watermarking.
  2. def resize_and_watermark(input_folder, output_folder, target_size, watermark_path):: Define a function to resize images and overlay watermarks.
  3. Check if the output folder exists. If not, create it using os.makedirs.
  4. Open the watermark image using Image.open() and convert it to the RGBA mode to handle transparency.
  5. Loop through the files in the input folder.
  6. Check if the file has a supported image extension (.png, .jpg, .jpeg).
  7. Build the paths for input and output images using os.path.join().
  8. Open the input image using Image.open().
  9. Resize the image using img.resize() with the target size and Image.ANTIALIAS for better quality.
  10. Calculate the position to paste the watermark in the bottom-right corner of the image.
  11. Use img.paste() to overlay the watermark on the image.
  12. Save the modified image to the output path using img.save().
  13. if __name__ == "__main__":: Entry point of the script where the processing is initiated.
  14. Specify the input and output folders, target size for resizing, and the path to the watermark image.
  15. Call the resize_and_watermark() function to process the images in the input folder and save the results in the output folder.

This script demonstrates a basic batch image processing workflow using Pillow. You can customize the input_folder, output_folder, target_size, and watermark_path variables to match your specific requirements. Additionally, you might want to explore further enhancements, such as specifying watermark opacity, watermark scaling, and different watermark positions based on your preferences.

Conclusion

The journey with image manipulation in Python using Pillow has been an exciting and creatively fulfilling experience. Pillow’s versatility and ease of use have empowered to transform ordinary images into extraordinary pieces of digital art.

Thank you for exploring this story!

--

--