Forum Archive

Unable to paste one PIL image onto another

abredall

So I'm trying to build a script with the Pillow module that will put a border around a selected image so all photos I upload will have the same minimum border width. However, contrarcy to the PIL documentation, I keep getting the error: "images do not match". It was my understanding that the only prerequisite to paste onto another image was the number of bands?

Below is my code. You can see in my comments near the bottom that I've even compared two identically generated images. If I change either of the first two arguments, I receive the error.

import Image as img
from photos import pick_asset, get_image

size = (1080, 1080)
max = size[0]*.85
og = pick_asset(multi=True)


for pic in og:
    shortest = 1
    longest = 1
    pic = pic.get_image()
    pic.convert('RGB')
    pic_size = list(pic.size)

    # creating the background
    border = img.new('RGB', size, 'white')
    border2 = img.new('RGB', (400,400), 'white')

    # determing which side is longest
    if pic_size[0] > pic_size[1]:
        longest = pic_size[0]
        shortest = pic_size[1]
    if pic_size[0] < pic_size[1]:
        longest = pic_size[1]
        shortest = pic_size[0]

    # resizing as needed
    divisor = shortest/longest
    multiplier = longest/shortest
    x = round(pic_size[0]*divisor)
    y = round(pic_size[1]*divisor)
    x2 = round(pic_size[0]*multiplier)
    y2 = round(pic_size[1]*multiplier)
    if longest > max:
        # pic too big. scale pic down
        pic.resize((x, y))
    if longest < max:
        # pic too small. scale down bg
        border.resize((x2, y2))


    new_pic = pic.copy()
    #final_pic = border.paste(pic)
    #print(str(pic_size[0]) + ", " + str(pic_size[1]))
    #final_pic = border.paste(border2)
    #final.save()

`

ccc

Not an answer but...

max() is a Python builtin so it is considered poor form to shadow it with a variable with the same name.

```python

determing which side is longest

if pic_size[0] > pic_size[1]:
    longest = pic_size[0]
    shortest = pic_size[1]
if pic_size[0] < pic_size[1]:
    longest = pic_size[1]
    shortest = pic_size[0]

could be written as

shortest = min(pic.size)
longest = max(pic.size)

or even

shortest, longest = sorted(pic.size)
abredall

@ccc Ahhh good catch! and Very helpful with your more Pythonic revision. I don't code too regularly so it helps a lot. Thanks!

mikael

@abredall, if PIL does not play nicely, this would be easy to do with ui.ImageContext. The only downside I see is that the conversion from PIL to ui.Image is a bit slow. That can be circumvented by using objc_util, though, if needed.

ccc

Still fails on border.paste(pic)

from console import show_image
from photos import pick_asset, get_image
from PIL import Image as img

size = (1080, 1080)
# max = size[0]*.85

for pic in pick_asset(multi=True):
    pic = pic.get_image()
    pic.save('input_image.png')
    show_image('input_image.png')
    print('A', pic.mode, pic.size)
    pic.convert('RGB')
    print('B', pic.mode, pic.size)
    shortest, longest = sorted(pic.size)
    print('C', shortest, longest)
    if longest > max(size):
        # image scale down code goes here
        pass

    # creating the background
    border = img.new('RGB', size, 'white')
    print('D', border.mode, border.size)
    border.paste(pic).save('final_pic.png')
    show_image('final_pic.png')
mikael

@abredall, I think paste needs a second box argument, even it is just (0, 0).

ccc

Correct... Centering the image in the border.

from console import show_image
from photos import pick_asset, get_image
from PIL import Image as img

size = (1080, 1080)
# max = size[0]*.85

for pic in pick_asset(multi=True):
    pic = pic.get_image()
    pic.convert('RGB')
    if max(pic.size) > max(size):
        # image scale down code goes here
        pass

    # creating the background
    border = img.new('RGBA', size, 'gray')
    top_left = [(b - p) // 2 for b, p in zip(border.size, pic.size)]
    border.paste(pic, tuple(top_left))
    border.save('final_pic.png')
    show_image('final_pic.png')

More cool tricks at https://note.nkmk.me/en/python-pillow-paste

mikael

@ccc, thanks, that link is a handy example/reference.

abredall

@mikael @ccc It's working wonders now, thank you! Just a dumb mistake as usual. Great link too!