'Python: Image resizing: keep proportion - add white background

I would like to create a Python script to resize images, but not changing its proportions, just by adding a white background

(So, a : 500*700 px image would transform to a 700*700 px image by adding 100 px of a white band on each side)

The three image types I use are .PNG, .JPG and .GIF. I am not even sure it is possible for Gifs, PNG and JPG would already be awesome.

In my case, they have to be squares. But if any of you manage to do it for adaptable to any proportion, it would benefit the maximum number of people that see this thread and you would be even more awesome !

I saw same threads for other languages but not python, do you guys know how you do this ?

PS : I am using Python 3

What I tried :

Combining 3 images together.

If we take our 500*700 px image : Creating two white images of 100*700px and put one on each side of the image. Inspired by :

Combine several images horizontally with Python

But, I am kind of new on python, and I haven't succeded.



Solution 1:[1]

Finally did it :

def Reformat_Image(ImageFilePath):

    from PIL import Image
    image = Image.open(ImageFilePath, 'r')
    image_size = image.size
    width = image_size[0]
    height = image_size[1]

    if(width != height):
        bigside = width if width > height else height

        background = Image.new('RGBA', (bigside, bigside), (255, 255, 255, 255))
        offset = (int(round(((bigside - width) / 2), 0)), int(round(((bigside - height) / 2),0)))

        background.paste(image, offset)
        background.save('out.png')
        print("Image has been resized !")

    else:
        print("Image is already a square, it has not been resized !")

Thanks to @Blotosmetek for the suggestion, pasting a centered image is definitely simpler than creating images and combining them !

PS : If you don't have PIL yet, the library's name to install it with pip is "pillow", not PIL. But still, you use it as PIL in the code.

Solution 2:[2]

Thanks @Jay D., here a bit more general version:

from PIL import Image

def resize(image_pil, width, height):
    '''
    Resize PIL image keeping ratio and using white background.
    '''
    ratio_w = width / image_pil.width
    ratio_h = height / image_pil.height
    if ratio_w < ratio_h:
        # It must be fixed by width
        resize_width = width
        resize_height = round(ratio_w * image_pil.height)
    else:
        # Fixed by height
        resize_width = round(ratio_h * image_pil.width)
        resize_height = height
    image_resize = image_pil.resize((resize_width, resize_height), Image.ANTIALIAS)
    background = Image.new('RGBA', (width, height), (255, 255, 255, 255))
    offset = (round((width - resize_width) / 2), round((height - resize_height) / 2))
    background.paste(image_resize, offset)
    return background.convert('RGB')

Solution 3:[3]

The other answer didn't work for me, I rewrote it and this worked:

def resize_with_pad(im, target_width, target_height):
    '''
    Resize PIL image keeping ratio and using white background.
    '''
    target_ratio = target_height / target_width
    im_ratio = im.height / im.width
    if target_ratio > im_ratio:
        # It must be fixed by width
        resize_width = target_width
        resize_height = round(resize_width * im_ratio)
    else:
        # Fixed by height
        resize_height = target_height
        resize_width = round(resize_height / im_ratio)

    image_resize = im.resize((resize_width, resize_height), Image.ANTIALIAS)
    background = Image.new('RGBA', (target_width, target_height), (255, 255, 255, 255))
    offset = (round((target_width - resize_width) / 2), round((target_height - resize_height) / 2))
    background.paste(image_resize, offset)
    return background.convert('RGB')

Solution 4:[4]

The accepted answer is great, I am just happy not to use OpenCV.

As @Nemanja mentioned, if you want to make it work for any aspect ration. Here is the snippet to use. I just twisted the code a bit.

from PIL import Image

def Reformat_Image_With_Ratio(ImageFilePath, desired_aspect_ratio):
    
    image = Image.open(ImageFilePath, 'r')
    width = image.width
    height = image.height
    img_aspect_ratio = width/height
    
    if (img_aspect_ratio != desired_aspect_ratio):
        bigside = width if width > height else height
        other_side = int(bigside * desired_aspect_ratio)
        background = Image.new('RGBA', (other_side, bigside), (255, 0, 0, 255))
        offset = (int(round(((bigside - width) / 2), 0)), int(round(((bigside - height) / 2),0)))

        background.paste(image, offset)
        background.save('out4.png')
        print("Image has been resized !")

    else:
        print("Image is already a valid aspect ratio, it has not been resized !")

Reformat_Image_With_Ratio('test.png', 9/16)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jay D.
Solution 2
Solution 3 pyjamas
Solution 4 Aditya Rajgor