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.


    Photo captions

    Pythonista
    3
    7
    1530
    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.
    • sgspecker
      sgspecker last edited by

      Is there a way to get and set captions on Photos using Pythonista?

      I didn't see a property listed in the Photos module API. Hopefully, I just missed it?

      Thanks,
      Scott

      cvp 3 Replies Last reply Reply Quote 0
      • JonB
        JonB last edited by

        There are similar questions in the apple developer forums and stackoverflow .. it seems that apple did not expose captions via PhotoKit. So I don't think you can get it, even using objc.

        1 Reply Last reply Reply Quote 0
        • cvp
          cvp @sgspecker last edited by cvp

          @sgspecker First of all, I don't know anything about this matter, BUT, after some Google searches and a lot of tests, I've discovered that the caption is passed into the shared asset.
          Try to share a photo where you have typed a caption to this little Pythonista script.

          @JonB never say never 😀

          For your info, it is not stored in the EXIF's but in the IPTC fields.

          from PIL import Image
          import appex
          fil = appex.get_attachments()[0]
          with Image.open(fil) as im:
          	for segment, content in im.applist:
          		if content.startswith(b'Photoshop'):
          			print(f"segment={segment}, content=Photoshop...")
          			ls = content.split(b'\x00')
          			for l in ls:
          				print(l)
          

          You will find in the output the caption you typed. I don't yet know how to identify the right field where it is stored, but it should be possible to do it.

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

            That's pretty interesting...

            Although I guess to set the caption would require figuring out which IPTC tag (maybe try 'Caption/Abstract', or just 'Caption'), and you'd be editing a copy, not the original...

            Does iOS provide IPTC editing functions? Looks like as part of CGImageProperties:
            tion/imageio/cgimageproperties?language=objc

            https://stackoverflow.com/questions/44517834/modifing-metadata-from-existing-phasset-seems-not-working

            Not clear if the approach here actually works to driectly modify the original.

            cvp 1 Reply Last reply Reply Quote 0
            • cvp
              cvp @JonB last edited by cvp

              @JonB I didn't think to update it, I was already happy to find a begin of way to get the caption.

              I think these infos are not stored in the photo file.
              If I import the same photo in Pythonista, these data are no more there.

              1 Reply Last reply Reply Quote 0
              • cvp
                cvp @sgspecker last edited by cvp

                @sgspecker here how to get the caption

                from PIL import Image
                import appex
                fil = appex.get_attachments()[0]
                with Image.open(fil) as im:
                	for segment, content in im.applist:
                		if content.startswith(b'Photoshop'):
                			# caption field identified by x1c0278 then length in 2 bytes x'0005' = 5
                			i = content.find(b'\x1c\x02\x78')
                			l = int.from_bytes(content[i+3:i+5], "big")   
                			caption = content[i+5:i+5+l].decode("utf-8") 
                			print(caption)
                			break
                
                1 Reply Last reply Reply Quote 0
                • cvp
                  cvp @sgspecker last edited by cvp

                  @sgspecker This allows to create a new photo with updated caption in camera roll if you share an existing photo which has already a caption

                  import appex
                  import console
                  import os
                  import photos
                  
                  def main():
                  	if appex.is_running_extension():
                  		fil = appex.get_attachments()[0]
                  	else:
                  		fil = 'a.jpg' 
                  	with open(fil, mode='rb') as fin:
                  		b = fin.read()
                  		#b'\xff\xed\xllllPhotoshop 3.0\x00' = marker APP1 
                  		#           -----
                  		#b'8BIM\x04\x04\x00\x00\x00\x00\x00\x17\x1c\x01Z\x00\x03\x1b%G\x1c\x02\x0\x0\x02
                  		#                                   ---
                  		#b'\x00\x02\x1c\x02x\x00\x03Cap\x00
                  		ip = b.find(b'Photoshop')
                  		if ip >= 0:
                  			#print(b[ip-6:ip+100])
                  			lip = int.from_bytes(b[ip-2:ip], "big")   
                  			i8 = b.find(b'8BIM',ip)
                  			if i8 >= 0:
                  					l8 = int.from_bytes(b[i8+10:i8+12], "big")   
                  					i = b.find(b'\x1c\x02x', i8)					
                  					# caption field identified by x'1c0278' then length in 2 bytes x'0005' = 5
                  					l = int.from_bytes(b[i+3:i+5], "big")   
                  					caption = b[i+5:i+5+l].decode("utf-8") 
                  					#print(caption)
                  					#return # if no update
                  					# 
                  					caption = console.input_alert('new caption?','', caption, 'ok', hide_cancel_button=True)
                  					lu = len(caption)
                  					bl = lu.to_bytes(2,'big')	# x'000l'
                  					# store new caption
                  					b = b[:i+3] + bl + caption.encode('utf-8') + b[i+5+l:]
                  					# change length of 8BIM marker
                  					l8aft = l8 - l + lu
                  					bl8aft = l8aft.to_bytes(2,'big')	# x'000l'
                  					b = b[:i8+10] + bl8aft + b[i8+12:]
                  					# change length of Photoshop marker at ip-2
                  					lipaft = lip - l + lu
                  					blaft = lipaft.to_bytes(2,'big')	# x'000l'
                  					b = b[:ip-2] + blaft + b[ip:]
                  	tmp = '_temp.jpg'
                  	with open(tmp, mode='wb') as fout:
                  		fout.write(b)
                  	asset = photos.create_image_asset(tmp)
                  	os.remove(tmp)
                  	appex.finish()
                  
                  if __name__ == '__main__':
                  	main()
                  
                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post
                  Powered by NodeBB Forums | Contributors