Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 24/04/2009, à 19:51

Aurel07

[python, pygtk] Import de photos via gphoto2

Bonjour,

Je vous fait part de mon premier script python élaboré (fier !) qui permet d'importer des photos a partir d'un appareil photo via gphoto2, le tout avec une interface graphique (gtk+glade). Il permet de selectionner les photos a importer a partir de thumbnails, importer dans un dossier specifique a chaque photo en lisant les exifs (typiquement /année/mois/jour), de renommer les photos selon le meme schema, de pivoter les photos, et de rajouter l'exif de lenstype pour les possesseurs du canon 350D (qui ne le fait pas tout seul, et ca permet d'avoir acces aux reglages des abberations avec DPP qui tourne bien avec wine).
S'il y a des experts de python qui passent, merci de jeter un oeil et corriger les trucs qui vont pas. Je dois avouer que j'en ai pas mal ch... sué pour les trucs genre threading.
Et puis ceux qui veulent essayer, merci de me faire part de vos bugs et impressions et conseils et remarques...
Dependances : python, gphoto2, gtk2, pyexiv2 (>1.3 si vous voulez ajouter le lenstype), et puis c'est tout je crois.

Voici la bete (1 script, 4 fichiers glade) :

importphotos.py :

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# Licence : GPLv3 voir : http://gplv3.fsf.org/


try:
    import os, sys
    import subprocess
    import shutil
    import gobject
    import time
    import threading
except:    
    print('Un problème est survenu, les bibliothèques python de base semblent manquer...\n(Ré)installer python semble une bonne idée.')
    sys.exit(1)    
    
try:
    import gtk
    import gtk.glade
    import pygtk
    pygtk.require("2.0")
except:
    print('gtk2 et libglade doivent etre installés')
    sys.exit(1)
      
try:   
    import pyexiv2    #Il faut pyexiv v.1.3 minimum pour pouvoir lire les lenstype dans les exifs.
    import Image      #Necessaire pour tourner les images
except:
    pass
    
gobject.threads_init()        #Pour que les threads soient lancés au moment opportun.
        
        
#############################################    
####  Fonctions agissant sur les photos  ####
#############################################        
        
def renom():
    #Fonction pour renommer les photos
    ext_det = Gui.image.split('.')
    ext = ext_det[len(ext_det) - 1]
    nom = ext_det[0]
    pattern_mod = Gui.renom_pattern.replace('%name', nom)
    nombis = Gui.date.strftime(pattern_mod) + '.' + ext
    os.rename(Gui.image, nombis)
    Gui.image = nombis
        
     
def lenstype():
    #Fonction pour rajouter le lenstype dans les exifs. 
    #C'est bien pour les Canon 350D qui ne le font pas automatiquement, et ca permet d'avoir la correction d'abheration avec DPP
    lens = Gui.image_exif.interpretedExifValue('Exif.CanonCs.Lens')
    lenstype_dic={"18.0 - 55.0" : 45, "200.0" : 151, "50.0" : 1}   #Dictionnaire des lenstype, a compléter bien sur !
    Gui.image_exif['Exif.CanonCs.Lens'] = lenstype_dic[lens]
    Gui.image_exif.writeMetadata()      
             
             
