Example #1
0
	def __init__(self, statusBar, geometry):
		QWidget.__init__(self)
		
		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()

		# Gestion de la configuration via EkdConfig
		# Paramètres de configuration
		self.config = EkdConfig
		self.nProc = 0

		vbox = QVBoxLayout() # Layout principal
		# Modification de structure pour mettre ce module conforme au nouveau design.
		# 1.Ajout du tab principal
		self.tabwidget=QTabWidget()

		# 2. Création du tab de sélection de fichier source - basé sur le widget de sélection standard
		self.afficheurImgSource=SelectWidget(geometrie = geometry)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSource # Fait le lien avec le sélecteur de fichier source.
		
		self.connect(self.afficheurImgSource, SIGNAL("pictureChanged(int)"), self.modifImgSource)
		self.connect(self.afficheurImgSource, SIGNAL("pictureSelected()"), self.modifImgSource)
		self.tabwidget.addTab(self.afficheurImgSource, _(u'Image(s) source'))

		# 3. Création du tab réglages

		self.listFileNames = []
		self.z = 1 # "Hauteur" initiale des graphicsItems ajoutés
		self.baseImage = None
		self.copiedItem = QByteArray()
		self.pasteOffset = 5
		self.prevPoint = QPoint()
		self.addOffset = 5
		self.borders = []

		self.widReglage = QWidget()

		self.view = GraphicsView()
		self.scene = QGraphicsScene(self)
		self.view.setScene(self.scene)
		
		# Image de fond
		self.background = QGraphicsPixmapItem()
		
		buttonLayout = QVBoxLayout()
		# Liste qui servira à activer/désactiver les boutons
		self.buttonsList = []
		# Liste des boutons à éviter sous PyQt4.1.0 (ex.ubuntu feisty) à cause d'un bogue
		# sur les fonctions associées
		self.buttonListeNoireFeisty = []
		self.zoomPlus = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_PLUS)
		self.zoomMoins = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_MOINS)
		self.zoomReel = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_REEL)
		self.zoomFit = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_FIT)
		layoutEdition = QHBoxLayout()
		for text, slot, icon in (
			(_(u"Ajouter &Texte"), self.addText, "Icones/text_add.png"),
			(_(u"Ajouter &Boite"), self.addBox, "Icones/ajouter_shape.png"),
			(_(u"Ajouter Ima&ge"), self.addPixmap, "Icones/image.png"),
			(_(u"C&opier"), self.copy, "Icones/copy.png"),
			(_(u"Cou&per"), self.cut, "Icones/cut.png"),
			(_(u"Co&ller"), self.paste, "Icones/paste.png"),
			(_(u"&Effacer..."), self.delete, "Icones/bin.png"),
			(_(u"&Monter"), self.upItem, "Icones/up.png"),
			(_(u"Descen&dre"), self.downItem, "Icones/down.png"),
			(_(u"Pivoter &Droite"), self.rotateR, "Icones/rotationd.png"),
			(_(u"Pivoter &Gauche"), self.rotateL, "Icones/rotationg.png"),
			(_(u"Zoom &fit"), self.zoomFit, "Icones/fenetre.png"),
			(_(u"Zoom &avant"), self.zoomPlus, "Icones/zoomplus.png"),
			(_(u"Zoom a&rrière"), self.zoomMoins, "Icones/zoommoins.png"),
			(_(u"Zoom &100%"), self.zoomReel, "Icones/taillereelle.png"),
			):
			if text in [_(u"C&opier"),_(u"Cou&per"),_(u"Co&ller"),_(u"&Effacer...")]:
				button = QToolButton()
				button.setIcon(QIcon(icon))
				button.setIconSize(QSize(16, 16))
				button.setToolTip(text)
				layoutEdition.addWidget(button)
				self.buttonListeNoireFeisty.append(button)
			else :
				if icon != None :
					button = QPushButton(QIcon(icon), text)
				else :
					button = QPushButton(text)
				buttonLayout.addWidget(button)

			button.setEnabled(False)
			self.buttonsList.append(button)
			self.connect(button, SIGNAL("clicked()"), slot)

			if text == _(u"&Effacer...") : # provisoire...
				buttonLayout.addLayout(layoutEdition)
				buttonLayout.addStretch(0)
			if text == _(u"Pivoter &Gauche"): # prochainement...
				buttonLayout.addStretch(0)
		buttonLayout.addStretch()

		# ComboBox de choix du format de sortie
		self.choixSortie = QComboBox()
		self.listFormatSortie = []
		self.indexFormatSortie = 0
		for text, format, extension, compression in (
				(_(u"PNG"),"PNG",u".png", 1),
				(_(u"JPEG"),"JPEG",u".jpg", 2),
				(_(u"BMP"),"BMP",u".bmp", 0),
				(_(u"TIFF"),"TIFF",u".tiff", 0),
				(_(u"PPM"),"PPM",u".ppm", 0)) :
			self.choixSortie.addItem(text)
			self.listFormatSortie.append([format,extension,compression])
		self.connect(self.choixSortie, SIGNAL("currentIndexChanged(int)"), self.setFormatSortie)
		buttonLayout.addWidget(self.choixSortie)
		
		self.labelQualite = QLabel(_(u"Qualité de l'image"))
		self.cbQualite = QComboBox()
		self.cbQualite.addItems(["0","10","20","30","40","50","60","70","80","85","90","95","100"])
		self.cbQualite.setCurrentIndex(8)
		hboxQ = QHBoxLayout()
		hboxQ.addWidget(self.labelQualite)
		hboxQ.addWidget(self.cbQualite)
		buttonLayout.addLayout(hboxQ)
		self.labelQualite.hide()
		self.cbQualite.hide()

		hbox = QHBoxLayout()
		hbox.addWidget(self.view, 1)
		hbox.addLayout(buttonLayout)
		self.widReglage.setLayout(hbox)
		self.tabwidget.addTab(self.widReglage, _(u"Réglage"))
		
		# 4. Création du tab de visualisation du résultat
		self.afficheurImgDestination=Lecture_VisionImage(statusBar)
		self.tabwidget.addTab(self.afficheurImgDestination, _(u'Visualisation des images créées'))

		# 5. Création du tab Info
		self.Logs = QTextEdit() # Zone d'affichage des infos (Zone acceptant le formatage HTML et avec assenceur automatique si nécessaire)
		self.tabwidget.addTab(self.Logs, _(u'Infos'))
		
		#-----------------
		# widgets du bas
		#-----------------
		
		# Boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		
		self.boutAppliquer=QPushButton(_(u"Appliquer"))
		self.boutAppliquer.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		
		# Bouton inactif au départ
		self.boutAppliquer.setEnabled(False)
		
		self.connect(self.boutAppliquer, SIGNAL("clicked()"), self.appliquer)
		
		# Ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		
		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()
		hbox.addWidget(self.boutAppliquer)

		vbox.addWidget(self.tabwidget)
		vbox.addWidget(ligne)
		vbox.addLayout(hbox)

		self.setLayout(vbox)
Example #2
0
	def __init__(self, statusBar, geometry):
        	QWidget.__init__(self)

		# -------------------------------
		# Parametres généraux du widget
		# -------------------------------
		#=== tout sera mis dans une boîte verticale ===#
		vbox=QVBoxLayout(self)

		#=== Création des répertoires temporaires ===#
		# Utilisation de EkdConfig
		self.repTampon = EkdConfig.getTempDir() + os.sep

		if os.path.isdir(self.repTampon) is False:
        		os.makedirs(self.repTampon)

		# Au cas où le répertoire existait déjà et qu'il n'était pas vide
		# -> purge (simple précausion)
		for toutRepCompo in glob.glob(self.repTampon+'*.*'):
			os.remove(toutRepCompo)

		#=== Drapeaux ===#
		# Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)

		# Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
		# Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
		self.conversionImg = 0

		# Est-ce qu'une prévisualisation a été appelée?
		self.previsualImg = 0
		# Est-ce que des images sources ont été modifiées? (c'est-à-dire ajoutées ou supprimées)
		self.modifImageSource = 0

		# Délai avant conversion
		self.timer = QTimer()
		self.connect(self.timer, SIGNAL('timeout()'), self.sonderTempsActuel)

		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()
		# Gestion de la configuration via EkdConfig
		# Paramètres de configuration
		self.config = EkdConfig
		# Identifiant du cadre
		self.idSection = "image_changer_format"
		# Log du terminal
		self.base.printSection(self.idSection)
		# Fonction appelant la fenêtre principale
		self.mainWindowFrameGeometry = geometry

		self.listeImgSource = []
		self.listeImgDestin = []

		#------------------------
		# Onglets et stacked
		#------------------------
		self.tabwidget=QTabWidget()

		#=== 1er onglet ===#
		self.framReglage=QFrame()
		vboxReglage=QVBoxLayout(self.framReglage)

		# boite de combo
		self.comboReglage=QComboBox()
		self.listeComboReglage=[(_(u'JPEG (.jpg)'), '.jpg'),\
					(_(u'JPEG (.jpeg)'), '.jpeg'),\
					(_(u'PNG (.png)'), '.png'),\
					(_(u'GIF (.gif)'), '.gif'),\
					(_(u'BMP (.bmp)'), '.bmp'),\
					(_(u'PPM (.ppm)'), '.ppm'),\
					(_(u'TIFF (.tiff)'), '.tiff'),\
					(_(u'TIF (.tif)'), '.tif')]

		# Se trouve directement dans l'onglet Réglages
		self.grid = QGridLayout()
		self.grid.addWidget(QLabel(_(u"Traitement à partir de l'image (numéro)")), 0, 0)
		self.spin1=SpinSlider(1, 100000, 1, '', self)
		self.grid.addWidget(self.spin1, 0, 1)
		self.connect(self.spin1, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		self.grid.addWidget(QLabel(_(u"Nombre de chiffres après le nom de l'image")), 1, 0)
		self.spin2=SpinSlider(3, 18, 6, '', self)
		self.grid.addWidget(self.spin2, 1, 1)
		self.connect(self.spin2, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)

		self.grid.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid)
		vboxReglage.addStretch()

		# Insertion des formats dans la combo box
		for i in self.listeComboReglage:
                	self.comboReglage.addItem(i[0],QVariant(i[1]))
		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"), self.changerComboReglage)
		# Affiche l'entrée de la boite de combo inscrite dans un fichier de configuration
		self.base.valeurComboIni(self.comboReglage, self.config, self.idSection, 'format')

		self.grid2 = QGridLayout()

		# Label qualité pour la qualité (compression) lors de la sauvegarde en JPEG
		self.labQualite=QLabel(_(u"Qualité"))
		self.labQualite.hide()

		self.grid2.addWidget(QLabel(_(u'Type de format après traitement')), 0, 0)
		self.grid2.addWidget(self.comboReglage, 0, 1)
		self.grid2.addWidget(self.labQualite, 2, 0)
		# Réglage de la qualité pour la qualité (compression) lors de la sauvegarde en JPEG
		self.spin3=SpinSlider(1, 100, 75, '', self)
		self.spin3.hide()

		i = self.comboReglage.currentIndex()
		idCombo=str(self.comboReglage.itemData(i).toStringList()[0])
		if idCombo in ['.jpg', '.jpeg']:
			self.labQualite.show()
			self.spin3.show()
		else:
			self.labQualite.hide()
			self.spin3.hide()

		self.grid2.addWidget(self.spin3, 2, 1)
		self.connect(self.spin3, SIGNAL("valueChanged(int)"), self.changeQualitePourJPEG)

		self.grid2.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid2)
		vboxReglage.addStretch()

		#=== 2ème onglet ===#
		# infos - logs
		self.zoneAffichInfosImg = QTextEdit("")
		if PYQT_VERSION_STR < "4.1.0":
			self.zoneAffichInfosImg.setText = self.zoneAffichInfosImg.setPlainText
		self.zoneAffichInfosImg.setReadOnly(True)
		self.framImg=QFrame()
		vboxReglage=QVBoxLayout(self.framImg)
		vboxReglage.addWidget(self.zoneAffichInfosImg)
		self.framImg.setEnabled(False)

		# -------------------------------------------------
		# Onglets d'affichage image source et destination
		# -------------------------------------------------

		# Là où s'afficheront les images
		self.afficheurImgSource=SelectWidget(geometrie = geometry)
 		self.afficheurImgDestination=Lecture_VisionImage(statusBar)

		self.indexTabImgSource = self.tabwidget.addTab(self.afficheurImgSource, _(u'Image(s) source'))
		self.indexTabReglage=self.tabwidget.addTab(self.framReglage, _(u'Réglages'))
		self.indexTabImgDestin=self.tabwidget.addTab(self.afficheurImgDestination, _(u'Image(s) après traitement'))
		self.indexTabInfo=self.tabwidget.addTab(self.framImg, _(u'Infos'))

		vbox.addWidget(self.tabwidget)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSource # Fait le lien avec le sélecteur de fichier source.

		#------------------
		# Widgets du bas
		#------------------

		# boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		boutAide.setFocusPolicy(Qt.NoFocus)
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		self.boutApPremImg = QPushButton(_(u" Voir le résultat"))
		self.boutApPremImg.setIcon(QIcon("Icones/icone_visionner_128.png"))
		self.boutApPremImg.setFocusPolicy(Qt.NoFocus)
		self.boutApPremImg.setEnabled(False)
		self.connect(self.boutApPremImg, SIGNAL("clicked()"), self.visu_1ere_img)
		self.boutApp=QPushButton(_(u" Appliquer"))
		self.boutApp.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		self.boutApp.setFocusPolicy(Qt.NoFocus)
		self.boutApp.setEnabled(False)
		self.connect(self.boutApp, SIGNAL("clicked()"), self.appliquer0)

		# Ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		vbox.addWidget(ligne)
		vbox.addSpacing(-5)	# la ligne doit être plus près des boutons

		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()	# espace entre les 2 boutons
		hbox.addWidget(self.boutApPremImg)
		hbox.addStretch()
		hbox.addWidget(self.boutApp)
		vbox.addLayout(hbox)

		self.setLayout(vbox)

		#------------------------------------------------
		# Barre de progression dans une fenêtre séparée
		#------------------------------------------------

		self.progress=QProgressDialog(_(u"Progression ..."), _(u"Arrêter le processus"), 0, 100)
		self.progress.setWindowTitle(_(u'EnKoDeur-Mixeur. Fenêtre de progression'))
		# Attribution des nouvelles dimensions
		self.progress.setMinimumWidth(500)
		self.progress.setMinimumHeight(100)

		self.connect(self.tabwidget, SIGNAL("currentChanged(int)"), self.fctTab)

		#----------------------------------------------------------------------------------------------------
		# Signal de présence d'images dans ler widget de sélection -> modifie le statut des boutons d'action
		#----------------------------------------------------------------------------------------------------

		self.connect(self.afficheurImgSource, SIGNAL("pictureChanged(int)"), self.modifBoutonsAction)

		#----------------------------------------------------------------------------------------------------
		# Signal pour afficher ou ne pas afficher les widgets de changement de qualité pour les images
		#----------------------------------------------------------------------------------------------------

		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"), self.changerQualJPEG)
