Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Add a Border to Your Photos With Python

DZone's Guide to

Add a Border to Your Photos With Python

Learn how you can use your programming skills to bring out your inner photographer, and enhance the look of your site via photo editing.

· Web Dev Zone
Free Resource

Add user login and MFA to your next project in minutes. Create a free Okta developer account, drop in one of our SDKs to your application and get back to building.

Sometimes it's fun to add a simple border to your photos. The Pillow package has a very easy method of adding such borders to your images via its ImageOps module. As usual, you will need to have Pillow installed to do any of the examples in this article. If you don't have it already, you can install it with pip:

pip install Pillow

Now that we've taken care of that bit of housekeeping, let's learn how to add a border!

Adding a Border

The focus of this article will be on using the ImageOps module to add our borders. For this example, we will use this photo of a neat butterfly I took. Let’s write some code!

from PIL import Image, ImageOps
 
 
def add_border(input_image, output_image, border):
    img = Image.open(input_image)
 
    if isinstance(border, int) or isinstance(border, tuple):
        bimg = ImageOps.expand(img, border=border)
    else:
        raise RuntimeError('Border is not an integer or tuple!')
 
    bimg.save(output_image)
 
if __name__ == '__main__':
    in_img = 'butterfly.jpg'
 
    add_border(in_img, output_image='butterfly_border.jpg',
               border=100)

In the code above, we create a function that can accept three arguments:

  • The input image path.
  • The output image path.
  • The border, which can be an integer or a tuple of up to 4 integers representing pixels for each of the four sides of the image.

We open the input image and then we check the border's type. Is it an int or a tuple or something else? If it's one of the first two, we add our border by calling the expand() function. Otherwise, we raise an error because we passed in an invalid type. Finally, we save the image. This is the result I got:

As you can see, when you just pass an integer in as your border, it applies to all four sides of the image. If we want the border on the top and bottom to be different then the right and left, we need to specify that. Let's update the code and see what happens!

from PIL import Image, ImageOps


def add_border(input_image, output_image, border):
    img = Image.open(input_image)

    if isinstance(border, int) or isinstance(border, tuple):
        bimg = ImageOps.expand(img, border=border)
    else:
        raise RuntimeError('Border is not an integer or tuple!')

    bimg.save(output_image)

if __name__ == '__main__':
    in_img = 'butterfly.jpg'

    add_border(in_img,
               output_image='butterfly_border_top_bottom.jpg',
               border=(10, 50))

Here we want to add a 10-pixel border to the left and right sides and a 50-pixel border to the top and bottom of the image. If you run this code, you should get the following result:

Now let’s try specifying different values for all four sides!

from PIL import Image, ImageOps
 
 
def add_border(input_image, output_image, border):
    img = Image.open(input_image)
 
    if isinstance(border, int) or isinstance(border, tuple):
        bimg = ImageOps.expand(img, border=border)
    else:
        raise RuntimeError('Border is not an integer or tuple!')
 
    bimg.save(output_image)
 
if __name__ == '__main__':
    in_img = 'butterfly.jpg'
 
    add_border(in_img,
               output_image='butterfly_border_all_different.jpg',
               border=(10, 30, 20, 50))

In this example, we tell Pillow that we want a border where the left side is 10-pixels, the top is 30-pixels, the right is 20-pixels and the bottom is 50-pixels wide. When I ran this code, I got this:

Frankly, I don't know why you would want all four sides to have a different size border, but if you do, it's easy to apply.

Changing the Border Color

You can also set the color of the border that you're adding. The default was obviously black. The Pillow package supports specifying colors via "#rgb" (i.e. "#ff0000" for red), "rgb (red, green, blue)" where the RGB values are integers between 0 and 255, HSL values or HTML color names. Let's update our code and add some color to our border:

from PIL import Image, ImageOps


def add_border(input_image, output_image, border, color=0):
    img = Image.open(input_image)

    if isinstance(border, int) or isinstance(border, tuple):
        bimg = ImageOps.expand(img, border=border, fill=color)
    else:
        raise RuntimeError('Border is not an integer or tuple!')

    bimg.save(output_image)

if __name__ == '__main__':
    in_img = 'butterfly.jpg'

    add_border(in_img,
               output_image='butterfly_border_indianred.jpg',
               border=100,
               color='indianred')

You will note that we added a new parameter here that specifies the color we want our border to be. The default is black, which is zero (0). In this example, we pass in the HTML color 'indianred'. Here is the result:

You could get the same effect by changing the passed in value from 'indianred' to '#CD5C5C'.

Just for fun, try changing the value you pass in to 'rgb(255,215,0)', which is a Gold color. If you do, you can get your border to look like this:

Note that you could also pass in 'gold', 'Gold' or '#FFD700' and it would have resulted in the same color.

Wrapping Up

At this point, you should know how to add simple borders to your photos. As you've seen, you can change the number of pixels of border color for each side individually or for pairs or even for all four sides simultaneously. You can also change the color of the border to pretty much any color under the sun. Take some time to play around with the code and see what you can come up with!

Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
image processing ,python ,web dev

Published at DZone with permission of Mike Driscoll, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}