def pivot():
    #Fonction pour pivoter les images selon les données exifs. 
    #A la fin, la donnée exifs d'orientation est toujours mise a 1, c'est a dire que la premiere ligne de pixel est en haut, et la premiere colonne a gauche.
    #Meriterait une simplification
    orient = 0
    try:
        orient = Gui.image_exif["Exif.Image.Orientation"]      #Cf le manuel d'exifs pour comprendre les significations des chiffres
    except:
        pass
        
    if orient == 2:
        subprocess.Popen(["jpegtran", "-flip", "horizontal", "-copy", "all", "-outfile", "tmp", Gui.image])  #je prefere passer par jpegtran, je maitrise pas PIL
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 3:
        a=subprocess.Popen(["jpegtran", "-rotate", "180", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 4:
        a=subprocess.Popen(["jpegtran", "-flip", "vertical", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 5:
        a=subprocess.Popen(["jpegtran", "-flip", "horizontal", "-copy", "all", "-outfile", "tmp1", Gui.image])
        a.wait()
        a=subprocess.Popen(["jpegtran", "-rotate", "270", "-copy", "all", "-outfile", "tmp", "tmp1"])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 6:
        a=subprocess.Popen(["jpegtran", "-rotate", "90", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 7:
        a=subprocess.Popen(["jpegtran", "-flip", "horizontal", "-copy", "all", "-outfile", "tmp1", Gui.image])
        a.wait()
        a=subprocess.Popen(["jpegtran", "-rotate", "90", "-copy", "all", "-outfile", "tmp", "tmp1"])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 8:
        a=subprocess.Popen(["jpegtran", "-rotate", "270", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    Gui.image_exif.writeMetadata()
            
        
def classe():
    #Pour classer (ca deplace les images dans le dossier approprié
    Gui.repclasse = Gui.date.strftime(Gui.classe_pattern)
    if not os.path.isdir(Gui.basedossier + "/" + Gui.repclasse):
        os.makedirs(Gui.basedossier + "/" + Gui.repclasse)
    shutil.move(Gui.image, Gui.basedossier + "/" + Gui.repclasse) 
        
        
def catalogue():
    #Créer les liens dans un dossier catalogue.
    if not os.path.isdir(Gui.dossier_catalogue):
        os.makedirs(Gui.dossier_catalogue)
       
    if Gui.classerphotoselect.get_active():
        os.symlink(Gui.basedossier + "/" + Gui.repclasse + "/" + Gui.image, Gui.dossier_catalogue + "/" + Gui.image)
    else:
        os.symlink(Gui.basedossier + "/"+ Gui.image, Gui.dossier_catalogue + "/" + Gui.image)
        

###########################################    
####  Classe de la fenetre principale  ####
###########################################        
     
class Interface:
    """Mon programme d'import de photos depuis mon Canon 350D"""

    def __init__(self):     
        #Set the Glade file
        self.gui=gtk.glade.XML(install_dossier + "/Interface.glade")
         
        #Dans la foulee on chope la fenetre principale, ca sert a rien c'est pour
        #montrer qu'on peut le faire c'est tout ^^
        self.win=self.gui.get_widget("MainWindow")
        self.win.set_title('PympPhotos')
       
                
        #On chope le reste, et ca, ca va servir...
        self.gphotoappselect = self.gui.get_widget("gphotoappselect")  
        self.labelgphoto = self.gui.get_widget("labelgphoto")
        self.importdossierselect = self.gui.get_widget("importdossierselect")
        self.iconview = self.gui.get_widget("iconview")
        self.dossierimport = self.gui.get_widget("dossierimport")
        self.dossierbase = self.gui.get_widget("dossierbase")
        self.renommerphotoselect = self.gui.get_widget("renommerphotoselect")
        self.classerphotoselect = self.gui.get_widget("classerphotoselect")
        self.creercatalogueselect = self.gui.get_widget("creercatalogueselect")
        self.renompattern = self.gui.get_widget("renompattern")
        self.classpattern = self.gui.get_widget("classpattern")
        self.pivoterselect = self.gui.get_widget("pivoterselect")
        self.objectifcr2select = self.gui.get_widget("objectifcr2select")
        self.dossiercatalogue = self.gui.get_widget("dossiercatalogue")
        self.importall = self.gui.get_widget("importall")   
        
        #On relie les signaux (cliques sur boutons, cochage des cases, ...) aux fonctions appropriées
        dic = { "on_MainWindow_destroy" : gtk.main_quit,
                "on_Fermer_clicked" : gtk.main_quit,
                "on_Go_clicked" : self.go_clicked,
                "on_rafrachir_bouton_clicked" : self.rafraichir_clicked,
                "on_select_all_bouton_clicked" : self.select_all, 
                "on_aiderenom_clicked" : self.aiderenom_fenetre,
                "on_aideclass_clicked" : self.aideclass_fenetre
                }
                                
        #Auto-connection des signaux (ca fait un peu film de SF)        
        self.gui.signal_autoconnect(dic)
                
        #création des repertoires necessaires
        self.home_path = os.environ['HOME']
        self.importphotos_path = self.home_path + "/.importphotos"
        self.thumbs_path = self.importphotos_path + "/thumbs"
        if not os.path.isdir(self.importphotos_path):
            os.makedirs(self.importphotos_path)
        if not os.path.isdir(self.thumbs_path):
            os.makedirs(self.thumbs_path)
                        
        #set-up des valeurs par defaut    
        self.dossierimport.set_filename("/media")
        self.dossierbase.set_filename(self.home_path + "/Images/Photos")
        self.dossiercatalogue.set_filename(self.home_path)
        self.classerphotoselect.set_active(True)
        self.objectifcr2select.set_active(True)
        self.pivoterselect.set_active(True)
                
        #Test préliminaire au lancement, pour voir si un appareil est connecté          
        self.testapp()
                                               
    def testapp(self):
        #Comme y'a pas de bindings pour python de libgphoto2, on est obligés de passer par le programme gphoto2
        gphoto2 = subprocess.Popen(["gphoto2", "--auto-detect"], stdout=subprocess.PIPE)
        gphoto2_result = gphoto2.stdout.read()
               
        #Teste la presence d'un appareil photo par gphoto2 et l'affiche dans labelgphoto
        if (gphoto2_result.count("\n")>2):                                      #Si appareil photo present...
            affiche_app = gphoto2_result.splitlines()[3]                        #on attrape le nom de l'appareil
            self.labelgphoto.set_text(affiche_app)                              #Affiche l'appareil en dessous de la case a cocher
            self.gphotoappselect.set_sensitive(True)                            #Rend la case a cocher sensible
            self.gphotoappselect.set_active(True)                               #selectionne par defaut
        else:
            self.labelgphoto.set_text("Pas d'appareil détecté")                 #Sinon, "pas d'appareil" est affiché.
                                 
    def rafraichir_clicked(self, widget):
        self.rafraichir = Progress_rafraichir()                                 #On "instancie" la classe de progression du rafraichissement des icones
                    
    def select_all(self, widget):
        self.iconview.select_all()
   
    def go_clicked(self, widget):                                               #On "instancie" la classe de progression de l'import
        self.progress_action = Progress_action()
        
    def aiderenom_fenetre(self, widget):                                        #Fenetre d'aide pour remplir renommer les photos
        a=AideRenom()
    
    def aideclass_fenetre(self, widget):                                        #Pareil mais pour les classer...
        b=AideClass()
        

##################################    
####  Aide pour le renommage  ####
##################################

class AideRenom:

    def __init__(self):
        #Initialisation de l'interface de la fenetre 
        self.fenetre = gtk.glade.XML(install_dossier + "/aide_renom.glade")         #Tout est dans le fichier glade
        self.dialog=self.fenetre.get_widget("dialog1")
        self.dic1 = {"on_bouton_fermer_clicked" : self.fermeture, 
                     "on_dialog1_destroy" : self.fermeture}
        self.fenetre.signal_autoconnect(self.dic1)

    def fermeture(self, widget):
        self.dialog.destroy()
        

#################################    
####  Aide pour le classage  ####
#################################

class AideClass:

    def __init__(self):
        #Initialisation de l'interface de la fenetre 
        self.fenetre = gtk.glade.XML(install_dossier + "/aide_class.glade") 
        self.dialog=self.fenetre.get_widget("dialog1")
        self.dic1 = {"on_bouton_fermer_clicked" : self.fermeture, 
                     "on_dialog1_destroy" : self.fermeture}
        self.fenetre.signal_autoconnect(self.dic1)
        
    def fermeture(self, widget):
        self.dialog.destroy()
        

##########################################    
####  Rafraichissement de l'iconview  ####
##########################################

class Progress_rafraichir:

    def __init__(self):
        #Initialisation de l'interface de la fenetre de progression
        self.progress = gtk.glade.XML(install_dossier + "/Progress.glade") 
        self.progress_win = self.progress.get_widget("dialog1")
        self.progress_label = self.progress.get_widget("progress_label")
        self.info_label = self.progress.get_widget("info_label")
        self.progress_bar = self.progress.get_widget("progressbar1")
        self.progress_stop_button = self.progress.get_widget("stop_button")
        
        #Dictionnaire pour fermer la fenetre
        self.dic1 = {"on_stop_button_clicked" : self.close_progress, 
                     "on_dialog1_destroy" : self.close_progress}
        self.progress.signal_autoconnect(self.dic1)
        
        #On affiche ce qu'on fait (création des icones)
        self.info_label.set_text("Création des thumbnails...")
        self.progress_label.set_text('Veuillez patienter...')
        
        self.thread_icon = Thread_Icon()                        #On prepare le thread qui va faire tout le boulot
        self.thread_icon.start()                                #On le lance
        timer = gobject.timeout_add (100, self.pulsate)         #Fait pulser la barre a intervalles reguliers 
        
        #Rq: Il n'est pas possible de faire une vraie barre de progression car lorsqu'on import avec gphoto2, 
        #c'est un seul processus qui ne rend pas la main entre les images (et du coup, on ne peut pas l'interrompre avant qu'il ai finit)
    
    def pulsate(self):
        if self.thread_icon.is_alive():             #Tant que le thread est en cours, 
            self.progress_bar.pulse()               #on fait pulser la barre
            return True                            #et on renvoie True pour que gobject.timeout recommence
        else:
            self.progress_bar.set_fraction(1)
            self.progress_bar.set_text('Thumbnails Importés!')
            self.progress_win.destroy()
            return False
            
    def close_progress(self, widget):
        #subprocess.Popen(["kill", "-9", str(self.thread_icon.pid)])   #Je sais pas pourquoi, mais ca kill l'interface principale...
        self.progress_win.destroy()
        
        

#############################################    
####  Thread de création des thumbnails  ####
#############################################       
        
        
class Thread_Icon(threading.Thread):
    def __init__(self):
        super(Thread_Icon, self).__init__()
        self.pid=os.getpid()                                                    #on chope le pid pour pouvoir le tuer apres, meme si ca marche pas...
        
    def run(self):
        Gui.list_thumbs = gtk.ListStore(str, gtk.gdk.Pixbuf, int)
        if Gui.gphotoappselect.get_active():                                   #Si l'appareil detecte par gphoto2 est selectionné...
            os.chdir(Gui.thumbs_path)                                          #On se déplace dans le dossier qui va récupérer tous les thumbs
            #On récupère les thumbnails avec l'option qui va bien de gphoto2
            gphoto_thumbs_en_cours = subprocess.Popen(["gphoto2", "-T"], stdout=subprocess.PIPE)
            gphoto2_thumb_result=gphoto_thumbs_en_cours.stdout.read()           #On recupere la sortie de l'import des thumbs
            gphoto2_list_thumbs = gphoto2_thumb_result.splitlines()
                        
            for indice in range(1, len(gphoto2_list_thumbs)):                         #Pour tous les thumbs dans la liste...
                mots = gphoto2_list_thumbs[indice-1].split(" ")
                thumb = mots[len(mots)-1]                                              #C'est le nom du thumbnail !
                pixbuf = gtk.gdk.pixbuf_new_from_file(Gui.thumbs_path + "/" + thumb)   #on creer un pixbuf
                Gui.list_thumbs.append([thumb, pixbuf, indice])                        #et on l'ajoute a la liste : 
                #le nom, le pixbuf, et un numero qui permet de savoir quelle image correspond a quel thumbnail (gphoto2, c'est un peu mal fait quand meme...)
               
        elif Gui.importdossierselect.get_active():                             #Si l'import de dossier est activé.
            Gui.impdossier = Gui.dossierimport.get_filename()                   #On récupère le path du dossier
            images_import = os.listdir(Gui.impdossier)                          #On liste les fichiers et on les trie par ordre alphabetique
            images_import.sort()
            
            for image in images_import:
                try:                                    #On passe par try, parce que les fichiers autre que les images ne passeront pas
                    pixbuf = gtk.gdk.pixbuf_new_from_file(Gui.impdossier + "/" + image)
                    height = pixbuf.get_height()
                    width = pixbuf.get_width()
                    if width >= height:                                          # redimensionnement du pixbuff en max(height, width) = 160          
                        nheight = 160*height/width
                        scaled_buf = pixbuf.scale_simple(160,nheight,gtk.gdk.INTERP_BILINEAR)
                    else:
                        nwidth = 160*width/height
                        scaled_buf = pixbuf.scale_simple(nwidth,160,gtk.gdk.INTERP_BILINEAR)
                        
                    Gui.list_thumbs.append([image, scaled_buf, 0])     #le nom, le pixbuf, et 0 pour savoir que l'image vient du dossier d'import et pas de gphoto2
                except:
                    pass
            
        #Generation de la IconView
        Gui.iconview.set_pixbuf_column(1)                              
        Gui.iconview.set_text_column(0)
       #Gui.iconview.set_item_width(180)
        Gui.iconview.set_model(Gui.list_thumbs)   
           
        #supprime les thumbnails de thumb_path
        for thumb in os.listdir(Gui.thumbs_path):
            os.remove(Gui.thumbs_path + "/" + thumb)
         
        
    
###########################################################    
####  Classe de la fenetre de progression des actions  ####
###########################################################

class Progress_action:

    def __init__(self):
        #Initialisation de l'interface de la fenetre de progression
        self.progress = gtk.glade.XML(install_dossier + "/Progress.glade") 
        self.progress_win = self.progress.get_widget("dialog1")
        self.progress_label = self.progress.get_widget("progress_label")
        self.info_label = self.progress.get_widget("info_label")
        self.progress_bar = self.progress.get_widget("progressbar1")
        self.progress_stop_button = self.progress.get_widget("stop_button")
        self.dic1 = {"on_stop_button_clicked" : self.close_progress, 
                     "on_dialog1_destroy" : self.close_progress}
        self.progress.signal_autoconnect(self.dic1)
        
        #on récupère la liste des images selectionnées
        self.selection = Gui.iconview.get_selected_items()
                
        if self.selection and not Gui.importall.get_active():      #Si on n'a pas coche la case "tout importer", alors ca va bien se passer, tu auras une barre de progression qui avance en meme temps que chaque photo est traitee, etc. Pas de probleme donc.
            self.info_label.set_label("Import en cours...")
            self.nombre_photos = len(self.selection)                #Combien y'a t'il d'images selectionnées ???
            task = self.action()                                    #Je sais pas pourquoi, mais ca marche. Cf faq de pyGTK, comment faire une progressbar
            gobject.idle_add(task.next)
        elif Gui.importall.get_active():                           #en mode tout importer, la barre de progression pulse seulement vu que le thread gphoto2 -P ne rend pas la main entre 2 photos. (et que c'est chiant de lui demander le nombre de photos)
            self.info_label.set_text("Import de toutes les photos...")
            self.progress_label.set_text('Veuillez patienter...')
            self.thread_import = Thread_Import()                    #On prepare le thread qui va faire tout le boulot
            self.thread_import.start()                              #On le lance
            timer = gobject.timeout_add (100, self.pulsate)         #Fait pulser la barre a intervalles reguliers 
        else:
            self.info_label.set_label("Pas de fichier sélectionnés")
            

    def pulsate(self):
        if self.thread_import.is_alive():           #Tant que le thread est en cours, 
            self.progress_bar.pulse()               #on fait pulser la barre
            return True                            #et on renvoie True pour que gobject.timeout recommence
        else:
            self.progress_bar.set_fraction(1)
            self.progress_bar.set_text('Images Importées!')
            return False
        
    
    def action(self):
        #recuperation des données rentrées :
        Gui.renom_pattern = Gui.renompattern.get_text()                         #comment renommer
        Gui.classe_pattern = Gui.classpattern.get_text()                        #comment classer
        Gui.dossier_catalogue = Gui.dossiercatalogue.get_filename()             #comment classer
        Gui.basedossier = Gui.dossierbase.get_filename()                        #on recupere le dossier de base
        os.chdir(Gui.basedossier)                                               #on se place dans ce dossier
        
        numero = 1
        
        for index in self.selection:                                           # Pout chaque image selectionnée...
            thumb_carac = Gui.list_thumbs[index[0]]                             #recuperer le nom et le numero associés aux thumbnails
            nom = thumb_carac[0]
            num = thumb_carac[2]
            
            if num == 0:                                                       #alors, c'est un importdossier
                shutil.copy2(Gui.impdossier + "/" + nom, Gui.basedossier)      #on copie dans le dossier de base
                Gui.image=nom                                                  #Nom de l'image
                Gui.image_exif = pyexiv2.Image(Gui.image)                      #Exifs de l'image
                Gui.image_exif.readMetadata()
                try:
                    Gui.date = Gui.image_exif['Exif.Image.DateTime']               #Date de creation par les exifs
                except:
                    Gui.date = 0
                
                if Gui.renommerphotoselect.get_active() and Gui.date:
                    renom()
                if Gui.objectifcr2select.get_active() and Gui.image.endswith((".CR2", ".cr2")):
                    lenstype()
                if Gui.pivoterselect.get_active() and Gui.image.endswith((".JPG", ".jpg", ".jpeg", ".JPEG")):
                    pivot()
                if Gui.classerphotoselect.get_active() and Gui.date:
                    classe()
                if Gui.creercatalogueselect.get_active():
                    catalogue()
                
            elif num > 0:                               #alors c'est par gphoto2
                gphoto_import_process = subprocess.Popen(["gphoto2", "-p", str(num)], stdout=subprocess.PIPE)
                gphoto_import_process.wait()
                gphoto_import_result = gphoto_import_process.stdout.read()
                a = gphoto_import_result.split(' ')
                Gui.image = a[len(a)-1].split("\n")[0]
                Gui.image_exif = pyexiv2.Image(Gui.image)
                Gui.image_exif.readMetadata()
                try:
                    Gui.date = Gui.image_exif['Exif.Image.DateTime']               #Date de creation par les exifs
                except:
                    Gui.date = 0
                
                if Gui.renommerphotoselect.get_active():
                    renom()
                if Gui.objectifcr2select.get_active() and Gui.image.endswith((".CR2", ".cr2")):
                    lenstype()
                if Gui.pivoterselect.get_active() and Gui.image.endswith((".JPG", ".jpg", ".jpeg", ".JPEG")):
                    pivot()
                if Gui.classerphotoselect.get_active():
                    classe()
                if Gui.creercatalogueselect.get_active():
                    catalogue()
            
            fraction = float(numero) / self.nombre_photos                              # Faut faire avancer la barre de défilement
            self.progress_bar.set_fraction(fraction)
            self.progress_bar.set_text(str(numero) + "/" + str(self.nombre_photos) + "Images")
            self.progress_label.set_text("Import de " + Gui.image + " terminé")
            numero = numero + 1
            yield True                                                          #quand le gobject.idle_add recoit ce True, il met a jour la fenetre
            
        yield False
        self.info_label.set_label("Import terminé !")
            
###fonction pour fermer la fenetre 
            
    def close_progress(self, widget):
        self.progress_win.destroy()


################################################    
####  Thread d'import de toutes les photos  ####
################################################

class Thread_Import(threading.Thread):
    def __init__(self):
        super(Thread_Import, self).__init__()
        self.pid=os.getpid()
        
    def run(self):           
        #recuperation des données rentrées :
        Gui.renom_pattern = Gui.renompattern.get_text()                         #comment renommer
        Gui.classe_pattern = Gui.classpattern.get_text()                        #comment classer
        Gui.dossier_catalogue = Gui.dossiercatalogue.get_filename()             #comment classer
        Gui.basedossier = Gui.dossierbase.get_filename()                        #on recupere le dossier de base
        os.chdir(Gui.basedossier)                                               #on se place dans ce dossier
                
        if Gui.gphotoappselect.get_active(): 
            self.import_tout = subprocess.Popen(["gphoto2", "-P"])              #Importe toutes les photos via gphoto2
            self.import_tout.wait()
                         
        elif Gui.importdossierselect.get_active(): 
            Gui.progress_action.info_label.set_label("Import des images depuis le dossier...")
            Gui.impdossier = Gui.dossierimport.get_filename()
            for Gui.image in os.listdir(Gui.impdossier):
                if not os.path.isdir(Gui.impdossier + "/" + Gui.image) and Gui.image.endswith((".CR2", ".cr2"".JPG", ".jpg", ".jpeg", ".JPEG", ".png", ".PNG", ".gif", ".GIF")):
                    shutil.copy2(Gui.impdossier + "/" + Gui.image, Gui.basedossier)
                                    
        liste_image = os.listdir(Gui.basedossier)
        for i in liste_image:
            if not i.endswith((".CR2", ".cr2"".JPG", ".jpg", ".jpeg", ".JPEG", ".png", ".PNG", ".gif", ".GIF")):
                liste_image.remove(i)
                
        for Gui.image in liste_image:
            Gui.image_exif = pyexiv2.Image(Gui.image)                          #Exifs de l'image
            Gui.image_exif.readMetadata()
            try:
                Gui.date = Gui.image_exif['Exif.Image.DateTime']               #Date de creation par les exifs
            except:
                Gui.date = 0
               
            if Gui.renommerphotoselect.get_active() and Gui.date:
                renom()
            if Gui.objectifcr2select.get_active() and Gui.image.endswith((".CR2", ".cr2")):
                lenstype()
            if Gui.pivoterselect.get_active() and Gui.image.endswith((".JPG", ".jpg", ".jpeg", ".JPEG")):
                pivot()
            if Gui.classerphotoselect.get_active() and Gui.date:
                classe()
            if Gui.creercatalogueselect.get_active():
                catalogue()
                
        Gui.progress_action.info_label.set_label("Import terminé !")

###########################################################    
####  Initialisation et appel de la classe principale  ####
###########################################################            
                        
if __name__ == "__main__":
    install_dossier=sys.path[0]                                                #On recupere le dossier d'install
    Gui = Interface()                                                          #Initialise l'interface
    gtk.main()                                                                 #Lance la boucle principale

les .glade au prochain message...

Hors ligne

#2 Le 24/04/2009, à 19:51

Aurel07

Re : [python, pygtk] Import de photos via gphoto2

Voila le reste :

aide_class.glade :

<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkDialog" id="dialog1">
    <property name="visible">True</property>
    <property name="border_width">5</property>
    <property name="type_hint">normal</property>
    <property name="has_separator">False</property>
    <child internal-child="vbox">
      <widget class="GtkVBox" id="dialog-vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child>
          <widget class="GtkFrame" id="cadre">
            <property name="visible">True</property>
            <property name="label_xalign">0</property>
            <property name="shadow_type">none</property>
            <child>
              <widget class="GtkAlignment" id="alignment1">
                <property name="visible">True</property>
                <property name="left_padding">12</property>
                <child>
                  <widget class="GtkLabel" id="label1">
                    <property name="visible">True</property>
                    <property name="label" translatable="yes">Les donn&#xE9;es sont extraites des infos exifs de chaque photo.
    %H : Heure
    %A : jour ex : lundi
    %a : Abr&#xE9;viation du jour ex : lun
    %d : Jour du mois ex : 01
    %B : Mois
    %b : Abr&#xE9;viation du mois ex : Jan
    %m : Num&#xE9;ro du mois
    %Y : Ann&#xE9;e ex : 2006
    %y : 2 derniers chiffres de lann&#xE9;e ex : 06
    %P : Mod&#xE8;le de lappareil
    
    Exemple : taper %Y/%B/%d/ pour des dossiers type dossier/de/base/ann&#xE9;e/mois/jour/</property>
                  </widget>
                </child>
              </widget>
            </child>
            <child>
              <widget class="GtkLabel" id="label_cadre">
                <property name="visible">True</property>
                <property name="label" translatable="yes">&lt;b&gt;Aide pour classer&lt;/b&gt;</property>
                <property name="use_markup">True</property>
              </widget>
              <packing>
                <property name="type">label_item</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <widget class="GtkHButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <widget class="GtkButton" id="bouton_fermer">
                <property name="label" translatable="yes">Fermer</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_bouton_fermer_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="expand">False</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>

aide_renom.glade :     

<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkDialog" id="dialog1">
    <property name="visible">True</property>
    <property name="border_width">5</property>
    <property name="type_hint">normal</property>
    <property name="has_separator">False</property>
    <child internal-child="vbox">
      <widget class="GtkVBox" id="dialog-vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child>
          <widget class="GtkFrame" id="cadre">
            <property name="visible">True</property>
            <property name="label_xalign">0</property>
            <property name="shadow_type">none</property>
            <child>
              <widget class="GtkAlignment" id="alignment1">
                <property name="visible">True</property>
                <property name="left_padding">12</property>
                <child>
                  <widget class="GtkLabel" id="label1">
                    <property name="visible">True</property>
                    <property name="label" translatable="yes">Il est possible de renommer les photos avec du texte simple, 
ou des donn&#xE9;es extraites des infos exifs de chaque photo. 
Les possibilit&#xE9;s sont :
    %M : Minutes
    %H : Heure
    %A : jour ex : lundi
    %a : Abr&#xE9;viation du jour ex : lun
    %d : Jour du mois ex : 01
    %B : Mois
    %b : Abr&#xE9;viation du mois ex : Jan
    %m : Num&#xE9;ro du mois
    %Y : Ann&#xE9;e ex : 2006
    %y : 2 derniers chiffres de lann&#xE9;e ex : 06</property>
                  </widget>
                </child>
              </widget>
            </child>
            <child>
              <widget class="GtkLabel" id="label_cadre">
                <property name="visible">True</property>
                <property name="label" translatable="yes">&lt;b&gt;Aide pour renommer&lt;/b&gt;</property>
                <property name="use_markup">True</property>
              </widget>
              <packing>
                <property name="type">label_item</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <widget class="GtkHButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <widget class="GtkButton" id="bouton_fermer">
                <property name="label" translatable="yes">Fermer</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_bouton_fermer_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="expand">False</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>

Interface.glade :

<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkDialog" id="MainWindow">
    <property name="width_request">650</property>
    <property name="visible">True</property>
    <property name="border_width">5</property>
    <property name="type_hint">normal</property>
    <property name="has_separator">False</property>
    <signal name="destroy" handler="on_MainWindow_destroy"/>
    <child internal-child="vbox">
      <widget class="GtkVBox" id="dialog-vbox">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child>
          <widget class="GtkHBox" id="hbox1">
            <property name="visible">True</property>
            <property name="resize_mode">immediate</property>
            <property name="spacing">6</property>
            <child>
              <widget class="GtkAspectFrame" id="Controles">
                <property name="visible">True</property>
                <property name="label_xalign">0</property>
                <property name="shadow_type">none</property>
                <property name="yalign">0</property>
                <child>
                  <widget class="GtkVBox" id="vbox1">
                    <property name="visible">True</property>
                    <property name="spacing">12</property>
                    <child>
                      <widget class="GtkFrame" id="provenance_frame">
                        <property name="visible">True</property>
                        <property name="label_xalign">0</property>
                        <child>
                          <widget class="GtkAlignment" id="alignment1">
                            <property name="visible">True</property>
                            <property name="left_padding">12</property>
                            <child>
                              <widget class="GtkVBox" id="vbox2">
                                <property name="visible">True</property>
                                <child>
                                  <widget class="GtkCheckButton" id="gphotoappselect">
                                    <property name="label" translatable="yes">Appareil d&#xE9;tect&#xE9; par gphoto2</property>
                                    <property name="visible">True</property>
                                    <property name="sensitive">False</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                    <signal name="toggled" handler="on_gphotoappselect_toggled"/>
                                  </widget>
                                  <packing>
                                    <property name="position">0</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkLabel" id="labelgphoto">
                                    <property name="height_request">48</property>
                                    <property name="visible">True</property>
                                    <property name="justify">fill</property>
                                  </widget>
                                  <packing>
                                    <property name="position">1</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkCheckButton" id="importdossierselect">
                                    <property name="label" translatable="yes">Dossier &#xE0; importer</property>
                                    <property name="visible">True</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                    <signal name="toggled" handler="on_importdossierselect_toggled"/>
                                  </widget>
                                  <packing>
                                    <property name="position">2</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkFileChooserButton" id="dossierimport">
                                    <property name="visible">True</property>
                                    <property name="action">select-folder</property>
                                  </widget>
                                  <packing>
                                    <property name="fill">False</property>
                                    <property name="position">3</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkHSeparator" id="hseparator1">
                                    <property name="height_request">6</property>
                                    <property name="visible">True</property>
                                  </widget>
                                  <packing>
                                    <property name="expand">False</property>
                                    <property name="position">4</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkCheckButton" id="importall">
                                    <property name="label" translatable="yes">Tout importer ?</property>
                                    <property name="visible">True</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                  </widget>
                                  <packing>
                                    <property name="position">5</property>
                                  </packing>
                                </child>
                              </widget>
                            </child>
                          </widget>
                        </child>
                        <child>
                          <widget class="GtkLabel" id="label1">
                            <property name="visible">True</property>
                            <property name="label" translatable="yes">&lt;b&gt;Provenance&lt;/b&gt;</property>
                            <property name="use_markup">True</property>
                          </widget>
                          <packing>
                            <property name="type">label_item</property>
                          </packing>
                        </child>
                      </widget>
                      <packing>
                        <property name="fill">False</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <widget class="GtkFrame" id="repbase_frame">
                        <property name="visible">True</property>
                        <property name="label_xalign">0</property>
                        <child>
                          <widget class="GtkAlignment" id="alignment2">
                            <property name="visible">True</property>
                            <property name="left_padding">12</property>
                            <child>
                              <widget class="GtkVBox" id="vbox3">
                                <property name="visible">True</property>
                                <child>
                                  <widget class="GtkLabel" id="label5">
                                    <property name="visible">True</property>
                                    <property name="label" translatable="yes">R&#xE9;pertoire de base</property>
                                  </widget>
                                  <packing>
                                    <property name="position">0</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkFileChooserButton" id="dossierbase">
                                    <property name="visible">True</property>
                                    <property name="action">select-folder</property>
                                  </widget>
                                  <packing>
                                    <property name="fill">False</property>
                                    <property name="position">1</property>
                                  </packing>
                                </child>
                              </widget>
                            </child>
                          </widget>
                        </child>
                        <child>
                          <widget class="GtkLabel" id="label2">
                            <property name="visible">True</property>
                            <property name="label" translatable="yes">&lt;b&gt;R&#xE9;pertoire de base&lt;/b&gt;</property>
                            <property name="use_markup">True</property>
                          </widget>
                          <packing>
                            <property name="type">label_item</property>
                          </packing>
                        </child>
                      </widget>
                      <packing>
                        <property name="fill">False</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                    <child>
                      <widget class="GtkFrame" id="actions_frame">
                        <property name="visible">True</property>
                        <property name="label_xalign">0</property>
                        <child>
                          <widget class="GtkAlignment" id="alignment3">
                            <property name="visible">True</property>
                            <property name="left_padding">12</property>
                            <child>
                              <widget class="GtkVBox" id="vbox4">
                                <property name="visible">True</property>
                                <child>
                                  <widget class="GtkCheckButton" id="renommerphotoselect">
                                    <property name="label" translatable="yes">Renommer les photos</property>
                                    <property name="visible">True</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                    <signal name="toggled" handler="on_renommerphotoselect_toggled"/>
                                  </widget>
                                  <packing>
                                    <property name="position">0</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkHBox" id="hbox2">
                                    <property name="visible">True</property>
                                    <child>
                                      <widget class="GtkEntry" id="renompattern">
                                        <property name="visible">True</property>
                                        <property name="can_focus">True</property>
                                        <property name="text" translatable="yes">%H-%M-%name</property>
                                      </widget>
                                      <packing>
                                        <property name="position">0</property>
                                      </packing>
                                    </child>
                                    <child>
                                      <widget class="GtkHButtonBox" id="hbuttonbox1">
                                        <property name="visible">True</property>
                                        <child>
                                          <widget class="GtkButton" id="aiderenom">
                                            <property name="label" translatable="yes">Aide</property>
                                            <property name="visible">True</property>
                                            <property name="can_focus">True</property>
                                            <property name="receives_default">True</property>
                                            <signal name="clicked" handler="on_aiderenom_clicked"/>
                                          </widget>
                                          <packing>
                                            <property name="expand">False</property>
                                            <property name="fill">False</property>
                                            <property name="position">0</property>
                                          </packing>
                                        </child>
                                      </widget>
                                      <packing>
                                        <property name="position">1</property>
                                      </packing>
                                    </child>
                                  </widget>
                                  <packing>
                                    <property name="fill">False</property>
                                    <property name="position">1</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkCheckButton" id="classerphotoselect">
                                    <property name="label" translatable="yes">Classer les photos</property>
                                    <property name="visible">True</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                    <signal name="toggled" handler="on_classerphotoselect_toggled"/>
                                  </widget>
                                  <packing>
                                    <property name="position">2</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkHBox" id="hbox3">
                                    <property name="visible">True</property>
                                    <child>
                                      <widget class="GtkEntry" id="classpattern">
                                        <property name="visible">True</property>
                                        <property name="can_focus">True</property>
                                        <property name="text" translatable="yes">%Y/%B/%d/</property>
                                      </widget>
                                      <packing>
                                        <property name="position">0</property>
                                      </packing>
                                    </child>
                                    <child>
                                      <widget class="GtkHButtonBox" id="hbuttonbox2">
                                        <property name="visible">True</property>
                                        <child>
                                          <widget class="GtkButton" id="aideclass">
                                            <property name="label" translatable="yes">Aide</property>
                                            <property name="visible">True</property>
                                            <property name="can_focus">True</property>
                                            <property name="receives_default">True</property>
                                            <signal name="clicked" handler="on_aideclass_clicked"/>
                                          </widget>
                                          <packing>
                                            <property name="expand">False</property>
                                            <property name="fill">False</property>
                                            <property name="position">0</property>
                                          </packing>
                                        </child>
                                      </widget>
                                      <packing>
                                        <property name="position">1</property>
                                      </packing>
                                    </child>
                                  </widget>
                                  <packing>
                                    <property name="fill">False</property>
                                    <property name="position">3</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkCheckButton" id="creercatalogueselect">
                                    <property name="label" translatable="yes">Cr&#xE9;er un dossier catalogue</property>
                                    <property name="visible">True</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                    <signal name="toggled" handler="on_creercatalogueselect_toggled"/>
                                  </widget>
                                  <packing>
                                    <property name="position">4</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkFileChooserButton" id="dossiercatalogue">
                                    <property name="visible">True</property>
                                    <property name="action">select-folder</property>
                                  </widget>
                                  <packing>
                                    <property name="fill">False</property>
                                    <property name="position">5</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkCheckButton" id="pivoterselect">
                                    <property name="label" translatable="yes">Pivoter .jpg selon exifs</property>
                                    <property name="visible">True</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                    <signal name="toggled" handler="on_pivoterselect_toggled"/>
                                  </widget>
                                  <packing>
                                    <property name="position">6</property>
                                  </packing>
                                </child>
                                <child>
                                  <widget class="GtkCheckButton" id="objectifcr2select">
                                    <property name="label" translatable="yes">Objectif dans les .cr2</property>
                                    <property name="visible">True</property>
                                    <property name="can_focus">True</property>
                                    <property name="receives_default">False</property>
                                    <property name="draw_indicator">True</property>
                                    <signal name="toggled" handler="on_objectifcr2select_toggled"/>
                                  </widget>
                                  <packing>
                                    <property name="position">7</property>
                                  </packing>
                                </child>
                              </widget>
                            </child>
                          </widget>
                        </child>
                        <child>
                          <widget class="GtkLabel" id="label3">
                            <property name="visible">True</property>
                            <property name="label" translatable="yes">&lt;b&gt;Actions &#xE0; effectuer&lt;/b&gt;</property>
                            <property name="use_markup">True</property>
                          </widget>
                          <packing>
                            <property name="type">label_item</property>
                          </packing>
                        </child>
                      </widget>
                      <packing>
                        <property name="fill">False</property>
                        <property name="position">2</property>
                      </packing>
                    </child>
                  </widget>
                </child>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkFrame" id="selection_frame">
                <property name="visible">True</property>
                <property name="label_xalign">0</property>
                <child>
                  <widget class="GtkVBox" id="vbox5">
                    <property name="visible">True</property>
                    <child>
                      <widget class="GtkScrolledWindow" id="scrolledwindow1">
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <child>
                          <widget class="GtkIconView" id="iconview">
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="selection_mode">multiple</property>
                            <property name="row_spacing">1</property>
                            <property name="column_spacing">1</property>
                            <property name="margin">1</property>
                          </widget>
                        </child>
                      </widget>
                      <packing>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <widget class="GtkHButtonBox" id="hbuttonbox3">
                        <property name="height_request">36</property>
                        <property name="visible">True</property>
                        <property name="spacing">5</property>
                        <property name="layout_style">end</property>
                        <child>
                          <widget class="GtkButton" id="select_all_bouton">
                            <property name="label" translatable="yes">Tout s&#xE9;lectionner</property>
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="receives_default">True</property>
                            <signal name="clicked" handler="on_select_all_bouton_clicked"/>
                          </widget>
                          <packing>
                            <property name="expand">False</property>
                            <property name="fill">False</property>
                            <property name="position">0</property>
                          </packing>
                        </child>
                        <child>
                          <widget class="GtkButton" id="rafrachir_bouton">
                            <property name="label" translatable="yes">Rafra&#xEE;chir</property>
                            <property name="visible">True</property>
                            <property name="can_focus">True</property>
                            <property name="receives_default">True</property>
                            <signal name="clicked" handler="on_rafrachir_bouton_clicked"/>
                          </widget>
                          <packing>
                            <property name="expand">False</property>
                            <property name="fill">False</property>
                            <property name="position">1</property>
                          </packing>
                        </child>
                      </widget>
                      <packing>
                        <property name="expand">False</property>
                        <property name="pack_type">end</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                  </widget>
                </child>
                <child>
                  <widget class="GtkLabel" id="selection_label">
                    <property name="visible">True</property>
                    <property name="label" translatable="yes">&lt;b&gt;S&#xE9;lection&lt;/b&gt;</property>
                    <property name="use_markup">True</property>
                  </widget>
                  <packing>
                    <property name="type">label_item</property>
                  </packing>
                </child>
              </widget>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <widget class="GtkHButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <widget class="GtkButton" id="Go">
                <property name="label" translatable="yes">Go !</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_Go_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <widget class="GtkButton" id="Fermer">
                <property name="label" translatable="yes">Fermer</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_Fermer_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">1</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="expand">False</property>
            <property name="fill">False</property>
            <property name="pack_type">end</property>
            <property name="position">1</property>
          </packing>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>

Progress.glade :

<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkDialog" id="dialog1">
    <property name="visible">True</property>
    <property name="border_width">5</property>
    <property name="type_hint">normal</property>
    <property name="has_separator">False</property>
    <signal name="destroy" handler="on_dialog1_destroy"/>
    <child internal-child="vbox">
      <widget class="GtkVBox" id="dialog-vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child>
          <widget class="GtkLabel" id="info_label">
            <property name="visible">True</property>
            <property name="label" translatable="yes">label</property>
          </widget>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <widget class="GtkProgressBar" id="progressbar1">
            <property name="visible">True</property>
          </widget>
          <packing>
            <property name="fill">False</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <widget class="GtkLabel" id="progress_label">
            <property name="visible">True</property>
            <property name="xalign">0</property>
          </widget>
          <packing>
            <property name="position">3</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <widget class="GtkHButtonBox" id="dialog-action_area1">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <widget class="GtkButton" id="stop_button">
                <property name="label" translatable="yes">Fermer</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_stop_button_clicked"/>
              </widget>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
          </widget>
          <packing>
            <property name="expand">False</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </widget>
    </child>
  </widget>
</glade-interface>

Pour le lancer, copier les fichiers dans un meme dossier (avec les bons noms), chmod +x sur importphotos.py et le lancer en console de preference (y'aura surement plein d'erreurs !)

Hors ligne

#3 Le 05/05/2009, à 21:49

l e . n o x

Re : [python, pygtk] Import de photos via gphoto2

Bonsoir smile

J'aime bien les commentaires dans ton code big_smile

Bon !! voici mes premières remontées d'info wink

@ordiportable:~$ '/home/xxx/Bureau/Script.sh' 
Traceback (most recent call last):
  File "/home/xxx/Bureau/Script.sh", line 552, in <module>
    Gui = Interface()                                                          #Initialise l'interface
  File "/home/xxxx/Bureau/Script.sh", line 196, in __init__
    self.testapp()
  File "/home/xxx/Bureau/Script.sh", line 200, in testapp
    gphoto2 = subprocess.Popen(["gphoto2", "--auto-detect"], stdout=subprocess.PIPE)
  File "/usr/lib/python2.6/subprocess.py", line 595, in __init__
    errread, errwrite)
  File "/usr/lib/python2.6/subprocess.py", line 1092, in _execute_child
    raise child_exception
OSError: [Errno 2] Aucun fichier ou dossier de ce type

Bonne continuation, cool comme taf wink

Dernière modification par l e . n o x (Le 05/05/2009, à 21:49)


Zik Fan : " Vous seul savez mieux que quiconque comment organiser votre bibliothèque musicale ! "

Linux, y a moins bien.
Mais c'est plus cher. ;O)

Hors ligne

#4 Le 07/05/2009, à 23:23

Aurel07

Re : [python, pygtk] Import de photos via gphoto2

C'est que gphoto2 n'est pas installé ! Un sudo apt-get install gphoto2 devrait resoudre le probleme.
D'ailleurs, je serais interesse de voir ce que te donne la commande "gphoto2 --auto-detect", surtout si tu as autre chose qu'un canon 350D.
Merci du retour !

Hors ligne

#5 Le 08/05/2009, à 00:57

l e . n o x

Re : [python, pygtk] Import de photos via gphoto2

Bonsoir Aurel07 smile

En effet après un petit

sudo apt-get install gphoto2

tout est rentré dans l'ordre, l'interface ce lance .... (sans appareil photos connectés)
Mais,ben c normal il y a un mais smile voici ce qui suit, avec 2 appareils photos differents :

ordiportable:~$ '/home/xxxx/Bureau/Script.py' 
Traceback (most recent call last):
  File "/home/xxxx/Bureau/Script.py", line 552, in <module>
    Gui = Interface()                                                          #Initialise l'interface
  File "/home/xxxx/Bureau/Script.py", line 196, in __init__
    self.testapp()
  File "/home/xxxx/Bureau/Script.py", line 205, in testapp
    affiche_app = gphoto2_result.splitlines()[3]                        #on attrape le nom de l'appareil
IndexError: list index out of range

Voici le feedback suite à un "gphoto2 --auto-detect"

Pour le Canon IXUS60

ordiportable:~$ gphoto2 --auto-detect
Modèle                        Port                                             
----------------------------------------------------------
Canon Digital IXUS 60 (PTP mode) usb:

et un de plus pour la route, le Canon IXUS70

ordiportable:~$ gphoto2 --auto-detect
Modèle                        Port                                             
----------------------------------------------------------
Canon Digital IXUS 70 (PTP mode) usb:

En espèrent que cela sera suffisant pour tes tests big_smile

Je vais jeter un coup d'oeil de plus pres sur ton code cela m'apprendra surement des choses, car il y a certaine chose comme le fait de faire évoluer la "progresse barre" ainsi que les autoscroll dans un "textview" me dépasse grandement.

Si cela ne te prends pas trop de temps pourrez tu m'aiguiller ou au mieux corriger ce bout de code pour que la progess barre et l'Autoscroll fonctione sur cette GUI ?
1241460042.png

Post et code visible ici : http://forum.ubuntu-fr.org/viewtopic.php?pid=2617512#p2617512

Merci et bon week end prolongé wink

Dernière modification par l e . n o x (Le 08/05/2009, à 01:03)


Zik Fan : " Vous seul savez mieux que quiconque comment organiser votre bibliothèque musicale ! "

Linux, y a moins bien.
Mais c'est plus cher. ;O)

Hors ligne

#6 Le 08/05/2009, à 12:59

Aurel07

Re : [python, pygtk] Import de photos via gphoto2

En effet, je vois ou se situe le probleme. Chez moi, y'a 4 lignes pour cette commande, et je prenais la derniere (ligne 3 (vu qu'on part de 0)) :

Modèle                        Port                                             
----------------------------------------------------------
Canon Digital Rebel XT (normal mode) usb:            
Canon Digital Rebel XT (normal mode) usb:002,004

Du coup, il suffit de changer le [3] en [2] a la ligne 205 du script python.

Je regarderai ton prog, voir si je peux aider !

Hors ligne

#7 Le 08/05/2009, à 23:34

l e . n o x

Re : [python, pygtk] Import de photos via gphoto2

Bonsoir Aurel07 smile

Du coup, il suffit de changer le [3] en [2] a la ligne 205 du script python

Modifs effectués, en effet l'appareil photo est correctement détecter aucunes erreurs en retour wink

INSTALLATION :
Sous Jaunty, voici a première vu toutes les dépendances nécessaires :

sudo apt-get install python python-pyexiv2 gphoto2 python-gtk2

Voici le soft à télécharger sous forme d'archive : http://ordiboy.free.fr/open/Linux/AurelPhoto/AurelPhoto.0.2.tar.gz

A tous les testeurs, prés feu partez .... big_smile

Si python-pyexiv2 n'est pas installé voici l'erreur :

Traceback (most recent call last):
  File "/home/xxxx/Bureau/Photo2/Photo2.py", line 458, in action
    Gui.image_exif = pyexiv2.Image(Gui.image)
NameError: global name 'pyexiv2' is not defined

Petit feedback pour ce soir :

ce qui fonctionne avec ma config pour ce soir :
- La GUI
- La détection de l'appareil photo.
- Les previews
- La barre de progression.

ce qui ne fonctionne pas encore sur ma config :
- après sélection de plusieurs ou 1 seule photo
+ option pivoter & .cr2 "décoché" ou "coché"
+ option renommer & classer "décoché" ou "coché"
L'interface se bloque (et j'ai patienté plus de 5 mins) sans avoir erreur retourné par le terminal.

EDIT : Si je coche la case Tout importer cela démarre.
- Toutes les photos sont copiées dans le dossier "Images" (meme si je choisi un autre dossier.)
-  Barre de progression OK
- Puis voici l'erreur :

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python2.6/threading.py", line 525, in __bootstrap_inner
    self.run()
  File "/home/xxx/Bureau/AurelPhoto.0.2/AurelPhoto.py", line 538, in run
    pivot()
  File "/home/xxx/Bureau/AurelPhoto.0.2/AurelPhoto.py", line 109, in pivot
    Gui.image_exif.writeMetadata()
IOError: IMG_1094.JPG: Failed to open the data source:  (2)

En esperant que cela pourra aider smile

Bonne soirée et merci beaucoup pour le coup de pousse avec la GUI de DivFix  big_smile

Dernière modification par l e . n o x (Le 08/05/2009, à 23:59)


Zik Fan : " Vous seul savez mieux que quiconque comment organiser votre bibliothèque musicale ! "

Linux, y a moins bien.
Mais c'est plus cher. ;O)

Hors ligne

#8 Le 21/05/2009, à 11:41

Aurel07

Re : [python, pygtk] Import de photos via gphoto2

Salut,

Je viens de faire quelques modifs (j'ai ete bien occupe la semaine derniere, pas le temps d'arranger le programme...). Ca corrigera le dernier probleme (celui avec les exifs qui veulent pas s'ecrire) (en fait, si les exifs ne veulent pas s'ecrire, je passe (try, except, pass)) plus 2 ou 3 autres, mais pour le reste, ca se passe tres bien chez moi... alors j'ai du mal a voir ce qu'il faudrait corriger...
je vais essayer sur ma debian un de ces 4, voir si c'est different.

Voila le code (les .glade ne changent pas) :

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# Licence : GPLv3 voir : http://gplv3.fsf.org/
# Dependances : python, gtk2, pygtk, libjpeg-progs, gphoto2, pyexiv2

try:
    import os, sys
    import subprocess
    import shutil
    import gobject
    import time
    import threading
except:    
    print('Un problème est survenu, les bibliothèques python de base semblent manquer...\n(Ré)installer python semble une bonne idée.')
    sys.exit(1)    
    
try:
    import gtk
    import gtk.glade
    import pygtk
    pygtk.require("2.0")
except:
    print('gtk2 et libglade doivent etre installés')
    sys.exit(1)
      
try:   
    import pyexiv2    #Il faut pyexiv v.1.3 minimum pour pouvoir lire les lenstype dans les exifs.
    import Image      #Necessaire pour tourner les images
    import time
except:
    pass
    
gobject.threads_init()        #Pour que les threads soient lancés au moment opportun.
        
        
#############################################    
####  Fonctions agissant sur les photos  ####
#############################################        
        
def renom():
    #Fonction pour renommer les photos
    ext_det = Gui.image.split('.')
    ext = ext_det[len(ext_det) - 1]
    nom = ext_det[0]
    pattern_mod = Gui.renom_pattern.replace('%name', nom)
    nombis = Gui.date.strftime(pattern_mod) + '.' + ext
    os.rename(Gui.image, nombis)
    Gui.image = nombis
        
     
def lenstype():
    #Fonction pour rajouter le lenstype dans les exifs. 
    #C'est bien pour les Canon 350D qui ne le font pas automatiquement, et ca permet d'avoir la correction d'abheration avec DPP
    lens = Gui.image_exif.interpretedExifValue('Exif.CanonCs.Lens')
    lenstype_dic={"18.0 - 55.0" : 45, "200.0" : 151, "50.0" : 1}   #Dictionnaire des lenstype, a compléter bien sur !
    Gui.image_exif['Exif.CanonCs.Lens'] = lenstype_dic[lens]
    Gui.image_exif.writeMetadata()      
             
             
def pivot():
    #Fonction pour pivoter les images selon les données exifs. 
    #A la fin, la donnée exifs d'orientation est toujours mise a 1, c'est a dire que la premiere ligne de pixel est en haut, et la premiere colonne a gauche.
    #Meriterait une simplification
    orient = 0
    try:
        orient = Gui.image_exif["Exif.Image.Orientation"]      #Cf le manuel d'exifs pour comprendre les significations des chiffres
    except:
        pass
        
    if orient == 2:
        subprocess.Popen(["jpegtran", "-flip", "horizontal", "-copy", "all", "-outfile", "tmp", Gui.image])  #je prefere passer par jpegtran, je maitrise pas PIL
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 3:
        a=subprocess.Popen(["jpegtran", "-rotate", "180", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 4:
        a=subprocess.Popen(["jpegtran", "-flip", "vertical", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 5:
        a=subprocess.Popen(["jpegtran", "-flip", "horizontal", "-copy", "all", "-outfile", "tmp1", Gui.image])
        a.wait()
        a=subprocess.Popen(["jpegtran", "-rotate", "270", "-copy", "all", "-outfile", "tmp", "tmp1"])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 6:
        a=subprocess.Popen(["jpegtran", "-rotate", "90", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 7:
        a=subprocess.Popen(["jpegtran", "-flip", "horizontal", "-copy", "all", "-outfile", "tmp1", Gui.image])
        a.wait()
        a=subprocess.Popen(["jpegtran", "-rotate", "90", "-copy", "all", "-outfile", "tmp", "tmp1"])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    if orient == 8:
        a=subprocess.Popen(["jpegtran", "-rotate", "270", "-copy", "all", "-outfile", "tmp", Gui.image])
        a.wait()
        os.rename("tmp", Gui.image)
        Gui.image_exif["Exif.Image.Orientation"]=1
    
    try:
        Gui.image_exif.writeMetadata()
    except:
        print("erreur d'écriture des metadonnées")
            
        
def classe():
    #Pour classer (ca deplace les images dans le dossier approprié
    Gui.repclasse = Gui.date.strftime(Gui.classe_pattern)
    if not os.path.isdir(Gui.basedossier + "/" + Gui.repclasse):
        os.makedirs(Gui.basedossier + "/" + Gui.repclasse)
    shutil.move(Gui.image, Gui.basedossier + "/" + Gui.repclasse) 
        
        
def catalogue():
    #Créer les liens dans un dossier catalogue.
    if not os.path.isdir(Gui.dossier_catalogue):
        os.makedirs(Gui.dossier_catalogue)
       
    if Gui.classerphotoselect.get_active():
        os.symlink(Gui.basedossier + "/" + Gui.repclasse + "/" + Gui.image, Gui.dossier_catalogue + "/" + Gui.image)
    else:
        os.symlink(Gui.basedossier + "/"+ Gui.image, Gui.dossier_catalogue + "/" + Gui.image)
        

###########################################    
####  Classe de la fenetre principale  ####
###########################################        
     
class Interface:
    """Mon programme d'import de photos depuis mon Canon 350D"""

    def __init__(self):     
        #Set the Glade file
        self.gui=gtk.glade.XML(install_dossier + "/Interface.glade")
         
        #Dans la foulee on chope la fenetre principale, ca sert a rien c'est pour
        #montrer qu'on peut le faire c'est tout ^^
        self.win=self.gui.get_widget("MainWindow")
        self.win.set_title('PympPhotos')
       
                
        #On chope le reste, et ca, ca va servir...
        self.gphotoappselect = self.gui.get_widget("gphotoappselect")  
        self.labelgphoto = self.gui.get_widget("labelgphoto")
        self.importdossierselect = self.gui.get_widget("importdossierselect")
        self.iconview = self.gui.get_widget("iconview")
        self.dossierimport = self.gui.get_widget("dossierimport")
        self.dossierbase = self.gui.get_widget("dossierbase")
        self.renommerphotoselect = self.gui.get_widget("renommerphotoselect")
        self.classerphotoselect = self.gui.get_widget("classerphotoselect")
        self.creercatalogueselect = self.gui.get_widget("creercatalogueselect")
        self.renompattern = self.gui.get_widget("renompattern")
        self.classpattern = self.gui.get_widget("classpattern")
        self.pivoterselect = self.gui.get_widget("pivoterselect")
        self.objectifcr2select = self.gui.get_widget("objectifcr2select")
        self.dossiercatalogue = self.gui.get_widget("dossiercatalogue")
        self.importall = self.gui.get_widget("importall")   
        
        #On relie les signaux (cliques sur boutons, cochage des cases, ...) aux fonctions appropriées
        dic = { "on_MainWindow_destroy" : gtk.main_quit,
                "on_Fermer_clicked" : gtk.main_quit,
                "on_Go_clicked" : self.go_clicked,
                "on_rafrachir_bouton_clicked" : self.rafraichir_clicked,
                "on_select_all_bouton_clicked" : self.select_all, 
                "on_aiderenom_clicked" : self.aiderenom_fenetre,
                "on_aideclass_clicked" : self.aideclass_fenetre
                }
                                
        #Auto-connection des signaux (ca fait un peu film de SF)        
        self.gui.signal_autoconnect(dic)
                
        #création des repertoires necessaires
        self.home_path = os.environ['HOME']
        self.importphotos_path = self.home_path + "/.importphotos"
        self.thumbs_path = self.importphotos_path + "/thumbs"
        if not os.path.isdir(self.importphotos_path):
            os.makedirs(self.importphotos_path)
        if not os.path.isdir(self.thumbs_path):
            os.makedirs(self.thumbs_path)
                        
        #set-up des valeurs par defaut    
        self.dossierimport.set_filename("/media")
        self.dossierbase.set_filename(self.home_path + "/Images/Photos")
        self.dossiercatalogue.set_filename(self.home_path)
        self.classerphotoselect.set_active(True)
        self.objectifcr2select.set_active(True)
        self.pivoterselect.set_active(True)
                
        #Test préliminaire au lancement, pour voir si un appareil est connecté          
        self.testapp()
                                               
    def testapp(self):
        #Comme y'a pas de bindings pour python de libgphoto2, on est obligés de passer par le programme gphoto2
        gphoto2 = subprocess.Popen(["gphoto2", "--auto-detect"], stdout=subprocess.PIPE)
        gphoto2_result = gphoto2.stdout.read()
               
        #Teste la presence d'un appareil photo par gphoto2 et l'affiche dans labelgphoto
        if (gphoto2_result.count("\n")>2):                                      #Si appareil photo present...
            affiche_app = gphoto2_result.splitlines()[2]                        #on attrape le nom de l'appareil
            self.labelgphoto.set_text(affiche_app)                              #Affiche l'appareil en dessous de la case a cocher
            self.gphotoappselect.set_sensitive(True)                            #Rend la case a cocher sensible
            self.gphotoappselect.set_active(True)                               #selectionne par defaut
        else:
            self.labelgphoto.set_text("Pas d'appareil détecté")                 #Sinon, "pas d'appareil" est affiché.
                                 
    def rafraichir_clicked(self, widget):
        self.rafraichir = Progress_rafraichir()                                 #On "instancie" la classe de progression du rafraichissement des icones
                    
    def select_all(self, widget):
        self.iconview.select_all()
   
    def go_clicked(self, widget):                                               #On "instancie" la classe de progression de l'import
        self.progress_action = Progress_action()
        
    def aiderenom_fenetre(self, widget):                                        #Fenetre d'aide pour remplir renommer les photos
        a=AideRenom()
    
    def aideclass_fenetre(self, widget):                                        #Pareil mais pour les classer...
        b=AideClass()
        

##################################    
####  Aide pour le renommage  ####
##################################

class AideRenom:

    def __init__(self):
        #Initialisation de l'interface de la fenetre 
        self.fenetre = gtk.glade.XML(install_dossier + "/aide_renom.glade")         #Tout est dans le fichier glade
        self.dialog=self.fenetre.get_widget("dialog1")
        self.dic1 = {"on_bouton_fermer_clicked" : self.fermeture, 
                     "on_dialog1_destroy" : self.fermeture}
        self.fenetre.signal_autoconnect(self.dic1)

    def fermeture(self, widget):
        self.dialog.destroy()
        

#################################    
####  Aide pour le classage  ####
#################################

class AideClass:

    def __init__(self):
        #Initialisation de l'interface de la fenetre 
        self.fenetre = gtk.glade.XML(install_dossier + "/aide_class.glade") 
        self.dialog=self.fenetre.get_widget("dialog1")
        self.dic1 = {"on_bouton_fermer_clicked" : self.fermeture, 
                     "on_dialog1_destroy" : self.fermeture}
        self.fenetre.signal_autoconnect(self.dic1)
        
    def fermeture(self, widget):
        self.dialog.destroy()
        

##########################################    
####  Rafraichissement de l'iconview  ####
##########################################

class Progress_rafraichir:

    def __init__(self):
        #Initialisation de l'interface de la fenetre de progression
        self.progress = gtk.glade.XML(install_dossier + "/Progress.glade") 
        self.progress_win = self.progress.get_widget("dialog1")
        self.progress_label = self.progress.get_widget("progress_label")
        self.info_label = self.progress.get_widget("info_label")
        self.progress_bar = self.progress.get_widget("progressbar1")
        self.progress_stop_button = self.progress.get_widget("stop_button")
        
        #Dictionnaire pour fermer la fenetre
        self.dic1 = {"on_stop_button_clicked" : self.close_progress, 
                     "on_dialog1_destroy" : self.close_progress}
        self.progress.signal_autoconnect(self.dic1)
        
        #On affiche ce qu'on fait (création des icones)
        self.info_label.set_text("Création des thumbnails...")
        self.progress_label.set_text('Veuillez patienter...')
        
        self.thread_icon = Thread_Icon()                        #On prepare le thread qui va faire tout le boulot
        self.thread_icon.start()                                #On le lance
        timer = gobject.timeout_add (100, self.pulsate)         #Fait pulser la barre a intervalles reguliers 
        
        #Rq: Il n'est pas possible de faire une vraie barre de progression car lorsqu'on import avec gphoto2, 
        #c'est un seul processus qui ne rend pas la main entre les images (et du coup, on ne peut pas l'interrompre avant qu'il ai finit)
    
    def pulsate(self):
        if self.thread_icon.is_alive():             #Tant que le thread est en cours, 
            self.progress_bar.pulse()               #on fait pulser la barre
            return True                            #et on renvoie True pour que gobject.timeout recommence
        else:
            self.progress_bar.set_fraction(1)
            self.progress_bar.set_text('Thumbnails Importés!')
            self.progress_win.destroy()
            return False
            
    def close_progress(self, widget):
        #subprocess.Popen(["kill", "-9", str(self.thread_icon.pid)])   #Je sais pas pourquoi, mais ca kill l'interface principale...
        self.progress_win.destroy()
        
        

#############################################    
####  Thread de création des thumbnails  ####
#############################################       
        
        
class Thread_Icon(threading.Thread):
    def __init__(self):
        super(Thread_Icon, self).__init__()
        self.pid=os.getpid()                                                    #on chope le pid pour pouvoir le tuer apres, meme si ca marche pas...
        
    def run(self):
        Gui.list_thumbs = gtk.ListStore(str, gtk.gdk.Pixbuf, int)
        if Gui.gphotoappselect.get_active():                                   #Si l'appareil detecte par gphoto2 est selectionné...
            os.chdir(Gui.thumbs_path)                                          #On se déplace dans le dossier qui va récupérer tous les thumbs
            #On récupère les thumbnails avec l'option qui va bien de gphoto2
            gphoto_thumbs_en_cours = subprocess.Popen(["gphoto2", "-T"], stdout=subprocess.PIPE)
            gphoto2_thumb_result=gphoto_thumbs_en_cours.stdout.read()           #On recupere la sortie de l'import des thumbs
            gphoto2_list_thumbs = gphoto2_thumb_result.splitlines()
                        
            for indice in range(1, len(gphoto2_list_thumbs)):                         #Pour tous les thumbs dans la liste...
                mots = gphoto2_list_thumbs[indice-1].split(" ")
                thumb = mots[len(mots)-1]                                              #C'est le nom du thumbnail !
                pixbuf = gtk.gdk.pixbuf_new_from_file(Gui.thumbs_path + "/" + thumb)   #on creer un pixbuf
                Gui.list_thumbs.append([thumb, pixbuf, indice])                        #et on l'ajoute a la liste : 
                #le nom, le pixbuf, et un numero qui permet de savoir quelle image correspond a quel thumbnail (gphoto2, c'est un peu mal fait quand meme...)
               
        elif Gui.importdossierselect.get_active():                             #Si l'import de dossier est activé.
            Gui.impdossier = Gui.dossierimport.get_filename()                   #On récupère le path du dossier
            images_import = os.listdir(Gui.impdossier)                          #On liste les fichiers et on les trie par ordre alphabetique
            images_import.sort()
            
            for image in images_import:
                try:                                    #On passe par try, parce que les fichiers autre que les images ne passeront pas
                    pixbuf = gtk.gdk.pixbuf_new_from_file(Gui.impdossier + "/" + image)
                    height = pixbuf.get_height()
                    width = pixbuf.get_width()
                    if width >= height:                                          # redimensionnement du pixbuff en max(height, width) = 160          
                        nheight = 160*height/width
                        scaled_buf = pixbuf.scale_simple(160,nheight,gtk.gdk.INTERP_BILINEAR)
                    else:
                        nwidth = 160*width/height
                        scaled_buf = pixbuf.scale_simple(nwidth,160,gtk.gdk.INTERP_BILINEAR)
                        
                    Gui.list_thumbs.append([image, scaled_buf, 0])     #le nom, le pixbuf, et 0 pour savoir que l'image vient du dossier d'import et pas de gphoto2
                except:
                    pass
            
        #Generation de la IconView
        Gui.iconview.set_pixbuf_column(1)                              
        Gui.iconview.set_text_column(0)
       #Gui.iconview.set_item_width(180)
        Gui.iconview.set_model(Gui.list_thumbs)   
           
        #supprime les thumbnails de thumb_path
        for thumb in os.listdir(Gui.thumbs_path):
            os.remove(Gui.thumbs_path + "/" + thumb)
         
        
    
###########################################################    
####  Classe de la fenetre de progression des actions  ####
###########################################################

class Progress_action:

    def __init__(self):
        #Initialisation de l'interface de la fenetre de progression
        self.progress = gtk.glade.XML(install_dossier + "/Progress.glade") 
        self.progress_win = self.progress.get_widget("dialog1")
        self.progress_label = self.progress.get_widget("progress_label")
        self.info_label = self.progress.get_widget("info_label")
        self.progress_bar = self.progress.get_widget("progressbar1")
        self.progress_stop_button = self.progress.get_widget("stop_button")
        self.dic1 = {"on_stop_button_clicked" : self.close_progress, 
                     "on_dialog1_destroy" : self.close_progress}
        self.progress.signal_autoconnect(self.dic1)
        
        #on récupère la liste des images selectionnées
        self.selection = Gui.iconview.get_selected_items()
                
        if self.selection and not Gui.importall.get_active():      #Si on n'a pas coche la case "tout importer", alors ca va bien se passer, tu auras une barre de progression qui avance en meme temps que chaque photo est traitee, etc. Pas de probleme donc.
            self.info_label.set_label("Import en cours...")
            self.nombre_photos = len(self.selection)                #Combien y'a t'il d'images selectionnées ???
            task = self.action()                                    #Je sais pas pourquoi, mais ca marche. Cf faq de pyGTK, comment faire une progressbar
            gobject.idle_add(task.next)
        elif Gui.importall.get_active():                           #en mode tout importer, la barre de progression pulse seulement vu que le thread gphoto2 -P ne rend pas la main entre 2 photos. (et que c'est chiant de lui demander le nombre de photos)
            self.info_label.set_text("Import de toutes les photos...")
            self.progress_label.set_text('Veuillez patienter...')
            self.thread_import = Thread_Import()                    #On prepare le thread qui va faire tout le boulot
            self.thread_import.start()                              #On le lance
            timer = gobject.timeout_add (100, self.pulsate)         #Fait pulser la barre a intervalles reguliers 
        else:
            self.info_label.set_label("Pas de fichier sélectionnés")
            

    def pulsate(self):
        if self.thread_import.is_alive():           #Tant que le thread est en cours, 
            self.progress_bar.pulse()               #on fait pulser la barre
            return True                            #et on renvoie True pour que gobject.timeout recommence
        else:
            self.progress_bar.set_fraction(1)
            self.progress_bar.set_text('Images Importées!')
            return False
        
    
    def action(self):
        #recuperation des données rentrées :
        Gui.renom_pattern = Gui.renompattern.get_text()                         #comment renommer
        Gui.classe_pattern = Gui.classpattern.get_text()                        #comment classer
        Gui.dossier_catalogue = Gui.dossiercatalogue.get_filename()             #comment classer
        Gui.basedossier = Gui.dossierbase.get_filename()                        #on recupere le dossier de base
        os.chdir(Gui.basedossier)                                               #on se place dans ce dossier
        
        numero = 1
        
        for index in self.selection:                                           # Pout chaque image selectionnée...
            thumb_carac = Gui.list_thumbs[index[0]]                             #recuperer le nom et le numero associés aux thumbnails
            nom = thumb_carac[0]
            num = thumb_carac[2]
            
            if num == 0:                                                       #alors, c'est un importdossier
                shutil.copy2(Gui.impdossier + "/" + nom, Gui.basedossier)      #on copie dans le dossier de base
                Gui.image=nom                                                  #Nom de l'image
                Gui.image_exif = pyexiv2.Image(Gui.image)                      #Exifs de l'image
                Gui.image_exif.readMetadata()
                try:
                    Gui.date = Gui.image_exif['Exif.Image.DateTime']               #Date de creation par les exifs
                except:
                    Gui.date = 0
                
                if Gui.renommerphotoselect.get_active() and Gui.date:
                    renom()
                if Gui.objectifcr2select.get_active() and Gui.image.endswith((".CR2", ".cr2")):
                    lenstype()
                if Gui.pivoterselect.get_active() and Gui.image.endswith((".JPG", ".jpg", ".jpeg", ".JPEG")):
                    pivot()
                if Gui.classerphotoselect.get_active() and Gui.date:
                    classe()
                if Gui.creercatalogueselect.get_active():
                    catalogue()
                
            elif num > 0:                               #alors c'est par gphoto2
                gphoto_import_process = subprocess.Popen(["gphoto2", "-p", str(num)], stdout=subprocess.PIPE)
                gphoto_import_process.wait()
                gphoto_import_result = gphoto_import_process.stdout.read()
                a = gphoto_import_result.split(' ')
                Gui.image = a[len(a)-1].split("\n")[0]
                Gui.image_exif = pyexiv2.Image(Gui.image)
                Gui.image_exif.readMetadata()
                try:
                    Gui.date = Gui.image_exif['Exif.Image.DateTime']               #Date de creation par les exifs
                except:
                    Gui.date = 0
                
                if Gui.renommerphotoselect.get_active():
                    renom()
                if Gui.objectifcr2select.get_active() and Gui.image.endswith((".CR2", ".cr2")):
                    lenstype()
                if Gui.pivoterselect.get_active() and Gui.image.endswith((".JPG", ".jpg", ".jpeg", ".JPEG")):
                    pivot()
                if Gui.classerphotoselect.get_active():
                    classe()
                if Gui.creercatalogueselect.get_active():
                    catalogue()
            
            fraction = float(numero) / self.nombre_photos                              # Faut faire avancer la barre de défilement
            self.progress_bar.set_fraction(fraction)
            self.progress_bar.set_text(str(numero) + "/" + str(self.nombre_photos) + "Images")
            self.progress_label.set_text("Import de " + Gui.image + " terminé")
            numero = numero + 1
            yield True                                                          #quand le gobject.idle_add recoit ce True, il met a jour la fenetre
            
        yield False
        self.info_label.set_label("Import terminé !")
            
###fonction pour fermer la fenetre 
            
    def close_progress(self, widget):
        self.progress_win.destroy()


################################################    
####  Thread d'import de toutes les photos  ####
################################################

class Thread_Import(threading.Thread):
    def __init__(self):
        super(Thread_Import, self).__init__()
        self.pid=os.getpid()
        
    def run(self):           
        time.sleep(1)
        #recuperation des données rentrées :
        Gui.renom_pattern = Gui.renompattern.get_text()                         #comment renommer
        Gui.classe_pattern = Gui.classpattern.get_text()                        #comment classer
        Gui.dossier_catalogue = Gui.dossiercatalogue.get_filename()             #comment catalogue
        Gui.basedossier = Gui.dossierbase.get_filename()                        #on recupere le dossier de base
        os.chdir(Gui.basedossier)                                               #on se place dans ce dossier
                        
        if Gui.gphotoappselect.get_active(): 
            self.import_tout = subprocess.Popen(["gphoto2", "-P"])              #Importe toutes les photos via gphoto2
            self.import_tout.wait()
                         
        elif Gui.importdossierselect.get_active(): 
            Gui.progress_action.info_label.set_label("Import des images depuis le dossier...")
            Gui.impdossier = Gui.dossierimport.get_filename()
            for Gui.image in os.listdir(Gui.impdossier):
                if Gui.image.endswith((".CR2", ".cr2", ".JPG", ".jpg", ".jpeg", ".JPEG", ".png", ".PNG", ".gif", ".GIF")):
                    shutil.copy2(Gui.impdossier + "/" + Gui.image, Gui.basedossier)
                                    
        liste_image1 = os.listdir(Gui.basedossier)
        liste_image=[]        
        for i in liste_image1:
            if i.endswith((".CR2", ".cr2", ".JPG", ".jpg", ".jpeg", ".JPEG", ".png", ".PNG", ".gif", ".GIF")):
                liste_image.append(i)
                
        for Gui.image in liste_image:
            Gui.image_exif = pyexiv2.Image(Gui.image)                          #Exifs de l'image
            Gui.image_exif.readMetadata()
            try:
                Gui.date = Gui.image_exif['Exif.Image.DateTime']               #Date de creation par les exifs
            except:
                Gui.date = 0
               
            if Gui.renommerphotoselect.get_active() and Gui.date:
                renom()
            if Gui.objectifcr2select.get_active() and Gui.image.endswith((".CR2", ".cr2")):
                lenstype()
            if Gui.pivoterselect.get_active() and Gui.image.endswith((".JPG", ".jpg", ".jpeg", ".JPEG")):
                pivot()
            if Gui.classerphotoselect.get_active() and Gui.date:
                classe()
            if Gui.creercatalogueselect.get_active():
                catalogue()
                
        Gui.progress_action.info_label.set_label("Import terminé !")

###########################################################    
####  Initialisation et appel de la classe principale  ####
###########################################################            
                        
if __name__ == "__main__":
    install_dossier=sys.path[0]                                                #On recupere le dossier d'install
    Gui = Interface()                                                          #Initialise l'interface
    gtk.main()                                                                 #Lance la boucle principale

PS : modifs apportées le 22 mai a 13h51, testé sur Jaunty Jackalope, pas de probleme rencontre apres quelques tests. (sudo apt-get install libjpeg-progs pour avoir le pivotage)

Dernière modification par Aurel07 (Le 22/05/2009, à 14:01)

Hors ligne