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.


    Get filenames for photos from camera roll

    Pythonista
    6
    27
    20723
    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.
    • coomlata1
      coomlata1 last edited by coomlata1

      I would like to retrieve the filenames of photos from the iPhone camera roll. I can get the local id of a photo or collection of photos using the asset.local_id property, but that is a long string of letters and numbers, not the actual filename. I have found nothing in the documentation that would help. There must be a get_filename property that I am missing.

      I could get the filenames in the Pythonista 2 and earlier photos module using photos.get_metadata(index).get('filename') but that doesn't work when using the new asset properties of the photos module in Pythonista 2.1.

      The orientation of photo was available in the metadata using get('Orientation') but I don't know how to access this using the new photos module.

      Any help is greatly appreciated.

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

        If you don't mind dabbling with the objc module

        from objc_util import ObjCInstance
        str(ObjCInstance(photos.get_assets()[0]).filename())
        

        Not sure why filename is not one of the asset attributes...
        probably just oversight

        1 Reply Last reply Reply Quote 1
        • omz
          omz last edited by

          @JonB That's a good workaround. The reason this isn't an attribute of the Asset class is that it's undocumented, and therefore (I assume) considered private API.

          The "official" way to get a filename for an asset would be to use PHAssetResource (which was added in iOS 9), and I've experimented with that, but found it to be unreliable. There seems to be some kind of bug that makes this API stop returning valid data after some time, so getting the resources (and file names) of a single asset would usually work, but doing this in a loop starts to fail at some point... To be honest, I wasn't even aware that PHAsset has a private filename property, but this seems to be the best way to get this info for now.

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

            In Pythonista 2, see topic
            I already used this way to get the filename of an asset:

            str(ObjCInstance(photos.get_assets()[0]).valueForKey_('filename'))
            

            and of course also

            str(ObjCInstance(photos.get_assets()[0]).valueForKey_('orientation'))
            
            1 Reply Last reply Reply Quote 1
            • coomlata1
              coomlata1 last edited by coomlata1

              @JonB @omz @cvp

              Thank you for the information and code snippets. That's just what I needed to rewrite a script written several years ago using the old photo module attributes. Much appreciated!!!

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

                Updated script using the new photos module attributes and the info provided to me by @JonB @omz and @cvp is now available here.

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

                  JonB (and cvp),
                  I'm using the information you provided above as a means of copying video files over ftp. The asset "get_image_data" doesn't work.
                  Everything you've mentioned above works just fine. I even open the video file in binary read mode "rb" successfully (no exceptions), however, when I hand the opened file object on to ftplib's "ftp.storbinary" method I get the following error: ErrNo 2: No such file or directory: 'IMG_0463.MOV'. I find it interesting that the same file object opened just fine using "open", but there is an error when using storbinary.

                  Am I missing something, or is there something special about these files that is super-top-secret that we aren't supposed to be able to do with these files? If so, can you recommend another method or line-of-thought?

                  Thanks again!

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

                    Just to be sure, did you copy the photo as a local file and did you change current directory before the ftp command?

                    file_path = os.path.expanduser('~/Documents/'+local_file_folder)
                    os.chdir(file_path)
                    local_file = open(file_name,'rb')
                    ftp.storbinary('STOR '+server_file,local_file,blocksize=8192)
                    local_file.close()
                    
                    1 Reply Last reply Reply Quote 0
                    • billbris
                      billbris last edited by

                      cvp,

                      No, I did not copy the file locally. Since I had the filename I figured I would open it and use it. That is beginning to sound naive.
                      Does the step-by-step process have to look something like this:

                      1. Get video filename
                      2. Open video file.
                      3. Save the video file someplace local (to the app/sandbox).
                      4. Close the video file.
                      5. Re-open the newly created video file in local-space and then hand that local-space video file to FTP

                      Is this close? If so, is there a better way? If not... gadzooks.

                      Thanks for putting up with my inane questions.
                      Bill

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

                        I think it should work so...

                        The asset property filename is only a text (metadata,Exif), it isn't the real name of the file...

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

                          you should be able to pass the BytesIO object from get_image_data directly to storbinary. No opening it, reading it, etc

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

                            You're surely right but it is still a copy from the camera roll to a Pythonista memory area (not a file, but is it a difference between a file and an object?) and after that a transfer to FTP.
                            I think that @billbris hoped a direct transfer from the camera roll file to FTP.

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

                              @billbris
                              As @JonB said

                              import photos
                              from objc_util import *
                              from ftplib import FTP
                              import console
                              p = photos.pick_asset(assets=photos.get_assets(media_type='video'))
                              file_name = str(ObjCInstance(p).valueForKey_('filename'))
                              b = p.get_image_data()
                              try:
                              	ftp = FTP('Server') #connect
                              	ftp.encoding = 'utf-8'
                              	ftp.login('User','pwd')
                              	ftp.storbinary('STOR '+file_name,b)
                              	ftp.close()
                              except Exception as e:
                              	console.alert('Error ',str(e),'ok',hide_cancel_button=True)	
                              
                              
                              1 Reply Last reply Reply Quote 0
                              • JonB
                                JonB last edited by

                                I don't think we have access to the original file, even through objc. Maybe I am wrong -- does someone have an example where you can directly open a full path provided by an asset (in ObjC)? my attempts to do that recently gave me access denied errors.

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

                                  When we share a file, we have access to read it without being authorized to remove or rename it.

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

                                    I follow this for assets of type image (re: photos), however, this method just doesn't work for video.

                                    Yes, I was attempting to open the video using the filename, and then use that binary file object as the direct source of sending it via FTP to the server. Although I can open the video file by name the FTP server says it cannot find the file of the same name.

                                    Example:
                                    video_filename = str(ObjCInstance(asset).filename())
                                    video_file_object = open(video_filename, 'rb') #this is succesful
                                    ftp.storbinary("STOR "+video_target_filename, video_file_object) #video file object has read method so it should work

                                    This results in a file not found error for the video_filename.

                                    My overall question is what is the preferred/best method of copying a video file via FTP since get_image_data doesn't work?

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

                                      Did you try the little script I posted just before?
                                      It works
                                      File name is only a name, a string, not a file, thus you can't send it!
                                      your line is just an open, not a read and close thus the file is not yet written.
                                      Thus the file does not exist and your ftp command will give this error.
                                      But my script, as adviced by @JonB , does not need to really write a file before sending it via FTP.
                                      Please try my script with your videos and you'll see the .mov on your server

                                      If you want to work through a file, you need to create the file, that will say write the asset to a file, before it can be opened in read for ftp send.

                                      In summary:

                                      • a photo/video of the camera roll is a file which you can read via photos asset into a Pythonista local object, the real name of this file is not the filename value
                                      • filename is a metadata of the asset, and just a string in Pythonista
                                      • if you want, you can create a Pythonista local file containing the bytes of this object, and you can give to this file any name you want, and by example the filename string
                                      • you can send to your ftp server, either directly the object (my script) or a file that you need first to create locally (open for writing, write, close)
                                      loc_file = open(file_name,mode='wb')
                                      loc_file.write(b.getvalue())
                                      loc_file.close()
                                      
                                      1 Reply Last reply Reply Quote 0
                                      • billbris
                                        billbris last edited by

                                        cvp,

                                        Thanks for the input. I used your script from above and I get the same problem that I've grown to expect. It seems that get_image_data only returns the first frame (or something). A file with the correct name is created on the FTP server just as expected, however, the contents are not that of a valid video (.MOV). In fact the file size is approximately 110Kb on my Windows machine and that is rather small for a 30 second video.

                                        This brings me back to the original problem.

                                        I will try copying the video file from the photo assets to a sandbox/local directory and then pass that on to the FTP server.

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

                                          The problem is that you DO NOT GET even read access to video files unless you specifically request it. The following fails

                                          p = photos.pick_asset(assets=photos.get_assets(media_type='video'))
                                          file_name = str(ObjCInstance(p).valueForKey_('filename'))
                                          P=ObjCInstance(p)
                                          
                                          try:
                                          	print(str(P.pathForOriginalFile()))
                                          	open(str(P.pathForOriginalFile()),'rb')
                                          except PermissionError:
                                          	print('Could not open')
                                          

                                          (The other examples people used above tried to read files in the script folder, which will certainly fail unless you have already created such a file!)

                                          Now, it turns out you can get read access to the file, but it takes a few extra steps:
                                          https://gist.github.com/de01d929d3477a4c8e7ae9517d5b3d70

                                          With this I was able to read a few dozen moviews taken in my ipad. Note video files are big, so if you want to read to a file (though not needed...) you should read in chunks.

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

                                            @billbris sorry, I did not understand your real problem of only one frame, and I did not check the size of my file on FTP server, shame on me

                                            @jonb and one more time, Thanks to the biggest guru of this forum. I'm not sure that I will still try to help here 😢
                                            In my example, I never read a file, I write it, thus I did not get any error, it I agree that only one frame has been written.

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