Forum Archive

Managing photos

frankL

I am trying to pick a photo from my iphone camera roll and then store the location of the photo in a csv file. Then be able to open the csv file, retrieve the location, and view the photo. I am able to pick the photo, print the “_photos2.Asset” class to the console which looks like this:

And the photo is shown in the console. Here is my script:

import photos
import ui
import csv
all_assets = photos.get_assets()
assets = photos.pick_asset(assets=all_assets, title=’Pick a photo’)
new_asset = assets[0]
print(new_asset)
img = new_asset.get_ui_image()
img.show()

How can I get the photo location in a csv storable form, store it in a csv file, and once I open the csv and retrieve the location, show the photo either in the console or preferably in a subview?

cvp

@frankL I thought you already did it in the topic

frankL

That was for videos. Photos seems to be different.

cvp

@frankL ok, sorry, mistake

cvp

@frankL try this with a photo of which you know the name:

import ui
import os

path = '/var/mobile/Media/DCIM/'#108APPLE/IMG_8955.JPG'

v = ui.ImageView()
v.present('sheet')
l = os.listdir(path)
for apple in l:
    ll = os.listdir(path+apple)
    print(apple)
    for ff in ll:
        print(ff)
        if ff == 'IMG_8662.PNG':
            v.image = ui.Image.named(path+apple+'/'+ff)

cvp

@frankL or

import photos
import ui
import os

assets = photos.get_assets()
asset = photos.pick_asset(assets)
fil = str(ObjCInstance(asset).filename())
print(fil)

path = '/var/mobile/Media/DCIM/'#108APPLE/IMG_8955.JPG'

v = ui.ImageView()
v.present('sheet')
l = os.listdir(path)
for apple in l:
    ll = os.listdir(path+apple)
    print(apple)
    for ff in ll:
        print(ff)
        if ff == fil:
            v.image = ui.Image.named(path+apple+'/'+ff)
frankL

For the first script, how do I get the name of the photo? I ran the script as is and it printed thousands of items in the console each in the form of:
IMG_xxxx.HEIC
I assume that there is one of these for every photo in my camera roll.

For the second script, after I picked a photo, I get an error message:

fil = str(ObjCInstance(asset).filename())
NameError: name 'ObjCInstance' is not defined.

cvp

@frankL sorry, I forgot

from objc_util import *

I guess it was loaded on my Pythonista by another script I ran

cvp

@frankL said:

thousands of items

Ok, comment the print lines

frankL

With 'from objc_util import *' the second script runs and with the second and third print lines commented, I get the selected image name "IMG_1343.JPG" and the image is displayed in the subview. How do I find out which directory "/xxxAPPLE/ the image is in? When I uncommented the second print line, I get a list of about 30 directories.

cvp

@frankL that's all folks

import photos
import ui
from objc_util import *
assets = photos.get_assets()
asset = photos.pick_asset(assets)
fil = str(ObjCInstance(asset).filename())
dir = str(ObjCInstance(asset).directory())
path = '/var/mobile/Media/' + dir + '/' + fil
v = ui.ImageView()
v.present('sheet')
v.image = ui.Image.named(path)          
frankL

Perfect! Thank you!

frankL

cvp, one more question: I have the following script in which I can pick a photo and save it to a csv file with a button push or show the previously saved photo with the other button push. The only problem is that I haven't been able to change the size or aspect ratio of the displayed photo. I tried setting the frame for the subview and that doesn't seem to work. How can I fix this? Thanks.

import photos
import ui
from objc_util import *
import csv
import os
#
def open_photo_ref():
    matrix=[]
    my_path=os.path. abspath("photo_file.csv")
    with open(my_path,'r',encoding='utf-8') as reader:
        reader=csv.DictReader(reader)
        for row in reader:
            matrix.append([row['Index'], row['Path']])
    return matrix
#
#
def save_photo(photo_path):
    save_path='/private/var/mobile/Containers/Shared/AppGroup/99B62839-B39E-4ADF-9308-D5D986E28E91/Pythonista3/Documents/Frank/photo_file.csv'
    headings=['Index', 'Path']
    with open(save_path, 'w', newline='',encoding='utf-8') as out_file:
            csv.writer(out_file).writerow(headings)
            new_row = [0, photo_path]
            csv.writer(out_file). writerow(new_row)
    return