Example #3
0
class Image_Divers_TxtSurImg(QWidget):
	# -----------------------------------
	# Cadre accueillant les widgets de :
	# Image >> Divers >> Texte sur images
	# -----------------------------------
	
	ZOOM_MOINS,ZOOM_PLUS,ZOOM_REEL,ZOOM_FIT = range(4)

	def __init__(self, statusBar, geometry):
		QWidget.__init__(self)
		
		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()

		# Gestion de la configuration via EkdConfig
		# Paramètres de configuration
		self.config = EkdConfig
		self.nProc = 0

		vbox = QVBoxLayout() # Layout principal
		# Modification de structure pour mettre ce module conforme au nouveau design.
		# 1.Ajout du tab principal
		self.tabwidget=QTabWidget()

		# 2. Création du tab de sélection de fichier source - basé sur le widget de sélection standard
		self.afficheurImgSource=SelectWidget(geometrie = geometry)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSource # Fait le lien avec le sélecteur de fichier source.
		
		self.connect(self.afficheurImgSource, SIGNAL("pictureChanged(int)"), self.modifImgSource)
		self.connect(self.afficheurImgSource, SIGNAL("pictureSelected()"), self.modifImgSource)
		self.tabwidget.addTab(self.afficheurImgSource, _(u'Image(s) source'))

		# 3. Création du tab réglages

		self.listFileNames = []
		self.z = 1 # "Hauteur" initiale des graphicsItems ajoutés
		self.baseImage = None
		self.copiedItem = QByteArray()
		self.pasteOffset = 5
		self.prevPoint = QPoint()
		self.addOffset = 5
		self.borders = []

		self.widReglage = QWidget()

		self.view = GraphicsView()
		self.scene = QGraphicsScene(self)
		self.view.setScene(self.scene)
		
		# Image de fond
		self.background = QGraphicsPixmapItem()
		
		buttonLayout = QVBoxLayout()
		# Liste qui servira à activer/désactiver les boutons
		self.buttonsList = []
		# Liste des boutons à éviter sous PyQt4.1.0 (ex.ubuntu feisty) à cause d'un bogue
		# sur les fonctions associées
		self.buttonListeNoireFeisty = []
		self.zoomPlus = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_PLUS)
		self.zoomMoins = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_MOINS)
		self.zoomReel = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_REEL)
		self.zoomFit = partial(self.zoom, Image_Divers_TxtSurImg.ZOOM_FIT)
		layoutEdition = QHBoxLayout()
		for text, slot, icon in (
			(_(u"Ajouter &Texte"), self.addText, "Icones/text_add.png"),
			(_(u"Ajouter &Boite"), self.addBox, "Icones/ajouter_shape.png"),
			(_(u"Ajouter Ima&ge"), self.addPixmap, "Icones/image.png"),
			(_(u"C&opier"), self.copy, "Icones/copy.png"),
			(_(u"Cou&per"), self.cut, "Icones/cut.png"),
			(_(u"Co&ller"), self.paste, "Icones/paste.png"),
			(_(u"&Effacer..."), self.delete, "Icones/bin.png"),
			(_(u"&Monter"), self.upItem, "Icones/up.png"),
			(_(u"Descen&dre"), self.downItem, "Icones/down.png"),
			(_(u"Pivoter &Droite"), self.rotateR, "Icones/rotationd.png"),
			(_(u"Pivoter &Gauche"), self.rotateL, "Icones/rotationg.png"),
			(_(u"Zoom &fit"), self.zoomFit, "Icones/fenetre.png"),
			(_(u"Zoom &avant"), self.zoomPlus, "Icones/zoomplus.png"),
			(_(u"Zoom a&rrière"), self.zoomMoins, "Icones/zoommoins.png"),
			(_(u"Zoom &100%"), self.zoomReel, "Icones/taillereelle.png"),
			):
			if text in [_(u"C&opier"),_(u"Cou&per"),_(u"Co&ller"),_(u"&Effacer...")]:
				button = QToolButton()
				button.setIcon(QIcon(icon))
				button.setIconSize(QSize(16, 16))
				button.setToolTip(text)
				layoutEdition.addWidget(button)
				self.buttonListeNoireFeisty.append(button)
			else :
				if icon != None :
					button = QPushButton(QIcon(icon), text)
				else :
					button = QPushButton(text)
				buttonLayout.addWidget(button)

			button.setEnabled(False)
			self.buttonsList.append(button)
			self.connect(button, SIGNAL("clicked()"), slot)

			if text == _(u"&Effacer...") : # provisoire...
				buttonLayout.addLayout(layoutEdition)
				buttonLayout.addStretch(0)
			if text == _(u"Pivoter &Gauche"): # prochainement...
				buttonLayout.addStretch(0)
		buttonLayout.addStretch()

		# ComboBox de choix du format de sortie
		self.choixSortie = QComboBox()
		self.listFormatSortie = []
		self.indexFormatSortie = 0
		for text, format, extension, compression in (
				(_(u"PNG"),"PNG",u".png", 1),
				(_(u"JPEG"),"JPEG",u".jpg", 2),
				(_(u"BMP"),"BMP",u".bmp", 0),
				(_(u"TIFF"),"TIFF",u".tiff", 0),
				(_(u"PPM"),"PPM",u".ppm", 0)) :
			self.choixSortie.addItem(text)
			self.listFormatSortie.append([format,extension,compression])
		self.connect(self.choixSortie, SIGNAL("currentIndexChanged(int)"), self.setFormatSortie)
		buttonLayout.addWidget(self.choixSortie)
		
		self.labelQualite = QLabel(_(u"Qualité de l'image"))
		self.cbQualite = QComboBox()
		self.cbQualite.addItems(["0","10","20","30","40","50","60","70","80","85","90","95","100"])
		self.cbQualite.setCurrentIndex(8)
		hboxQ = QHBoxLayout()
		hboxQ.addWidget(self.labelQualite)
		hboxQ.addWidget(self.cbQualite)
		buttonLayout.addLayout(hboxQ)
		self.labelQualite.hide()
		self.cbQualite.hide()

		hbox = QHBoxLayout()
		hbox.addWidget(self.view, 1)
		hbox.addLayout(buttonLayout)
		self.widReglage.setLayout(hbox)
		self.tabwidget.addTab(self.widReglage, _(u"Réglage"))
		
		# 4. Création du tab de visualisation du résultat
		self.afficheurImgDestination=Lecture_VisionImage(statusBar)
		self.tabwidget.addTab(self.afficheurImgDestination, _(u'Visualisation des images créées'))

		# 5. Création du tab Info
		self.Logs = QTextEdit() # Zone d'affichage des infos (Zone acceptant le formatage HTML et avec assenceur automatique si nécessaire)
		self.tabwidget.addTab(self.Logs, _(u'Infos'))
		
		#-----------------
		# widgets du bas
		#-----------------
		
		# Boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		
		self.boutAppliquer=QPushButton(_(u"Appliquer"))
		self.boutAppliquer.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		
		# Bouton inactif au départ
		self.boutAppliquer.setEnabled(False)
		
		self.connect(self.boutAppliquer, SIGNAL("clicked()"), self.appliquer)
		
		# Ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		
		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()
		hbox.addWidget(self.boutAppliquer)

		vbox.addWidget(self.tabwidget)
		vbox.addWidget(ligne)
		vbox.addLayout(hbox)

		self.setLayout(vbox)


	def setFormatSortie(self, index) :
		self.indexFormatSortie = index
		if self.listFormatSortie[index][2] == 2 :
			self.labelQualite.show()
			self.cbQualite.show()
		else :
			self.labelQualite.hide()
			self.cbQualite.hide()


	def modifImgSource(self, i=True):
		"""On active ou désactive les boutons d'action et on recharge le pseudo-aperçu de planche-contact
		en fonction du nombre d'images présentes dans le widget de sélection"""
		###self.displayImg()
		self.boutAppliquer.setEnabled(i)
		selectedImg = self.afficheurImgSource.getFile()
		if self.setBackgroundImg(selectedImg) :
			if PYQT_VERSION_STR != "4.1.0":
				for button in self.buttonsList:
					button.setEnabled(True)
			else:
				# Pour empêcher le bogue de PyQt4.1.0 Feisty
				for button in self.buttonsList:
					if button not in self.buttonListeNoireFeisty:
						button.setEnabled(True)
			self.zoom(Image_Divers_TxtSurImg.ZOOM_FIT)


	def setBackgroundImg (self, selectedImg) :
		if selectedImg and selectedImg != self.baseImage :
			self.baseImage = selectedImg
			# Création de l'objet QImage de l'image de base
			pixmap = QPixmap(self.baseImage)
			# Suppression de la précédente image si elle existait
			if not self.background.pixmap().isNull():
				self.scene.removeItem(self.background)
		
			# Ajout de la nouvelle image
			self.scene.setSceneRect(0, 0, pixmap.width(), pixmap.height())
			self.background = self.scene.addPixmap(pixmap)
			self.background.setZValue(0)
			return True
		else : return False


	def position(self, pixmap=None):
		#print "QCursor.pos()", QCursor.pos().x(), QCursor.pos().y()
		EkdPrint(u"QCursor.pos() %s %s" % (QCursor.pos().x(), QCursor.pos().y()))
		point = self.mapFromGlobal(QCursor.pos())
		#print "self.mapFromGlobal(QCursor.pos()", point.x(), point.y()
		EkdPrint(u"self.mapFromGlobal(QCursor.pos() %s %s" % (point.x(), point.y()))
		if not self.view.geometry().contains(point) or pixmap:
			#print "if not self.view.geometry().contains(point) or pixmap"
			EkdPrint(u"if not self.view.geometry().contains(point) or pixmap")
			coord = random.randint(36, 144)
			point = QPoint(coord, coord)
		else:
			#print "else de if not self.view..."
			EkdPrint(u"else de if not self.view...")
			if point == self.prevPoint:
				#print "if point == self.prevPoint"
				EkdPrint(u"if point == self.prevPoint")
				point += QPoint(self.addOffset, self.addOffset)
				self.addOffset += 5
			else:
				#print "else de if point..."
				EkdPrint(u"else de if point...")
				self.addOffset = 5
				self.prevPoint = point
		#print "point", point.x(), point.y(), '\n'
		EkdPrint("upoint %s %s\n" % (point.x(), point.y()))
		# La position du point haut-gauche du rectangle encadrant le texte
		#print "self.view.mapToScene(point)", self.view.mapToScene(point).x(), self.view.mapToScene(point).y()
		EkdPrint(u"self.view.mapToScene(point) %s %s" % (self.view.mapToScene(point).x(), self.view.mapToScene(point).y()))
		return self.view.mapToScene(point)


	def addText(self):
		self.z += 1
		dialog = TextItemDlg(position=self.position(), scene=self.scene, parent=self, z=self.z)
		dialog.exec_()
	

	def addBox(self):
		self.z += 1
		BoxItem(self.position(), self.scene, z=self.z)
	

	def addPixmap(self):
		formats = ["*.%s" % unicode(format).lower() \
			for format in QImageReader.supportedImageFormats()]
		path = self.base.getRepSource(self.config)
		txt = _(u"Fichiers Image")
		fname = unicode(QFileDialog.getOpenFileName(self, "Ouvrir des images",
			path, "%s (%s);;%s" %(txt, " ".join(formats), FORMAT)))
		if not fname: return
		self.base.setRepSource(self.config, fname)
		self.createPixmapItem(QPixmap(fname), self.position(pixmap=True))
	

	def createPixmapItem(self, pixmap, position, rotation=0):
		self.z += 1
		item = GraphicsPixmapItem(pixmap, position, rotation, z=self.z)
		item.setFlags(QGraphicsItem.ItemIsSelectable|
			QGraphicsItem.ItemIsMovable)
		self.scene.clearSelection()
		self.scene.addItem(item)
		item.setZValue(self.z+1)
		self.z += 1
		item.setSelected(True)
	

	def selectedItem(self):
		items = self.scene.selectedItems()
		if len(items) == 1:
			return items[0]
		return None
	

	def copy(self):
		item = self.selectedItem()
		if item is None:
			return
		self.copiedItem.clear()
		self.pasteOffset = 5
		stream = QDataStream(self.copiedItem, QIODevice.WriteOnly)
		self.writeItemToStream(stream, item)
	

	def cut(self):
		item = self.selectedItem()
		if item is None:
			return
		self.copy()
		self.scene.removeItem(item)
		del item
	

	def paste(self):
		if self.copiedItem.isEmpty():
			return
		stream = QDataStream(self.copiedItem, QIODevice.ReadOnly)
		self.readItemFromStream(stream, self.pasteOffset)
		self.pasteOffset += 5


	def upItem(self) :
		'''Fonction pour relever le/les item(s) sélectionné(s))'''
		for item in self.scene.selectedItems():
			z = item.zValue()
			item.setZValue(z+1)


	def downItem(self) :
		'''Fonction pour descendre le/les item(s) sélectionné(s))'''
		for item in self.scene.selectedItems():
			z = item.zValue()
			if z>1 : # Pour éviter de placer un élément en dessous de l'image source qui est au niveau 0.
				item.setZValue(z-1)
	

	def rotateR(self):
		for item in self.scene.selectedItems():
			item.setRotateR(22.5)
	

	def rotateL(self):
		for item in self.scene.selectedItems():
			item.setRotateL(22.5)
	

	def delete(self):
		items = self.scene.selectedItems()
		#print "items sélectionnés", items ###
		EkdPrint(u"items sélectionnés %s" % items)
		txt1,txt2=_(u"Effacer"),_(u"élément")
		if len(items) != 1: s = "s"
		else: s = ""
		if len(items) and QMessageBox.question(self,
			_(u"Texte sur images - Effacer"),
			"%s %d %s%s?" % (txt1,len(items),txt2,s),
			QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes:
			while items:
				item = items.pop()
				#print "item?", item
				EkdPrint(u"item? %s" % item)
				self.scene.removeItem(item)
				del item
	
	
	def readItemFromStream(self, stream, offset=0):
		type_ = QString()
		position = QPointF()
		stream >> type_ >> position
		rotation = stream.readInt16()
		if offset:
			position += QPointF(offset, offset)
		if type_ == "Text":
			text = QString()
			font = QFont()
			color = QColor()
			stream >> text >> font >> color
			self.z += 1
			TextItem(text, position, self.scene, font, color, rotation, self.z)
		elif type_ == "Pixmap":
			pixmap = QPixmap()
			stream >> pixmap
			self.createPixmapItem(pixmap, position, rotation)
		elif type_ == "Box":
			rect = QRectF()
			stream >> rect
			style = Qt.PenStyle(stream.readInt16())
			borderWidth = stream.readInt16()
			boxColor = QColor()
			stream >> boxColor 
			self.z += 1
			BoxItem(position, self.scene, style, borderWidth, boxColor, rect, rotation, self.z)
	

	def writeItemToStream(self, stream, item):
		if isinstance(item, QGraphicsTextItem):
			stream << QString("Text") << item.pos()
			stream.writeInt16(item.getRotate())
			stream << item.toPlainText() << item.font() << item.defaultTextColor()
		elif isinstance(item, QGraphicsPixmapItem):
			stream << QString("Pixmap") << item.pos()
			stream.writeInt16(item.getRotate())
			stream << item.pixmap()
		elif isinstance(item, BoxItem):
			stream << QString("Box") << item.pos()
			stream.writeInt16(item.getRotate())
			stream << item.rect
			stream.writeInt16(item.style)
			stream.writeInt16(item.borderWidth)
			stream << item.boxColor
	

	def appliquer(self):
		"Conversion des images: ajout de textes, images et boites"
		
		# Utilisation de la nouvelle boîte de dialogue de sauvegarde
		suffix=""
                fname = EkdSaveDialog(self, mode="image", suffix=suffix, title=_(u"Sauver"), multiple=True)
		fname = fname.getFile()

		if not fname: return

		# Gestion de l'extension
		if fname.endswith(self.listFormatSortie[self.indexFormatSortie][1]) :
			fname = fname[:-len(self.listFormatSortie[self.indexFormatSortie][1])]

		# Progression
		progress=QProgressDialog(_(u"Conversion en cours..."), _(u"Arrêter"), 0, 100)
		progress.setWindowTitle(_(u'EnKoDeur-Mixeur. Fenêtre de progression'))
		progress.show()
		progress.setValue(0)

		# Module traitement par lot
		lstImg = self.afficheurImgSource.getFiles()
		nbrImg = len(lstImg)
		lstFname = []
		k = 1
		for bimg in lstImg :
			self.setBackgroundImg(bimg)
			# Enregistrement de l'image composée
			imgDim = self.scene.sceneRect()
			imgFinal = QImage(imgDim.width(), imgDim.height(), QImage.Format_ARGB32)
			self.scene.clearSelection()
			self.scene.render(QPainter(imgFinal))
			if self.listFormatSortie[self.indexFormatSortie][2] == 2 : # Qualité = valeur de la combobox
				qu = int(self.cbQualite.currentText())
			elif self.listFormatSortie[self.indexFormatSortie][2] == 0 : # Qualité 100 pour les images sans compression
				qu = 100
			else : # Compression maximale pour les images PNG car format non destructif.
				qu = 0

			if imgFinal.save(fname+string.zfill(str(k), 5)+self.listFormatSortie[self.indexFormatSortie][1], self.listFormatSortie[self.indexFormatSortie][0], qu) :
				lstFname.append(fname+string.zfill(str(k), 5)+self.listFormatSortie[self.indexFormatSortie][1])
			else :
				#print "Erreur lors de la sauvegarde de l'image"
				EkdPrint(u"Erreur lors de la sauvegarde de l'image")
			progress.setValue(int(100*k/nbrImg))
			k += 1
		# Affichage du résultat
		self.afficheurImgDestination.cheminImage = u""
		self.afficheurImgDestination.updateImages(lstFname)
		# Mise à jour du log
		self.updateLog(lstImg, lstFname)


	def updateLog(self, images, sorties) :
		"""Fonction pour la mise à jour des informations de log données à l'utilisateur en fin de process sur les données entrées, et le résultat du process"""
		msgIm = _(u"<p>####################################<br># Image(s) chargée(s)<br>####################################</p>")
		for i in images :
			msgIm += unicode(i)+u"<br>"

		msgOut = _(u"<br><p>####################################<br># Fichier(s) de sortie<br>####################################</p>")
		for s in sorties :
			msgOut += unicode(s)+u"<br>"

		self.Logs.setHtml(QString(msgIm+msgOut))


	def zoom(self, val):
		if val==Image_Divers_TxtSurImg.ZOOM_PLUS:
			self.view.scale(1.2, 1.2)
		elif val==Image_Divers_TxtSurImg.ZOOM_MOINS:
			self.view.scale(0.8, 0.8)
		elif val==Image_Divers_TxtSurImg.ZOOM_REEL:
			self.view.resetTransform()
		elif val==Image_Divers_TxtSurImg.ZOOM_FIT :
			self.view.fitInView(self.background, Qt.KeepAspectRatio)
	

	def afficherAide(self):
		"Boîte de dialogue de l'aide"

		messageAide = EkdAide(parent=self)
		messageAide.setText(_(u"<p><b>Ici vous pouvez ajouter du texte, des cadres ou des petites images comme des logos sur des images. Cela peut être utile pour <i>signer</i> ou indiquer la provenance d'un lot d'images (avant par exemple de les diffuser sur internet).</b></p><p><b>De nombreux réglages vous sont proposés (dans l'onglet 'Réglage') afin d'inscrire et disposer comme bon vous semble du texte sur un lot d'images.</b></p>\
		\
		<p>Dans l'onglet <b>Image(s) source</b> cliquez sur le bouton <b>Ajouter</b>, une boîte de dialogue apparaît, sur la partie gauche sélectionnez le répertoire (au besoin dépliez les sous-répertoires), allez chercher vos image(s). Si vous voulez sélectionner plusieurs images d'un coup, maintenez la touche <b>CTRL</b> (ou <b>SHIFT</b>) du clavier enfoncée (tout en sélectionnant vos images), cliquez sur <b>Ajouter</b>. Toujours dans l'onglet <b>Image(s) source</b> sélectionnez une des miniatures.</p><p>Allez maintenant dans l'onglet <b>Réglages</b>, l'image de la miniature que vous venez de sélectionner est affichée. Vous pouvez zoomer ou dézoomer l'image avec le bouton du milieu de la souris. Dans cet onglet <b>Réglages</b> (et sur la droite), vous voyez toute une série de boutons (qui correspondent aux différentes actions que vous pouvez effectuer sur l'image ou sur le texte que vous allez écrire sur cette image). Nous allons maintenant, simplement ajouter un texte, pour ce faire cliquez sur le bouton <b>Ajouter texte</b>, la boîte de dialogue <b>Texte sur images - Ajouter texte</b> apparaît, avant d'écrire quoi que ce soit (dans le champ réservé à cet effet), faites le choix de la <b>Police</b>, de la <b>Taille</b> et de la <b>Couleur</b>, écrivez maintenant votre texte, une fois fait, cliquez sur le bouton <b>OK</b>. Vérifiez que votre texte ne dépasse pas de l'image (si cela est la cas, double-cliquez sur le texte en question, la boîte de dialogue de saisie va réapparaître) et faites ce qu'il faut ... . Vous pouvez positionner le texte sur l'image en bougeant le cadre où se trouve le texte avec la souris. Vous pouvez si vous le désirez ajouter une boîte (par le bouton <b>Ajouter Boîte</b>). Pour choisir le contour de la boîte, faites un clic droit dessus, un menu vous permettra de choisir le contour que vous désirez. En ce qui concerne la taille de la boîte, il est possible de régler la taille de celle-ci en pressant simultanément les touches <b>Shift</b> et <b>Flèche droite (ou gauche)</b> pour changer la taille en largeur, <b>Shift</b> et <b>Flèche haut (ou bas)</b> pour changer la taille en hauteur (pas besoin d'utiliser la souris pour changer la taille). Vous pouvez ajouter une image (par le bouton <b>Ajouter Image</b>), sélectionnez le chemin de votre image (puis l'image elle-même) dans la boîte de dialogue <b>Ouvrir des images</b>, cliquez sur le bouton <b>Ouvrir</b>. Certaines actions peuvent être effectuées (comme Copier, Couper, Coller, Effacer) par les boutons juste en dessous de <b>Ajouter Image</b> (positionnez votre souris sur ces boutons et il vous sera indiqué à quoi ils correspondent). Vous pouvez déplacer les éléments un à un dans la scène en cliquant dessus et en déplaçant la souris sans relacher le clic gauche (vu précédemment). Vous pouvez aussi déplacer plusieurs éléments en même temps comme expliqué précédemment mais en 'dessinant' au préalable un rectangle qui les englobera (bouton gauche de la souris maintenu en la déplaçant). L'ordre d'affichage des éléments peut-être modifié au moyen des boutons <b>Monter</b> et <b>Descendre</b>.</p><p>Sélectionnez votre format d'image (PNG, JPEG, BMP, TIFF ou PPM), c'est à dire votre extension d'image, dans la liste déroulante (tout en bas) prévue à cet effet. Dans le cas d'une sélection JPEG, n'oubliez pas de régler la <b>Qualité de l'image</b>.</p><p>Une fois tout ceci fait, cliquez sur le bouton <b>Appliquer</b>, sélectionnez le répertoire de sauvegarde, indiquez votre <b>Nom de fichier</b>, cliquez sur le bouton <b>Enregistrer</b>.</p><p>Si vous faites un clic droit de la souris (sur l'image) dans l'onglet <b>Visualisation des images créées</b>, vous accédez à des paramètres vous permettant différents affichages de la dite image. De même dans cet onglet vous pouvez lancer la visualisation des images par le bouton <b>Lancer le diaporama</b> (le bouton violet avec une flèche blanche vers la droite).</p><p>L'onglet <b>Infos</b> vous permet de voir le filtre utilisé, les image(s) chargée(s) et les image(s) convertie(s).</p>"))
		messageAide.show()


	def save(self) :
		self.afficheurImgSource.saveFileLocation(self.idSection)


	def load(self) :
		self.afficheurImgSource.loadFileLocation(self.idSection)
Example #4
0
	def __init__(self, statusBar, geometry):
        	QWidget.__init__(self)
		
		# ----------------------------
		# Quelques paramètres de base
		# ----------------------------

		# Paramètres de configuration
		self.config = EkdConfig
		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()
		self.idSection = "image_image_composite"
		# Log du terminal
		self.base.printSection(self.idSection)
		# Fonction appelant la fenêtre principale
		self.mainWindowFrameGeometry = geometry

		# Création des répertoires temporaires. Utilisation de EkdConfig
		self.repTampon = EkdConfig.getTempDir() + os.sep + "tampon" + os.sep + "temp_duplication" + os.sep
		if os.path.isdir(self.repTampon) is False:
        		os.makedirs(self.repTampon)
			
		# Au cas où le répertoire existait déjà et qu'il n'était pas vide 
		# -> purge (simple précausion)
		for toutRepCompo in glob.glob(self.repTampon+'*.*'):
			os.remove(toutRepCompo)
			
		# Répertoire tampon dans lequel est crée le compositing qui sera crée par le
		# bouton 'Voir le résultat'. Utilisation de EkdConfig
		self.repTamponVisuVoirRes = self.repTampon + "visu_voir_res_compo" + os.sep
		if os.path.isdir(self.repTamponVisuVoirRes) is False:
        		os.makedirs(self.repTamponVisuVoirRes)
		
		# Au cas où le répertoire existait déjà et qu'il n'était pas vide 
		# -> purge (simple précausion)
		for toutRepCompoVisu in glob.glob(self.repTamponVisuVoirRes+'*.*'):
			os.remove(toutRepCompoVisu)
		
		# Répertoire temporaire 1 pour les redimensionnement des images
		if os.path.isdir(self.repTampon+'redim_1/') is False:
        		os.makedirs(self.repTampon+'redim_1/')
		# Répertoire temporaire 2 pour les redimensionnement des images	
		if os.path.isdir(self.repTampon+'redim_2/') is False:
        		os.makedirs(self.repTampon+'redim_2/')
			
		# Au cas où le répertoire existait déjà et qu'il n'était pas vide 
		# -> purge (simple précausion)
		for toutRepCompoRedim in glob.glob(self.repTampon+'redim_1/'+'*.*'):
			if len(toutRepCompoRedim)>0:
				os.remove(toutRepCompoRedim)
		# ...
		for toutRepCompoRedim in glob.glob(self.repTampon+'redim_2/'+'*.*'):
			if len(toutRepCompoRedim)>0:
				os.remove(toutRepCompoRedim)
		
		#=== Drapeaux ===#
		# Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)
		
		# Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
		# Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
		self.conversionImg = 0
		
		# Est-ce qu'une prévisualisation a été appelée?
		self.previsualImg = 0
		# Est-ce que des images sources ont été modifiées? (c'est-à-dire ajoutées ou supprimées)
		self.modifImageSource = 0

		# Liste de chemins de fichiers avec et sans canal alpha et du dossier de sauvegarde
		self.listeChemAVcanAlph=[]
		self.listeChemSANScanAlph=[]
		self.listeImgDestin = []
		
		# Boite d'alignement vertical
		vbox=QVBoxLayout(self)
		
		# --------------------------------------------------
		# widgets du haut : titre + bouton de sélection
		# --------------------------------------------------
		
		hbox = QHBoxLayout()
		
		# Ajout du titre de la page et de l'aperçu à la boite verticale
		vbox.addLayout(hbox, 0)
		
		#=== Bouton de sélection des images alpha et sans alpha ===#
		hbox = QHBoxLayout()

		self.framReglage=QFrame()
		vboxReglage=QVBoxLayout(self.framReglage)

		# Pour la gestion du nombre d'images à traiter ##############
		self.grid = QGridLayout()
		self.grid.addWidget(QLabel(_(u"Traitement à partir de l'image (numéro)")), 0, 0)
		self.spin1=SpinSlider(1, 100000, 1, '', self)
		self.grid.addWidget(self.spin1, 0, 1)
		self.connect(self.spin1, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		self.grid.addWidget(QLabel(_(u"Nombre de chiffres après le nom de l'image")), 1, 0)
		self.spin2=SpinSlider(3, 18, 6, '', self)
		self.grid.addWidget(self.spin2, 1, 1)
		self.connect(self.spin2, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		
		self.grid.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid)
		vboxReglage.addStretch()

		# -------------------------------------------------
		# Onglets d'affichage image source et destination
		# -------------------------------------------------
		
		# On peut sélectionner les extensions qui doivent être visibles comme ceci:
		#self.afficheurImgSource=SelectWidget(extensions=["*.jpg", "*.png"], geometrie = self.mainWindowFrameGeometry)
		# Là uniquement les fichiers png et gif apparaissent ds la fenêtre de chargement
		# Ne pas oublier de mettre * avant le point et l'extension

		# Là où s'afficheront les images
		# Avec canal alpha
		self.afficheurImgSourceAvecCanalAlpha=SelectWidget(extensions=["*.png", "*.gif"], geometrie = self.mainWindowFrameGeometry)
		# Sans canal alpha
		self.afficheurImgSourceSansCanalAlpha=SelectWidget(geometrie = self.mainWindowFrameGeometry)

		# Gestion de la configuration via EkdConfig
		# Résultat du compositing
		self.afficheurImgDestination=Lecture_VisionImage(statusBar)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSourceSansCanalAlpha # Fait le lien avec le sélecteur de fichier source.
		### Remarque : Le choix a été fait de ne pas mettre la boîte de sélection des images alpha dans le tampon.
		
		# infos - logs
		self.zoneAffichInfosImg = QTextEdit("")
		if PYQT_VERSION_STR < "4.1.0":
			self.zoneAffichInfosImg.setText = self.zoneAffichInfosImg.setPlainText
		self.zoneAffichInfosImg.setReadOnly(True)
		self.fram=QFrame()
		vboxInfIm=QVBoxLayout(self.fram)
		vboxInfIm.addWidget(self.zoneAffichInfosImg)
		self.fram.setEnabled(False)
		
		self.tabwidget=QTabWidget()
		
		self.indexTabImgSourceAvCanAlph = self.tabwidget.addTab(self.afficheurImgSourceAvecCanalAlpha, _(u'Image(s) avec canal alpha'))
		self.indexTabImgSourceSansCanAlph = self.tabwidget.addTab(self.afficheurImgSourceSansCanalAlpha, _(u'Image(s) sans canal alpha'))
		self.indexTabReglage=self.tabwidget.addTab(self.framReglage, _(u'Réglages'))
		self.indexTabImgDestin=self.tabwidget.addTab(self.afficheurImgDestination, _(u'Image(s) après traitement'))
		self.indexTabInfo=self.tabwidget.addTab(self.fram, _(u'Infos'))
		
		vbox.addWidget(self.tabwidget)
		
		# -------------------------------------------------------------------
		# widgets du bas : ligne + boutons
		# -------------------------------------------------------------------
		
		# boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		self.boutApPremImg = QPushButton(_(u" Voir le résultat"))
		self.boutApPremImg.setIcon(QIcon("Icones/icone_visionner_128.png"))
		self.boutApPremImg.setFocusPolicy(Qt.NoFocus)
		self.boutApPremImg.setEnabled(False)
		self.connect(self.boutApPremImg, SIGNAL("clicked()"), self.visu_1ere_derniere_img)
		self.boutAppliquer=QPushButton(_(u" Appliquer et sauver"))
		self.boutAppliquer.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		self.boutAppliquer.setEnabled(False)
		self.connect(self.boutAppliquer, SIGNAL("clicked()"), self.appliquer)
		
		# ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		vbox.addWidget(ligne)
		vbox.addSpacing(-5)	# la ligne doit être plus près des boutons
		
		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()	# espace entre les 2 boutons
		hbox.addWidget(self.boutApPremImg)
		hbox.addStretch()
		hbox.addWidget(self.boutAppliquer)
		vbox.addLayout(hbox)
		
		# affichage de la boîte principale
		self.setLayout(vbox)
		
		self.connect(self.tabwidget, SIGNAL("currentChanged(int)"), self.fctTab)
		
		#----------------------------------------------------------------------------------------------------
		# Signal de présence d'images dans ler widget de sélection -> modifie le statut des boutons d'action
		#----------------------------------------------------------------------------------------------------
		
		self.connect(self.afficheurImgSourceSansCanalAlpha, SIGNAL("pictureChanged(int)"), self.modifBoutonsAction)
Example #5
0
class Image_Divers_ChangFormat(QWidget):
	"""# -----------------------------------
	# Cadre accueillant les widgets de :
	# Image >> Divers >> Changer format
	# Gestion de 16 formats de fichiers
	# -----------------------------------"""
	def __init__(self, statusBar, geometry):
        	QWidget.__init__(self)

		# -------------------------------
		# Parametres généraux du widget
		# -------------------------------
		#=== tout sera mis dans une boîte verticale ===#
		vbox=QVBoxLayout(self)

		#=== Création des répertoires temporaires ===#
		# Utilisation de EkdConfig
		self.repTampon = EkdConfig.getTempDir() + os.sep

		if os.path.isdir(self.repTampon) is False:
        		os.makedirs(self.repTampon)

		# Au cas où le répertoire existait déjà et qu'il n'était pas vide
		# -> purge (simple précausion)
		for toutRepCompo in glob.glob(self.repTampon+'*.*'):
			os.remove(toutRepCompo)

		#=== Drapeaux ===#
		# Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)

		# Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
		# Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
		self.conversionImg = 0

		# Est-ce qu'une prévisualisation a été appelée?
		self.previsualImg = 0
		# Est-ce que des images sources ont été modifiées? (c'est-à-dire ajoutées ou supprimées)
		self.modifImageSource = 0

		# Délai avant conversion
		self.timer = QTimer()
		self.connect(self.timer, SIGNAL('timeout()'), self.sonderTempsActuel)

		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()
		# Gestion de la configuration via EkdConfig
		# Paramètres de configuration
		self.config = EkdConfig
		# Identifiant du cadre
		self.idSection = "image_changer_format"
		# Log du terminal
		self.base.printSection(self.idSection)
		# Fonction appelant la fenêtre principale
		self.mainWindowFrameGeometry = geometry

		self.listeImgSource = []
		self.listeImgDestin = []

		#------------------------
		# Onglets et stacked
		#------------------------
		self.tabwidget=QTabWidget()

		#=== 1er onglet ===#
		self.framReglage=QFrame()
		vboxReglage=QVBoxLayout(self.framReglage)

		# boite de combo
		self.comboReglage=QComboBox()
		self.listeComboReglage=[(_(u'JPEG (.jpg)'), '.jpg'),\
					(_(u'JPEG (.jpeg)'), '.jpeg'),\
					(_(u'PNG (.png)'), '.png'),\
					(_(u'GIF (.gif)'), '.gif'),\
					(_(u'BMP (.bmp)'), '.bmp'),\
					(_(u'PPM (.ppm)'), '.ppm'),\
					(_(u'TIFF (.tiff)'), '.tiff'),\
					(_(u'TIF (.tif)'), '.tif')]

		# Se trouve directement dans l'onglet Réglages
		self.grid = QGridLayout()
		self.grid.addWidget(QLabel(_(u"Traitement à partir de l'image (numéro)")), 0, 0)
		self.spin1=SpinSlider(1, 100000, 1, '', self)
		self.grid.addWidget(self.spin1, 0, 1)
		self.connect(self.spin1, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		self.grid.addWidget(QLabel(_(u"Nombre de chiffres après le nom de l'image")), 1, 0)
		self.spin2=SpinSlider(3, 18, 6, '', self)
		self.grid.addWidget(self.spin2, 1, 1)
		self.connect(self.spin2, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)

		self.grid.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid)
		vboxReglage.addStretch()

		# Insertion des formats dans la combo box
		for i in self.listeComboReglage:
                	self.comboReglage.addItem(i[0],QVariant(i[1]))
		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"), self.changerComboReglage)
		# Affiche l'entrée de la boite de combo inscrite dans un fichier de configuration
		self.base.valeurComboIni(self.comboReglage, self.config, self.idSection, 'format')

		self.grid2 = QGridLayout()

		# Label qualité pour la qualité (compression) lors de la sauvegarde en JPEG
		self.labQualite=QLabel(_(u"Qualité"))
		self.labQualite.hide()

		self.grid2.addWidget(QLabel(_(u'Type de format après traitement')), 0, 0)
		self.grid2.addWidget(self.comboReglage, 0, 1)
		self.grid2.addWidget(self.labQualite, 2, 0)
		# Réglage de la qualité pour la qualité (compression) lors de la sauvegarde en JPEG
		self.spin3=SpinSlider(1, 100, 75, '', self)
		self.spin3.hide()

		i = self.comboReglage.currentIndex()
		idCombo=str(self.comboReglage.itemData(i).toStringList()[0])
		if idCombo in ['.jpg', '.jpeg']:
			self.labQualite.show()
			self.spin3.show()
		else:
			self.labQualite.hide()
			self.spin3.hide()

		self.grid2.addWidget(self.spin3, 2, 1)
		self.connect(self.spin3, SIGNAL("valueChanged(int)"), self.changeQualitePourJPEG)

		self.grid2.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid2)
		vboxReglage.addStretch()

		#=== 2ème onglet ===#
		# infos - logs
		self.zoneAffichInfosImg = QTextEdit("")
		if PYQT_VERSION_STR < "4.1.0":
			self.zoneAffichInfosImg.setText = self.zoneAffichInfosImg.setPlainText
		self.zoneAffichInfosImg.setReadOnly(True)
		self.framImg=QFrame()
		vboxReglage=QVBoxLayout(self.framImg)
		vboxReglage.addWidget(self.zoneAffichInfosImg)
		self.framImg.setEnabled(False)

		# -------------------------------------------------
		# Onglets d'affichage image source et destination
		# -------------------------------------------------

		# Là où s'afficheront les images
		self.afficheurImgSource=SelectWidget(geometrie = geometry)
 		self.afficheurImgDestination=Lecture_VisionImage(statusBar)

		self.indexTabImgSource = self.tabwidget.addTab(self.afficheurImgSource, _(u'Image(s) source'))
		self.indexTabReglage=self.tabwidget.addTab(self.framReglage, _(u'Réglages'))
		self.indexTabImgDestin=self.tabwidget.addTab(self.afficheurImgDestination, _(u'Image(s) après traitement'))
		self.indexTabInfo=self.tabwidget.addTab(self.framImg, _(u'Infos'))

		vbox.addWidget(self.tabwidget)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSource # Fait le lien avec le sélecteur de fichier source.

		#------------------
		# Widgets du bas
		#------------------

		# boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		boutAide.setFocusPolicy(Qt.NoFocus)
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		self.boutApPremImg = QPushButton(_(u" Voir le résultat"))
		self.boutApPremImg.setIcon(QIcon("Icones/icone_visionner_128.png"))
		self.boutApPremImg.setFocusPolicy(Qt.NoFocus)
		self.boutApPremImg.setEnabled(False)
		self.connect(self.boutApPremImg, SIGNAL("clicked()"), self.visu_1ere_img)
		self.boutApp=QPushButton(_(u" Appliquer"))
		self.boutApp.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		self.boutApp.setFocusPolicy(Qt.NoFocus)
		self.boutApp.setEnabled(False)
		self.connect(self.boutApp, SIGNAL("clicked()"), self.appliquer0)

		# Ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		vbox.addWidget(ligne)
		vbox.addSpacing(-5)	# la ligne doit être plus près des boutons

		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()	# espace entre les 2 boutons
		hbox.addWidget(self.boutApPremImg)
		hbox.addStretch()
		hbox.addWidget(self.boutApp)
		vbox.addLayout(hbox)

		self.setLayout(vbox)

		#------------------------------------------------
		# Barre de progression dans une fenêtre séparée
		#------------------------------------------------

		self.progress=QProgressDialog(_(u"Progression ..."), _(u"Arrêter le processus"), 0, 100)
		self.progress.setWindowTitle(_(u'EnKoDeur-Mixeur. Fenêtre de progression'))
		# Attribution des nouvelles dimensions
		self.progress.setMinimumWidth(500)
		self.progress.setMinimumHeight(100)

		self.connect(self.tabwidget, SIGNAL("currentChanged(int)"), self.fctTab)

		#----------------------------------------------------------------------------------------------------
		# Signal de présence d'images dans ler widget de sélection -> modifie le statut des boutons d'action
		#----------------------------------------------------------------------------------------------------

		self.connect(self.afficheurImgSource, SIGNAL("pictureChanged(int)"), self.modifBoutonsAction)

		#----------------------------------------------------------------------------------------------------
		# Signal pour afficher ou ne pas afficher les widgets de changement de qualité pour les images
		#----------------------------------------------------------------------------------------------------

		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"), self.changerQualJPEG)


	def modifBoutonsAction(self, i):
		"On active ou désactive les boutons d'action selon s'il y a des images ou pas dans le widget de sélection"
		self.boutApp.setEnabled(i)
		self.boutApPremImg.setEnabled(i)
		self.modifImageSource = 1


	def changerComboReglage(self, i):
		"""Récup/affichage ds le terminal de l'index de self.comboReglage"""
		#print self.comboReglage.currentText()
		EkdPrint(u"%s" % self.comboReglage.currentText())
		self.config.set(self.idSection, 'format', self.listeComboReglage[i][1])


	def changerQualJPEG(self):
		''' Changement de la qualité pour les images jpeg à l'enregistrement '''

		# Si on sélectionne le format JPEG (avec extension .jpg ou .jpeg) dans la liste
		# déroulante, on peut régler la qualité du JPEG pour la sauvegarde
		if self.comboReglage.currentIndex() in [0, 1]:
			self.labQualite.show()
			self.spin3.show()
		# Si on sélectionne tous les autres formats, les widgets n'apparaissent pas
		else:
			self.labQualite.hide()
			self.spin3.hide()


	def changeValNbreImg_1(self):
		"""Gestion du nombre d'images à traiter"""
		#print "Traitement a partir de l'image (numero):", self.spin1.value()
		EkdPrint(u"Traitement a partir de l'image (numero): %s" % self.spin1.value())
		#print "Nombre de chiffres apres le nom de l'image:", self.spin2.value()
		EkdPrint(u"Nombre de chiffres apres le nom de l'image: %s" % self.spin2.value())


	def changeQualitePourJPEG(self):
		#print "Compression JPEG, qualité:", self.spin3.value()
		EkdPrint(u"Compression JPEG, qualité: %s" % self.spin3.value())


	def fctTab(self, i):
		"Affichage d'une ou plusieurs images converties"

		# Cela ne concerne que l'onglet de visualisation des images après leur conversion
		if i == self.indexTabImgDestin:
			if self.conversionImg:
				# Affichage si on sauvegarde par le bouton Appliquer et sauver
				#print "La conversion vient d'avoir lieu -> affichage des images du lot de destination"
				EkdPrint(u"La conversion vient d'avoir lieu -> affichage des images du lot de destination")
				cheminImages = os.path.dirname(self.listeImgDestin[0])
				liste = []
				for fichier in self.listeImgDestin:
					liste.append(os.path.basename(fichier))
				self.afficheurImgDestination.updateImages(liste, cheminImages)
			elif not self.boutApp.isEnabled() or self.modifImageSource:
				# Si le bouton de conversion n'est pas actif, c'est qu'il n'y a plus d'image source
				# -> on n'a plus de raison de maintenir des images dans l'afficheur de résultat
				# Si les images sources ont été modifiées, on purge aussi l'afficheur de résultat
				self.afficheurImgDestination.updateImages([])
			self.conversionImg = 0
			self.modifImageSource = 0


	def metaFctTab(self, i):
		"""Changement d'onglet (conçu pour sélectionner les onglets "Images Source" après le chargement de nouvelles images sources ou "Images Après Traitement" après la conversion). But: s'assurer que la fonction associée au QTabWidget (affichage d'images, grisage/dégrisage du curseur...) sera bien appliquée même si on est déjà sur le bon onglet"""
		if self.tabwidget.currentIndex()!=i:
			self.tabwidget.setCurrentIndex(i)
		else: self.fctTab(i)


	def visu_1ere_img(self):
		"""Fonction pour faire une simulation de rendu (avec les réglages opérés dans l'onglet Réglages)
		et ce à partir du bouton Aperçu à partir de la première image, toujours dans l'onglet Réglages.
		Pour les commentaires, se référer à la fonction chang_format juste en dessous"""

		# Récupération du fichier sélectionné par l'utilisateur (si pas de fichier
		# sélectionné par l'utilisateur, la 1ère image de la liste est prise)
		file = self.afficheurImgSource.getFile()
		if not file: return
		self.listeImgSource = [file]

		i = self.comboReglage.currentIndex()
		ext=self.comboReglage.itemData(i).toString()
		ext=str(ext).lower()

		# Formats (extensions) supportées: .bmp, .gif, .jpeg, .jpg, .mng, .pbm, .pgm,
		# .png, .ppm, .svg, .tif, .tiff, .xbm, .xpm
		formats = [".%s" % unicode(format).lower() \
			for format in QImageReader.supportedImageFormats()]

		# Chemin+nom d'image pour la sauvegarde
		self.cheminCourantSauv = self.repTampon+'0_image_visu_'+string.zfill(1, 6)+ext

		# CONVERSION

		# Uniquement pour Linux et MacOSX
		if os.name in ['posix', 'mac']:
			# On sélectionne le 'Type de format après traitement' à JPEG (.jpg)
			# ou JPEG (.jpeg) le traitement se fait par Python Imaging Library
			if i in [0, 1]:
				im = Image.open(self.listeImgSource[0]).save(self.cheminCourantSauv, quality=self.spin3.value())
			# Si on sélectionne les autres entrées, le traitement se fait par ImageMagick
			else:
				import locale
				# Conversion immédiate dans le rep tampon
				os.system(("convert "+"\""+self.listeImgSource[0]+"\""+' '+"\""+self.cheminCourantSauv+"\"").encode(locale.getdefaultlocale()[1]))
				
		# Uniquement pour windows
		elif os.name == 'nt':
			# Dans la version windows les autres entrees ne sont pas traitees 
			# par ImageMagik mais directement par Python Imaging Library (car 
			# par le traitement avec ImageMagick rien ne s'affiche, bizarre !!!)
			if i in [0, 1, 2, 3, 4, 5, 6, 7]:
				im = Image.open(self.listeImgSource[0]).save(self.cheminCourantSauv, quality=self.spin3.value())

		# AFFICHAGE

		# Récup de l'extension chargée
		ext_chargee=os.path.splitext(self.listeImgSource[0])[1]

		# Si le format (l'extension) chargé et le format sélectionné pour la sortie
		# dans Réglages sont des formats supportés, l'image avec ce format est
		# simplement affichéé
		# ----------------------------------------------------------------------
		# Aussi bizarre que cela puisse paraître (et .xpm est un format reconnu)
		# la conversion en xpm se fait bien mais l'image n'est pas lue dans le
		# lecteur --> alors conversion en jpeg ... et l'image est lue
		# ----------------------------------------------------------------------
		if ext in formats:
			# Récupération de la liste contenant le chemin+fichier contenus
			# contenu dans le répertoire temporaire
			listeImgDestinVisuTmp_0=glob.glob(self.repTampon+'*.*')
			listeImgDestinVisuTmp_0.sort()
			# Elimination des fichiers parasites si multiples conversions
			# --> seulement l'extension de sortie sélectionnée est gardée
			for parctemp_0 in listeImgDestinVisuTmp_0:
				if os.path.splitext(parctemp_0)[1]!=ext:
					os.remove(parctemp_0)

		# Affichage de l'image temporaire
		# Ouverture d'une boite de dialogue affichant l'aperçu.
		#
		# Affichage par le bouton Voir le résultat
		visio = VisionneurEvolue(self.cheminCourantSauv)
		visio.redimenFenetre(self.mainWindowFrameGeometry, 1., 0.7)
		visio.exec_()

		return 0


	def chang_format(self):
		""" Changer format (gestion de différents formats de fichiers) """

		# Récupération de la liste des fichiers chargés
		self.listeChemin=self.afficheurImgSource.getFiles()

		# Récup du format sélectionné par l'utilisateur
		i = self.comboReglage.currentIndex()
		ext=self.comboReglage.itemData(i).toString()
		ext=str(ext).lower()
		#print "format:", ext
		EkdPrint(u"format: %s" % ext)

		nbreElem=len(self.listeChemin)

		# Liste pour affichage des images chargées (ds le tabwidget)
		listeAff_1=[]
		# Liste pour affichage des pages sauvegardées (ds le tabwidget)
		listeAff_2=[]

		# La page Image résultat devient visible
		#self.tabwidget.setCurrentIndex(self.indexImageResultat)

		# Liste des formats supportés pour l'affichage
		formats = [".%s" % unicode(format).lower() \
			for format in QImageReader.supportedImageFormats()]

		#print "formats:", formats
		EkdPrint(u"formats: %s" % formats)

		process = QProcess(self)

		# Boucle principale
		for parc in range(nbreElem):

			# Chemin de sauvegarde
			vraiCheminSauv = self.chemDossierSauv+'_'+string.zfill(parc+self.spin1.value(), self.spin2.value())+ext

			# On sélectionne le 'Type de format après traitement' à JPEG (.jpg) ou JPEG (.jpeg)
			
			# Uniquement pour Linux et MacOSX
			if os.name in ['posix', 'mac']:
				# le traitement se fait par Python Imaging Library
				if i in [0, 1]:

					im = Image.open(self.listeChemin[parc]).save(vraiCheminSauv, quality=self.spin3.value())
					
			# Uniquement pour windows
			elif os.name == 'nt':
				
				if i in [0, 1, 2, 3, 4, 5, 6, 7]:
					
					im = Image.open(self.listeChemin[parc]).save(vraiCheminSauv, quality=self.spin3.value())

			# Bouton Cancel pour arrêter la progression donc le process
			if (self.progress.wasCanceled()): break


			# Si on sélectionne les autres entrées, le traitement se fait par ImageMagick
			else:

				# Enregistrement/conversion des formats sélectionnés
				process.start("convert "+"\""+self.listeChemin[parc]+"\" "+"\""+vraiCheminSauv+"\"")

				# Ajout des images par la variable vraiCheminSauv dans la liste
				self.listeImgDestin.append(vraiCheminSauv)

				listeAff_1.append(self.listeChemin[parc])
				listeAff_2.append(vraiCheminSauv)

				# ================================================================== #
				# Calcule le pourcentage effectue a chaque passage et ce pour la
				# barre de progression .
				# ---------------------------------------------
				val_pourc=((parc+1)*100)/nbreElem

				# --------------------------------------------
				# Affichage de la progression (avec
				# QProgressDialog) ds une fenêtre séparée
				self.progress.setValue(val_pourc)
				QApplication.processEvents()
				# Bouton Cancel pour arrêter la progression donc le process
				if (self.progress.wasCanceled()): break
				# --------------------------------------------

				if not process.waitForStarted(3000):
					QMessageBox.warning(None, _(u"Erreur"), _(u"Bogue au lancement de la commande"))
				process.waitForFinished(-1)

		# Conditions d'affichage des images dans l'interface
		# Si le format est supporté pour l'affichage ...
		if ext in formats:

			# Affichage des images après traitement
			#
			# Changement d'onglet et fonctions associées
			self.conversionImg = 1
			self.metaFctTab(self.indexTabImgDestin)


		# La liste pour l'affichage des images ds l'interface est
		# vidée pour que les images affichées ne s'amoncellent pas
		# si plusieurs rendus à la suite
		self.listeImgDestin=[]

		# Affichage des infos sur l'image -------------------------
		# On implémente les chemins des fichiers dans une variable
		# pour préparer l'affichage des infos
		texte1=_(u" Image(s) chargée(s)")
		texte2=_(u" Image(s) convertie(s)")
		a='#'*36

		self.infosImgProv_1=a+'\n#'+texte1+'\n'+a
		self.infosImgProv_2=a+'\n#'+texte2+'\n'+a

		# Images chargées
		for parcStatRendu_1 in listeAff_1:
			self.infosImgProv_1=self.infosImgProv_1+'\n'+parcStatRendu_1

		# Pages sauvegardées
		for parcStatRendu_2 in listeAff_2:
			self.infosImgProv_2=self.infosImgProv_2+'\n'+parcStatRendu_2

		# affichage des infos dans l'onglet
		self.zoneAffichInfosImg.setText(self.infosImgProv_1+'\n\n'+self.infosImgProv_2+'\n\n')
		self.framImg.setEnabled(True)

		# remise à 0 de la variable provisoire de log
		self.infosImgProv=''
		# ---------------------------------------------------------


	def sonderTempsActuel(self):
		"""x ms après l'apparition de la boite de dialogue, on lance la conversion. But: faire en sorte que la boite de dialogue ait le temps de s'afficher correctement"""
		self.timer.stop()
		self.appliquer()


	def appliquer(self):
		"""Lancement de la fonction chang_format"""
		self.chang_format()


	def appliquer0(self):
		"""Préparation de la conversion"""

		suffix=""
		# Boîte de dialogue pour sauvegarder (nom du nouveau fichier)
                self.chemDossierSauv = EkdSaveDialog(self, mode="image", suffix=suffix, title=_(u"Sauver"), multiple=True)
		self.chemDossierSauv = self.chemDossierSauv.getFile()

		if not self.chemDossierSauv: return

		self.progress.reset()
		self.progress.show()
		self.progress.setValue(0)
		QApplication.processEvents()

		# Lancement de la conversion dans 250 ms (seule solution trouvée pour éviter
		# le grisage au début)
		self.timer.start(250)


	def afficherAide(self):
		"""Boîte de dialogue de l'aide"""

		# ATTENTION _ a été mis à la place de tr car le script de mise à jour gettext (mise_a_jour_gettext.py)
		# ne fonctionne pas pour ekdDoc.pot avec les clés --keyword donc les nouvelles lignes vides encore
		# non traduites de la doc se retrouveront dans ekd.pot au lieu de ekdDoc.pot

		# Utilisation de EkdAide
		messageAide=EkdAide(parent=self)
		messageAide.setText(_(u"<p><b>Vous pouvez ici changer/transformer le format des images (et par là même en changer leur extension). En ce qui concerne le JPEG, vous pourrez sélectionner deux types d'extension (jpeg ou jpg), toujours pour le JPEG, vous aurez aussi la possiblité de régler la qualité (c'est à dire la compression).</b></p><p><b>Les formats pris en compte sont: JPEG, PNG, GIF, BMP, PPM, TIFF et TIF.</b></p><p>Dans l'onglet <b>'Images sources'</b> cliquez sur le bouton <b>Ajouter</b>, une boîte de dialogue apparaît, sur la partie gauche sélectionnez le répertoire (au besoin dépliez les sous-répertoires), allez chercher vos image(s). Si vous voulez sélectionner plusieurs images d'un coup, maintenez la touche <b>CTRL</b> (ou <b>SHIFT</b>) du clavier enfoncée (tout en sélectionnant vos images), cliquez sur <b>Ajouter</b>.</p><p>Dans l'onglet <b>'Réglages'</b> faites les réglages du <b>'Traitement à partir de l'image (numéro)'</b> et du <b>'Nombre de chiffres après le nom de l'image' <font color='red'>(la plupart du temps les valeurs par défaut suffisent)</b></font>, ensuite choisissez votre <b>'Type de format après traitement'</b> et réglez la <b>'Qualité'</b> (disponible uniquement si vous avez sélectionné une image JPEG en sortie). Cliquez sur le bouton <b>'Voir le résultat'</b> (vous voyez à ce moment le résultat de vos réglages sur la première image du lot s'afficher dans une nouvelle fenêtre).</p></p><p>Une fois tout ceci fait, cliquez sur le bouton <b>'Appliquer'</b>, sélectionnez le répertoire de sauvegarde, indiquez votre <b>'Nom de fichier'</b>, cliquez sur le bouton <b>'Enregistrer'</b>.</p><p>Si vous faites un clic droit de la souris (sur l'image) dans l'onglet <b>Image(s) après traitement</b>, vous accédez à des paramètres vous permettant différents affichages de la dite image. De même dans cet onglet vous pouvez lancer la visualisation des images par le bouton <b>Lancer le diaporama</b> (le bouton violet avec une flèche blanche vers la droite).</p><p>L'onglet <b>'Infos'</b> vous permet de voir le filtre utilisé, les image(s) chargée(s) et les image(s) convertie(s).</p>"))
		messageAide.show()


	def save(self) :
		self.afficheurImgSource.saveFileLocation(self.idSection)
		EkdConfig.set(self.idSection, u'choixReglage', unicode(self.comboReglage.currentIndex()))
		EkdConfig.set(self.idSection, u'spin1', unicode(self.spin1.value()))
		EkdConfig.set(self.idSection, u'spin2', unicode(self.spin2.value()))
		EkdConfig.set(self.idSection, u'spin3', unicode(self.spin3.value()))


	def load(self) :
		self.afficheurImgSource.loadFileLocation(self.idSection)
		self.comboReglage.setCurrentIndex(int(EkdConfig.get(self.idSection, u'choixReglage')))
		self.spin1.setValue(int(EkdConfig.get(self.idSection, u'spin1')))
		self.spin2.setValue(int(EkdConfig.get(self.idSection, u'spin2')))	
		self.spin3.setValue(int(EkdConfig.get(self.idSection, u'spin3')))
Example #6
0
class Image_Divers_Compositing(QWidget):
	# -----------------------------------
	# Cadre accueillant les widgets de :
	# Image >> Divers >> Compositing
	# -----------------------------------
	def __init__(self, statusBar, geometry):
        	QWidget.__init__(self)
		
		# ----------------------------
		# Quelques paramètres de base
		# ----------------------------

		# Paramètres de configuration
		self.config = EkdConfig
		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()
		self.idSection = "image_image_composite"
		# Log du terminal
		self.base.printSection(self.idSection)
		# Fonction appelant la fenêtre principale
		self.mainWindowFrameGeometry = geometry

		# Création des répertoires temporaires. Utilisation de EkdConfig
		self.repTampon = EkdConfig.getTempDir() + os.sep + "tampon" + os.sep + "temp_duplication" + os.sep
		if os.path.isdir(self.repTampon) is False:
        		os.makedirs(self.repTampon)
			
		# Au cas où le répertoire existait déjà et qu'il n'était pas vide 
		# -> purge (simple précausion)
		for toutRepCompo in glob.glob(self.repTampon+'*.*'):
			os.remove(toutRepCompo)
			
		# Répertoire tampon dans lequel est crée le compositing qui sera crée par le
		# bouton 'Voir le résultat'. Utilisation de EkdConfig
		self.repTamponVisuVoirRes = self.repTampon + "visu_voir_res_compo" + os.sep
		if os.path.isdir(self.repTamponVisuVoirRes) is False:
        		os.makedirs(self.repTamponVisuVoirRes)
		
		# Au cas où le répertoire existait déjà et qu'il n'était pas vide 
		# -> purge (simple précausion)
		for toutRepCompoVisu in glob.glob(self.repTamponVisuVoirRes+'*.*'):
			os.remove(toutRepCompoVisu)
		
		# Répertoire temporaire 1 pour les redimensionnement des images
		if os.path.isdir(self.repTampon+'redim_1/') is False:
        		os.makedirs(self.repTampon+'redim_1/')
		# Répertoire temporaire 2 pour les redimensionnement des images	
		if os.path.isdir(self.repTampon+'redim_2/') is False:
        		os.makedirs(self.repTampon+'redim_2/')
			
		# Au cas où le répertoire existait déjà et qu'il n'était pas vide 
		# -> purge (simple précausion)
		for toutRepCompoRedim in glob.glob(self.repTampon+'redim_1/'+'*.*'):
			if len(toutRepCompoRedim)>0:
				os.remove(toutRepCompoRedim)
		# ...
		for toutRepCompoRedim in glob.glob(self.repTampon+'redim_2/'+'*.*'):
			if len(toutRepCompoRedim)>0:
				os.remove(toutRepCompoRedim)
		
		#=== Drapeaux ===#
		# Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)
		
		# Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
		# Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
		self.conversionImg = 0
		
		# Est-ce qu'une prévisualisation a été appelée?
		self.previsualImg = 0
		# Est-ce que des images sources ont été modifiées? (c'est-à-dire ajoutées ou supprimées)
		self.modifImageSource = 0

		# Liste de chemins de fichiers avec et sans canal alpha et du dossier de sauvegarde
		self.listeChemAVcanAlph=[]
		self.listeChemSANScanAlph=[]
		self.listeImgDestin = []
		
		# Boite d'alignement vertical
		vbox=QVBoxLayout(self)
		
		# --------------------------------------------------
		# widgets du haut : titre + bouton de sélection
		# --------------------------------------------------
		
		hbox = QHBoxLayout()
		
		# Ajout du titre de la page et de l'aperçu à la boite verticale
		vbox.addLayout(hbox, 0)
		
		#=== Bouton de sélection des images alpha et sans alpha ===#
		hbox = QHBoxLayout()

		self.framReglage=QFrame()
		vboxReglage=QVBoxLayout(self.framReglage)

		# Pour la gestion du nombre d'images à traiter ##############
		self.grid = QGridLayout()
		self.grid.addWidget(QLabel(_(u"Traitement à partir de l'image (numéro)")), 0, 0)
		self.spin1=SpinSlider(1, 100000, 1, '', self)
		self.grid.addWidget(self.spin1, 0, 1)
		self.connect(self.spin1, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		self.grid.addWidget(QLabel(_(u"Nombre de chiffres après le nom de l'image")), 1, 0)
		self.spin2=SpinSlider(3, 18, 6, '', self)
		self.grid.addWidget(self.spin2, 1, 1)
		self.connect(self.spin2, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		
		self.grid.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid)
		vboxReglage.addStretch()

		# -------------------------------------------------
		# Onglets d'affichage image source et destination
		# -------------------------------------------------
		
		# On peut sélectionner les extensions qui doivent être visibles comme ceci:
		#self.afficheurImgSource=SelectWidget(extensions=["*.jpg", "*.png"], geometrie = self.mainWindowFrameGeometry)
		# Là uniquement les fichiers png et gif apparaissent ds la fenêtre de chargement
		# Ne pas oublier de mettre * avant le point et l'extension

		# Là où s'afficheront les images
		# Avec canal alpha
		self.afficheurImgSourceAvecCanalAlpha=SelectWidget(extensions=["*.png", "*.gif"], geometrie = self.mainWindowFrameGeometry)
		# Sans canal alpha
		self.afficheurImgSourceSansCanalAlpha=SelectWidget(geometrie = self.mainWindowFrameGeometry)

		# Gestion de la configuration via EkdConfig
		# Résultat du compositing
		self.afficheurImgDestination=Lecture_VisionImage(statusBar)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSourceSansCanalAlpha # Fait le lien avec le sélecteur de fichier source.
		### Remarque : Le choix a été fait de ne pas mettre la boîte de sélection des images alpha dans le tampon.
		
		# infos - logs
		self.zoneAffichInfosImg = QTextEdit("")
		if PYQT_VERSION_STR < "4.1.0":
			self.zoneAffichInfosImg.setText = self.zoneAffichInfosImg.setPlainText
		self.zoneAffichInfosImg.setReadOnly(True)
		self.fram=QFrame()
		vboxInfIm=QVBoxLayout(self.fram)
		vboxInfIm.addWidget(self.zoneAffichInfosImg)
		self.fram.setEnabled(False)
		
		self.tabwidget=QTabWidget()
		
		self.indexTabImgSourceAvCanAlph = self.tabwidget.addTab(self.afficheurImgSourceAvecCanalAlpha, _(u'Image(s) avec canal alpha'))
		self.indexTabImgSourceSansCanAlph = self.tabwidget.addTab(self.afficheurImgSourceSansCanalAlpha, _(u'Image(s) sans canal alpha'))
		self.indexTabReglage=self.tabwidget.addTab(self.framReglage, _(u'Réglages'))
		self.indexTabImgDestin=self.tabwidget.addTab(self.afficheurImgDestination, _(u'Image(s) après traitement'))
		self.indexTabInfo=self.tabwidget.addTab(self.fram, _(u'Infos'))
		
		vbox.addWidget(self.tabwidget)
		
		# -------------------------------------------------------------------
		# widgets du bas : ligne + boutons
		# -------------------------------------------------------------------
		
		# boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		self.boutApPremImg = QPushButton(_(u" Voir le résultat"))
		self.boutApPremImg.setIcon(QIcon("Icones/icone_visionner_128.png"))
		self.boutApPremImg.setFocusPolicy(Qt.NoFocus)
		self.boutApPremImg.setEnabled(False)
		self.connect(self.boutApPremImg, SIGNAL("clicked()"), self.visu_1ere_derniere_img)
		self.boutAppliquer=QPushButton(_(u" Appliquer et sauver"))
		self.boutAppliquer.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		self.boutAppliquer.setEnabled(False)
		self.connect(self.boutAppliquer, SIGNAL("clicked()"), self.appliquer)
		
		# ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		vbox.addWidget(ligne)
		vbox.addSpacing(-5)	# la ligne doit être plus près des boutons
		
		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()	# espace entre les 2 boutons
		hbox.addWidget(self.boutApPremImg)
		hbox.addStretch()
		hbox.addWidget(self.boutAppliquer)
		vbox.addLayout(hbox)
		
		# affichage de la boîte principale
		self.setLayout(vbox)
		
		self.connect(self.tabwidget, SIGNAL("currentChanged(int)"), self.fctTab)
		
		#----------------------------------------------------------------------------------------------------
		# Signal de présence d'images dans ler widget de sélection -> modifie le statut des boutons d'action
		#----------------------------------------------------------------------------------------------------
		
		self.connect(self.afficheurImgSourceSansCanalAlpha, SIGNAL("pictureChanged(int)"), self.modifBoutonsAction)
		
		
	def modifBoutonsAction(self, i):
		"On active ou désactive les boutons d'action selon s'il y a des images ou pas dans le widget de sélection"
		self.boutAppliquer.setEnabled(i)
		self.boutApPremImg.setEnabled(i)
		self.modifImageSource = 1
	

	def changeValNbreImg_1(self):
		"""Gestion du nombre d'images à traiter"""
		#print "Traitement a partir de l'image (numero):", self.spin1.value()
		EkdPrint(u"Traitement a partir de l'image (numero): %s" % self.spin1.value())
		#print "Nombre de chiffres apres le nom de l'image:", self.spin2.value()
		EkdPrint(u"Nombre de chiffres apres le nom de l'image: %s" % self.spin2.value())


	def fctTab(self, i):
		"Affichage d'une ou plusieurs images converties"
		
		# Cela ne concerne que l'onglet de visualisation des images après leur conversion
		if i == self.indexTabImgDestin:
			if self.conversionImg:
				# Affichage si on sauvegarde par le bouton Appliquer et sauver
				#print "La conversion vient d'avoir lieu -> affichage des images du lot de destination"
				EkdPrint(u"La conversion vient d'avoir lieu -> affichage des images du lot de destination")
				cheminImages = os.path.dirname(self.listeImgDestin[0])
				liste = []
				for fichier in self.listeImgDestin:
					liste.append(os.path.basename(fichier))
				self.afficheurImgDestination.updateImages(liste, cheminImages)
			elif not self.boutAppliquer.isEnabled() or self.modifImageSource:
				# Si le bouton de conversion n'est pas actif, c'est qu'il n'y a plus d'image source
				# -> on n'a plus de raison de maintenir des images dans l'afficheur de résultat
				# Si les images sources ont été modifiées, on purge aussi l'afficheur de résultat
				self.afficheurImgDestination.updateImages([])
			self.conversionImg = 0
			self.modifImageSource = 0
	
	
	def metaFctTab(self, i):
		"""Changement d'onglet (conçu pour sélectionner les onglets "Images Source" après le chargement de nouvelles images sources ou "Images Après Traitement" après la conversion). But: s'assurer que la fonction associée au QTabWidget (affichage d'images, grisage/dégrisage du curseur...) sera bien appliquée même si on est déjà sur le bon onglet"""
		if self.tabwidget.currentIndex()!=i:
			self.tabwidget.setCurrentIndex(i)
		else: self.fctTab(i)


	def stat_dim_img_1(self):
		"""Calcul statistique des dimensions des images les plus présentes dans le lot"""
		
		# Récupération de la liste des fichiers chargés (avec canal alpha)
		self.listeChemAVcanAlph=self.afficheurImgSourceAvecCanalAlpha.getFiles()
		
		# Ouverture et mise ds une liste des dimensions des images
		listePrepaRedim=[Image.open(aA).size for aA in self.listeChemAVcanAlph]
		
		# Merci beaucoup à Marc Keller de la liste: python at aful.org de m'avoir
		# aidé pour cette partie (les 4 lignes en dessous)
		dictSeq={}.fromkeys(listePrepaRedim, 0)
		for cle in listePrepaRedim: dictSeq[cle]+=1
		self.lStatDimSeq=sorted(zip(dictSeq.itervalues(), dictSeq.iterkeys()), reverse=1)
		self.dimStatImg=self.lStatDimSeq[0][1]
		
		#print "Toutes les dimensions des images (avec le nbre d'images):", self.lStatDimSeq
		EkdPrint(u"Toutes les dimensions des images (avec le nbre d'images): " + str(self.lStatDimSeq))
		#print 'Dimension des images la plus presente dans la sequence:', self.dimStatImg
		EkdPrint(u'Dimension des images la plus presente dans la sequence: ' + str(self.dimStatImg))
		#print "Nombre de tailles d'images différentes dans le lot :", len(self.lStatDimSeq)
		EkdPrint(u"Nombre de tailles d'images différentes dans le lot: " + str(len(self.lStatDimSeq)))
		
		if len(self.lStatDimSeq)>1: return 0
		else: return 1
	
	
	def redim_img_1(self):
		"""Si l'utilisateur charge des images avec des tailles complètement différentes --> les images de la séquence  peuvent être redimensionnées"""
		
		if not self.stat_dim_img_1():
			reply = QMessageBox.warning(self, 'Message',
			_(u"Vos images ne sont pas toutes de la même taille. Voulez-vous redimensionner les images de sortie à la taille la plus répandue dans la séquence ?. Dans la plupart des cas il faut répondre oui."), QMessageBox.Yes, QMessageBox.No)
			if reply == QMessageBox.No:
				return
			
			# Les images de tailles différentes à la plus répandue sont redimensionnées
			# dans un répertoire temporaire.
			# Les images redimensionnées voient leur chemin modifié dans la liste des
			# chemins des images sources. Les autres chemins ne changent pas.
			index=0
			for chemImg in self.listeChemAVcanAlph:
				obImg=Image.open(chemImg)
				if obImg.size!=self.dimStatImg:
					pass
				sRedim=obImg.resize(self.dimStatImg, Image.ANTIALIAS)
				chemSortie = self.repTampon+'redim_1'+os.sep+os.path.basename(chemImg)
				sRedim.save(chemSortie)
				self.listeChemAVcanAlph[index] = chemSortie
				index += 1


	def stat_dim_img_2(self):
		"""Calcul statistique des dimensions des images les plus présentes dans le lot"""

		# Récupération de la liste des fichiers chargés (sans canal alpha)
		self.listeChemSANScanAlph=self.afficheurImgSourceSansCanalAlpha.getFiles()
		###########################################################################
		
		# Ouverture et mise ds une liste des dimensions des images
		listePrepaRedim=[Image.open(aA).size for aA in self.listeChemSANScanAlph]
		
		# Merci beaucoup à Marc Keller de la liste: python at aful.org de m'avoir
		# aidé pour cette partie (les 4 lignes en dessous)
		dictSeq={}.fromkeys(listePrepaRedim, 0)
		for cle in listePrepaRedim: dictSeq[cle]+=1
		self.lStatDimSeq=sorted(zip(dictSeq.itervalues(), dictSeq.iterkeys()), reverse=1)
		self.dimStatImg=self.lStatDimSeq[0][1]
		
		#print self.dimStatImg
		EkdPrint(self.dimStatImg)
		
		#print "Toutes les dimensions des images (avec le nbre d'images):", self.lStatDimSeq
		EkdPrint(u"Toutes les dimensions des images (avec le nbre d'images): " + str(self.lStatDimSeq))
		#print 'Dimension des images la plus presente dans la sequence:', self.dimStatImg
		EkdPrint(u'Dimension des images la plus presente dans la sequence: ' + str(self.dimStatImg))
		#print "Nombre de tailles d'images différentes dans le lot :", len(self.lStatDimSeq)
		EkdPrint(u"Nombre de tailles d'images différentes dans le lot: " + str(len(self.lStatDimSeq)))
		
		if len(self.lStatDimSeq)>1: return 0
		else: return 1
	
	
	def redim_img_2(self):
		"""Si l'utilisateur charge des images avec des tailles complètement différentes --> les images de la séquence  peuvent être redimensionnées"""
		
		if not self.stat_dim_img_2():
			reply = QMessageBox.warning(self, 'Message',
			_(u"Vos images ne sont pas toutes de la même taille. Voulez-vous redimensionner les images de sortie à la taille la plus répandue dans la séquence ?. Dans la plupart des cas il faut répondre oui."), QMessageBox.Yes, QMessageBox.No)
			if reply == QMessageBox.No:
				return
			
			# Les images de tailles différentes à la plus répandue sont redimensionnées
			# dans un répertoire temporaire.
			# Les images redimensionnées voient leur chemin modifié dans la liste des
			# chemins des images sources. Les autres chemins ne changent pas.
			index=0
			for chemImg in self.listeChemSANScanAlph:
				obImg=Image.open(chemImg)
				if obImg.size!=self.dimStatImg:
					pass
				sRedim=obImg.resize(self.dimStatImg, Image.ANTIALIAS)
				chemSortie = self.repTampon+'redim_2'+os.sep+os.path.basename(chemImg)
				sRedim.save(chemSortie)
				self.listeChemSANScanAlph[index] = chemSortie
				index += 1


	def visu_1ere_derniere_img(self):
		"""Visionnement du compositing avant application"""
		
		# Si l'utilisateur charge des images de taille différente, fait le traitement 
		# ...,  recharge de nouvelles images, il faut que les répertoires de redimen-
		# sionnement soient vidés
		
		listePresRedim_1=glob.glob(self.repTampon+'redim_1'+os.sep+'*.*')
		listePresRedim_1.sort()
		if len(listePresRedim_1)>0:
			for parcR_1 in listePresRedim_1: os.remove(parcR_1)
			
		listePresRedim_2=glob.glob(self.repTampon+'redim_2'+os.sep+'*.*')
		listePresRedim_2.sort()
		if len(listePresRedim_2)>0:
			for parcR_2 in listePresRedim_2: os.remove(parcR_2)
		

		# Récupération de la liste des fichiers chargés (avec canal alpha)
		self.listeChemAVcanAlph=self.afficheurImgSourceAvecCanalAlpha.getFiles()
		self.listeChemAVcanAlph.sort()
		
		# Récupération de la liste des fichiers chargés (sans canal alpha)
		self.listeChemSANScanAlph=self.afficheurImgSourceSansCanalAlpha.getFiles()
		self.listeChemSANScanAlph.sort()
		
		
		# Vérification du fait que les fichiers avec canal alpha chargés contiennent bien
		# un canal alpha (RGBA) ... sinon affichage d'une boîte de dialogue d'erreur et arrêt
		# du traitement des images
		for parcMode in self.listeChemAVcanAlph:
			imVerifCanAlph=Image.open(parcMode)
			if imVerifCanAlph.mode!='RGBA':
				messErr=QMessageBox(self)
				messErr.setText(_(u"<b>Vous avez chargé des images sans canal alpha</b> (c'est à dire sans transparence) et ce à partir de l'onglet <b>Image(s) avec canal alpha</b>. Sans transparence, vous ne pouvez, en aucun cas, appliquer un compositing (vos images doivent être en mode RGBA pour que cela réussisse) !."))
				messErr.setWindowTitle(_(u"Erreur"))
				messErr.setIcon(QMessageBox.Critical)
				messErr.exec_()
				return


		# ----- TRAVAIL PREPARATOIRE --- Redimensionnement des images -----------------
		try:
			
			nbreElem_1=len(self.listeChemAVcanAlph)
			nbreElem_2=len(self.listeChemSANScanAlph)
			# Appel des fonction de redimensionnement
			self.redim_img_1()
			self.redim_img_2()
			# Récup des listes contenant les fichiers
			repRedimTemp_1=glob.glob(self.repTampon+'redim_1'+os.sep+'*.*')
			repRedimTemp_1.sort()
			repRedimTemp_2=glob.glob(self.repTampon+'redim_2'+os.sep+'*.*')
			repRedimTemp_2.sort()
	
		except:
			messageErreur=QMessageBox(self)
			messageErreur.setText(_(u"<p>Vous n'avez pas chargé d'image(s) (bouton Ajouter) dans l'onglet <b>Image(s) avec canal aplpha</b>. Recommencez et chargez des images aussi bien dans <b>Image(s) avec canal aplpha</b>, que dans <b>Image(s) sans canal aplpha</b>.</p>"))
			messageErreur.setWindowTitle(_(u"Erreur"))
			messageErreur.setIcon(QMessageBox.Critical)
			messageErreur.exec_()
			return
		# -----------------------------------------------------------------------------
		
		
		try:
			# tImgAVcanAlph --> taille des images avec canal alpha
			# tImgSANScanAlph --> taille des images avec canal alpha
			# =/= --> différent
			# == --> strictement ègal
		
			# Si tImgAVcanAlph == entre elles et tImgSANScanAlph == entre elles
			# mais tImgAVcanAlph =/= tImgSANScanAlph (tImgAVcanAlph == tImgSANScanAlph
			# est aussi valable)
			if len(repRedimTemp_1)==0 and len(repRedimTemp_2)==0:
				im01=Image.open(self.listeChemAVcanAlph[nbreElem_1-1])
				im02=Image.open(self.listeChemSANScanAlph[0])
				# Redimensionnement à la tImgAVcanAlph
				im02=im02.resize(Image.open(self.listeChemAVcanAlph[nbreElem_1-1]).size, Image.ANTIALIAS)
				imgCompoUndeChaque=Image.composite(im01, im02, im01)
			# Si tImgAVcanAlph == entre elles et tImgSANScanAlph =/= entre elles
			elif len(repRedimTemp_1)==0 and len(repRedimTemp_2)>1:
				im01=Image.open(self.listeChemAVcanAlph[nbreElem_1-1])
				im02=Image.open(repRedimTemp_2[0])
				# Redimensionnement à la tImgAVcanAlph
				im02=im02.resize(Image.open(self.listeChemAVcanAlph[nbreElem_1-1]).size, Image.ANTIALIAS)
				imgCompoUndeChaque=Image.composite(im01, im02, im01)
			# Si tImgAVcanAlph =/= entre elles et tImgSANScanAlph =/= entre elles
			# Plusieurs images avec can alpha et plusieurs images sans can alpha
			elif len(repRedimTemp_1)>1 and len(repRedimTemp_2)>1:
				im01=Image.open(repRedimTemp_1[nbreElem_1-1])
				im02=Image.open(repRedimTemp_2[0])
				# Redimensionnement à la tImgAVcanAlph
				im02=im02.resize(Image.open(repRedimTemp_1[nbreElem_1-1]).size, Image.ANTIALIAS)
				imgCompoUndeChaque=Image.composite(im01, im02, im01)
			# Si tImgAVcanAlph =/= entre elles et tImgSANScanAlph == ... là on a
			# qu'une image sans canal alpha	ce qui correspond à un arrière plan fixe
			elif len(repRedimTemp_1)>1 and len(repRedimTemp_2)==0:
				im01=Image.open(repRedimTemp_1[nbreElem_1-1])
				im02=Image.open(self.listeChemSANScanAlph[0])
				# Redimensionnement à la tImgAVcanAlph
				im02=im02.resize(Image.open(repRedimTemp_1[nbreElem_1-1]).size, Image.ANTIALIAS)
				imgCompoUndeChaque=Image.composite(im01, im02, im01)
		
		except:
			messageErreur=QMessageBox(self)
			messageErreur.setText(_(u"<p><b>Première situation d'erreur:</b> Vous n'avez pas chargé d'image(s) (bouton Ajouter) dans l'onglet <b>Image(s) avec canal aplpha</b>. Recommencez et chargez des images aussi bien dans <b>Image(s) avec canal aplpha</b>, que dans <b>Image(s) sans canal aplpha</b>.</p><p><b>Seconde situation d'erreur:</b> la visualisation de l'image ne peut pas avoir lieu car vous avez répondu non au moins une fois au moment du redimensionnement des images. Recommencez et répondez oui aux deux boîtes de dialogue.</p>"))
			messageErreur.setWindowTitle(_(u"Erreur"))
			messageErreur.setIcon(QMessageBox.Critical)
			messageErreur.exec_()
			return
		
		# Sauvegarde des images resultant du Compositing
		self.cheminCourantSauv = self.repTamponVisuVoirRes+'visu_compositing_'+string.zfill((1), 6)+'.png'
		imgCompoUndeChaque.save(self.cheminCourantSauv, "PNG")

		# Affichage de l'image temporaire 
		# Ouverture d'une boite de dialogue affichant l'aperçu.
		#
		# Affichage par le bouton Voir le résultat
		visio = VisionneurEvolue(self.cheminCourantSauv)
		visio.redimenFenetre(self.mainWindowFrameGeometry, 1., 0.7)
		visio.exec_()
		
		return 0
	
	
	def appliquer(self):
		"""Appliquer le compositing"""

		# Si l'utilisateur charge des images de taille différente, fait le traitement 
		# ...,  recharge de nouvelles images, il faut que les répertoires de redimen-
		# sionnement soient vidés
		
		listePresRedim_1=glob.glob(self.repTampon+'redim_1'+os.sep+'*.*')
		listePresRedim_1.sort()
		if len(listePresRedim_1)>0:
			for parcR_1 in listePresRedim_1: os.remove(parcR_1)
			
		listePresRedim_2=glob.glob(self.repTampon+'redim_2'+os.sep+'*.*')
		listePresRedim_2.sort()
		if len(listePresRedim_2)>0:
			for parcR_2 in listePresRedim_2: os.remove(parcR_2)
		
		# La liste pour l'affichage des images ds l'interface est
		# vidée pour que les images affichées ne s'amoncellent pas
		# si plusieurs rendus à la suite
		self.listeImgDestin=[]

		# Récupération de la liste des fichiers chargés (avec canal alpha)
		self.listeChemAVcanAlph=self.afficheurImgSourceAvecCanalAlpha.getFiles()
		self.listeChemAVcanAlph.sort()
		# Récupération de la liste des fichiers chargés (sans canal alpha)
		self.listeChemSANScanAlph=self.afficheurImgSourceSansCanalAlpha.getFiles()
		self.listeChemSANScanAlph.sort()

		# Vérification du fait que les fichiers avec canal alpha chargés contiennent bien
		# un canal alpha (RGBA) ... sinon affichage d'une boîte de dialogue d'erreur et arrêt
		# du traitement des images
		for parcMode in self.listeChemAVcanAlph:
			imVerifCanAlph=Image.open(parcMode)
			if imVerifCanAlph.mode!='RGBA':
				messErr=QMessageBox(self)
				messErr.setText(_(u"<b>Vous avez chargé des images sans canal alpha</b> (c'est à dire sans transparence) et ce à partir de l'onglet <b>Image(s) avec canal alpha</b>. Sans transparence, vous ne pouvez, en aucun cas, appliquer un compositing (vos images doivent être en mode RGBA pour que cela réussisse) !."))
				messErr.setWindowTitle(_(u"Erreur"))
				messErr.setIcon(QMessageBox.Critical)
				messErr.exec_()
				return


		# ----- TRAVAIL PREPARATOIRE --- Redimensionnement des images -----------------
		try:
			
			nbreElem_1=len(self.listeChemAVcanAlph)
			nbreElem_2=len(self.listeChemSANScanAlph)
			# Appel des fonction de redimensionnement
			self.redim_img_1()
			self.redim_img_2()
			# Récup des listes contenant les fichiers
			### Le 18/09/09 ## ...+'redim_1/*.*' transformé en ...+'redim_1'+os.sep+'*.*'
			repRedimTemp_1=glob.glob(self.repTampon+'redim_1'+os.sep+'*.*')
			repRedimTemp_1.sort()
			### Le 18/09/09 ## ...+'redim_2/*.*' transformé en ...+'redim_2'+os.sep+'*.*'
			repRedimTemp_2=glob.glob(self.repTampon+'redim_2'+os.sep+'*.*')
			repRedimTemp_2.sort()
	
		except:
			messageErreur=QMessageBox(self)
			messageErreur.setText(_(u"<p>Vous n'avez pas chargé d'image(s) (bouton Ajouter) dans l'onglet <b>Image(s) avec canal aplpha</b>. Recommencez et chargez des images aussi bien dans <b>Image(s) avec canal aplpha</b>, que dans <b>Image(s) sans canal aplpha</b>.</p>"))
			messageErreur.setWindowTitle(_(u"Erreur"))
			messageErreur.setIcon(QMessageBox.Critical)
			messageErreur.exec_()
			return
		# -----------------------------------------------------------------------------
		

    		# -----------------------------------------------------------------------------
		# Boîte de dialogue pour sauvegarder (nom du nouveau fichier)
		#------------------------------------------------------------------------------

		# Utilisation de la nouvelle boîte de dialogue de sauvegarde
		suffix=""
                self.chemDossierSauv = EkdSaveDialog(self, mode="image", suffix=suffix, title=_(u"Sauver"), multiple=True)
		self.chemDossierSauv = self.chemDossierSauv.getFile()
		
		if not self.chemDossierSauv: return
		
		# Liste pour affichage (ds le tabwidget)
		listeAff_1=[]
		listeAff_2=[]
		listeAff_3=[]
		
		# Barre de progression dans une fenêtre séparée . Attention la fenêtre
		# de la barre se ferme dès que la progression est terminée . En cas de
		# process très court, la fenêtre peut n'apparaître que très brièvement
		# (voire pas du tout si le temps est très très court) .
		self.progress=QProgressDialog(_(u"Progression ..."), _(u"Arrêter le processus"), 0, 100)
		self.progress.setWindowTitle(_(u'EnKoDeur-Mixeur. Fenêtre de progression'))
		# Attribution des nouvelles dimensions 
		self.progress.setMinimumWidth(500)
		self.progress.setMinimumHeight(100)

		# On implémente les chemins des fichiers dans une variable
		# pour préparer l'affichage des infos
		texte1=_(u" Image(s) avec canal alpha chargée(s)")
		texte2=_(u" Image(s) sans canal alpha chargée(s)")
		texte3=_(u" Résultat image(s) composite")
		a='#'*36
		self.infosImgProv_1=a+'\n#'+texte1+'\n'+a
		self.infosImgProv_2=a+'\n#'+texte2+'\n'+a
		self.infosImgProv_3=a+'\n#'+texte3+'\n'+a
		
		# -------------------------------------------------------------------
		# Si le nbre d'images chargées avec canal alpha est égal à 1 ...
		# en fait si l'utilisateur ne charge qu'une image avec et sans canal
		# alpha ...
		# -------------------------------------------------------------------
		if nbreElem_1 == 1:
		
			try :
				
                		# Ouverture des images (im01 --> avec canal alpha et 
				# im02 --> sans canal alpha)
                		im01=Image.open(self.listeChemAVcanAlph[0])
                		im02=Image.open(self.listeChemSANScanAlph[0])
				
				# Récup de la dimension des l'image chargée avec canal alpha
				w_1, h_1=im01.size
				# Récup de la dimension des l'image chargée sans canal alpha
				w_2, h_2=im02.size
				# Redimensionnement de l'image sans canal alpha à la taille de l'image avec canal alpha
				if (int(w_1), int(h_1)) != (int(w_2), int(h_2)):
					im02=im02.resize(Image.open(self.listeChemAVcanAlph[0]).size, Image.ANTIALIAS)
				
                		# Application du compositing
                		imgCompoUndeChaque=Image.composite(im01, im02, im01)

                		# Sauvegarde des images resultant du Compositing
				self.cheminCourantSauv = self.chemDossierSauv+'_'+string.zfill(self.spin1.value(), self.spin2.value())+'.png'
				imgCompoUndeChaque.save(self.cheminCourantSauv, "PNG")

				# Ajout des images par la variable self.cheminCourantSauv dans la liste self.listeChemin
				# Cette liste sert à récupérer les images pour l'affichage des images ds l'inteface
				self.listeImgDestin.append(self.cheminCourantSauv)

				# Affichage des images après traitement
				#
				# Changement d'onglet et fonctions associées
				self.conversionImg = 1
				self.metaFctTab(self.indexTabImgDestin)
				
				# log
				listeAff_1.append(self.listeChemAVcanAlph[0])
				listeAff_2.append(self.listeChemSANScanAlph[0])
				listeAff_3.append(self.cheminCourantSauv)
				
			except: 
				messageErreur=QMessageBox(self)
				messageErreur.setText(_(u"<p>Vous n'avez pas chargé d'image(s) (bouton Ajouter) dans l'onglet <b>Image(s) avec canal aplpha</b>. Recommencez et chargez des images aussi bien dans <b>Image(s) avec canal aplpha</b>, que dans <b>Image(s) sans canal aplpha</b>.</p>"))
				messageErreur.setWindowTitle(_(u"Erreur"))
				messageErreur.setIcon(QMessageBox.Critical)
				messageErreur.exec_()

		# -------------------------------------------------------------------
		# Si le nbre d'images chargées sans canal alpha est supérieur à 1 ...
		# ce qui correspond à un travail avec un fond animé
		# -------------------------------------------------------------------
		elif nbreElem_2 > 1:
		
			self.progress.show()
		
			nbre=min(nbreElem_1, nbreElem_2)
			
			try :
				for parcoursComposit_un in range(nbre):
					
                			# Ouverture des images (imm1 --> avec canal alpha et 
					# imm2 --> sans canal alpha)
                			imm1=Image.open(self.listeChemAVcanAlph[parcoursComposit_un])
                			imm2=Image.open(self.listeChemSANScanAlph[parcoursComposit_un])

					# ------------ Images exactement de même taille ---------------------
					# Récup des dimensions des images chargées avec canal alpha
					w_1, h_1=imm1.size
					# Récup des dimensions des images chargées sans canal alpha
					w_2, h_2=imm2.size
					# Si l'utilisateur à chargé des images ayant strictement la même taille
					if w_1==w_2 and h_1==h_2:
						# Redimensionnement des images sans canal alpha à la taille
						# des images avec canal alpha
						imm2=imm2.resize(Image.open(self.listeChemAVcanAlph[0]).size, Image.ANTIALIAS)
					# -------------------------------------------------------------------
					# ------------ Images de tailles différentes ------------------------
					# Si l'utilisateur à chargé des images avec canal alpha ayant la même
					# taille entre elles mais n'ayant pas la même taille que les images
					# sans canal alpha (qui ont la même taille entre elles)
					if w_1!=w_2 or h_1!=h_2:
						# Redimensionnement des images sans canal alpha à la taille
						# des images avec canal alpha
						imm2=imm2.resize(Image.open(self.listeChemAVcanAlph[0]).size, Image.ANTIALIAS)
					# Si l'utilisateur charge des images avec avec canal alpha de tailles
					# différentes entre elles et des images sans canal alpha aussi différentes
					# entre elles, les images sans canal alpha sont redimensionnées à la dimension
					# des images avec canal alpha
					if len(repRedimTemp_1)>0 and len(repRedimTemp_2)>0:
						if (int(w_1), int(h_1)) != (int(w_2), int(h_2)):
							imm2=imm2.resize(Image.open(repRedimTemp_1[0]).size, Image.ANTIALIAS)
					# Si l'utilisateur charge des images avec canal alpha toutes de même taille mais
					# aussi charge des images sans canal alpha de tailles complètement différentes,
					# les images sans canal alpha sont redimensionnées à la dimension des images
					# avec canal alpha
					if len(repRedimTemp_2)>0 and len(repRedimTemp_1)==0:
						if (int(w_1), int(h_1)) != (int(w_2), int(h_2)):
							imm2=imm2.resize(Image.open(self.listeChemAVcanAlph[0]).size, Image.ANTIALIAS)
					# Si l'utilisateur charge des images sans canal alpha toutes de même taille mais
					# aussi charge des images avec canal alpha de tailles complètement différentes,
					# les images avec canal alpha sont redimensionnées à la dimension de la 1ère
					# image avec canal alpha
					if len(repRedimTemp_1)>0 and len(repRedimTemp_2)==0:
						if (int(w_1), int(h_1)) != (int(w_2), int(h_2)):
							imm1=imm1.resize(Image.open(self.listeChemAVcanAlph[0]).size, Image.ANTIALIAS)

                			# Application du compositing
                			imgCompo_1=Image.composite(imm1, imm2, imm1)

					# Sauvegarde des images resultant du Compositing
					self.cheminCourantSauv = self.chemDossierSauv+'_'+string.zfill(parcoursComposit_un+self.spin1.value(), self.spin2.value())+'.png'
					imgCompo_1.save(self.cheminCourantSauv, "PNG")

					# Ajout des images par la variable self.cheminCourantSauv dans la liste self.listeChemin
					# Cette liste sert à récupérer les images pour l'affichage des images ds l'inteface
					self.listeImgDestin.append(self.cheminCourantSauv)
					
					# Affichage des images après traitement
					#
					# Changement d'onglet et fonctions associées
					self.conversionImg = 1
					self.metaFctTab(self.indexTabImgDestin)
				
					# log
					listeAff_1.append(self.listeChemAVcanAlph[parcoursComposit_un])
					listeAff_2.append(self.listeChemSANScanAlph[parcoursComposit_un])
					listeAff_3.append(self.cheminCourantSauv)
					
					# --------------------------------------------
					# Affichage de la progression (avec
					# QProgressDialog) ds une fenêtre séparée
					val_pourc_1=((parcoursComposit_un+1)*100)/nbre

					# Bouton Cancel pour arrêter la progression donc le process
					if (self.progress.wasCanceled()): break

					self.progress.setValue(val_pourc_1)
			
					QApplication.processEvents()
					# --------------------------------------------

			except:
				messageErreur=QMessageBox(self)
				messageErreur.setText(_(u"<p><b>Première situation d'erreur:</b> Vous n'avez pas chargé d'image(s) (bouton Ajouter) dans l'onglet <b>Image(s) avec canal aplpha</b>. Recommencez et chargez des images aussi bien dans <b>Image(s) avec canal alpha</b>, que dans <b>Image(s) sans canal aplpha</b>.</p><p><b>Seconde situation d'erreur:</b> la visualisation et/ou le traitement image(s) ne peut pas avoir lieu car vous avez répondu non au moins une fois au moment du redimensionnement des images. Recommencez et répondez oui aux deux boîtes de dialogue.</p>"))
				messageErreur.setWindowTitle(_(u"Erreur"))
				messageErreur.setIcon(QMessageBox.Critical)
				messageErreur.exec_()
				
		# -------------------------------------------------------------------
		# Si le nbre d'images chargées sans canal alpha est égal à 1 ...
		# ce qui correspond à un travail avec un fond fixe (caméra fixe)
		# -------------------------------------------------------------------
		elif nbreElem_2 == 1:
			
			self.progress.show()
			
			listeTempCompo=[]
			
			try :
				for parcoursDupli in range(nbreElem_1):
					
					dupliString=self.listeChemSANScanAlph[0]
					
					# Ouverture de l'image 
					reS=Image.open(dupliString)
					
					# Sauvegarde de l'image après multiplication
					reS.save(str(self.repTampon+'d_'+string.zfill(parcoursDupli+self.spin1.value(), self.spin2.value())+'.png'), 'PNG')
					
					# Remplissage de la liste tampon
					listeTempCompo.append(self.repTampon+'d_'+string.zfill(parcoursDupli+self.spin1.value(), self.spin2.value())+'.png')
					
					# Copie de l'ensemble des images (avec canal alpha)
					# chargees par l'utilisateur, dans le sous-repertoire
					# temporaire --> /EkdConfig.getTempDir()/ekd/tampon/temp_duplication/ . Il est
					# indispensable que ces images se retrouvent dans le meme
					# repertoire que les images multipliées (sans canal alpha)
					for parCop in self.listeChemSANScanAlph: 
						cop=shutil.copy(parCop, self.repTampon)
						
					# Ouverture des images (imm3 --> avec canal alpha et 
					# imm4 --> sans canal alpha) 
					imm3=Image.open(self.listeChemAVcanAlph[parcoursDupli])
					imm4=Image.open(listeTempCompo[parcoursDupli])

					# ------------ Images de même taille --------------------------------
					# Récup des dimensions des images chargées avec canal alpha
					w_1, h_1=imm3.size
					# Récup des dimensions des images chargées sans canal alpha
					w_2, h_2=imm4.size
					# Si l'utilisateur à chargé des images ayant strictement la même taille
					if w_1==w_2 and h_1==h_2:
						# Redimensionnement des images sans canal alpha à la taille
						# des images avec canal alpha
						imm4=imm4.resize(Image.open(self.listeChemAVcanAlph[0]).size, Image.ANTIALIAS)
					# -------------------------------------------------------------------
					# ------------ Images de tailles différentes ------------------------
					# Si le rep /EkdConfig.getTempDir()/ekd/tampon/temp_duplication/redim_1 contient des fichiers ...
					if len(repRedimTemp_1)>0:
						# Ouverture de la dernière image dans:
						# /EkdConfig.getTempDir()/ekd/tampon/temp_duplication/redim_1
						imm3=Image.open(repRedimTemp_1[parcoursDupli])
						# Dimension (w_1 --> largeur, h_1 --> hauteur)
						w_1, h_1=imm3.size
					# Si le rep /EkdConfig.getTempDir()/ekd/tampon/temp_duplication/redim_2 contient des fichiers ...
					if len(repRedimTemp_2)>0:
						# Ouverture de la première image dans:
						# /EkdConfig.getTempDir()/ekd/tampon/temp_duplication/redim_2
						imm4=Image.open(repRedimTemp_2[parcoursDupli])
						# Dimension (w_2 --> largeur, h_2 --> hauteur)
						w_2, h_2=imm4.size
					# Si l'utilisateur charge des images avec canal alpha de taille complètement différentes 
					# (les images sont redimensionnées ds le rep tempo redim_1)de l'image sans canal alpha, 
					# l'image sans canal alpha est redimensionnée à la taille des images avec canal alpha du 
					# répertoire temporaire. Autrement l'image sans canal alpha est redimensionnée à la taille 
					# de la 1ère image avec canal alpha chargée
					if len(repRedimTemp_1)>0:
						if (int(w_1), int(h_1)) != (int(w_2), int(h_2)):
							imm4=imm4.resize(Image.open(repRedimTemp_1[0]).size, Image.ANTIALIAS)
					else:
						imm4=imm4.resize(Image.open(self.listeChemAVcanAlph[0]).size, Image.ANTIALIAS)
					
					# Application du compositing .
					imgCompo_2=Image.composite(imm3, imm4, imm3)
					
					# Sauvegarde des images resultant du Compositing
					self.cheminCourantSauv = self.chemDossierSauv+'_'+string.zfill(parcoursDupli+self.spin1.value(), self.spin2.value())+'.png'
					# ----------------------------------------------------------------------
					imgCompo_2.save(self.cheminCourantSauv, "PNG")

					# Ajout des images par la variable self.cheminCourantSauv dans la liste self.listeChemin
					# Cette liste sert à récupérer les images pour l'affichage des images ds l'inteface
					self.listeImgDestin.append(self.cheminCourantSauv)
					
					# Affichage des images après traitement
					#
					# Changement d'onglet et fonctions associées
					self.conversionImg = 1
					self.metaFctTab(self.indexTabImgDestin)
				
					# log
					listeAff_1.append(self.listeChemAVcanAlph[parcoursDupli])
					listeAff_2.append(listeTempCompo[parcoursDupli])
					listeAff_3.append(self.cheminCourantSauv)
					
					# --------------------------------------------
					# Affichage de la progression (avec
					# QProgressDialog) ds une fenêtre séparée .
					val_pourc_2=((parcoursDupli+1)*100)/nbreElem_1
	
					# Bouton Cancel pour arrêter la progression donc le process
					if (self.progress.wasCanceled()): break
	
					self.progress.setValue(val_pourc_2)
			
					QApplication.processEvents()
					# --------------------------------------------

			except:
				messageErreur=QMessageBox(self)
				messageErreur.setText(_(u"<p><b>Première situation d'erreur:</b> Vous n'avez pas chargé d'image(s) (bouton Ajouter) dans l'onglet <b>Image(s) avec canal aplpha</b>. Recommencez et chargez des images aussi bien dans <b>Image(s) avec canal alpha</b>, que dans <b>Image(s) sans canal aplpha</b>.</p><p><b>Seconde situation d'erreur:</b> la visualisation et/ou le traitement image(s) ne peut pas avoir lieu car vous avez répondu non au moins une fois au moment du redimensionnement des images. Recommencez et répondez oui aux deux boîtes de dialogue.</p>"))
				messageErreur.setWindowTitle(_(u"Erreur"))
				messageErreur.setIcon(QMessageBox.Critical)
				messageErreur.exec_()

		# Images chargées avec canal alpha
		for parcStatRendu_1 in listeAff_1:
			self.infosImgProv_1=self.infosImgProv_1+'\n'+parcStatRendu_1
			
		# Pages sauvegardées
		for parcStatRendu_2 in listeAff_2:
			self.infosImgProv_2=self.infosImgProv_2+'\n'+parcStatRendu_2
			
		# Compositing
		for parcStatRendu_3 in listeAff_3:
			self.infosImgProv_3=self.infosImgProv_3+'\n'+parcStatRendu_3
		
		# affichage des infos dans l'onglet
		self.zoneAffichInfosImg.setText(self.infosImgProv_1+'\n\n'+self.infosImgProv_2+'\n\n'+self.infosImgProv_3+'\n\n')
		self.fram.setEnabled(True)
	
	
	def afficherAide(self):
		"""Boîte de dialogue de l'aide"""

		# Utilisation de EkdAide
		messageAide=EkdAide(parent=self)
		messageAide.setText(tr(u"<p><b>Vous allez ici superposer des images avec un canal alpha (transparence) sur d'autres images sans canal alpha (ces dernières sont en quelque sorte l'arrière-plan). Vous avez aussi ici la possibilité de travailler avec un arrière-plan composé d'une seule image, en cas de travail en plan fixe (le programme duplique lui-même les images).</b></p><p><b>Voilà la définition que donne Wikipédia du terme compositing (c'est le terme exact): 'La composition (en anglais compositing) est un ensemble de méthodes numériques consistant à mélanger plusieurs sources d’images pour en faire un plan unique qui sera intégré dans le montage. Pour un film d'animation, il s'agit de l'étape finale de fabrication qui consiste à assembler toutes les couches des décors, des personnages et à réaliser les effets de caméra, à animer certains déplacements, et effets spéciaux. En cinéma de prise de vue réel, il consiste surtout à réaliser des effets spéciaux et à truquer des vidéos. C'est l'un des derniers maillons de la chaîne de l'image dans la réalisation d'un film.<br>Les sources peuvent être des images numérisées de cinéma, de dessin, de vidéo, des images numériques (dessin, 3D, effets spéciaux).'<br>Source: http://fr.wikipedia.org/wiki/Compositing</b></p><p>Dans l'onglet <b>'Image(s) avec canal alpha'</b> cliquez sur le bouton <b>Ajouter</b>, une boîte de dialogue apparaît, sur la partie gauche sélectionnez le répertoire (au besoin dépliez les sous-répertoires), allez chercher vos image(s). Passez maintenant dans l'onglet <b>'Image(s) sans canal alpha'</b> cliquez sur le bouton <b>Ajouter</b>, une boîte de dialogue apparaît, sur la partie gauche sélectionnez le répertoire (au besoin dépliez les sous-répertoires), allez chercher vos image(s). Si vous voulez sélectionner plusieurs images d'un coup, maintenez la touche <b>CTRL</b> (ou <b>SHIFT</b>) du clavier enfoncée (tout en sélectionnant vos images).</p><p>Dans <b>'Réglages'</b> faites les réglages du <b>'Traitement à partir de l'image (numéro)'</b> et du <b>'Nombre de chiffres après le nom de l'image' <font color='red'>(la plupart du temps les valeurs par défaut suffisent)</font></b>. Cliquez sur le bouton <b>'Voir le résultat'</b> vous voyez à ce moment là, le résultat du compositing entre la dernière image du lot de votre premier groupe d'image (images avec transparence) et la première image du lot de votre second groupe d'image (images sans transparence), s'afficher dans une nouvelle fenêtre.</p>Pour finir cliquez sur le bouton <b>'Appliquer et sauver'</b>, entrez le titre de votre futur compositing (après <b>'Nom de fichier'</b>) dans cette dernière boîte (vous aurez évidemment pris soin de sélectionner le répertoire de destination de votre compositing). Cliquez sur le bouton <b>'Enregistrer'</b>.<p>Si vous faites un clic droit de la souris (sur l'image) dans l'onglet <b>Image(s) après traitement</b>, vous accédez à des paramètres vous permettant différents affichages de la dite image. De même dans cet onglet vous pouvez lancer la visualisation des images par le bouton <b>Lancer le diaporama</b> (le bouton violet avec une flèche blanche vers la droite).</p><p>L'onglet <b>'Infos'</b> vous permet de voir le filtre utilisé, les image(s) chargée(s) et les image(s) convertie(s).</p>"))
		messageAide.show()


	def save(self) :
		self.afficheurImgSourceAvecCanalAlpha.saveFileLocation(self.idSection, u'sourcesa')
		self.afficheurImgSourceSansCanalAlpha.saveFileLocation(self.idSection, u'sourcessa')
		EkdConfig.set(self.idSection, u'spin1', unicode(self.spin1.value()))
		EkdConfig.set(self.idSection, u'spin2', unicode(self.spin2.value()))


	def load(self) :
		self.afficheurImgSourceAvecCanalAlpha.loadFileLocation(self.idSection, u'sourcesa')
		self.afficheurImgSourceSansCanalAlpha.loadFileLocation(self.idSection, u'sourcessa')
		self.spin1.setValue(int(EkdConfig.get(self.idSection, u'spin1')))
		self.spin2.setValue(int(EkdConfig.get(self.idSection, u'spin2')))	
Example #7
0
	def __init__(self, statusBar, geometry):

        	QWidget.__init__(self)
		
		# ----------------------------
		# Quelques paramètres de base
		# ----------------------------
		
		#=== Création des répertoires temporaires ===#
		# Gestion du repertoire tmp avec EkdConfig 
		self.repTampon = EkdConfig.getTempDir() + os.sep + "tampon" + os.sep + "image_divers_redimensionner" + os.sep


		if os.path.isdir(self.repTampon) is False:
        		os.makedirs(self.repTampon)
		if os.path.isdir(self.repTampon+'redim'+os.sep) is False:
        		os.makedirs(self.repTampon+'redim'+os.sep)	
		# Si le répertoire /tmp/ekd/tampon/image_divers_redimensionner/redim
		# n'est pas vide, il est expressément vidé de tout son contenu
		tempr=glob.glob(self.repTampon+'redim'+os.sep+'*.*')
		if len(tempr)>0:
			for parc in tempr: os.remove(parc)
		
		#=== Variable contenant les titres du log ===#
		self.infosImgTitre = []
		txt = _(u"Image(s) chargée(s)")
		a='#'*36
		b = a + '\n# ' + txt + '\n' + a + '\n'
		txt=_(u"Image(s) convertie(s)")
		c = a + '\n# ' + txt + '\n' + a + '\n'
		self.infosImgTitre.append(b)
		self.infosImgTitre.append(c)
		
		#=== Drapeaux ===#
		# Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)
		
		# Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
		# Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
		self.conversionImg = 0
		
		# Est-ce qu'une prévisualisation a été appelée?
		self.previsualImg = 0
		# Est-ce que des images sources ont été modifiées? (c'est-à-dire ajoutées ou supprimées)
		self.modifImageSource = 0
		
		# Identifiant des filtres utilisant partiellement ou intégralement un module python durant 
		# la conversion
		self.filtresPython=['redim_avec_ratio', 'redim_sans_ratio']
		
		self.timer = QTimer()
		self.connect(self.timer, SIGNAL('timeout()'), self.sonderTempsActuel)
		
		self.process = QProcess()
		self.connect(self.process, SIGNAL('finished(int)'), self.finConversion)
		
		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()

		# Gestion de la configuration via EkdConfig

		# Paramètres de configuration
		self.config = EkdConfig
		# Identifiant du cadre
		self.idSection = "image_redimensionner"
		# Log du terminal
		self.base.printSection(self.idSection)
		# Fonction appelant la fenêtre principale
		self.mainWindowFrameGeometry = geometry

		self.listeImgSource = []
		self.listeImgDestin = []
		
		# Boite d'alignement vertical
		vbox=QVBoxLayout(self)
		
		# ----------------------------------------
		# Bouton de sélection des images sources
		# ----------------------------------------
		
		self.tabwidget=QTabWidget()
		# Rq: le signal est placé à la fin de __init__ à cause d'une bizarrerie sous qt4.4
		
		#------------------
		# Onglet Réglages
		#------------------
		
		self.framReglage=QFrame()
		vboxReglage=QVBoxLayout(self.framReglage)
		
		# Gestion du nombre d'images à traiter
		self.grid = QGridLayout()
		self.grid.addWidget(QLabel(_(u"Traitement à partir de l'image (numéro)")), 0, 0)
		self.spin1_ImTrait=SpinSlider(1, 100000, 1, '', self)
		self.grid.addWidget(self.spin1_ImTrait, 0, 1)
		self.connect(self.spin1_ImTrait, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		self.grid.addWidget(QLabel(_(u"Nombre de chiffres après le nom de l'image")), 1, 0)
		self.spin2_ImTrait=SpinSlider(3, 18, 6, '', self)
		self.grid.addWidget(self.spin2_ImTrait, 1, 1)
		self.connect(self.spin2_ImTrait, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		
		self.grid.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid)
		vboxReglage.addStretch()
		
		#=== Stacked ===#
		
		self.stacked = QStackedWidget()
		self.stacked.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed))
		
		#=== Instanciation des widgets du stacked  ===#
		
		# Widgets du stacked avec une seule boite de spin
		self.stacked_redim_avec_ratio = SpinSliders(self, 10,6000,640, _(u"nouvelle largeur"), 'largeur_ratio')
		
		# Widgets du stacked avec 2 boites de spin
		self.stacked_redim_sans_ratio = SpinSliders(self, 10,6000,640,_(u"nouvelle largeur"),'largeur_sans_ratio',
					10,6000,480, _(u"nouvelle hauteur"), 'longueur_sans_ratio')
		
		# Ajout des widgets aux stacked
		indexStacked_redim_avec_ratio = self.stacked.addWidget(self.stacked_redim_avec_ratio)
		indexStacked_redim_sans_ratio = self.stacked.addWidget(self.stacked_redim_sans_ratio)
		
		#=== Autres widgets de l'onglet réglagle ===#
		
		#---- boite de combo
		self.comboReglage=QComboBox()
		# Paramètres de la liste de combo: [(nom entrée, identifiant, index du stacked,
		# instance stacked),...]
		self.listeComboReglage=[\
			(_(u'Redimensionner en tenant compte des proportions'), 'redim_avec_ratio',
				indexStacked_redim_avec_ratio, self.stacked_redim_avec_ratio),
			(_(u'Redimensionner sans tenir compte des proportions'), 'redim_sans_ratio',
				indexStacked_redim_sans_ratio, self.stacked_redim_sans_ratio)]
		
		# Insertion des codecs de compression dans la boite de combo
		for i in self.listeComboReglage:
                	self.comboReglage.addItem(i[0], QVariant(i[1]))
		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"), self.changerComboReglage)
		# Affiche l'entrée de la boite de combo inscrite dans un fichier de configuration
		self.base.valeurComboIni(self.comboReglage, self.config, self.idSection, 'methode')
		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"),
				self.changerApercu)
		
		#---- Pseudo-aperçu de la redimension
		self.apercu = Apercu((400, 300), statusBar)
		
		self.connect(self.stacked_redim_avec_ratio.spin, SIGNAL("valueChanged(int)"),
				self.changerApercu)
		self.connect(self.stacked_redim_sans_ratio.spin1, SIGNAL("valueChanged(int)"),
				self.changerApercu)
		self.connect(self.stacked_redim_sans_ratio.spin2, SIGNAL("valueChanged(int)"),
				self.changerApercu)
		# On donne les valeurs de largeur et hauteur des images converties à l'aperçu
		self.changerApercu()
		
		# Légende de l'aperçu
		coulSource, coulConvert = self.apercu.couleurContourSourceConvert()
		self.legendeSource = ElementLegende(": " +\
			_(u"Contours des images sources (taille la plus fréquente en foncé)"), coulSource)
		self.legendeConvert = ElementLegende(": "+ _(u"Contours des images à convertir"), coulConvert)
		self.legendeSource.hide()
		self.legendeConvert.hide()
		
		#=== Mise-en-page ===#
		
		hbox = QHBoxLayout()
		hbox.addWidget(QLabel(_(u'Type')))
		hbox.addWidget(self.comboReglage)
		hbox.setAlignment(Qt.AlignHCenter)
		
		vboxReglage.addLayout(hbox)
		vboxReglage.addWidget(self.stacked)
		hboxApercu = QHBoxLayout()
		hboxApercu.addStretch()
		hboxApercu.addWidget(self.apercu)
		hboxApercu.addStretch()
		vboxReglage.addLayout(hboxApercu)
		vboxReglage.addWidget(self.legendeSource)
		vboxReglage.addWidget(self.legendeConvert)
		vboxReglage.addStretch()
		
		#----------------
		# Onglet de log
		#----------------
		
		self.zoneAffichInfosImg = QTextEdit("")
		if PYQT_VERSION_STR < "4.1.0":
			self.zoneAffichInfosImg.setText = self.zoneAffichInfosImg.setPlainText
		self.zoneAffichInfosImg.setReadOnly(True)
		self.framInfos=QFrame()
		vboxInfIm=QVBoxLayout(self.framInfos)
		vboxInfIm.addWidget(self.zoneAffichInfosImg)

		# -------------------------------------------------
		# Onglets d'affichage image source et destination
		# -------------------------------------------------

		# Là où s'afficheront les images
		self.afficheurImgSource=SelectWidget(geometrie = self.mainWindowFrameGeometry)
		
		# Gestion de la configuration via EkdConfig
		self.afficheurImgDestination=Lecture_VisionImage(statusBar)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSource # Fait le lien avec le sélecteur de fichier source.
		
		vbox.addWidget(self.tabwidget)

		self.indexTabImgSource = self.tabwidget.addTab(self.afficheurImgSource, _(u'Image(s) source'))
		self.indexTabReglage=self.tabwidget.addTab(self.framReglage, _(u'Réglages'))
		self.indexTabImgDestin = self.tabwidget.addTab(self.afficheurImgDestination, _(u'Image(s) après traitement'))
		self.indexTabInfo=self.tabwidget.addTab(self.framInfos, _(u'Infos'))
		
		# -------------------------------------------
		# widgets du bas : curseur + ligne + boutons
		# -------------------------------------------
		
		# Boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		self.boutApPremImg = QPushButton(_(u" Voir le résultat"))
		self.boutApPremImg.setIcon(QIcon("Icones/icone_visionner_128.png"))
		self.boutApPremImg.setFocusPolicy(Qt.NoFocus)
		# Bouton inactif au départ
		self.boutApPremImg.setEnabled(False)
		self.connect(self.boutApPremImg, SIGNAL("clicked()"), self.visu_1ere_derniere_img)
		self.boutAppliquer=QPushButton(_(u" Appliquer et sauver"))
		self.boutAppliquer.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		# Bouton inactif au départ
		self.boutAppliquer.setEnabled(False)
		self.connect(self.boutAppliquer, SIGNAL("clicked()"), self.appliquer0)
		
		# Ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		vbox.addWidget(ligne)
		vbox.addSpacing(-5)	# la ligne doit être plus près des boutons
		
		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()
		hbox.addWidget(self.boutApPremImg)
		hbox.addStretch()
		hbox.addWidget(self.boutAppliquer)
		vbox.addLayout(hbox)
		
		#-----------------------------
		# Barre de progression
		#-----------------------------
		
		self.progress=QProgressDialog(_(u"Conversion en cours..."), _(u"Arrêter"), 0, 100)
		self.progress.setWindowTitle(_(u'EnKoDeur-Mixeur. Fenêtre de progression'))
		self.progress.setMinimumWidth(500)
		self.progress.setMinimumHeight(100)
		self.connect(self.progress, SIGNAL("canceled()"), self.arretProgression)
		
		# affichage de la boîte principale
		self.setLayout(vbox)

		self.connect(self.tabwidget, SIGNAL("currentChanged(int)"), self.fctTab)

		#----------------------------------------------------------------------------------------------------
		# Signal de présence d'images dans ler widget de sélection -> modifie le statut des boutons d'action
		#----------------------------------------------------------------------------------------------------
		
		self.connect(self.afficheurImgSource, SIGNAL("pictureChanged(int)"), self.modifImgSource)
