Last Updated on July 14, 2022 by Jay
This tutorial will go through how to use Python to add a watermark (either text or an image file) to an image. Previously, we learned about how to add text to an image file. This time, let’s try to add a logo and text to an image.
Library
Similar to the previous tutorial, we’ll be using the Pillow (Python Imaging Library) library. We can install the library by typing the below into the command prompt:
pip install Pillow
One thing to note about using the Pillow library. To import it, we need to use the name PIL instead of Pillow:
import PIL # correct import
import Pillow # throws ModuleNotFoundError: No module named 'Pillow'
Prepare The Watermark Image (logo)
By adding a watermark to an image, we are basically putting an image (the watermark) on top of another image. Being able to control the logo image transparency will help make the final resulting image look much better. Therefore, It’s best to have the watermark image in PNG file format which supports transparency in images.
If your watermark file is in JPG/JPEG format, do not worry. We are NOT going to use some converter to convert JPG to PNG either. Python can add the needed “transparency” to the image!
Difference Between PNG and JPG
While there are a few differences between a PNG file and a JPG file, we are mostly concerned with the transparency feature of an image. Image Transparency basically refers to whether an image can see through or not.
Let’s load two image files into Python. These are the same image, but in different formats, one is PNG and the other is JPG. Let’s take a look at the difference between the two image files.
from PIL import Image, ImageDraw
import numpy as np
watermark_png = Image.open(r'C:\Users\jay\Desktop\PythonInOffice\python_add_watermark_to_images\logo.png')
watermark_jpg = Image.open(r'C:\Users\jay\Desktop\PythonInOffice\python_add_watermark_to_images\logo.jpg')
png = np.array(watermark_png)
png.shape
(500, 500, 4)
jpg = np.array(watermark_jpg)
jpg.shape
(500, 500, 3)
An image file is basically a bunch of numbers to a computer’s eyes. Loading the two image files into a NumPy array will help visualize this concept.
Both PNG and JPG images have a size of 500 x 500 pixels. However, the last number in shape attributes is different: JPG has 3 while PNG has 4. Let’s display the numpy array to see the difference.
The values inside each array represent the color for each pixel. For example in the PNG file, [0,0,0,0] means black BUT fully transparent. whereas in the JPG file, [255, 255, 255] represents a pixel with white color.
The first three integer values (shown above) are the RGB (red, green, and blue) values. The 4th integer inside the PNG array is called the “alpha channel” which controls the degree of transparency (hence the name “RGBA“). As shown, PNG has support for transparency (i.e. alpha channel), but JPG doesn’t have it.
One thing to note here:
- A value of 255 for RGB means the max value of each color. Having all three values at max, (255, 255, 255) is basically white color.
- A value of 255 for the alpha channel means non-transparent; while a value of 0 alpha means fully transparent.
Add An Alpha Channel to JPG file
The Pillow library makes it really easy to convert a JPG file into PNG format. We can use the putalpha() method to add an alpha channel (i.e. the fourth integer) to a JPG image. Note the argument inside can range from 0 to 255. A value of 0 means fully transparent, i.e. we will not see anything; and 255 means not transparent. I’m picking a number 180 here so our watermark image will be somewhat semi-transparent.
watermark_jpg.putalpha(100)
Remove White Background of Image
There’s another problem with this image – it has a white background. Normally a PNG file would have a “transparent” background. We can “remove” the white background by setting the alpha channel to 0 (transparent) for all the white pixels on the image.
In other words, for each pixel with an RGB value [255,255,255,180], we’ll set the alpha channel to 0 to make the pixel fully see-through.
Since we have already put the image’s RGBA values into a Numpy array, manipulating color is easy. To find all the pixels with white color, we can create a mask with white pixels = True, and False otherwise. The below code checks whether all of the R, G, and B values are equal to 255 for every single pixel of the image. Note transparent_watermark[:,:,0] returns an array of just the first element (i.e. integer values for “R”) of all 500×500 pixels.
Then we assign a new value [255,255,255,0] to the pixels meeting the criteria. This step effectively turns all the white pixels into fully transparent.
mask = (transparent_watermark[:,:,0] == 255) & (transparent_watermark[:,:,1] == 255) & (transparent_watermark[:,:,2] == 255)
mask.shape
(500, 500)
transparent_watermark[:,:,0].shape
(500, 500)
transparent_watermark[mask] = [255,255,255,0]
Convert The Numpy Array Into An Image
We can use the Image.fromarray() method from the PIL library to convert a NumPy array back into an image file.
watermark_final = Image.fromarray(transparent_watermark)
Use Python To Add A Watermark to An Image File
Now we are done preparing the logo image. It’s time to add it as a watermark to a base image. We are going to first resize() the watermark image to be 1/5 of the base image. Feel free to use another size that fits your need.
img = Image.open(r'C:\Users\jay\Desktop\PythonInOffice\python_add_watermark_to_images\flower.jpg')
width, height = img.size
width, height
(3651, 2664)
watermark_final = watermark_final.resize((int(width/5), int(height/5)))
Then we are going to create an empty “canvas” that is the same size as the base image, and we’ll set this canvas to be transparent everywhere.
transparent = Image.new(mode='RGBA',size = (width,height), color=0)
Once the canvas is set, we’ll 1) paste the base image, and 2) paste the watermark image on top of the base image. As shown below, the Image.paste() method has three arguments:
- im – the source image
- box – the (x,y) coordinate for the starting point (upper left corner) to paste the image
- mask – a mask/filter that help cut out all the transparent pixels from the pasted image
transparent.paste(img)
wm_position = (int(3/4*width), int(3/4 * height))
transparent.paste(im=watermark, box=wm_position, mask=watermark)
There we have successfully added a JPG format watermark on to another image!