#
#              MAIN PROGRAM             #
#
#
w, h = ui.get_screen_size()
h -= 64
bh = bw = 80  # label height and button width 
mg = 10  # margin 
view = ui.View(name='Show Photo', bg_color='#D98880', frame=(0, 0, w, h)) 
#
def photo_action(sender):
    matrix = open_photo_ref()
    row= matrix[0]
    my_path = row[1]
    v = ui.ImageView(frame=(0,0,500,200))
    v.image = ui.Image.named(my_path)
    v.present('sheet')
    return
#
photo_button = ui.Button(frame=(150,10,130,0),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=photo_action, font=('Arial Rounded MT Bold',18)) photo_button.title='show'
photo_button.width=100
photo_button.height=40
view.add_subview(photo_button)

#
def pick_action(sender):
    assets = photos.get_assets()
    asset = photos.pick_asset(assets)
    fil = str(ObjCInstance(asset).filename())
    dir = str(ObjCInstance(asset).directory())
    path = '/var/mobile/Media/' + dir + '/' + fil
    path_string = str(path)
    save_photo(path_string)
    return
#
pick_button = ui.Button(frame=(10,10,130,0),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=pick_action, font=('Arial Rounded MT Bold',18)) pick_button.title='pick'
pick_button.width=100
pick_button.height=40
view.add_subview(pick_button)

#########################################
nav_view = ui.NavigationView(view)
nav_view.present('sheet')
#########################################
cvp

@frankL I could help but, first of all, please post your code between 2 lines of 3 backsticks or use button to insert your code.

Otherwise, we don't see your code indentation and can't copy it easily for testing.

frankL

Is this better?

import photos
import ui
from objc_util import *
import csv
import os
#
def open_photo_ref():
    matrix=[]
    my_path=os.path. abspath("photo_file.csv")
    with open(my_path,'r',encoding='utf-8') as reader:
        reader=csv.DictReader(reader)
        for row in reader:
            matrix.append([row['Index'], row['Path']])
    return matrix
#
#
def save_photo(photo_path):
    save_path='/private/var/mobile/Containers/Shared/AppGroup/99B62839-B39E-4ADF-9308-D5D986E28E91/Pythonista3/Documents/Frank/photo_file.csv'
    headings=['Index', 'Path']
    with open(save_path, 'w', newline='',encoding='utf-8') as out_file:
            csv.writer(out_file).writerow(headings)
            new_row = [0, photo_path]
            csv.writer(out_file). writerow(new_row)
    return


#
#              MAIN PROGRAM             #
#
#
w, h = ui.get_screen_size()
h -= 64
bh = bw = 80  # label height and button width 
mg = 10  # margin 
view = ui.View(name='Show Photo', bg_color='#D98880', frame=(0, 0, w, h)) 
#
def photo_action(sender):
    matrix = open_photo_ref()
    row= matrix[0]
    my_path = row[1]
    v = ui.ImageView(frame=(0,0,500,200))
    v.image = ui.Image.named(my_path)
    v.present('sheet')
    return
#
photo_button = ui.Button(frame=(150,10,130,0),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=photo_action, font=('Arial Rounded MT Bold',18)) photo_button.title='show'
photo_button.width=100
photo_button.height=40
view.add_subview(photo_button)

#
def pick_action(sender):
    assets = photos.get_assets()
    asset = photos.pick_asset(assets)
    fil = str(ObjCInstance(asset).filename())
    dir = str(ObjCInstance(asset).directory())
    path = '/var/mobile/Media/' + dir + '/' + fil
    path_string = str(path)
    save_photo(path_string)
    return
#
pick_button = ui.Button(frame=(10,10,130,0),border_color='black', border_width=2, corner_radius = 10, tint_color = 'black', background_color='#EAECEE', action=pick_action, font=('Arial Rounded MT Bold',18)) pick_button.title='pick'
pick_button.width=100
pick_button.height=40
view.add_subview(pick_button)

#########################################
nav_view = ui.NavigationView(view)
nav_view.present('sheet')
#########################################
cvp

@frankL in your show photo, see the doc of ui.ImageView.content_mode and try

    v.content_mode = ui.CONTENT_SCALE_ASPECT_FIT

