omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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

    Pythonista
    pil pythonista pythonista 3 pillow python 3
    3
    9
    4327
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • abredall
      abredall last edited by ccc

      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()
      

      `

      1 Reply Last reply Reply Quote 0
      • ccc
        ccc last edited by

        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)
        abredall 1 Reply Last reply Reply Quote 0
        • abredall
          abredall @ccc last edited by

          @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 2 Replies Last reply Reply Quote 0
          • mikael
            mikael @abredall last edited by

            @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.

            1 Reply Last reply Reply Quote 0
            • ccc
              ccc last edited by 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')
              
              1 Reply Last reply Reply Quote 0
              • mikael
                mikael @abredall last edited by

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

                1 Reply Last reply Reply Quote 1
                • ccc
                  ccc last edited by 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 1 Reply Last reply Reply Quote 2
                  • mikael
                    mikael @ccc last edited by

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

                    abredall 1 Reply Last reply Reply Quote 0
                    • abredall
                      abredall @mikael last edited by

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

                      1 Reply Last reply Reply Quote 0
                      • First post
                        Last post
                      Powered by NodeBB Forums | Contributors