Example #8
0
class Image_Divers_Redimensionner(QWidget):
	"""# -----------------------------------
	# Cadre accueillant les widgets de :
	# Image >> Divers >> Redimensionner
	# -----------------------------------"""
	def __init__(self, statusBar, geometry):

        	QWidget.__init__(self)
		
		# ----------------------------
		# Quelques paramètres de base
		# ----------------------------
		
		#=== Création des répertoires temporaires ===#
		# Gestion du repertoire tmp avec EkdConfig 
		self.repTampon = EkdConfig.getTempDir() + os.sep + "tampon" + os.sep + "image_divers_redimensionner" + os.sep


		if os.path.isdir(self.repTampon) is False:
        		os.makedirs(self.repTampon)
		if os.path.isdir(self.repTampon+'redim'+os.sep) is False:
        		os.makedirs(self.repTampon+'redim'+os.sep)	
		# Si le répertoire /tmp/ekd/tampon/image_divers_redimensionner/redim
		# n'est pas vide, il est expressément vidé de tout son contenu
		tempr=glob.glob(self.repTampon+'redim'+os.sep+'*.*')
		if len(tempr)>0:
			for parc in tempr: os.remove(parc)
		
		#=== Variable contenant les titres du log ===#
		self.infosImgTitre = []
		txt = _(u"Image(s) chargée(s)")
		a='#'*36
		b = a + '\n# ' + txt + '\n' + a + '\n'
		txt=_(u"Image(s) convertie(s)")
		c = a + '\n# ' + txt + '\n' + a + '\n'
		self.infosImgTitre.append(b)
		self.infosImgTitre.append(c)
		
		#=== Drapeaux ===#
		# Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)
		
		# Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
		# Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
		self.conversionImg = 0
		
		# Est-ce qu'une prévisualisation a été appelée?
		self.previsualImg = 0
		# Est-ce que des images sources ont été modifiées? (c'est-à-dire ajoutées ou supprimées)
		self.modifImageSource = 0
		
		# Identifiant des filtres utilisant partiellement ou intégralement un module python durant 
		# la conversion
		self.filtresPython=['redim_avec_ratio', 'redim_sans_ratio']
		
		self.timer = QTimer()
		self.connect(self.timer, SIGNAL('timeout()'), self.sonderTempsActuel)
		
		self.process = QProcess()
		self.connect(self.process, SIGNAL('finished(int)'), self.finConversion)
		
		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()

		# Gestion de la configuration via EkdConfig

		# Paramètres de configuration
		self.config = EkdConfig
		# Identifiant du cadre
		self.idSection = "image_redimensionner"
		# Log du terminal
		self.base.printSection(self.idSection)
		# Fonction appelant la fenêtre principale
		self.mainWindowFrameGeometry = geometry

		self.listeImgSource = []
		self.listeImgDestin = []
		
		# Boite d'alignement vertical
		vbox=QVBoxLayout(self)
		
		# ----------------------------------------
		# Bouton de sélection des images sources
		# ----------------------------------------
		
		self.tabwidget=QTabWidget()
		# Rq: le signal est placé à la fin de __init__ à cause d'une bizarrerie sous qt4.4
		
		#------------------
		# Onglet Réglages
		#------------------
		
		self.framReglage=QFrame()
		vboxReglage=QVBoxLayout(self.framReglage)
		
		# Gestion du nombre d'images à traiter
		self.grid = QGridLayout()
		self.grid.addWidget(QLabel(_(u"Traitement à partir de l'image (numéro)")), 0, 0)
		self.spin1_ImTrait=SpinSlider(1, 100000, 1, '', self)
		self.grid.addWidget(self.spin1_ImTrait, 0, 1)
		self.connect(self.spin1_ImTrait, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		self.grid.addWidget(QLabel(_(u"Nombre de chiffres après le nom de l'image")), 1, 0)
		self.spin2_ImTrait=SpinSlider(3, 18, 6, '', self)
		self.grid.addWidget(self.spin2_ImTrait, 1, 1)
		self.connect(self.spin2_ImTrait, SIGNAL("valueChanged(int)"), self.changeValNbreImg_1)
		
		self.grid.setAlignment(Qt.AlignHCenter)
		vboxReglage.addLayout(self.grid)
		vboxReglage.addStretch()
		
		#=== Stacked ===#
		
		self.stacked = QStackedWidget()
		self.stacked.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed))
		
		#=== Instanciation des widgets du stacked  ===#
		
		# Widgets du stacked avec une seule boite de spin
		self.stacked_redim_avec_ratio = SpinSliders(self, 10,6000,640, _(u"nouvelle largeur"), 'largeur_ratio')
		
		# Widgets du stacked avec 2 boites de spin
		self.stacked_redim_sans_ratio = SpinSliders(self, 10,6000,640,_(u"nouvelle largeur"),'largeur_sans_ratio',
					10,6000,480, _(u"nouvelle hauteur"), 'longueur_sans_ratio')
		
		# Ajout des widgets aux stacked
		indexStacked_redim_avec_ratio = self.stacked.addWidget(self.stacked_redim_avec_ratio)
		indexStacked_redim_sans_ratio = self.stacked.addWidget(self.stacked_redim_sans_ratio)
		
		#=== Autres widgets de l'onglet réglagle ===#
		
		#---- boite de combo
		self.comboReglage=QComboBox()
		# Paramètres de la liste de combo: [(nom entrée, identifiant, index du stacked,
		# instance stacked),...]
		self.listeComboReglage=[\
			(_(u'Redimensionner en tenant compte des proportions'), 'redim_avec_ratio',
				indexStacked_redim_avec_ratio, self.stacked_redim_avec_ratio),
			(_(u'Redimensionner sans tenir compte des proportions'), 'redim_sans_ratio',
				indexStacked_redim_sans_ratio, self.stacked_redim_sans_ratio)]
		
		# Insertion des codecs de compression dans la boite de combo
		for i in self.listeComboReglage:
                	self.comboReglage.addItem(i[0], QVariant(i[1]))
		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"), self.changerComboReglage)
		# Affiche l'entrée de la boite de combo inscrite dans un fichier de configuration
		self.base.valeurComboIni(self.comboReglage, self.config, self.idSection, 'methode')
		self.connect(self.comboReglage, SIGNAL("currentIndexChanged(int)"),
				self.changerApercu)
		
		#---- Pseudo-aperçu de la redimension
		self.apercu = Apercu((400, 300), statusBar)
		
		self.connect(self.stacked_redim_avec_ratio.spin, SIGNAL("valueChanged(int)"),
				self.changerApercu)
		self.connect(self.stacked_redim_sans_ratio.spin1, SIGNAL("valueChanged(int)"),
				self.changerApercu)
		self.connect(self.stacked_redim_sans_ratio.spin2, SIGNAL("valueChanged(int)"),
				self.changerApercu)
		# On donne les valeurs de largeur et hauteur des images converties à l'aperçu
		self.changerApercu()
		
		# Légende de l'aperçu
		coulSource, coulConvert = self.apercu.couleurContourSourceConvert()
		self.legendeSource = ElementLegende(": " +\
			_(u"Contours des images sources (taille la plus fréquente en foncé)"), coulSource)
		self.legendeConvert = ElementLegende(": "+ _(u"Contours des images à convertir"), coulConvert)
		self.legendeSource.hide()
		self.legendeConvert.hide()
		
		#=== Mise-en-page ===#
		
		hbox = QHBoxLayout()
		hbox.addWidget(QLabel(_(u'Type')))
		hbox.addWidget(self.comboReglage)
		hbox.setAlignment(Qt.AlignHCenter)
		
		vboxReglage.addLayout(hbox)
		vboxReglage.addWidget(self.stacked)
		hboxApercu = QHBoxLayout()
		hboxApercu.addStretch()
		hboxApercu.addWidget(self.apercu)
		hboxApercu.addStretch()
		vboxReglage.addLayout(hboxApercu)
		vboxReglage.addWidget(self.legendeSource)
		vboxReglage.addWidget(self.legendeConvert)
		vboxReglage.addStretch()
		
		#----------------
		# Onglet de log
		#----------------
		
		self.zoneAffichInfosImg = QTextEdit("")
		if PYQT_VERSION_STR < "4.1.0":
			self.zoneAffichInfosImg.setText = self.zoneAffichInfosImg.setPlainText
		self.zoneAffichInfosImg.setReadOnly(True)
		self.framInfos=QFrame()
		vboxInfIm=QVBoxLayout(self.framInfos)
		vboxInfIm.addWidget(self.zoneAffichInfosImg)

		# -------------------------------------------------
		# Onglets d'affichage image source et destination
		# -------------------------------------------------

		# Là où s'afficheront les images
		self.afficheurImgSource=SelectWidget(geometrie = self.mainWindowFrameGeometry)
		
		# Gestion de la configuration via EkdConfig
		self.afficheurImgDestination=Lecture_VisionImage(statusBar)
		## ---------------------------------------------------------------------
		# Variables pour la fonction tampon
		## ---------------------------------------------------------------------
		self.typeEntree = "image" # Défini le type de fichier source.
		self.typeSortie = "image" # Défini le type de fichier de sortie.
		self.sourceEntrees = self.afficheurImgSource # Fait le lien avec le sélecteur de fichier source.
		
		vbox.addWidget(self.tabwidget)

		self.indexTabImgSource = self.tabwidget.addTab(self.afficheurImgSource, _(u'Image(s) source'))
		self.indexTabReglage=self.tabwidget.addTab(self.framReglage, _(u'Réglages'))
		self.indexTabImgDestin = self.tabwidget.addTab(self.afficheurImgDestination, _(u'Image(s) après traitement'))
		self.indexTabInfo=self.tabwidget.addTab(self.framInfos, _(u'Infos'))
		
		# -------------------------------------------
		# widgets du bas : curseur + ligne + boutons
		# -------------------------------------------
		
		# Boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		self.boutApPremImg = QPushButton(_(u" Voir le résultat"))
		self.boutApPremImg.setIcon(QIcon("Icones/icone_visionner_128.png"))
		self.boutApPremImg.setFocusPolicy(Qt.NoFocus)
		# Bouton inactif au départ
		self.boutApPremImg.setEnabled(False)
		self.connect(self.boutApPremImg, SIGNAL("clicked()"), self.visu_1ere_derniere_img)
		self.boutAppliquer=QPushButton(_(u" Appliquer et sauver"))
		self.boutAppliquer.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		# Bouton inactif au départ
		self.boutAppliquer.setEnabled(False)
		self.connect(self.boutAppliquer, SIGNAL("clicked()"), self.appliquer0)
		
		# Ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		vbox.addWidget(ligne)
		vbox.addSpacing(-5)	# la ligne doit être plus près des boutons
		
		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()
		hbox.addWidget(self.boutApPremImg)
		hbox.addStretch()
		hbox.addWidget(self.boutAppliquer)
		vbox.addLayout(hbox)
		
		#-----------------------------
		# Barre de progression
		#-----------------------------
		
		self.progress=QProgressDialog(_(u"Conversion en cours..."), _(u"Arrêter"), 0, 100)
		self.progress.setWindowTitle(_(u'EnKoDeur-Mixeur. Fenêtre de progression'))
		self.progress.setMinimumWidth(500)
		self.progress.setMinimumHeight(100)
		self.connect(self.progress, SIGNAL("canceled()"), self.arretProgression)
		
		# affichage de la boîte principale
		self.setLayout(vbox)

		self.connect(self.tabwidget, SIGNAL("currentChanged(int)"), self.fctTab)

		#----------------------------------------------------------------------------------------------------
		# Signal de présence d'images dans ler widget de sélection -> modifie le statut des boutons d'action
		#----------------------------------------------------------------------------------------------------
		
		self.connect(self.afficheurImgSource, SIGNAL("pictureChanged(int)"), self.modifImgSource)
		
		
	def changeValNbreImg_1(self):
		"""gestion du nombre d'images à traiter"""
		#print "Traitement a partir de l'image (numero):", self.spin1_ImTrait.value()
		EkdPrint(u"Traitement a partir de l'image (numero): %s" % self.spin1_ImTrait.value())
		#print "Nombre de chiffres apres le nom de l'image:", self.spin2_ImTrait.value()
		EkdPrint(u"Nombre de chiffres apres le nom de l'image: %s" % self.spin2_ImTrait.value())


	def modifImgSource(self, i):
		"""On active ou désactive les boutons d'action et on recharge le pseudo-aperçu de planche-contact
		en fonction du nombre d'images présentes dans le widget de sélection"""
		self.boutAppliquer.setEnabled(i)
		self.boutApPremImg.setEnabled(i)
		self.modifImageSource = 1
		if i :
			# Redessinage du canevas de peudo-aperçu
			self.stat_dim_img()
			liste = [i[1] for i in self.lStatDimSeq]
			self.apercu.setImageTaillePlusFrequente(self.imageTaillePlusFrequente)
			self.apercu.setListeTailleImage(liste)
			# Affichage de la légende
			self.legendeSource.show()
			self.legendeConvert.show()

	
	def fctTab(self, i):
		"Affichage d'une ou plusieurs images converties"
		
		# Cela ne concerne que l'onglet de visualisation des images après leur conversion
		if i == self.indexTabImgDestin:
			if self.conversionImg:
				# Affichage si on sauvegarde par le bouton Appliquer et sauver
				#print "La conversion vient d'avoir lieu -> affichage des images du lot de destination"
				EkdPrint(u"La conversion vient d'avoir lieu -> affichage des images du lot de destination")
				cheminImages = os.path.dirname(self.listeImgDestin[0])
				liste = []
				for fichier in self.listeImgDestin:
					liste.append(os.path.basename(fichier))
				self.afficheurImgDestination.updateImages(liste, cheminImages)
			elif not self.boutAppliquer.isEnabled() or self.modifImageSource:
				# Si le bouton de conversion n'est pas actif, c'est qu'il n'y a plus d'image source
				# -> on n'a plus de raison de maintenir des images dans l'afficheur de résultat
				# Si les images sources ont été modifiées, on purge aussi l'afficheur de résultat
				self.afficheurImgDestination.updateImages([])
			self.conversionImg = 0
			self.modifImageSource = 0
	
	
	def metaFctTab(self, i):
		"""Changement d'onglet (conçu pour sélectionner les onglets "Images Source" après le chargement de nouvelles images sources ou "Images Après Traitement" après la conversion). But: s'assurer que la fonction associée au QTabWidget (affichage d'images, grisage/dégrisage du curseur...) sera bien appliquée même si on est déjà sur le bon onglet"""
		if self.tabwidget.currentIndex()!=i:
			self.tabwidget.setCurrentIndex(i)
		else: self.fctTab(i)
		
	
	def changerComboReglage(self, i):
		"""L'entrée sélectionnée de la boîte de combo modifie le QFrame de réglage du codec associée"""
		self.stacked.setCurrentIndex(self.listeComboReglage[i][2])
		self.config.set(self.idSection, 'methode', self.listeComboReglage[i][1])
	
	
	def logFinal(self, titreFiltre):
		"""Affichage des informations de conversion"""
		a='#'*36
		# On ne récupère pas l'ancien % car il est arrondi
		pourCent=round(float(len(self.listeImgDestin))/len(self.listeImgSource)*100)
		pourCent = "%.0f" %pourCent
		b = a + '\n# ' + _(u'Filtre utilisé: ') + titreFiltre + '\n' + a + '\n'
		c = _(u"nombre d'images converties / nombre d'images sources")+" = "+str(len(self.listeImgDestin))+" / "\
		+str(len(self.listeImgSource))+" = " + pourCent +" %\n\n"
		
		# Affichage information de la nouvelle résolution des images
		# Pour les commentaires voir dans la fonction appliquer
		if self.listeComboReglage[self.i][1]=='redim_avec_ratio':
			spin=self.listeComboReglage[self.i][3].spin.value() # nouvelle largeur
			obImg=Image.open(self.listeImgSource[0])
			w, h=obImg.size
			ratio=float(w)/float(h)
			calcHaut=float(spin)/ratio
			d = a+'\n# '+_(u"Nouvelle résolution image(s): ")+'\n'+a+'\n'+str(spin)+' x '+str(int(calcHaut))
			
		elif self.listeComboReglage[self.i][1]=='redim_sans_ratio':
			spin1=self.listeComboReglage[self.i][3].spin1.value() # nouvelle largeur
			spin2=self.listeComboReglage[self.i][3].spin2.value() # nouvelle hauteur
			obImg=Image.open(self.listeImgSource[0])
			d=a+'\n# '+_(u"Nouvelle résolution image(s): ")+'\n'+a+'\n'+str(spin1)+' x '+str(spin2)
		
		# Le dernier '\n' est parfois nécessaire pour voir la dernière ligne!
		self.zoneAffichInfosImg.setText(b+c+self.infosImgTitre[0]+\
		"\n".join(self.listeImgSource)+'\n\n'+self.infosImgTitre[1]+"\n".join(self.listeImgDestin)+'\n\n'+d+'\n')
	

	def changerApercu(self, i=None):
		"Modification de l'aperçu quand une valeur de la nouvelle largeur ou hauteur est donnée"
		
		index = self.comboReglage.currentIndex()
		if self.comboReglage.itemData(index).toString() == "redim_sans_ratio":
			largeur = self.stacked_redim_sans_ratio.spin1.value()
			hauteur = self.stacked_redim_sans_ratio.spin2.value()
		elif self.comboReglage.itemData(index).toString() == "redim_avec_ratio":
			largeur = self.stacked_redim_avec_ratio.spin.value()
			hauteur = None
		
		self.apercu.setSizeConvertImages(largeur, hauteur)
	
	
	def stat_dim_img(self):
		"""Calcul statistique des dimensions des images les plus présentes dans le lot
		et récupération de l'adresse d'une image de la taille la plus fréquente du lot"""

		# Récupération de la liste des fichiers chargés
		self.listeImgSource=self.afficheurImgSource.getFiles()
		
		# Ouverture et mise ds une liste des dimensions des images
		listePrepaRedim=[Image.open(aA).size for aA in self.listeImgSource]
		
		# Merci beaucoup à Marc Keller de la liste: python at aful.org de m'avoir
		# aidé pour cette partie (les 4 lignes en dessous)
		dictSeq={}.fromkeys(listePrepaRedim, 0)
		for cle in listePrepaRedim: dictSeq[cle]+=1
		self.lStatDimSeq=sorted(zip(dictSeq.itervalues(), dictSeq.iterkeys()), reverse=1)
		self.dimStatImg=self.lStatDimSeq[0][1]
		
		# On récupère l'adresse d'une image de la taille la plus fréquente du lot
		for index, taille in enumerate(listePrepaRedim):
			if taille == self.lStatDimSeq[0][1]:
				self.imageTaillePlusFrequente = self.listeImgSource[index]
				break
		
		#print "Toutes les dimensions des images (avec le nbre d'images):", self.lStatDimSeq
		EkdPrint(u"Toutes les dimensions des images (avec le nbre d'images): " + str(self.lStatDimSeq))
		#print 'Dimension des images la plus presente dans la sequence:', self.dimStatImg
		EkdPrint(u'Dimension des images la plus presente dans la sequence: ' + str(self.dimStatImg))
		#print "Nombre de tailles d'images différentes dans le lot :", len(self.lStatDimSeq)
		EkdPrint(u"Nombre de tailles d'images différentes dans le lot: " + str(len(self.lStatDimSeq)))
		
		if len(self.lStatDimSeq)>1:
			return 0
		else:
			return 1
	
	
	def redim_img(self):
		"""Si l'utilisateur charge des images avec des tailles complètement différentes --> les images de la séquence  peuvent être redimensionnées"""
		
		if not self.stat_dim_img():
			reply = QMessageBox.warning(self, 'Message',
			_(u"Vos images ne sont pas toutes de la même taille. Voulez-vous redimensionner les images de sortie à la taille la plus répandue dans la séquence?"), QMessageBox.Yes, QMessageBox.No)
			if reply == QMessageBox.No:
				return
			
			# Les images de tailles différentes à la plus répandue sont redimensionnées
			# dans un répertoire temporaire.
			# Les images redimensionnées voient leur chemin modifié dans la liste des
			# chemins des images sources. Les autres chemins ne changent pas.
			index=0
			for chemImg in self.listeImgSource:
				obImg=Image.open(chemImg)
				if obImg.size!=self.dimStatImg:
					pass
				sRedim=obImg.resize(self.dimStatImg, Image.ANTIALIAS)
				chemSortie = self.repTampon+'redim/'+os.path.basename(chemImg)
				sRedim.save(chemSortie)
				self.listeImgSource[index] = chemSortie
				index += 1

	
	def arretProgression(self):
		"""Si le filtre appliqué est 100 % shell, alors la conversion est immédiatement stoppée après un clic sur le bouton de la QProgessDialog. Pas la peine d'attendre la fin de la conversion de l'image en cours comme pour les autres types de filtres."""
		
		if self.listeComboReglage[self.i][1] in self.filtresPython: return
		self.process.kill()
		if len(self.listeImgDestin)!=0:
			self.conversionImg = 1
			self.logFinal(self.listeComboReglage[self.i][0])
			self.tabwidget.setCurrentIndex(self.indexTabInfo)
		else: # Onglet de log -> on remet les infos de départ
			self.zoneAffichInfosImg.setText(self.infosImgTitre[0]+"\n".join(self.listeImgSource))
	
	
	def finConversion(self, statutDeSortie):
		"""Choses à faire à la fin de l'encodage d'une image quand le filtre sélectionné est constitué d'une seule commande shell"""
		
		if statutDeSortie==1:
			#print "Problème lors de la conversion!"
			EkdPrint(u"Problème lors de la conversion !")
			messageAide=QMessageBox(self)
			messageAide.setText(_(u"Une erreur s'est produite durant la conversion"))
			messageAide.setWindowTitle(_(u"Aide"))
			messageAide.setIcon(QMessageBox.Warning)
			messageAide.exec_()
			self.logFinal(self.listeComboReglage[self.i][0])
			self.tabwidget.setCurrentIndex(self.indexTabInfo)
			return
		
		# On passe à l'image suivante s'il en reste
		elif self.opReccurApresApp():
			self.appliquer()
	
	
	def opReccurApresApp(self):
		"""Opérations à effectuer après chaque appel du moteur."""
		
		if self.listeComboReglage[self.i][1] in self.filtresPython:
			modulePython = 1 # conversion python (+ shell pour certains filtres)
		
		self.listeImgDestin.append(self.cheminCourantSauv)
		pourCent=int((float(self.j+1)/self.nbrImg)*100)
		
		self.progress.setValue(pourCent)
		#!!!Rafraichissement indispensable pour la transmission immédiate du signal QProgressDialog().wasCanceled
		if modulePython: QApplication.processEvents()
		
		# Opérations de fin de conversion
		if pourCent==100:
			# Condition à respecter pour qu'un affichage d'une nouvelle image ait lieu dans l'onglet "Images après traitement"
			self.conversionImg = 1
			# Boite de dialogue d'information
			messageAide=QMessageBox(self)
			messageAide.setText(_(u"Le traitement a été appliqué avec succès!"))
			messageAide.setWindowTitle(self.listeComboReglage[self.i][0])
			messageAide.setIcon(QMessageBox.Information)
			messageAide.exec_()
			# Mise-à-jour du log
			self.logFinal(self.listeComboReglage[self.i][0])
			# Changement d'onglet et fonctions associées
			self.metaFctTab(self.indexTabImgDestin)
			return 0
		
		# Opérations à faire lors de l'arrêt de la conversion suite au clic sur le bouton annuler de la barre de progression
		elif self.progress.wasCanceled():
			if modulePython:
				# Condition à respecter pour qu'un affichage d'une nouvelle image ait lieu dans l'onglet "Images après traitement"
				self.conversionImg = 1
				# Mise-à-jour du log
				self.logFinal(self.listeComboReglage[self.i][0])
				# Affichage de l'onglet d'infos
				self.tabwidget.setCurrentIndex(self.indexTabInfo)
			return 0
		
		return 1
	
	
	def sonderTempsActuel(self):
		"""x ms après l'apparition de la boite de dialogue, on lance la conversion. But: faire en sorte que la boite de dialogue ait le temps de s'afficher correctement"""
		self.timer.stop()
		self.appliquer()
	
	
	def appliquer0(self):
		"""Préparation de la conversion"""
		
		# Redimensionner les images de tailles différentes?
		self.redim_img()

		# Récupération de la liste des fichiers chargés
		self.listeChemin=self.afficheurImgSource.getFiles()
		
		# Utilisation de la nouvelle boîte de dialogue de sauvegarde
		suffix=""
                self.cheminSauv = EkdSaveDialog(self, mode="image", suffix=suffix, title=_(u"Sauver"), multiple=True)
		self.cheminSauv = self.cheminSauv.getFile()
		
		if not self.cheminSauv: return
		
		#print 'Chemin+nom de sauvegarde:', self.cheminSauv

		# Extension/format des images
		self.ext = os.path.splitext(self.listeChemin[0])[1]
		
		# Liste des indices des images [0,1,2,...,nombre d'images-1]
		self.listeIndex = range(len(self.listeChemin))
		
		# Nombre d'images sources
		self.nbrImg = len(self.listeChemin)
		
		# Récupération de l'identifiant du codec
		self.i = self.comboReglage.currentIndex()
		
		# Indice de l'image à convertir
		self.j = 0
		
		self.progress.reset() # wasCanceled est remis à 0 -> la conversion ne s'arrête pas à la 1ère img
		self.progress.show()
		self.progress.setValue(0)
		QApplication.processEvents()
		
		# Lancement de la conversion dans 250 ms
		self.timer.start(250)
		
		
	def visu_1ere_derniere_img(self):
		"""Conversion des images"""
		
		# Récupération de l'identifiant du codec
		i = self.comboReglage.currentIndex()
		
		# Récupération du fichier sélectionné par l'utilisateur (si pas de fichier
		# sélectionné par l'utilisateur, la 1ère image de la liste est prise)
		file = self.afficheurImgSource.getFile()
		if not file: return
		self.listeChemin = [file]
		
		if self.listeComboReglage[i][1]=='redim_avec_ratio':
			""" Redimensionnement des images avec ratio """

			# Récup réglage ci-dessous
			spin = self.listeComboReglage[i][3].spin.value() # nouvelle largeur
				
			# Chemin de sauvegarde
			self.cheminCourantSauv = self.repTampon+'image_visu_redim_'+string.zfill(1, 6)+'.jpg'
				
			# Ouverture des images. Conversion et sauvegarde
			obImg = Image.open(self.listeChemin[0])
			
			# Recup dimensions de l'image
			w, h = obImg.size
			# Calcul du ratio de chaque image chargee
			ratio=float(w)/float(h)
			# Calcul de future hauteur avec les dimensions donnees par l'utilisateur
			calcHaut=float(spin)/ratio
			# Redimensionnement et sauvegarde des images
			finRedimSansRatio=obImg.resize((int(spin), int(calcHaut)), Image.ANTIALIAS).save(self.cheminCourantSauv)
			
			# Affichage de l'image temporaire 
			# Ouverture d'une boite de dialogue affichant l'aperçu.
			#
			# Affichage par le bouton Voir le résultat
			visio = VisionneurEvolue(self.cheminCourantSauv)
			visio.redimenFenetre(self.mainWindowFrameGeometry, 1., 0.7)
			visio.exec_()
		
			return 0
			
		elif self.listeComboReglage[i][1]=='redim_sans_ratio':
			""" Redimensionnement des images sans ratio """

			# Récup réglages ci-dessous
			spin1 = self.listeComboReglage[i][3].spin1.value() # nouvelle largeur
			spin2 = self.listeComboReglage[i][3].spin2.value() # nouvelle hauteur
				
			# Chemin de sauvegarde
			self.cheminCourantSauv = self.repTampon+'image_visu_redim_'+string.zfill(1, 6)+'.jpg'
				
			# Ouverture des images. Conversion et sauvegarde
			obImg = Image.open(self.listeChemin[0])
			
			# Redimensionnement et sauvegarde des images
			finRedimSansRatio=obImg.resize((int(spin1), int(spin2)), Image.ANTIALIAS).save(self.cheminCourantSauv)
			
			# Affichage de l'image temporaire 
			# Ouverture d'une boite de dialogue affichant l'aperçu.
			#
			# Affichage par le bouton Voir le résultat
			visio = VisionneurEvolue(self.cheminCourantSauv)
			visio.redimenFenetre(self.mainWindowFrameGeometry, 1., 0.7)
			visio.exec_()
		
			return 0
		
	
	def appliquer(self):
		"""Conversion des images"""
		
		# La liste pour l'affichage des images ds l'interface est
		# vidée pour que les images affichées ne s'amoncellent pas
		# si plusieurs rendus à la suite
		self.listeImgDestin=[]

		#print "Indice de l'image à encoder :", self.j
		EkdPrint(u"Indice de l'image à encoder: %s" % self.j)
		
		if self.listeComboReglage[self.i][1]=='redim_avec_ratio':
			""" Redimensionnement des images avec ratio """
			for self.j in self.listeIndex:
				# Récup réglage ci-dessous
				spin = self.listeComboReglage[self.i][3].spin.value() # nouvelle largeur
				
				# Chemin de sauvegarde
				self.cheminCourantSauv = self.cheminSauv+'_'+string.zfill(self.j+self.spin1_ImTrait.value(), self.spin2_ImTrait.value())+self.ext
				
				# Ouverture des images. Conversion et sauvegarde
				obImg = Image.open(self.listeImgSource[self.j])
				# Recup dimensions de l'image
				w, h = obImg.size
				# Calcul du ratio de chaque image chargee
				ratio=float(w)/float(h)
				# Calcul de future hauteur avec les dimensions donnees par l'utilisateur
				calcHaut=float(spin)/ratio
				# Redimensionnement et sauvegarde des images
				finRedimSansRatio=obImg.resize((int(spin), int(calcHaut))).save(self.cheminCourantSauv)
				if not self.opReccurApresApp(): return
				
		elif self.listeComboReglage[self.i][1]=='redim_sans_ratio':
			""" Redimensionnement des images sans ratio """
			for self.j in self.listeIndex:
				# Récup réglages ci-dessous
				spin1 = self.listeComboReglage[self.i][3].spin1.value() # nouvelle largeur
				spin2 = self.listeComboReglage[self.i][3].spin2.value() # nouvelle hauteur
				
				# Chemin de sauvegarde
				self.cheminCourantSauv = self.cheminSauv+'_'+string.zfill(self.j+self.spin1_ImTrait.value(), self.spin2_ImTrait.value())+self.ext
				
				# Ouverture des images. Conversion et sauvegarde en niveaux de gris
				obImg = Image.open(self.listeImgSource[self.j])
				# Redimensionnement et sauvegarde des images
				finRedimSansRatio=obImg.resize((int(spin1), int(spin2))).save(self.cheminCourantSauv)
				if not self.opReccurApresApp(): return
				
		# Affichage des images après traitement
		#
		# Changement d'onglet et fonctions associées
		self.conversionImg = 1
		self.metaFctTab(self.indexTabImgDestin)
			
			
	def afficherAide(self):
		"""Boîte de dialogue de l'aide"""
		
		# Nouvelle fenêtre d'aide
		messageAide=EkdAide(parent=self)
		messageAide.setText(tr(u"<p><b>Vous pouvez ici changer la résolution (c'est à dire la taille, plus précisément la largeur et la hauteur) des images.</b></p><p><b>Dans l'onglet 'Réglages' il est possible de redimensionner les images en tenant compte du ratio, c'est à dire des proportions de chaque image (là on ne donne que la largeur, EKD se changeant de calculer la hauteur ; cela permet de ne pas déformer les images lors du changement de résolution), mais aussi de définir soi-même la taille de chaque image (en changeant à la fois la largeur et la hauteur).</b></p><p>Dans l'onglet <b>'Image(s) source'</b> cliquez sur le bouton <b>Ajouter</b>, une boîte de dialogue apparaît, sur la partie gauche sélectionnez le répertoire (au besoin dépliez les sous-répertoires), allez chercher vos image(s). Si vous voulez sélectionner plusieurs images d'un coup, maintenez la touche <b>CTRL</b> (ou <b>SHIFT</b>) du clavier enfoncée (tout en sélectionnant vos images), cliquez sur <b>Ajouter</b>.</p><p>Dans l'onglet <b>'Réglages'</b> faites les réglages du <b>'Traitement à partir de l'image (numéro)'</b> et du <b>'Nombre de chiffres après le nom de l'image' <font color='red'>(la plupart du temps les valeurs par défaut suffisent)</font></b>, ensuite sélectionnez votre <b>'Type'</b> (<b>Redimensionner en tenant compte des proportions</b> ou <b>Redimensionner sans tenir compte des proportions</b>), faites les réglages par rapport au <b>'Type'</b> choisi (vous pouvez voir en temps réel la taille de la première image du lot changer à mesure que vous réglez la <b>nouvelle largeur</b> et/ou la <b>nouvelle hauteur</b>).</p><p>En complément, vous pouvez cliquer sur le bouton <b>'Voir le résultat'</b>, vous voyez à ce moment là le résultat de vos réglages s'afficher dans une nouvelle fenêtre (particulièrement utile pour voir les déformations dues au redimensionnement pour <b>Redimensionner sans tenir compte des proportions</b>).</p><p>Une fois tout ceci fait, cliquez sur le bouton <b>'Appliquer et sauver'</b>, sélectionnez le répertoire de sauvegarde, indiquez votre <b>'Nom de fichier'</b>, cliquez sur le bouton <b>'Enregistrer'</b>.</p><p>Si vous faites un clic droit de la souris (sur l'image) dans l'onglet <b>'Images après traitement'</b>, vous accédez à des paramètres vous permettant différents affichages de la dite image. De même dans cet onglet vous pouvez lancer la visualisation des images par le bouton <b>Lancer le diaporama</b> (le bouton violet avec une flèche blanche vers la droite).</p><p>L'onglet <b>'Infos'</b> vous permet de voir les image(s) chargée(s), les image(s) convertie(s) et la nouvelle résolution des images.</p>"))
		messageAide.show()


	def save(self) :
		self.afficheurImgSource.saveFileLocation(self.idSection)
		EkdConfig.set(self.idSection, u'spin1_ImTrait', unicode(self.spin1_ImTrait.value()))
		EkdConfig.set(self.idSection, u'spin2_ImTrait', unicode(self.spin2_ImTrait.value()))
		EkdConfig.set(self.idSection, u'stacked_redim_avec_ratio', unicode(self.stacked_redim_avec_ratio.spin.value()))
		EkdConfig.set(self.idSection, u'stacked_redim_sans_ratio1', unicode(self.stacked_redim_sans_ratio.spin.value()))
		EkdConfig.set(self.idSection, u'stacked_redim_sans_ratio2', unicode(self.stacked_redim_sans_ratio.spin2.value()))
		EkdConfig.set(self.idSection, u'type_redim', unicode(self.comboReglage.currentIndex()))


	def load(self) :
		self.afficheurImgSource.loadFileLocation(self.idSection)
		self.spin1_ImTrait.setValue(int(EkdConfig.get(self.idSection, 'spin1_ImTrait')))
		self.spin2_ImTrait.setValue(int(EkdConfig.get(self.idSection, 'spin2_ImTrait')))
		self.stacked_redim_avec_ratio.spin.setValue(int(EkdConfig.get(self.idSection, 'stacked_redim_avec_ratio')))	
		self.stacked_redim_sans_ratio.spin.setValue(int(EkdConfig.get(self.idSection, 'stacked_redim_sans_ratio1')))	
		self.stacked_redim_sans_ratio.spin2.setValue(int(EkdConfig.get(self.idSection, 'stacked_redim_sans_ratio2')))	
		self.comboReglage.setCurrentIndex(int(EkdConfig.get(self.idSection, 'type_redim')))