And if you want you can resize our frame with the same ratio as the photo

frankL

That worked for displaying the photo. How would I resize the frame the same as the photo?

cvp

@frankL if you photo is, for instance 3000x4000, it is not possible to display the same frame on the iDevice, thus you have to keep the ratio, not the size, wait 5' I come back

cvp

@frankL that should be ok

    v = ui.ImageView()
    v.content_mode = ui.CONTENT_SCALE_ASPECT_FIT
    v.image = ui.Image.named(my_path)
    w,h = v.image.size
    ws = 500    # example only
    hs = ws * h/w
    v.frame=(0,0,ws,hs)

frankL

That doesn't seem to change anything.

cvp

@frankL said:

That doesn't seem to change anything.

True if your photo is ratio 5/2 with your frame 500,200.

What do you really want and which is the size width/height of your photo?

And did you read the doc of ui.ImageView.content_mode?

frankL

You're right about the photo ratio. It is doing the right thing.

I've been reading the image section in this doc:
http://omz-software.com/pythonista/docs/ios/ui.html#image
Which I just realized is the general section. But I found the Image module documentation (actually the list of all modules which I haven't seen before). I see that I have a lot to learn. Thanks for all of your help.

cvp

@frankL be careful that there are two kinds of images:
1) ui.Image which is the Pythonista version of UIImage standard iOS image
2) PIL Image which comes from a Python module named PIL
The forum contains a lot of topics about tHem and their conversion in both directions.
Good luck

frankL

If I have the path to several photos on my iphone, for example:

/var/mobile/Media/DCIM/131APPLE/IMG_1415.HEIC
/var/mobile/Media/DCIM/131APPLE/IMG_1412.HEIC
/var/mobile/Media/DCIM/131APPLE/IMG_1389.HEIC
/var/mobile/Media/DCIM/131APPLE/IMG_1388.HEIC
/var/mobile/Media/DCIM/131APPLE/IMG_1373.JPG

How can I show these as thumbnails in a subview?

cvp

@frankL said:

How can I show these as thumbnails in a subview?

All photos in one view? Or I don't understand

You have the code to display one in an ImageView. If it has small frame, the photo will be a thumbnail.

frankL

Yes, all photos in one view. Just like you see when you use
asset = photos.pick_asset(assets)

cvp

@frankL very quick and dirty (up to you to compute correct frame and scales)

Or you add one ImageView as subview per photo in your view

import ui
v = ui.ImageView()
v.frame = (0,0,400,100)
with ui.ImageContext(400,100) as ctx:
    u = ui.Image.named('test:Lenna').draw(0,0,200,100)
    u = ui.Image.named('test:Mandrill').draw(200,0,200,100)
    v.image = ctx.get_image()
v.present('sheet')

cvp

@frankL you can also modify this script (try it so) to support your own photos instead of photos from camera roll.
Easy modification if you have an array of your paths
- self.assets = array of your paths
- photo.image = ui.image.named(your array[row])

from  objc_util import *
import os
import photos
import ui

class PhotosPickerTableView(ui.View):

    def __init__(self,w,h,d):
        self.width = w
        self.height = h
        self.selected = None

        ok = ui.ButtonItem()
        ok.image = ui.Image.named('iob:ios7_checkmark_outline_32')
        ok.action = self.ok_action
        self.right_button_items = (ok,)

        tbl = ui.TableView()    
        tbl.frame = (0,0,d,h)
        tbl.row_height = d
        self.assets = photos.get_assets()
        tbl.data_source = ui.ListDataSource(items=range(len(self.assets)))
        tbl.separator_color=(1,0,0,0)
        tbl.delegate = self
        tbl.data_source.tableview_cell_for_row = self.tableview_cell_for_row
        tbl.background_color = (0,0,0,0)
        self.add_subview(tbl)

        pha =ui.View(name='photo_area')     
        pha.frame = (d,0,w-d,h)
        self.add_subview(pha)
        img = ui.ImageView(name='selected_photo')
        img.frame = (0,0,w-d,h)
        img.content_mode=ui.CONTENT_SCALE_ASPECT_FIT
        img.background_color = (0.5,0.5,0.5,1)
        pha.add_subview(img)

        self.tableview_did_select(tbl,0,0)

        self.photo_scale = 1        

    def ok_action(self,sender):
        self.close()

    def tableview_did_select(self, tableview, section, row):
        ui_image = self.assets[row].get_ui_image()
        self['photo_area']['selected_photo'].image = ui_image
        self.selected = row

    def tableview_cell_for_row(self,tableview, section, row):
        cell = ui.TableViewCell()
        v = 0.4 + (row % 2)*0.4
        cell.bg_color = (v,v,v,v)
        selected_cell = ui.View()
        #selected_cell.bg_color = 'blue'
        selected_cell.border_width = 2
        selected_cell.border_color = 'blue'
        cell.selected_background_view = selected_cell
        photo = ui.ImageView()
        photo.frame = (0,0,tableview.row_height,tableview.row_height)
        photo.image = self.assets[row].get_ui_image()
        photo.content_mode = ui.CONTENT_SCALE_ASPECT_FIT
        cell.content_view.add_subview(photo)
        return cell

