#!/usr/bin/env python # -*- coding: utf-8 -*- # Licence : GPLv3 voir : http://gplv3.fsf.org/ try: import os, sys import os.path import subprocess import shutil import gobject import time import threading import multiprocessing import re import ConfigParser import operator except: print('An error occured. Python or one of its sub modules is absent...\nIt would be wise to check your python installation.') sys.exit(1) try: import Image except: print('Python Imaging Library is missing.') try: import gtk import gtk.glade import pygtk pygtk.require("2.0") except: print('gtk2, pygtk or libglade is missing.') sys.exit(1) # Bad, bad, really bad coder... Global variables... global session_images_bak session_images_bak=[] global session_options_bak session_options_bak=[] APP = 'MacroFusion' if os.path.exists('/usr/share/mfusion/ui/DOFuseInterface.glade') \ and os.path.exists('/usr/share/mfusion/ui/Progress.glade') \ and os.path.exists('/usr/share/pixmaps/macrofusion/logoMF.png') \ and os.path.exists('/usr/share/pixmaps/macrofusion/logoSplash.png'): # print ("System wide install!") DIR = '/usr/share/locale/' IMG = '/usr/share/pixmaps/macrofusion/' UI = '/usr/share/mfusion/ui/' elif os.path.exists(sys.path[0] + "/ui/DOFuseInterface.glade"): # print ("Local run!") DIR = sys.path[0] + '/locale/' IMG = sys.path[0] + '/images/' UI = sys.path[0] + '/ui/' else: print ("That's me, your MacroFusion. Make your mind - local or system wide install?") sys.exit(1) import locale import gettext for module in (gettext, gtk.glade): module.bindtextdomain(APP, DIR) module.textdomain(APP) locale.setlocale(locale.LC_ALL, '') #gettext.bindtextdomain(APP, DIR) #gettext.textdomain(APP) #gettext.install(APP) _ = gettext.gettext gobject.threads_init() #Pour que les threads soient lancés au moment opportun. def toggled_cb(cell, path, user_data): model, column = user_data model[path][column] = not model[path][column] return # PLEASE REAPAIR!! Python-imaging can't open .tiff (or some of them) def creer_miniature(chemin,taille): outfile=donnees.previs_dossier + '/' + os.path.split(chemin)[1] try: im = Image.open(chemin) im.thumbnail(taille) im.save(outfile, "JPEG") except IOError: print _("Generating %s thumbnail failed.") % chemin return outfile #################################################### ########Classe des données########################## #################################################### class Donnees: """Données utiles""" def __init__(self): self.install_dossier=sys.path[0] #On recupere le dossier d'install self.home_dossier = (os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config')) + '/mfusion' # self.home_dossier = os.environ['HOME'] #On créé les dossiers pour mettre les preview self.enfuse_dossier = self.home_dossier self.previs_dossier = self.enfuse_dossier + "/preview" if not os.path.isdir(self.enfuse_dossier): os.makedirs(self.enfuse_dossier) if not os.path.isdir(self.previs_dossier): os.makedirs(self.previs_dossier) self.default_folder=os.path.expanduser('~/') self.default_file="" def check_install(self, name): a=False for dir in os.environ['PATH'].split(":"): prog = os.path.join(dir, name) if os.path.exists(prog): a=True return a ############################################################## ###########Classe de l'interface############################## ############################################################## class Interface: """Interface pour le logiciel d'exposition-fusion enfuse""" def __init__(self): # Set default icon gtk.window_set_default_icon_from_file(IMG + 'logoMF.png') self.cpus = multiprocessing.cpu_count() if not donnees.check_install("enfuse"): self.messageinthebottle(_("Can't find Enfuse.\nPlease check enblend/enfuse is installed.\nStopping...")) sys.exit() # Check cpus if self.cpus>1 and donnees.check_install("enfuse-mp"): print _("Will use all the powers of your CPU!") self.enfuser = "enfuse-mp" else: self.enfuser = "enfuse" #Set the Glade file self.gui=gtk.glade.XML(fname=UI + "DOFuseInterface.glade", domain=APP) #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('MacroFusion') #On chope le reste, et ca, ca va servir... self.listeimages = self.gui.get_widget("listeimages") self.buttonajoutfichiers = self.gui.get_widget("buttonajoutfichiers") self.buttonenleverfichier = self.gui.get_widget("buttonenleverfichier") self.statusbar = self.gui.get_widget("status1") self.statusbar.push(1, _("CPU Cores: %s") % self.cpus) self.hscaleexp = self.gui.get_widget("hscaleexp") self.ajus_exp = gtk.Adjustment(value=1, lower=0, upper=1, step_incr=0.1, page_incr=0.1, page_size=0) self.hscaleexp.set_adjustment(self.ajus_exp) self.spinbuttonexp = self.gui.get_widget("spinbuttonexp") self.spinbuttonexp.set_digits(1) self.spinbuttonexp.set_value(1) self.spinbuttonexp.set_adjustment(self.ajus_exp) self.hscalecont = self.gui.get_widget("hscalecont") self.ajus_cont = gtk.Adjustment(value=0, lower=0, upper=1, step_incr=0.1, page_incr=0.1, page_size=0) self.hscalecont.set_adjustment(self.ajus_cont) self.spinbuttoncont = self.gui.get_widget("spinbuttoncont") self.spinbuttoncont.set_digits(1) self.spinbuttoncont.set_value(0) self.spinbuttoncont.set_adjustment(self.ajus_cont) self.hscalesat = self.gui.get_widget("hscalesat") self.ajus_sat = gtk.Adjustment(value=0.2, lower=0, upper=1, step_incr=0.1, page_incr=0.1, page_size=0) self.hscalesat.set_adjustment(self.ajus_sat) self.spinbuttonsat = self.gui.get_widget("spinbuttonsat") self.spinbuttonsat.set_digits(1) self.spinbuttonsat.set_value(0.2) self.spinbuttonsat.set_adjustment(self.ajus_sat) self.hscalemu = self.gui.get_widget("hscalemu") self.ajus_mu = gtk.Adjustment(value=0.5, lower=0, upper=1, step_incr=0.01, page_incr=0.1, page_size=0) self.hscalemu.set_adjustment(self.ajus_mu) self.spinbuttonmu = self.gui.get_widget("spinbuttonmu") self.spinbuttonmu.set_digits(2) self.spinbuttonmu.set_value(0.5) self.spinbuttonmu.set_adjustment(self.ajus_mu) self.hscalesigma = self.gui.get_widget("hscalesigma") self.ajus_sigma = gtk.Adjustment(value=0.2, lower=0, upper=1, step_incr=0.01, page_incr=0.1, page_size=0) self.hscalesigma.set_adjustment(self.ajus_sigma) self.spinbuttonsigma = self.gui.get_widget("spinbuttonsigma") self.spinbuttonsigma.set_digits(2) self.spinbuttonsigma.set_value(0.2) self.spinbuttonsigma.set_adjustment(self.ajus_sigma) self.buttonpreview = self.gui.get_widget("buttonpreview") self.checkbuttontiff = self.gui.get_widget("checkbuttontiff") self.checkbuttonjpeg = self.gui.get_widget("checkbuttonjpeg") self.buttonfusion = self.gui.get_widget("buttonfusion") self.buttonbeforeafter = self.gui.get_widget("buttonbeforeafter") self.buttonedit = self.gui.get_widget("buttoneditw") self.imagepreview = self.gui.get_widget("imagepreview") self.imagepreview.set_from_file(IMG + "logoSplash.png") self.progressbar = self.gui.get_widget("progressbar") self.checkbuttonexif = self.gui.get_widget("checkbuttonexif") #valeurs des options et configurations : self.check_pyramidelevel = self.gui.get_widget("check_pyramidelevel") self.spinbuttonlevel = self.gui.get_widget("spinbuttonlevel") self.check_hardmask = self.gui.get_widget("check_hardmask") self.check_contwin = self.gui.get_widget("check_contwin") self.spinbuttoncontwin = self.gui.get_widget("spinbuttoncontwin") self.check_courb = self.gui.get_widget("check_courb") self.check_prctcourb = self.gui.get_widget("check_prctcourb") self.spinbuttoncourb = self.gui.get_widget("spinbuttoncourb") self.check_detecbord = self.gui.get_widget("check_detecbord") self.spinbuttonEdge = self.gui.get_widget("spinbuttonEdge") # self.spinbuttonEdge.set_value(self.conf.getint('prefs', 'w')) self.spinbuttonLceS = self.gui.get_widget("spinbuttonLceS") self.spinbuttonLceF = self.gui.get_widget("spinbuttonLceF") self.check_lces = self.gui.get_widget("check_lces") self.check_lcef = self.gui.get_widget("check_lcef") self.check_ciecam = self.gui.get_widget("check_ciecam") self.check_desatmeth = self.gui.get_widget("check_desatmeth") self.combobox_desatmet = self.gui.get_widget("combobox_desatmet") self.spinbuttonlargeurprev = self.gui.get_widget("spinbuttonlargeurprev") self.spinbuttonhauteurprev = self.gui.get_widget("spinbuttonhauteurprev") self.checkbuttoncache = self.gui.get_widget("checkbuttoncache") self.spinbuttoncache = self.gui.get_widget("spinbuttoncache") self.checkbuttonbloc = self.gui.get_widget("checkbuttonbloc") self.spinbuttonbloc = self.gui.get_widget("spinbuttonbloc") self.checkbuttontaillefinale = self.gui.get_widget("checkbuttontaillefinale") self.spinbuttonlargeurfinale = self.gui.get_widget("spinbuttonlargeurfinale") self.spinbuttonhauteurfinale = self.gui.get_widget("spinbuttonhauteurfinale") self.spinbuttonxoff = self.gui.get_widget("spinbuttonxoff") self.spinbuttonyoff = self.gui.get_widget("spinbuttonyoff") self.checkbuttonjpegorig = self.gui.get_widget("checkbuttonjpegorig") self.hscalecomprjpeg = self.gui.get_widget("hscalecomprjpeg") self.combtiff = self.gui.get_widget("combtiff") self.checkbutton_a5_align = self.gui.get_widget("checkbutton_a5_align") self.checkbutton_a5_crop = self.gui.get_widget("checkbutton_a5_crop") self.checkbutton_a5_shift = self.gui.get_widget("checkbutton_a5_shift") self.checkbutton_a5_field = self.gui.get_widget("checkbutton_a5_field") self.combobox_desatmet.set_active(0) self.combtiff.set_active(0) if not donnees.check_install('exiftool'): self.checkbuttonexif.set_sensitive(False) self.messageinthebottle(_("Exiftool is missing!\n\n Cannot copy exif info.")) if not donnees.check_install('align_image_stack'): self.checkbutton_a5_align.set_sensitive(False) self.checkbutton_a5_crop.set_sensitive(False) self.checkbutton_a5_field.set_sensitive(False) self.checkbutton_a5_shift.set_sensitive(False) #self.checkbutton_a5_align.set_sensitive(False) self.messageinthebottle(_("Hugin tools (align_image_stack) are missing !\n\n Cannot auto align images.")) # Read values from config self.conf = ConfigParser.ConfigParser() if os.path.isfile(donnees.enfuse_dossier + '/mfusion.cfg'): self.conf.read(donnees.enfuse_dossier + '/mfusion.cfg') if self.conf.has_option('prefs', 'pwidth'): self.spinbuttonlargeurprev.set_value(self.conf.getint('prefs', 'pwidth')) if self.conf.has_option('prefs', 'pheight'): self.spinbuttonhauteurprev.set_value(self.conf.getint('prefs', 'pheight')) if self.conf.has_option('prefs', 'cachebutton'): self.checkbuttoncache.set_active(self.conf.getboolean('prefs', 'cachebutton')) if self.conf.has_option('prefs', 'cachesize'): self.spinbuttoncache.set_value(self.conf.getint('prefs', 'cachesize')) if self.conf.has_option('prefs', 'blocbutton'): self.checkbuttonbloc.set_active(self.conf.getboolean('prefs', 'blocbutton')) if self.conf.has_option('prefs', 'blocsize'): self.spinbuttonbloc.set_value(self.conf.getint('prefs', 'blocsize')) if self.conf.has_option('prefs', 'outsize'): self.checkbuttontaillefinale.set_active(self.conf.getboolean('prefs', 'outsize')) if self.conf.has_option('prefs', 'outwidth'): self.spinbuttonlargeurfinale.set_value(self.conf.getint('prefs', 'outwidth')) if self.conf.has_option('prefs', 'outheight'): self.spinbuttonhauteurfinale.set_value(self.conf.getint('prefs', 'outheight')) if self.conf.has_option('prefs', 'xoff'): self.spinbuttonxoff.set_value(self.conf.getint('prefs', 'xoff')) if self.conf.has_option('prefs', 'yoff'): self.spinbuttonyoff.set_value(self.conf.getint('prefs', 'yoff')) if self.conf.has_option('prefs', 'jpegdef'): self.checkbuttonjpegorig.set_active(self.conf.getboolean('prefs', 'jpegdef')) if self.conf.has_option('prefs', 'jpegcompr'): self.hscalecomprjpeg.set_value(self.conf.getfloat('prefs', 'jpegcompr')) if self.conf.has_option('prefs', 'tiffcomp'): self.combtiff.set_active(self.conf.getint('prefs', 'tiffcomp')) if self.conf.has_option('prefs', 'exif'): self.checkbuttonexif.set_active(self.conf.getboolean('prefs', 'exif')) #On relie les signaux (cliques sur boutons, cochage des cases, ...) aux fonctions appropriées dic = { "on_mainwindow_destroy" : self.exit_app, "on_buttonannuler_clicked" : self.exit_app, "on_menufilequit_activate" : self.exit_app, "on_menufileopen_activate" : self.ouverture, "on_buttonajoutfichiers_clicked" : self.ajout, "on_menufileadd_activate" : self.ajout, "on_buttonenleverfichier_clicked" : self.ttenlever, "on_menufileenlever_activate" : self.enlever, "on_menufilettenlever_activate" : self.ttenlever, "on_buttonpreview_clicked" : self.preview, "on_menufilesave_activate" : self.fusion, "on_buttonfusion_clicked" : self.fusion, "on_buttoneditw_clicked" : self.sendto, "on_buttonbeforeafter_pressed" : self.baswitch, "on_buttonbeforeafter_released" : self.baswitch, "on_imagemenuitem10_activate" : self.apropos } #Auto-connection des signaux self.gui.signal_autoconnect(dic) #initialisation de la liste d'images a fusionner self.inittreeview() def exit_app(self, action): # cancel = self.autosave_image() # if cancel: # return True self.stop_now = True self.closing_app = True self.save_settings() self.cleanup() sys.exit(0) def cleanup(self): # os.remove(donnees.enfuse_dossier + "/session.sav") for self.files in os.walk(donnees.previs_dossier): for self.filename in self.files[2]: os.remove(donnees.previs_dossier + "/" + self.filename) def inittreeview(self): """initialisation de la liste d'images a importer""" self.liststoreimport = gtk.ListStore(bool, str, str) #création de la listestore qui contiendra les noms d'images self.listeimages.set_model(self.liststoreimport) #on donne la liststore au l'afficheur treeview self.colonneselect = gtk.TreeViewColumn('') #Premiere colonne : self.listeimages.append_column(self.colonneselect) #on l'ajoute au TreeView self.select=gtk.CellRendererToggle() #On creer le cellrender pour avoir des boutons toggle self.colonneselect.pack_start(self.select, True) #on met le cellrender dans la colonne self.colonneselect.add_attribute(self.select, 'active', 0) #on met les boutons actifs par défaut self.colonneimages = gtk.TreeViewColumn(_('Image')) #deuxieme colonne, titre 'Image' self.listeimages.append_column(self.colonneimages) #on rajoute la colonne dans le treeview self.cell = gtk.CellRendererText() #Ce sera des cellules de texte self.colonneimages.pack_start(self.cell, True) #que l'on met dans la colonne self.colonneimages.add_attribute(self.cell, 'text', 1) #et on specifie que c'est du texte simple self.select.connect("toggled", toggled_cb, (self.liststoreimport, 0)) #Pour que les boutons de selection marchent def ouverture(self, widget): FenOuv=Fenetre_Ouvrir(self.liststoreimport,0) self.liststoreimport=FenOuv.get_model() #self.raffraichissementlisteimages() def ajout(self, widget): FenOuv=Fenetre_Ouvrir(self.liststoreimport,1) self.liststoreimport=FenOuv.get_model() #self.raffraichissementlisteimages() def raffraichissementlisteimages(self): #self.listeimages.set_model(self.liststoreimport) self.treeselectionsuppr=self.listeimages.get_selection() #pour récupérer quels fichiers sont selectionnés self.treeselectionsuppr.set_mode(gtk.SELECTION_MULTIPLE) #Pour pouvoir en selectionner plusieurs def enlever(self, widget): self.treeselectionsuppr=self.listeimages.get_selection() #pour récupérer quels fichiers sont selectionnés self.treeselectionsuppr.set_mode(gtk.SELECTION_MULTIPLE) #Pour pouvoir en selectionner plusieurs (model, pathlist) = self.treeselectionsuppr.get_selected_rows() for i in pathlist: treeiter = model.get_iter(i) self.liststoreimport.remove(treeiter) def ttenlever(self, widget): self.liststoreimport.clear() def preview(self, widget): self.taille=(self.spinbuttonlargeurprev.get_value(), self.spinbuttonhauteurprev.get_value()) self.name=donnees.previs_dossier + "/" + "preview.jpg" item=0 if len(self.liststoreimport)>0: self.ref=zip(*self.liststoreimport)[0] for item in self.ref: if item: item=-1 self.thread_preview = Thread_Preview(self.taille, self.get_options(), self.get_options_align(), self.liststoreimport) self.thread_preview.start() timer = gobject.timeout_add (100, self.pulsate) break if item==0: self.messageinthebottle(_("Please add some images!\n\n Can't fuse anything.")) def get_options_align(self): self.options_align=[] if self.checkbutton_a5_align.get_active(): if self.checkbutton_a5_crop.get_active(): self.options_align.append('-C') if self.checkbutton_a5_shift.get_active(): self.options_align.append('-i') if self.checkbutton_a5_field.get_active(): self.options_align.append('-m') return self.options_align def get_options(self): options=["--exposure-weight=" + str(self.spinbuttonexp.get_value()), "--exposure-mu=" + str(self.spinbuttonmu.get_value()), "--exposure-sigma=" + str(self.spinbuttonsigma.get_value()), "--saturation-weight=" + str(self.spinbuttonsat.get_value()), "--contrast-weight=" + str(self.spinbuttoncont.get_value())] if self.check_pyramidelevel.get_active(): options.append('-l ' + str(self.spinbuttonlevel.get_value_as_int())) if self.check_hardmask.get_active(): options.append('--hard-mask') if self.check_contwin.get_active(): options.append('--contrast-window-size=' + str(self.spinbuttoncontwin.get_value_as_int())) if self.check_courb.get_active(): if self.check_prctcourb.get_active(): options.append('--contrast-min-curvature=' + str(self.spinbuttoncourb.get_value()) + "%") else: options.append('--contrast-min-curvature=' + str(self.spinbuttoncourb.get_value())) if self.check_detecbord.get_active(): opts='--contrast-edge-scale=' + str(self.spinbuttonEdge.get_value()) + ':' if self.check_lces.get_active(): opts+=str(self.spinbuttonLceS.get_value()) + '%:' else: opts+=str(self.spinbuttonLceS.get_value()) + ':' if self.check_lcef.get_active(): opts+=str(self.spinbuttonLceF.get_value()) + '%' else: opts+=str(self.spinbuttonLceF.get_value()) + '' options.append(opts) # + str(self.spinbuttonLceF.get_value()) + '%') if self.check_ciecam.get_active(): options.append('-c') if self.check_desatmeth.get_active(): opt={-1:None, 0:"average", 1:'l-star', 2:'lightness', 3:'value', 4:'luminance'} options.append('--gray-projector=' + opt[self.combobox_desatmet.get_active()]) if not self.checkbuttoncache.get_active(): options.append('-m ' + str(self.spinbuttoncache.get_value_as_int())) if not self.checkbuttonbloc.get_active(): options.append('-b ' + str(self.spinbuttonbloc.get_value_as_int())) if not self.checkbuttontaillefinale.get_active(): options.append('-f ' + str(self.spinbuttonlargeurfinale.get_value_as_int()) + 'x' + str(self.spinbuttonhauteurfinale.get_value_as_int()) + 'x' + str(self.spinbuttonxoff.get_value_as_int()) + 'x' + str(self.spinbuttonyoff.get_value_as_int())) if self.name.endswith(('.tif', '.tiff', '.TIF', '.TIFF')): tiffopt={0:"NONE", 1:"PACKBITS", 2:"LZW", 3:"DEFLATE"} options.append("--compression=" + tiffopt[self.combtiff.get_active()]) if self.name.endswith(('.jpg', '.jpeg', '.JPG', '.JPEG')) and (not self.checkbuttonjpegorig.get_active()): options.append("--compression=" + str(int(self.hscalecomprjpeg.get_value()))) return options def pulsate(self): if self.thread_preview.isAlive(): #Tant que le thread est en cours, self.progressbar.set_text(_("Calculating preview...")) self.progressbar.pulse() #on fait pulser la barre return True #et on renvoie True pour que gobject.timeout recommence else: self.progressbar.set_fraction(1) self.progressbar.set_text(_("Preview generated")) self.imagepreview.set_from_file(donnees.previs_dossier + "/" + "preview.jpg") return False def baswitch(self, widget): if (not int(self.buttonbeforeafter.get_relief())) and (os.path.exists(donnees.previs_dossier + "/preview_.jpg")): self.buttonbeforeafter.props.relief = gtk.RELIEF_NONE self.imagepreview.set_from_file(donnees.previs_dossier + "/preview_.jpg") elif os.path.exists(donnees.previs_dossier + "/preview_.jpg"): self.buttonbeforeafter.props.relief = gtk.RELIEF_NORMAL self.imagepreview.set_from_file(donnees.previs_dossier + "/preview.jpg") # self.buttonbeforeafter.set_label("gfdgdf") def fusion(self,widget): FenPar=Fenetre_Parcourir() self.name = FenPar.get_name() if self.name: if not re.search('.jpeg$|.jpg$|.tiff$', self.name, flags=re.IGNORECASE): self.name+=".jpg" self.enroute('') def sendto(self, widget): self.name=(donnees.previs_dossier + "/sendto.tif") if self.enroute(self.name) == -1: self.messageinthebottle(_("No preview, no output, no edit.\n\n Game Over.")) return def messageinthebottle(self, message): self.messaga=gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK, message_format=(message)) if self.messaga.run() == gtk.RESPONSE_OK: self.messaga.destroy() def enroute(self, issend): self.issend=issend self.liste_images=[] self.liste_aligned=[] index = 0 for item in self.liststoreimport: if item[0]: self.liste_images.append(item[2]) self.liste_aligned.append(donnees.previs_dossier + "/out" + format(index, "04d") + ".tif") index += 1 if not Gui.checkbutton_a5_align.get_active(): self.liste_aligned=self.liste_images if self.liste_images.count(self.name): self.messageinthebottle(_("Can't overwrite input image!\n\n Please change the output filename.")) return -1 if len(self.liste_images) == 0: self.messageinthebottle(_("Please add some images!\n\n Can't fuse anything.")) return -1 command_a=['align_image_stack', '-a', donnees.previs_dossier + '/out'] + self.get_options_align() + self.liste_images command=[Gui.enfuser, "-o", self.name] + self.get_options() + self.liste_aligned ProFus=Progress_Fusion(command, command_a, self.liste_aligned, self.issend) def apropos(self, widget): self.fen=AproposFen() def save_settings(self): conf = ConfigParser.ConfigParser() conf.add_section('prefs') # conf.set('prefs', 'w', self.spinbuttonEdge.get_value_as_int()) conf.set('prefs', 'pwidth', self.spinbuttonlargeurprev.get_value_as_int()) conf.set('prefs', 'pheight', self.spinbuttonhauteurprev.get_value_as_int()) conf.set('prefs', 'cachebutton', self.checkbuttoncache.get_active()) conf.set('prefs', 'cachesize', self.spinbuttoncache.get_value_as_int()) conf.set('prefs', 'blocbutton', self.checkbuttonbloc.get_active()) conf.set('prefs', 'blocsize', self.spinbuttonbloc.get_value_as_int()) conf.set('prefs', 'outsize', self.checkbuttontaillefinale.get_active()) conf.set('prefs', 'outwidth', self.spinbuttonlargeurfinale.get_value_as_int()) conf.set('prefs', 'outheight', self.spinbuttonhauteurfinale.get_value_as_int()) conf.set('prefs', 'xoff', self.spinbuttonxoff.get_value_as_int()) conf.set('prefs', 'yoff', self.spinbuttonyoff.get_value_as_int()) conf.set('prefs', 'jpegdef', self.checkbuttonjpegorig.get_active()) conf.set('prefs', 'jpegcompr', int(self.hscalecomprjpeg.get_value())) conf.set('prefs', 'tiffcomp', str(self.combtiff.get_active())) conf.set('prefs', 'exif', str(self.checkbuttonexif.get_active())) if not os.path.exists(donnees.enfuse_dossier): os.makedirs(donnees.enfuse_dossier) conf.write(file(donnees.enfuse_dossier + '/mfusion.cfg', 'w')) # Also, save accel_map: # gtk.accel_map_save(self.config_dir + '/accel_map') return #################################################################### ###########Classe pour choisir les images a fusionner############### #################################################################### class Fenetre_Ouvrir: """La classe qui ouvre la fenetre de choix de fichiers, et qui retourne le ListStore par la methode get_model""" def __init__(self,model,bitajout): """Lance la fenetre de selection et créé la listsore a partir des fichiers selectionnés""" self.filtre=gtk.FileFilter() self.filtre.add_mime_type("image/jpeg") self.filtre.add_mime_type("image/tiff") self.liststoreimport=model #on repart de l'ancien modele if bitajout: self.fenetre_ouvrir = gtk.FileChooserDialog(_("Add images..."), None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) self.fenetre_ouvrir.set_select_multiple(True) self.fenetre_ouvrir.set_current_folder(donnees.default_folder) self.fenetre_ouvrir.set_filter(self.filtre) else: self.fenetre_ouvrir = gtk.FileChooserDialog(_("Open images..."), None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) self.fenetre_ouvrir.set_select_multiple(True) self.fenetre_ouvrir.set_current_folder(donnees.default_folder) self.fenetre_ouvrir.set_filter(self.filtre) self.liststoreimport.clear() #On remet le model a 0 (oublie des anciennes images) if(self.fenetre_ouvrir.run() == gtk.RESPONSE_OK): self.fichiers = self.fenetre_ouvrir.get_filenames() donnees.default_file=self.fichiers[0] for fichier in self.fichiers: self.liststoreimport.append([1,os.path.basename(fichier),fichier]) donnees.default_folder=self.fenetre_ouvrir.get_current_folder() self.fenetre_ouvrir.destroy() def get_model(self): """ Retourne la liststore """ if self.liststoreimport: return self.liststoreimport else: return None ##################################################################### #########Classe pour la fenetre pour choisir le fichier final######## ##################################################################### class Fenetre_Parcourir: """La classe qui ouvre la fenetre de choix pour enregistrer le fichier""" def __init__(self): self.fenetre_ouvrir = gtk.FileChooserDialog(_("Save file..."), None, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) self.fenetre_ouvrir.set_current_folder(donnees.default_folder) # self.fenetre_ouvrir.set_filename(donnees.default_file) self.fenetre_ouvrir.set_current_name('output.jpg') self.fenetre_ouvrir.set_do_overwrite_confirmation(True) if (self.fenetre_ouvrir.run() == gtk.RESPONSE_OK): self.resultat=self.fenetre_ouvrir.get_filename() self.fenetre_ouvrir.destroy() def get_name(self): try: return self.resultat except AttributeError: return "" ##################################################################### #########Thread pour la prévisualisation############################# ##################################################################### class Thread_Preview(threading.Thread): def __init__(self, taille, options, options_align, liste): threading.Thread.__init__ (self) self.taille=taille self.options=options self.liste=liste self.options_align=options_align def run(self): images_a_fusionner=[] images_a_align=[] index = 0 global session_images_bak global session_options_bak for item in self.liste: if item[0]: chemin_miniature=creer_miniature(item[2],(int(self.taille[0]), int(self.taille[1]))) images_a_align.append(chemin_miniature) images_a_fusionner.append(donnees.previs_dossier + "/test" + format(index, "04d") + ".tif") index += 1 if not Gui.checkbutton_a5_align.get_active(): images_a_fusionner=images_a_align if os.path.exists(donnees.previs_dossier + "/preview.jpg"): shutil.copy(donnees.previs_dossier + "/" + "preview.jpg", donnees.previs_dossier + "/" + "preview_.jpg") if Gui.checkbutton_a5_align.get_active() and \ (len(images_a_align) != len(session_images_bak) \ or len(self.options_align) != len(session_options_bak) \ or len(list(axz for axz in images_a_align if axz not in session_images_bak)) \ or len(list(axz2 for axz2 in self.options_align if axz2 not in session_options_bak))): command=["align_image_stack", "-a", donnees.previs_dossier + "/test"] + self.options_align + images_a_align Gui.statusbar.push(15, _(":: Align photos...")) preview_process=subprocess.Popen(command, stdout=subprocess.PIPE) preview_process.wait() session_options_bak=self.options_align session_images_bak=images_a_align Gui.statusbar.push(15, _(":: Fusion photos...")) command=[Gui.enfuser, "-o", donnees.previs_dossier + "/" + "preview.jpg"] + self.options + images_a_fusionner preview_process=subprocess.Popen(command, stdout=subprocess.PIPE) preview_process.wait() ####################################################################### #########Fenetre de progression lors de la fusion finale############### ####################################################################### class Progress_Fusion: def __init__(self, command, command_a, liste_aligned, issend): self.progress = gtk.glade.XML(fname=UI + "Progress.glade", domain=APP) 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) self.info_label.set_text(_('Fusion images...')) self.thread_fusion = Thread_Fusion(command, command_a, liste_aligned, issend) #On prepare le thread qui va faire tout le boulot self.thread_fusion.start() #On le lance timer = gobject.timeout_add (100, self.pulsate) def pulsate(self): if self.thread_fusion.isAlive(): #Tant que le thread est en cours, self.progress_bar.set_text(_("Fusion, please wait...")) 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(_("Fused !")) self.close_progress(self) return False def close_progress(self, widget): self.progress_win.destroy() ############################################################################## ###########Thread de fusion des vraies images################################# ############################################################################## class Thread_Fusion(threading.Thread): def __init__(self, command, command_a, liste_aligned, issend): threading.Thread.__init__ (self) self.command=command self.command_a=command_a self.issend=issend self.liste_aligned=liste_aligned def run(self): if Gui.checkbutton_a5_align.get_active(): align_process=subprocess.Popen(self.command_a, stdout=subprocess.PIPE) align_process.wait() fusion_process=subprocess.Popen(self.command, stdout=subprocess.PIPE) fusion_process.wait() # fusion_process=subprocess.call(self.command) if Gui.checkbuttonexif.get_active(): exif_copy = subprocess.Popen(["exiftool", "-tagsFromFile", Gui.liste_images[0], "-overwrite_original", Gui.name]) exif_copy.wait() if len(self.issend) > 0: subprocess.Popen(['gimp', self.issend], stdout=subprocess.PIPE) ######################################## #### Classe de la fenêtre a propos #### ######################################## class AproposFen: def __init__(self): # self.about = gtk.glade.XML(donnees.install_dossier + "/Apropos.glade", domain=APP) # self.aboutdialog = self.about.get_widget("aboutdialog1") self.aboutdialog = gtk.AboutDialog() self.aboutdialog.set_name("MacroFusion") self.aboutdialog.set_modal(True) self.aboutdialog.set_position(gtk.WIN_POS_CENTER) self.aboutdialog.set_version('0.5') self.aboutdialog.set_comments('A GTK Gui for the excellent Enfuse.\n Based on EnfuseGui by Chez Gholyo.\n\n(c) 2011 Dariusz Duma ') self.pixbuf=gtk.gdk.pixbuf_new_from_file(IMG + "logoMF.png") self.aboutdialog.set_logo(self.pixbuf) self.aboutdialog.connect("response", self.close_about) self.aboutdialog.show() def close_about(self, widget, event): self.aboutdialog.destroy() ########################################################### #### Initialisation et appel de la classe principale #### ########################################################### if __name__ == "__main__": donnees=Donnees() #Initialisation des variables Gui = Interface() #Initialise l'interface gtk.main() #Lance la boucle principale