Example #9
0
    def __init__(self, statusBar, geometry):
        # -------------------------------
        # Parametres généraux du widget
        # -------------------------------

        # === Variable de configuration ===#
        self.config = EkdConfig

        self.baseImg = BaseImg()  # module de image
        # Fonction appelant la fenêtre principale
        self.mainWindowFrameGeometry = geometry

        # === tout sera mis dans une boîte verticale ===#
        vbox = QVBoxLayout()

        # === Identifiant de la classe ===#
        self.idSection = "animation_convertir_une_video_en_images"

        super(Animation_ConvertirUneAnimEnImg, self).__init__(titre=_(u"Conversion d'une vidéo en images"))
        self.printSection()

        ######## Gestion de la nouvelle interface de chargement #######
        ## -------------------------------------------------------------------
        ## on utilise le selecteur d'image pour les vidéos
        from gui_modules_image.selectWidget import SelectWidget

        # Là où on naviguera entre les fichiers
        self.afficheurVideoSource = SelectWidget(
            extensions=["*.avi", "*.mpg", "*.mpeg", "*.mjpeg", "*.flv", "*.mp4", "*.h264", "*.dv", "*.vob"],
            mode="texte",
            video=True,
        )
        ###################################################################################
        # Onglets
        self.indexVideoSource = self.add(self.afficheurVideoSource, _(u"Video(s) source"))
        self.connect(self.afficheurVideoSource, SIGNAL("fileSelected"), self.getFile)
        self.connect(self.afficheurVideoSource, SIGNAL("pictureChanged(int)"), self.getFile)
        ## -------------------------------------------------------------------

        ## ---------------------------------------------------------------------
        # Variables pour la fonction tampon
        ## ---------------------------------------------------------------------
        self.typeEntree = "video"  # Défini le type de fichier source.
        self.typeSortie = "image"  # Défini le type de fichier de sortie.
        self.sourceEntrees = self.afficheurVideoSource  # Fait le lien avec le sélecteur de fichier source.

        # === Drapeaux ===#
        # Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)

        # Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
        # Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
        self.conversionImg = 0

        # === Accès à la barre des tâches ===#
        # On ne passe pas tout le parent, mais juste ce dont on a besoin
        self.statusBar = statusBar

        # -------------------------------------------------------------------
        # Boîte de groupe : "Fichier vidéo source"
        # -------------------------------------------------------------------
        self.afficheurImgDestination = Lecture_VisionImage(self.statusBar)
        #####################################################################################################

        self.listeImgDestin = []

        # ----------
        # Onglets
        # ----------
        self.dicoTab = {}

        self.add(self.afficheurImgDestination, _(u"Visualisation"))

        self.addLog()
