Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Unable to paste one PIL image onto another
-
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()
`
-
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.# 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)
-
@ccc Ahhh good catch! and Very helpful with your more Pythonic revision. I don't code too regularly so it helps a lot. Thanks!
-
@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 toui.Image
is a bit slow. That can be circumvented by usingobjc_util
, though, if needed. -
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')
-
@abredall, I think
paste
needs a secondbox
argument, even it is just(0, 0)
. -
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
-
@ccc, thanks, that link is a handy example/reference.
-