def main():

    # Hide script
    w,h = ui.get_screen_size()
    mi = min(w,h)*0.9
    my_back = PhotosPickerTableView(mi,mi,100)
    my_back.background_color='white'
    my_back.name = 'Photos Picker via TableView'    

    my_back.present('sheet',hide_title_bar=False)   
    my_back.wait_modal()

# Protect against import    
if __name__ == '__main__':
    main()
frankL

Thank you. That is cool looking. But I don't see where to input my array of paths. When I ran the script, it pulls from my camera roll.

cvp

@frankL

from  objc_util import *
import os
import photos
import ui

class PhotosPickerTableView(ui.View):

    def __init__(self,w,h,d):
        self.width = w
        self.height = h
        self.selected = None

        ok = ui.ButtonItem()
        ok.image = ui.Image.named('iob:ios7_checkmark_outline_32')
        ok.action = self.ok_action
        self.right_button_items = (ok,)

        tbl = ui.TableView()    
        tbl.frame = (0,0,d,h)
        tbl.row_height = d
        self.assets = ['test:Lenna','test:Mandrill','test:Numbers','test:Pattern','test:Peppers','test:Boat','test:Bridge','test:Sailboat']
        tbl.data_source = ui.ListDataSource(items=range(len(self.assets)))
        tbl.separator_color=(1,0,0,0)
        tbl.delegate = self
        tbl.data_source.tableview_cell_for_row = self.tableview_cell_for_row
        tbl.background_color = (0,0,0,0)
        self.add_subview(tbl)

        pha =ui.View(name='photo_area')     
        pha.frame = (d,0,w-d,h)
        self.add_subview(pha)
        img = ui.ImageView(name='selected_photo')
        img.frame = (0,0,w-d,h)
        img.content_mode=ui.CONTENT_SCALE_ASPECT_FIT
        img.background_color = (0.5,0.5,0.5,1)
        pha.add_subview(img)

        self.tableview_did_select(tbl,0,0)

        self.photo_scale = 1        

    def ok_action(self,sender):
        self.close()

    def tableview_did_select(self, tableview, section, row):
        ui_image = ui.Image.named(self.assets[row])
        self['photo_area']['selected_photo'].image = ui_image
        self.selected = row

    def tableview_cell_for_row(self,tableview, section, row):
        cell = ui.TableViewCell()
        v = 0.4 + (row % 2)*0.4
        cell.bg_color = (v,v,v,v)
        selected_cell = ui.View()
        #selected_cell.bg_color = 'blue'
        selected_cell.border_width = 2
        selected_cell.border_color = 'blue'
        cell.selected_background_view = selected_cell
        photo = ui.ImageView()
        photo.frame = (0,0,tableview.row_height,tableview.row_height)
        photo.image = ui.Image.named(self.assets[row])
        photo.content_mode = ui.CONTENT_SCALE_ASPECT_FIT
        cell.content_view.add_subview(photo)
        return cell

def main():

    # Hide script
    w,h = ui.get_screen_size()
    mi = min(w,h)*0.9
    my_back = PhotosPickerTableView(mi,mi,100)
    my_back.background_color='white'
    my_back.name = 'Photos Picker via TableView'    

    my_back.present('sheet',hide_title_bar=False)   
    my_back.wait_modal()

# Protect against import    
if __name__ == '__main__':
    main()
frankL

That's awesome! Thank you