Example #10
0
class Animation_ConvertirUneAnimEnImg(Base):
    # ----------------------------------------------------------------------------------------
    # Cadre accueillant les widgets de : Animation >> Séparer le flux vidéo et le flux audio
    # ----------------------------------------------------------------------------------------

    def __init__(self, statusBar, geometry):
        # -------------------------------
        # Parametres généraux du widget
        # -------------------------------

        # === Variable de configuration ===#
        self.config = EkdConfig

        self.baseImg = BaseImg()  # module de image
        # Fonction appelant la fenêtre principale
        self.mainWindowFrameGeometry = geometry

        # === tout sera mis dans une boîte verticale ===#
        vbox = QVBoxLayout()

        # === Identifiant de la classe ===#
        self.idSection = "animation_convertir_une_video_en_images"

        super(Animation_ConvertirUneAnimEnImg, self).__init__(titre=_(u"Conversion d'une vidéo en images"))
        self.printSection()

        ######## Gestion de la nouvelle interface de chargement #######
        ## -------------------------------------------------------------------
        ## on utilise le selecteur d'image pour les vidéos
        from gui_modules_image.selectWidget import SelectWidget

        # Là où on naviguera entre les fichiers
        self.afficheurVideoSource = SelectWidget(
            extensions=["*.avi", "*.mpg", "*.mpeg", "*.mjpeg", "*.flv", "*.mp4", "*.h264", "*.dv", "*.vob"],
            mode="texte",
            video=True,
        )
        ###################################################################################
        # Onglets
        self.indexVideoSource = self.add(self.afficheurVideoSource, _(u"Video(s) source"))
        self.connect(self.afficheurVideoSource, SIGNAL("fileSelected"), self.getFile)
        self.connect(self.afficheurVideoSource, SIGNAL("pictureChanged(int)"), self.getFile)
        ## -------------------------------------------------------------------

        ## ---------------------------------------------------------------------
        # Variables pour la fonction tampon
        ## ---------------------------------------------------------------------
        self.typeEntree = "video"  # Défini le type de fichier source.
        self.typeSortie = "image"  # Défini le type de fichier de sortie.
        self.sourceEntrees = self.afficheurVideoSource  # Fait le lien avec le sélecteur de fichier source.

        # === Drapeaux ===#
        # Une conversion (même partielle) a-t-elle eu lieu après le chargement des images? (1: vrai)

        # Est-ce que des images ont été converties et qu'elles n'ont pas encore été montrées?
        # Marche aussi quand la conversion a été arrêté avant la fin de la 1ère image
        self.conversionImg = 0

        # === Accès à la barre des tâches ===#
        # On ne passe pas tout le parent, mais juste ce dont on a besoin
        self.statusBar = statusBar

        # -------------------------------------------------------------------
        # Boîte de groupe : "Fichier vidéo source"
        # -------------------------------------------------------------------
        self.afficheurImgDestination = Lecture_VisionImage(self.statusBar)
        #####################################################################################################

        self.listeImgDestin = []

        # ----------
        # Onglets
        # ----------
        self.dicoTab = {}

        self.add(self.afficheurImgDestination, _(u"Visualisation"))

        self.addLog()

    def fctTab(self):
        "Affichage d'une ou plusieurs images converties"

        # Cela ne concerne que l'onglet de visualisation des images après leur conversion
        # Affichage si on sauvegarde par le bouton Appliquer et sauver
        # print "La conversion vient d'avoir lieu -> affichage des images du lot de destination"
        EkdPrint(u"La conversion vient d'avoir lieu -> affichage des images du lot de destination")
        cheminImages = os.path.dirname(self.listeImgDestin[0])
        liste = []
        for fichier in self.listeImgDestin:
            liste.append(os.path.basename(fichier))
        self.afficheurImgDestination.updateImages(liste, cheminImages)

        self.conversionImg = 0

        ####################################################################
        # Car erreur: Traceback (most recent call last): ... KeyError: 'images'
        # Affichage (après conversion) de l'onglet contenant les images
        ####################################################################

        # On libere la memoire
        del cheminImages, liste, fichier

    def ouvrirSource(self, nomEntree=None):
        """Récupération du chemin de la vidéo sélectionnée et activation de certains widgets"""

        chemin = self.recupSource(nomEntree)

        if not chemin:
            return
        self.ligneEditionSource.setText(chemin)

        self.boutApp.setEnabled(True)

        self.mplayer.setEnabled(True)
        self.mplayer.listeVideos = [chemin]

        self.tab.setCurrentIndex(self.dicoTab["video"])

        # On libere la memoire
        del chemin

    def getFile(self):
        """
		# On utilise la nouvelle interface de récupération des vidéos
		Récupération de la vidéo source selectionnée
		"""
        self.chemin = self.afficheurVideoSource.getFile()
        self.boutApp.setEnabled(True)

        self.boutApp.setEnabled(True)
        if self.idSection == "animation_filtresvideo":
            self.boutApercu.setEnabled(True)
            self.filtreDecouper.setButtonEnabled(True)
            # On emet un signal quand le fichier est chargé
        self.emit(SIGNAL("loaded"))
        return self.chemin
        ###################################################################################

    def appliquer(self, nomSortie=None, ouvert=1):
        """ Appelle la boite de dialogue de sélection de fichier à sauver et appel de la fonction de conversion d'une vidéo en images """

        # === Détermination des chemins d'entrée et sortie ===#
        chemin = self.getFile()

        if not nomSortie:
            suffix = ""
            saveDialog = EkdSaveDialog(self, mode="image", suffix=suffix, title=_(u"Sauver"), multiple=True)
            cheminFichierEnregistrerVideo = saveDialog.getFile()

        else:  # module séquentiel
            cheminFichierEnregistrerVideo = nomSortie

        if not cheminFichierEnregistrerVideo:
            return
        ###################################################################################

        # Préfixe des images
        prefixeImg = os.path.basename(cheminFichierEnregistrerVideo)

        # Chemin du répertoire de sortie des images
        cheminRepDestination = (
            os.path.dirname(cheminFichierEnregistrerVideo) + os.sep + os.path.basename(cheminFichierEnregistrerVideo)
        )

        cheminVideoSource = unicode(self.getFile())
        ###################################################################################
        try:
            #### la conversion de vidéo en images est maintenant gérée par FFmpeg #####
            ffmpeg = WidgetFFmpeg("jpeg", cheminVideoSource, cheminRepDestination, laisserOuvert=ouvert)
            ffmpeg.setWindowTitle(_(u"Convertir une animation en images"))
            ffmpeg.exec_()
            ##################################################################################################

        except:
            messageErreur = QMessageBox(self)
            messageErreur.setText(_(u"Problème lors de la conversion d'une vidéo en images (ffmpeg) %s") % e)
            messageErreur.setWindowTitle(_(u"Erreur"))
            messageErreur.setIcon(QMessageBox.Warning)
            messageErreur.exec_()
            return

        imgDep = glob.glob(cheminRepDestination + "*.png")

        imgDep.sort()

        # Nettoyage ... insertion des images dans la liste de visualisation
        self.listeImgDestin = []
        for parc_1 in imgDep:
            # Condition pour détection windows
            if os.name == "nt":
                if "\\" in parc_1:
                    self.listeImgDestin.append(parc_1.replace("\\", "/"))
            # Condition pour détection Linux ou MacOSX
            elif os.name in ["posix", "mac"]:
                self.listeImgDestin.append(parc_1)

                # Affichage des images après traitement (appel de la fonction fctTab)
        self.conversionImg = 1
        self.fctTab()
        ### Information à l'utilisateur
        self.infoLog(None, cheminVideoSource, None, self.listeImgDestin)

        return self.listeImgDestin  # module séquentiel

        # ATTENTION IL FAUT AJOUTER CECI NE PAS OUBLIER !!!
        # La liste pour l'affichage des images ds l'interface est
        # vidée pour que les images affichées ne s'amoncellent pas
        # si plusieurs rendus à la suite
        self.listeImgDestin = []

        # On libere la memoire
        del nomSortie, rep, chemin, prefixeImg, cheminRepDestination, cheminRepDestination, cheminVideoSource, commande, mencoder, listeFichiers, nomFichier

    def sequentiel(self, entree, sortie, ouvert=0):
        """Utile dans le module du même nom. Applique les opérations de la classe. Retourne le vrai nom du fichier de sortie"""
        self.ouvrirSource(entree)
        return self.appliquer(sortie, ouvert)

    def sequentielReglage(self):
        """Utile dans le module du même nom. Récupère le widget de réglage associé à l'identifiant donné en 1er argument. Retourne l'instance du widget de réglage"""
        groupReglage = QGroupBox(_(u"Réglages: convertir une animation en images"))
        hbox = QHBoxLayout(groupReglage)
        hbox.addWidget(QLabel(_(u"<center>Pas de réglages ici</center>")))
        return groupReglage

    def afficherAide(self):
        """ Boîte de dialogue de l'aide """
        super(Animation_ConvertirUneAnimEnImg, self).afficherAide(
            _(
                u"<p><b>Qu’est-ce qu’une vidéo en fin de compte ?. La réponse est des images se succédant à une certaine fréquence (24 images par seconde, par exemple), que nous interprétons comme un mouvement, c’est-à-dire une image animée. Traiter une vidéo dans EKD, c’est donner à cette vidéo la possibilité de se séparer en images (le nombre d'images contenues ici sera la durée de la vidéo en secondes multiplié par son nombre d'images par seconde). C'est ce que se propose de faire cette fonction.</b></p><p>Dans l'onglet <b>'Vidéo(s) source'</b> cliquez sur le bouton <b>Ajouter</b>, une boîte de dialogue apparaît, sur la partie gauche sélectionnez le répertoire (au besoin dépliez les sous-répertoires), allez chercher la/les vidéo(s). Si vous voulez sélectionner plusieurs vidéos d'un coup, maintenez la touche <b>CTRL</b> (ou <b>SHIFT</b>) du clavier enfoncée (tout en sélectionnant vos vidéos), cliquez sur <b>Ajouter</b>.</p><p>Vous pouvez dès lors sélectionner une vidéo dans la liste et la visionner (par le bouton juste à la droite de cette liste), vous noterez que vous pouvez visionner la vidéo en quatre tiers, en seize neuvième ou avec les proportions d'origine de la vidéo (w;h). De même si vous le désirez, vous pouvez obtenir des informations complètes sur la vidéo sélectionnée, et ce par le bouton <b>'Infos'</b> (en bas).</p><p>Cliquez ensuite sur le bouton <b>'Appliquer'</b>, sélectionnez le répertoire de sauvegarde, indiquez votre <b>'Nom de fichier'</b>, cliquez sur le bouton <b>'Enregistrer'</b> et attendez le temps de la conversion. A la fin cliquez sur le bouton <b>'Voir les informations d'encodage'</b> et fermez cette dernière fenêtre après avoir vu les informations en question.</p><p>Vous pouvez voir le résultat de la conversion en images dans l'onglet <b>Visualisation</b>. Dans cet onglet vous pouvez faire défiler les images par le bouton <b>Lancer le diaporama</b> (le bouton violet avec une flèche blanche vers la droite). Si vous faites un clic droit de la souris sur une des images résultantes, vous accédez à des paramètres vous permettant différents affichages de la dite image.</p><p>L'onglet <b>'Infos'</b> vous permet de voir les vidéos chargées (avec leurs chemins exacts) avant et après conversion.</p>"
            )
        )

    def saveFiles(self):
        """
		# On sauvegarde la liste des fichiers chargés
		"""
        self.afficheurVideoSource.saveFileLocation(self.idSection)

    def loadFiles(self):
        """
		# On sauvegarde la liste des fichiers chargés
		"""
        self.afficheurVideoSource.loadFileLocation(self.idSection)

    def load(self):
        """
		Chargement de la configuration de tous les objets
		"""
        self.loadFiles()

    def save(self):
        """
		Sauvegarde de la configuration de tous les objets
		"""
        self.saveFiles()