Wiki Root66

Le Wiki de Root66, tuto, infos et astuces

Outils pour utilisateurs

Outils du site


creer_des_diaporamas_a_partir_d_images_jpeg

Introduction

Les scripts Python et Bash présentés dans cet article servent à créer des diaporamas à partir d'images JPEG. Ces outils sont très proches de celui présenté ici : Modifier des images JPEG. Il est plus que recommandé de commencer par lire et appliquer cet article pour les raisons suivantes :

  • Les images produites sont directement utiles à la création des diaporamas,
  • Les logiciels nécessaires (Python, Pmw, fenêtres de dialogues) sont exactement les mêmes, donc commencer par les installer en suivant les conseils correspondants.

Cet article se bornera donc à présenter les compléments. En fait on va présenter 2 outils légèrement distincts, identiques du point de vue aspect, mais avec des nuances de traitements :

  • Le 1er pourra produire des diaporamas dont on spécifiera la durée de chaque diapo en secondes, avec possibilité d'ajoûter des diapos à un film existant, et estimation/mesure de la durée nécessaire à la création du diaporama;
  • Le 2ème pourra produire des diaporamas dont on spécifiera la durée de chaque diapo en nombre de “frames” (images), sachant qu'il y en a 25 par seconde, et possibilité de tronquer la durée du film si la bande sonore est plus longue que les diapos. On a donc là un outil pour adapter très précisément les durées des diapos, par exemple pour que la durée totale s'adapte à une bande sonore donnée avec une extrême précision. Par contre on ne pourra pas prolonger un diaporama existant comme précédemment.

Dans les 2 cas on pourra ensuite graver un CD au format SVCD, format lisible par certains lecteurs DVD de salon (mais pas tous !). Le SVCD semble être très prisé notamment en Chine, car il permet de diffuser des films sur supports CD, moins chers et plus répandus, au détriment d'une qualité moindre. La résolution des images est cependant adaptée aux téléviseurs classiques actuels. Sinon les diaporamas produits sont lisibles par tout logiciel multimédia Linux (Totem, Mplayer, Amarok, Xine, etc…).

L'article peut paraître long et compliqué, mais en fait l'essentiel consiste à effectuer quelques copier/coller dans des fichiers. Ceux qui voudront en savoir plus pourront bien sûr décortiquer les commandes d'appel des différents logiciels mis en oeuvre, de quoi passer un moment assez long et ardu… Pour les pressés qui n'ont pas besoin d'IHM ni des options annexes de gravure de CD, les scripts bash principaux seront suffisants, et on pourra même les simplifier un peu. ;-)

Article rédigé par Jeanmm 8-)
Version initiale : 14/8/2006.

Solution proposée

On va donc proposer ici un jeu de scripts Python et Bash qui vont nous permettre de réaliser les outils suivants :

 :wiki-diaporama-1.jpg

 :wiki-diaporama-2.jpg

Marrant, non ? On dirait un jeu des 7 différences ;-)

Pré-requis

Logiciels

Les logiciels suivants doivent être disponibles :

  • Python, Pmw, scripts de sélection de fichier et de dossier : voir le détail dans l'article Modifier des images JPEG,
  • ImageMagick (outils convert, identify et composite),
  • mjpegtools (outils jpeg2yuv, yuvscaler, mpeg2enc, mplex),
  • vcdimager, cdrecord, cdrdao,
  • éventuellement : audacity, Gimp,
  • lecteur vidéo (totem, mplayer,…).

On vérifiera si les paquetages correspondants sont disponibles dans sa distribution, sinon on pourra fouiller sur le net pour se procurer ces logiciels. Pour ceux qui veulent en savoir un peu plus sur ces outils, voici quelques liens :

Pour ceux qui ont une Mandriva, étudier aussi le script images2mpg; il n'a été découvert qu'après rédaction de ces scripts. Il se peut que ce script existe aussi dans d'autres distributions.

Images de fond et sons

Il est de plus nécessaire de disposer de 2 fichiers particuliers dans le dossier de travail (dans les scripts qui suivent ce dossier s'appelle Diaporama dans le home de l'utilisateur) :

  • un fichier sonore, dont les scripts supposent disposer, sous le nom “musique.mp2” : attention, il s'agit bien d'un format mp2, beaucoup plus fiable que le mp3 pour ce genre de manips (certains fichiers mp3 fonctionnent, mais pas tous, l'outil de multiplexage mplex étant relativement exigeant sur les propriétés de la bande sonore à ajoûter aux images);
  • un fond d'écran sur lequel chaque diapo sera superposée; ici on doit avoir un tel fond dans un fichier nommé “fond720x576.ppm”; il est par exemple très facile de se créer un tel fond avec Gimp en étalant un motif ou une couleur de fond sur une nouvelle image de la bonne taille (720 de large, 576 de haut) et enregistrée au format ppm.

Pour obtenir un fichier mp2 à partir d'un ficher wav, on pourra utiliser la commande bash suivante :

cat fichier.wav | mp2enc -v 1 -V -o fichier.mp2

Et si on part d'un fichier mp3 on pourra d'abord le convertir en wav avec audacity, puis du wav en mp2 avec la manip ci-dessus. Audacity est un superbe outil d'édition de fichiers musicaux, à essayer !

Les scripts présentés dans cet article utilisent des noms de fichiers fixes, mais rien n'empêche de les adapter à ses besoins, par exemple en rendant ces données aussi configurables.

Images pour diapos

Les images à transformer en diapos doivent être copiées dans le dossier de travail avant d'utiliser les scripts. Tous les fichiers de suffixes JEPG, JPG, jpeg et jpg seront pris, renommés en jpg, avec suppression d'éventuels blancs dans les noms, puis triés alphabétiquement (ces traitements pourront être supprimés des scripts si on n'en a pas besoin).

On pourra se servir de l'outil Modifier des images JPEG pour modifier les noms des images en AAMMJJ-HHMMSS.jpg, ce qui fera correspondre le tri alphabétique au tri par dates.

Script Bash principal 1

Avant d'utiliser les scripts de manière routinière, il est nécessaire de les tester en mode ligne de commande, en ne mettant que 2 images dans le dossier de travail (pas la peine de perdre du temps…).

La plupart des boutons des fenêtres présentées ci-dessus déclenchent des scripts Bash dont le déroulement sera visible dans la zone de texte en bas de la fenêtre. Commençons donc par le script bash principal du 1er outil (configuration en secondes); on copiera en root le texte suivant dans /usr/local/bin/diapo-Secondes.sh :

#!/bin/bash
###################################################################
# Script pour créer un diaporama MPEG / SVCD à partir d'images JPEG
###################################################################
 
# On traite tous les fichiers.jpg d'un dossier accessible en écriture.
# (en fait tous fichiers de suffixes .jpg, .jpeg, .JPG et .JPEG)
 
# Auteur  : Jeanmm
# Date    : août 2006
# Licence : GPL
# Lien    : www.root66.net
 
# Consommations en fichiers (estimations) :
# - en images cibles de taille normale :
#   - Ficher.mpg :   0.13 Mo/s, soit 0.67 Mo / image de 5s
# - en images cibles de demi-taille :
#   - Ficher.mpg :   0.12 Mo/s, soit 0.62 Mo / image de 5s
 
# 3 paramètres possibles :
# - durée de chaque diapo
# - nom du dossier des images et films
# - oui/non pour prolonger un film existant
 
echo ""
echo "Creation de film mpg a partir d'images jpg"
echo "------------------------------------------"
echo ""
 
# Dossier des images jpg et des vidéos créées (param 2 si existant)
# -----------------------------------------------------------------
 
if [ ! 0$2 == 0 ] ; then
  cd $2
fi
echo "Dossier des images et videos : $PWD"
 
 
# Dossier des fichiers utiles autres
# ----------------------------------
# (images de fond, musiques, fichiers temporaires...)
# On pourra prévoir un dossier à part
 
dfu=$PWD
 
 
# Taille des images cibles PAL/SECAM :
# ------------------------------------
 
# mettre un commentaire devant les lignes non souhaitées;
# la taille normale sert aux films SVCD, de format "-f 4";
# la demie-taille sert aux films VCD, de format "-f 1".
 
# Taille normale = 720x576, avec marges de 10+10
tailleM=720x576
taille=700x556
tailleX=700
tailleY=556
 
# Demi-taille totale = 352x288, avec marges de 10+10
#tailleM=352x288
#taille=332x268
#tailleX=332
#tailleY=268
 
# IMPORTANT : des fichiers fond$tailleM.ppm doivent exister
# dans le dossier $dfu, de taillesM exactes ci-dessus.
 
# Par ailleurs il faut y mettre aussi un fichier musique.mp2
# pour l'ajoût de musique de fond.
 
 
# Suppression des blancs dans les noms des fichiers
# -------------------------------------------------
 
for a in `find . -maxdepth 1 -type f -name "*"` ; do
  b=$(echo "$a" | sed -e 's/[[:blank:]]/_/g')
  if [ ! -e "$b" ] ; then
    echo "mv \"$a\" $b"
    mv "$a" $b
  fi
done
 
# On renomme les fichiers .JPG , .JPEG et .jpeg en .jpg
# -----------------------------------------------------
 
for a in `find . -maxdepth 1 -type f -name "*.JPG"` ; do
  b=$(echo $a | sed -e 's/JPG$/jpg/')
  if [ ! -e "$b" ] ; then
    echo "mv $a $b"
    mv $a $b
  fi
done
 
for a in `find . -maxdepth 1 -type f -name "*.JPEG"` ; do
  b=$(echo "$a" | sed -e 's/JPEG$/jpg/')
  if [ ! -e "$b" ] ; then
    echo "mv $a $b"
    mv $a $b
  fi
done
 
for a in `find . -maxdepth 1 -type f -iname "*.jpeg"` ; do
  b=$(echo $a | sed -e 's/jpeg$/jpg/')
  if [ ! -e "$b" ] ; then
    echo "mv $a $b"
    mv $a $b
  fi
done
 
 
# Comptage des images
# -------------------
 
countT=0
for ii in `find . -maxdepth 1 -type f -iname "*.jpg"` ; do
  countT=$[$countT + 1]
done
test $countT -eq 0 && echo "Aucune image.jpg dans le dossier ?" && exit 0
echo "Nombre total d'images : $countT"
 
 
# Durée de chaque diapo en secondes
# ---------------------------------
# (valeur modifiable par paramètre d'appel N° 1 sinon par question)
 
duree=8
 
if [ ! 0$1 == 0 ] ; then
  duree=$1
else
  echo ""
  echo -n "Choisissez la durée des diapos (${duree} secondes par defaut) : "
  read duree2
  if [ ! "x${duree2}" == "x" ] ; then
    duree=$duree2
  fi
fi
nbsec=$[ $duree * $countT ]
nbmin=`echo $nbsec | awk '{printf "%.1f", $1/60}'`
echo "Duree de chaque diapo : $duree secondes, soit en tout $nbsec secondes / $nbmin minutes"
 
 
# Test si film existant
# ---------------------
 
# si param 3 on ne pose pas la question de garder un film existant
 
if [ -f diaporama.mpg ] ; then
    ooo=`ls -la diaporama.mpg | awk '{printf "%.1f", $5/1024/1024}'`
    if [ -f diaporama-duree.txt ] ; then
	# nbsec0 = nb de secondes déjà disponibles
	nbsec0=`tail -n 1 diaporama-duree.txt`
        nbmin0=`echo $nbsec0 | awk '{printf "%.1f", $1/60}'`
	echo "Le film diaporama.mpg existe deja : $ooo Mo / $nbsec0 secondes / $nbmin0 minutes"
    else
	# on suppose qu'un Mo correspond à 8 secondes
	nbsec0=`echo $ooo | awk '{printf "%d", $1*8}' `
        nbmin0=`echo $nbsec0 | awk '{printf "%.1f", $1/60}'`
        echo "Le film diaporama.mpg existe deja : $ooo Mo"
	echo "duree estimee : $nbsec0 secondes / $nbmin0 minutes"
    fi
 
    if [ ! 0$3 == 0 ] ; then
        ooo=$3
    else
        echo -n "==> tapez 'oui' pour le prolonger : "
        read ooo
    fi
 
    if [ ! "x$ooo" == "xoui" ] ; then
        rm -f diaporama.mpg
	rm -f diaporama-duree.txt 2>/dev/null
	nbsec0=0
    fi
else
    nbsec0=0
fi
 
 
# inits divers
# ------------
 
# nb total d'images vidéo (25 par seconde)
nbframes=$[ $duree * 25 ]
 
rm -f $dfu/diaporama.log $dfu/video*.mpg $dfu/diaporama-x*.mpg diaporama-SVCD.mpg 2>/dev/null
 
 
# Calculs de temps estimatifs
# ---------------------------
 
# unite en secondes, unite100 = 100 * unite (entier)
if [ -f $dfu/diaporama-unite-calcul.txt ] ; then
    unite100=`cat $dfu/diaporama-unite-calcul.txt`
    unite=`echo "$unite100" | awk '{printf "%.2f", $1/100}'`
else
    unite=6
    unite100=600
    echo "600" >$dfu/diaporama-unite-calcul.txt
fi
 
echo "--------------------------------------------------------------------------"
nbest=`echo "$nbsec $unite100" | awk '{printf "%.0f", $1*$2/100}'`
nbest2=`echo "$nbsec $unite100" | awk '{printf "%.1f", $1*$2/6000}'`
echo "Duree de traitement estimee : $nbest secondes / $nbest2 minutes,"
echo "avec ${unite} secondes de traitement par seconde de film."
 
h1=`date +"%H"`
m1=`date +"%M"`
s1=`date +"%S"`
st=`echo "$h1 $m1 $s1 $nbest" | awk '{printf "%.2d", $1*3600+$2*60+$3+$4}'`
h2=`echo "$st" | awk '{printf "%0.2d", $st/3600}'`
m2=`echo "$st $h2" | awk '{printf "%0.2d", ($1-$2*3600)/60}'`
s2=`echo "$st $h2 $m2" | awk '{printf "%0.2d", $1-$2*3600-$3*60}'`
echo "Il est ${h1}h ${m1}m ${s1}s ==> fin estimee à ${h2}h ${m2}m ${s2}s."
echo "----------------------------------------------------------"
 
 
# Boucle sur chaque image
# -----------------------
 
# Les images sont triées par noms, on a donc par exemple intérêt à les
# avoir nommées "AAMMJJ-HHMMSS.jpg"
 
count=0
for ii in `find . -maxdepth 1 -type f -iname "*.jpg" | sort` ; do
    counti=$[$count + 1]
 
    # Conversion de taille d'image
 
    echo "Conversion de l'image `printf "%3.3d" $counti`/`printf "%3.3d" $countT` : $ii"
    convert -resize $taille $ii /tmp/tempo1.jpg 2>>$dfu/diaporama.log
 
    # calculs pour centrer l'image sur le fond, avec marges +10+10
 
    x=`identify -format '%w' /tmp/tempo1.jpg`
    y=`identify -format '%h' /tmp/tempo1.jpg`
    dx=$[ ( $tailleX - $x ) / 2 + 10 ]
    dy=$[ ( $tailleY - $y ) / 2 + 10 ]
 
    # fusion image + fond => tempo2.jpg
 
    composite -geometry +$dx+$dy /tmp/tempo1.jpg $dfu/fond$tailleM.ppm /tmp/tempo2.jpg 2>>$dfu/diaporama.log
 
    # Conversion en film élémentaire => $dfu/videoXXX.mpg
 
    jpeg2yuv -v 0 -f 25 -n 1 -l $nbframes -I p -j /tmp/tempo2.jpg  2>>$dfu/diaporama.log | yuvscaler -v 0 -O SVCD 2>>$dfu/diaporama.log | mpeg2enc -v 0 -a 2 -f 4 -V 230 --correct-svcd-hds --interlace-mode 1 -o $dfu/video`printf "%3.3d" $count`.mpg 2>>$dfu/diaporama.log
 
    count=$[$count + 1]
done
 
 
# Concaténation des $dfu/videoXXX.mpg => diaporama.mpg ; le fait
# de mettre >> permet l'ajout si le fichier existe.
 
echo "Creation des videos"
cat $dfu/video*.mpg >>diaporama.mpg && rm -f $dfu/video*.mpg 2>/dev/null
 
# Ajout de son (seul le mp2 semble convenir; voir fin de script)
# le son est obligatoire pour concaténer proprement et autoriser
# les étapes ultérieures vcdimager/cdrdao pour la gravure.
 
nbsecT=$[ $nbsec+$nbsec0 ]
echo "$nbsecT" >diaporama-duree.txt
mplex -f 4 -l $nbsecT -b 230 $dfu/musique.mp2 diaporama.mpg -o $dfu/diaporama-x%3.3d.mpg -v 1 2>>$dfu/diaporama.log
# concaténation des portions (en nombre aléatoire)
cat $dfu/diaporama-x*.mpg >diaporama-SVCD.mpg && rm -f $dfu/diaporama-x*.mpg 2>/dev/null
 
# Suppression de log si vide
test -s $dfu/diaporama.log || rm -f $dfu/diaporama.log
 
 
# Temps final et ajustement de l'estimation future
# ------------------------------------------------
 
echo "----------------------------------------------------------"
h3=`date +"%H"`
m3=`date +"%M"`
s3=`date +"%S"`
echo "Il est ${h3}h ${m3}m ${s3}s"
st2=`echo "$h1 $m1 $s1 $h3 $m3 $s3" | awk '{printf "%d", ($4-$1)*3600+($5-$2)*60+($6-$3)}'`
if [ "$st2" != "$nbest" ] ; then
    echo "Duree necessaire : $st2 secondes aulieu de $nbest secondes,"
    unite2=`echo "$st2 $nbsec" | awk '{printf "%.2f", $1/$2}'`
    unite200=`echo "$st2 $nbsec" | awk '{printf "%d", $1/$2*100}'`
    err=`echo "$st2 $nbest" | awk '{printf "%+.1f", ($1-$2)*100/$2}'`
    echo "$unite200" >$dfu/diaporama-unite-calcul.txt
    echo "soit ${unite2} secondes de traitement / seconde de film"
    echo "l'estimation de temps etait juste à ${err}% pres"
else
    echo "L'estimation de temps etait correcte !"
fi
 
echo "----------------------------------------------------------"
ooo=`ls -la diaporama.mpg | awk '{printf "%.1f", $5/1024/1024}'`
echo "Film de base : diaporama.mpg, de taille $ooo Mo"
ooo=`ls -la diaporama-SVCD.mpg | awk '{printf "%.1f", $5/1024/1024}'`
echo "Film SVCD : diaporama-SVCD.mpg, de taille $ooo Mo"
nbmin=`echo $nbsecT | awk '{printf "%.1f", $1/60}'`
echo "Duree totale : $nbsecT secondes / $nbmin minutes"
echo "Le film diaporama-SVCD.mpg peut etre grave."
echo "Traitement termine :)"
exit 0
 
# Infos diverses :
# Comment obtenir du mp2 à partir de wav :
# cat musique.wav | mp2enc -v 1 -V -o musique.mp2
# Conversion de mp3 en wav : par audacity (export wav) ou ripage konqueror

On rendra le script exécutable, par exemple par commande :

chmod +x /usr/local/bin/diapo-Secondes.sh

Si on a préparé tous les fichiers dans le dossier de travail (image de fond, fichier de musique, images à convertir en diapos), lancer le script en ligne de commande pour vérifier le déroulement. A noter que les erreurs sont mises dans un fichier diaporama.log.

Si tout se déroule bien on aura les diaporamas suivants dans le dossier :

  • diaporama.mpg : succession d'images sans le son;
  • diaporama-SVCD.mpg : succession d'images avec le son;

L'option qui permet d'ajoûter des diapos à un diaporama existant consiste à étendre le fichier diaporama.mpg puis à recréer complètement le fichier diaporama-SVCD.mpg à partir du nouveau diaporama.mpg. A noter qu'un fichier diaporama.mpg créé à partir du 2ème outil qu'on présentera ci-dessous est tout-à-fait compatible et peut aussi être étendu grâce à ce 1er script. D'ailleurs on pourrait créer un outil unique regroupant toutes les options des 2 outils.

On pourra tester le résultat en démarrant un lecteur multimédia sur ces fichiers. Si tout est OK, on pourra passer à l'étape suivante, l'encapsulation de ce script dans l'outil Python avec fenêtre graphique.

Script Python principal 1

Avant d'utiliser les scripts Python de manière routinière, il est aussi nécessaire de les tester en mode ligne de commande.

Pour le script Python principal du 1er outil (configuration en secondes); on copiera en root le texte suivant dans /usr/local/bin/diapo-Secondes.py :

#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
 
# Ce script Python affiche une fenêtre de paramétrage et de lancement de scripts bash
# qui permettent de créer un diaporama à partir d'images JPG, et éventuellement
# un CD de type SVCD contenant ce diaporama.
#
# Auteur  : Jeanmm
# Date    : août 2006
# Licence : GPL
# Lien    : www.root66.net
 
import sys, os, string
from   Tkinter import *
import Pmw
import tkMessageBox
from   DialogueDossiersJmm           import DirBrowserDialog
from   DialogueFichiersEtDossiersJmm import PmwFileDialog
 
# Données générales
# -----------------
 
# Titre de la fenetre
MonTitre1  = "Creation de diaporama"
 
# Dossier par défaut
MonDossier = os.path.join(os.getenv('HOME'), 'Diaporama')
 
# Logos pour agrementer la fenetre
MonLogoDossier = '/usr/local/divers/LogoDossier.gif'
MonLogo        = '/usr/local/divers/decor.gif'
 
# Les scripts bash à exécuter
MonScript0 = 'diapo-test.sh'
MonScript1 = 'diapo-Secondes.sh'
MonScript2 = 'cd-effacement'
MonScript3 = 'cd-gravure-SVCD'
MonScript4 = 'cd-ejection'
 
# Option générale de listage de numéros de lignes
NumLi = 0 # 0=non, 1=oui
ii=0
 
# Nom de l'option choisie (prolonger ou créer film)
nomOption='oui' # 'oui' ==> on prolonge
 
# Dossiers accessibles cycliquement par F3
Dossiers=['','',''] # dossier courant, courant au lancement, et home
NumDos=0
 
 
# Sous-programmes divers
# ======================
 
# Parcours cyclique de 3 noms de dossiers par F3
# ----------------------------------------------
 
def f3(ev=None):
    global NumDos
    NumDos=NumDos+1
    if NumDos==3:
        NumDos=0
    entree1.delete(0,END)
    entree1.insert(END, Dossiers[NumDos])
 
# Parcours de dossiers général par F4
#------------------------------------
 
def f4(ev=None):
    texte2['text']=""
 
    if os.path.isdir(entree1.get()):
        rep=entree1.get()
    else:
        texte2.configure(fg='red', font=('Times', 12, 'bold'))
        texte2['text']="Le Dossier n'existe pas ?!?"
        entree1.focus_set()
        entree1.xview(END)
        return
 
    dirBrowserDialog = DirBrowserDialog(fen1,
        label = '',
        path = entree1.get(),
        title = 'Selection de dossier')
 
    dir = dirBrowserDialog.activate()
    fen1.focus_set()
    #print 'Dossier sélectionné :', dir
    if dir != None:
        entree1.delete(0,END)
        entree1.insert(END, dir)
    entree1.xview(END)
    entree1.focus_set()
 
# Recherche de fichiers JPG par F5
#---------------------------------
 
def f5(ev=None):
    texte2['text']=""
 
    f0=PmwFileDialog(fen1)
    f0.title("Listage des noms d'images.jpg")
    fname=f0.askfilename(directory=entree1.get(), filter='*.jpg')
 
# Rafraichissement de fenêtre en cas de déplacement
# ------------------------------------------------
 
def rafraichissement(ev):
    fen1.update_idletasks()
 
# Lecture d'une ligne de fichier
# ------------------------------
 
# Comme readline, mais en plus de '\n' on teste '\r'.
# Permet de découper les sorties du programme de gravure
# en plusieurs lignes écrites au fur et à mesure, par exemple :
#   Wrote 1 of 4 MB (Buffers 100%  99%).
#   Wrote 2 of 4 MB (Buffers 100%  99%).
#   Wrote ...
# aulieu d'une ligne unique en fin de gravure :
#   Wrote 1 of 4 MB (Buffers 100%  99%).\rWrote 2 of 4 MB (Buffers 100%  99%).\rWrote ...
 
def lecture_ligne():
    global fout      # fichier lu (stdout de script en cours)
    txt=fout.read(1) # lecture/test de chaque caractère
    ligne=''         # ligne couramment lue
    while txt:
        if txt=='\n':
            ligne = ligne + txt
            break
        elif txt=='\r':
            ligne = ligne + '\n'
            break
        else:
            ligne = ligne + txt
        txt=fout.read(1) # caractère suivant
    return ligne
 
# quitter le programme
# --------------------
 
# on simule le clic sur le bouton Quitter quand il est sélectionné + touche entrée
def quitter(ev=None):
    bouton3.invoke()
 
 
# Sous-programmes de Traitement
# =============================
 
# Test des options et fichiers
# ----------------------------
 
def tests_options(ev=None):
 
    global ii        # Numéro de ligne
    global nomOption # Nom de l'option choisie
    global Dossiers  # Noms dossiers
 
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    # Option choisie
    if nomOption=='':
        texte2['text']="Choisissez d'abord une option"
        return
 
    texte2['text']='Tests en cours...'
    fen1.update_idletasks()
 
    # Traitement du dossier
    try:
        os.chdir(entree1.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="Le Dossier n'existe pas !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="Le Dossier n'existe pas ?!?"
        entree1.focus_set()
        return
    Dossiers[0]=entree1.get()
 
    # Durée de chaque diapo
 
    try:
        dureeDiapo = int(entree2.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="La duree de chaque diapo est invalide !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="La duree de chaque diapo est invalide ?!?"
        entree2.focus_set()
        return
 
    if dureeDiapo < 1: # Nb >= 1
        dureeDiapo=1
        entree2.delete(0,END)
        entree2.insert(END, '1')
 
    # Lancement du script 0 avec arg dossier
 
    fin,fout=os.popen4(MonScript0 + ' ' + entree1.get())
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
    texte2['text']='OK - '
 
    while txt:
        txt=fout.readline()
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if ligne[0:16]=='Aucune image.jpg':
            texte2['text']='Aucune image.jpg - '
            zoneListage.insert(END, ligne, 'rouge')
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    MonFic=entree1.get()
    if MonFic[-1:0]=='/':
        Pass
    else:
        MonFic = MonFic + '/'
    MonFic = MonFic + 'diaporama.mpg'
 
    if os.path.isfile(MonFic):
        texte2['text']= texte2['text'] + "le film diaporama.mpg existe"
    else:
        texte2['text']= texte2['text'] + "le film diaporama.mpg n'existe pas"
    zoneListage.see(END)
    fen1.update_idletasks()
 
 
# Création de diaporama
# ---------------------
 
def creation_diaporama(ev=None):
 
    global ii        # Numéro de ligne
    global nomOption # Nom de l'option choisie
    global Dossiers  # Noms dossiers
 
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    # Option choisie
    if nomOption=='':
        texte2['text']="Choisissez d'abord une option"
        return
 
    texte2['text']='Creation de diaporama en cours...'
    fen1.update_idletasks()
 
    # Traitement du dossier
    try:
        os.chdir(entree1.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="Le Dossier n'existe pas !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="Le Dossier n'existe pas ?!?"
        entree1.focus_set()
        return
    Dossiers[0]=entree1.get()
 
    # Durée de chaque diapo
 
    try:
        dureeDiapo = int(entree2.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="La duree de chaque diapo est invalide !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="La duree de chaque diapo est invalide ?!?"
        entree2.focus_set()
        return
    if dureeDiapo < 1: # Nb >= 1
        dureeDiapo=1
        entree2.delete(0,END)
        entree2.insert(END, '1')
 
    # Lancement du script avec args duree + dossier + option oui/non
 
    fin,fout=os.popen4(MonScript1 + ' ' + str(dureeDiapo) + ' ' + entree1.get() + ' ' + nomOption)
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=fout.readline()
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if ligne[0:16]=='Aucune image.jpg':
            texte2['text']='Aucune image.jpg dans le dossier ?'
            zoneListage.insert(END, ligne, 'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    texte2['text']='OK - diaporama cree'
    fen1.update_idletasks()
 
 
# Effacement d'un CD-RW
# ---------------------
 
def effacer_cd(ev=None):
 
    global ii        # Numéro de ligne
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    texte2['text']='Effacement de CD-RW en cours...'
    fen1.update_idletasks()
 
    if tkMessageBox.askokcancel("Effacement de CD", "Confirmez ou annulez l'effacement"):
        pass
    else:
        texte2['text']='OK'
        fen1.update_idletasks()
        return
 
    # Lancement du script
 
    fin,fout=os.popen4(MonScript2)
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=fout.readline()
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if txt[0:17]=='cdrecord: No disk':
            texte2['text']='Pas de CD dans le graveur ?'
            txt='Pas de CD dans le graveur ?\n'
            zoneListage.insert(END, txt,'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    ligne='OK - CD efface\n'
    zoneListage.insert(END, ligne)
    zoneListage.see(END)
    texte2['text']='OK - CD efface'
    fen1.update_idletasks()
 
 
# Gravude d'un CD-SVCD
# --------------------
 
def graver_SVCD(ev=None):
 
    global ii        # Numéro de ligne
    global fout      # fichier stdout du script
 
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    MonFic = entree1.get() + '/diaporama-SVCD.mpg'
 
    if os.path.isfile(MonFic):
        pass
    else:
        texte2['text']= "le film " + MonFic + " n'existe pas ?"
        return
 
    texte2['text']='Gravure de SVCD en cours...'
    fen1.update_idletasks()
 
    # Lancement du script
 
    fin,fout=os.popen4(MonScript3 + ' ' + MonFic)
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=lecture_ligne() # lecture perso avec test '\r'
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if ligne[0:8]=='++ WARN:':
            pass
        elif ligne[0:23]=='WARNING: Unit not ready':
            texte2['text']='Pas de CD dans le graveur ?'
            ligne='Pas de CD dans le graveur ?\n'
            zoneListage.insert(END, ligne,'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        elif ligne[0:24]=='Disk seems to be written':
            texte2['text']='Le CD semble deja grave ?'
            ligne='Le CD semble deja grave ?\n'
            zoneListage.insert(END, ligne,'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        elif ligne[-2:]=='\\r':
            ligne=ligne[0:-2] + '\n'
            zoneListage.insert(END, ligne)
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    texte2['text']='OK - CD grave'
    fen1.update_idletasks()
 
 
# Ejection d'un CD
# --------------------
 
def ejecter_CD(ev=None):
 
    global ii        # Numéro de ligne
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    texte2['text']='Ejection de CD en cours...'
    fen1.update_idletasks()
 
    # Lancement du script
 
    fin,fout=os.popen4(MonScript4)
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=fout.readline()
    ligne='OK, CD ejecte\n'
    zoneListage.insert(END, ligne)
    zoneListage.see(END)
    fin.close()
    fout.close()
    texte2['text']='OK, CD ejecte'
    fen1.update_idletasks()
 
 
# =========================================================
#       ----------- Programme principal -----------
# =========================================================
 
# Instanciation d'une fenêtre Pmw (Python méga-widgets)
# -----------------------------------------------------
 
fen1 = Pmw.initialise()
fen1.title(MonTitre1)
fen1.bind("<Alt-F4>", quitter)
fen1.bind("<Configure>", rafraichissement)
 
# Dossiers pour touche F3
Dossiers[0]=MonDossier
Dossiers[1]=os.getcwd()
Dossiers[2]=os.getenv('HOME')
 
fen1.bind("<F3>", f3)
fen1.bind("<F4>", f4)
fen1.bind("<F5>", f5)
 
 
# creation des widgets de configuration/lancement des scripts
# ===========================================================
 
# Ligne 1
# -------
 
# dossier des images/films
texte1 = Label(fen1, text='  Dossier :')
texte1.grid(row=1, column=1, sticky=E, padx=5, pady=5)
 
 
# Saisie de nom de dossier
# alternatives : f3 pour 3 valeurs prédéfinies, f4 pour dialogue
entree1 = Entry(fen1, width=70, bg='white')
entree1.grid(row=1, column=2, columnspan=2, sticky=W, padx=5, pady=5)
entree1.insert(END, MonDossier)
entree1.focus_set()
 
# Bouton pour dialogue de parcours de dossier (aussi par f4)
logo=PhotoImage(file=MonLogoDossier)
bouton0 = Button(fen1, activebackground='DeepSkyBlue2', image=logo, command=f4)
bouton0.grid(row=1, column=4, sticky=W, padx=0, pady=3)
bouton0.bind("<Return>",f4)
 
# Ligne 2
# -------
 
# durée de chaque diapo
 
texte2 = Label(fen1, text='    Duree :')
texte2.grid(row=2, column=1, sticky=E, padx=5, pady=5)
 
entree2 = Entry(fen1, width=4, bg='white')
entree2.grid(row=2, column=2, sticky=W, padx=5, pady=5)
entree2.insert(END, '6')
 
# Ligne 3
# -------
 
# option de prolongement/écrasement de film
 
texte3 = Label(fen1, text='   Option :')
texte3.grid(row=3, column=1, sticky=E, padx=5, pady=5)
 
class ZoneRadio(Frame):
    """Utilisation de widgets 'boutons radio'"""
    def __init__(self, boss=None):
        """Création d'un champ d'entrée avec 2 boutons radio"""
        Frame.__init__(self)
        self.pack()
        self.configure(relief=GROOVE, bd=2)
        # Nom français et nom technique des quatre styles de police :
        texteOption =["Prolonger le film existant", "Creer un nouveau film"]
        valeurOption =["oui", "non"]
        # Le style actuel est mémorisé dans un 'objet-variable' Tkinter ;
        self.opt = StringVar()
        self.opt.set(valeurOption[0])
        # Création des boutons radio
        for n in range(2):
            bout = Radiobutton(self,
                text = texteOption[n],
                variable = self.opt,
                value = valeurOption[n],
                command = self.modifOption)
            bout.pack(side=LEFT, padx=5)
 
    def modifOption(self):
        global nomOption
        nomOption = self.opt.get()
 
zoneradio1=ZoneRadio()
zoneradio1.grid(row=3, column=2, columnspan=2, sticky=W, padx=5, pady=5)
 
# Ligne 4
# -------
 
# messages divers
 
texte2 = Label(fen1, text='Dossier courant : ' + os.getcwd())
texte2.grid(row=4, column=2, columnspan=2, padx=5, pady=5)
 
# Ligne 5
# -------
 
# boutons d'actions pour diaporama et bouton quitter
 
# bouton de lancement de tests
bouton1 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Tester les options et fichiers", command=tests_options)
bouton1.grid(row=5, column=2, padx=5, pady=5)
bouton1.bind("<Return>",tests_options)
 
# bouton de création de diaporama
bouton2 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Creer un Diaporama", command=creation_diaporama)
bouton2.grid(row=5, column=3, padx=5, pady=5)
bouton2.bind("<Return>",creation_diaporama)
 
# bouton pour quitter
bouton3 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=15, text='Quitter', command=fen1.quit)
bouton3.grid(row=5, column=4, columnspan=2, padx=5, pady=5)
bouton3.bind("<Return>",quitter)
 
# Ligne 6
# -------
 
# boutons d'actions pour gravure
 
# bouton pour effacer un CD-RW
bouton4 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Effacer un CD-RW", command=effacer_cd)
bouton4.grid(row=6, column=2, padx=5, pady=5)
bouton4.bind("<Return>",effacer_cd)
 
# bouton pour graver un CD
bouton5 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Graver un SVCD", command=graver_SVCD)
bouton5.grid(row=6, column=3, padx=5, pady=5)
bouton5.bind("<Return>",graver_SVCD)
 
# bouton pour éjecter un CD
bouton6 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=15, text="Ejecter le CD", command=ejecter_CD)
bouton6.grid(row=6, column=4, columnspan=2, padx=5, pady=5)
bouton6.bind("<Return>",ejecter_CD)
 
# Logo en bout de lignes 1 à 4
# ----------------------------
 
can1 = Canvas(fen1, width=90, height=106, bg='AntiqueWhite3')
photo = PhotoImage(file=MonLogo)
item = can1.create_image(45, 53, image=photo)
can1.grid(row=1, column=5, rowspan=4, padx=4, pady=4)
 
 
# Zone de listage des résultats du script
# ---------------------------------------
 
# C'est un rectangle de la largeur totale de la fenêtre,
# avec ascenseurs automatiques si nécessaire.
 
zoneListage = Pmw.ScrolledText(fen1,
    text_font   = 'Courier 11 normal', text_bg = 'AliceBlue',
    text_padx   = 10, text_pady = 10, text_wrap = 'none',
    borderframe = 1,
    borderframe_borderwidth = 3,
    borderframe_relief = RIDGE,
    usehullsize = 1,
    hull_width = 710, hull_height = 350)
 
zoneListage.grid(row=7, column=1, columnspan=5, padx=4, pady=4)
zoneListage._textbox['takefocus'] = 0
 
ii=0   # Compteur des lignes insérées
 
# balise pour lignes rouges créées ici (en plus
# des lignes noires générées par le script)
 
zoneListage.tag_configure('rouge', foreground='red')
 
# texte d'explications en début de zone
 
titre = """
Cet outil sert à créer un Diaporama à partir d'images JPG
---------------------------------------------------------
 
Choisissez :
- le dossier de base contenant les images à traiter et les films créés,
- la durée de chaque diapo en secondes,
- si un éventuel film existant doit être prolongé (en gardant les diapos
  précédentes inchangées en début de film), ou si on le supprime/recrée.
 
Un 1er bouton permet de tester si un film existe déjà, s'il y a des images
dans le dossier, et aussi si les autres options choisies sont correctes.
Il est donc conseillé de l'actionner systématiquement.
 
Un second bouton permet ensuite de créer effectivement un diaporama
à partir des images contenues dans le dossier.
 
Trois autres boutons permettent de simplifier la manipulation des CD :
- effacement de CD-RW
- gravure d'un SVCD à partir du film-diaporama du dossier courant
- éjection du CD.
\n"""
 
zoneListage.insert(END, titre)
 
 
# Lancement de l'application
# --------------------------
 
fen1.mainloop()

Si on lance une première fois ce script tout seul ça plantera. Il est en effet nécessaire d'avoir installé Pmw et les scripts DialogueDossiersJmm.py et DialogueFichiersEtDossiersJmm comme expliqué ici : Modifier des images JPEG.

Si tout marche la fenêtre va s'afficher, et on pourra appuyer sur le bouton “Creer un Diaporama” pour lancer le script bash qu'on vient de mettre au point à l'étape précédente.

Ouf ! Pour ceux qui en sont arrivé ici le plus dur est fait ! Il resta à ajoûter les petits scripts bash complémentaires pour que les autres boutons fassent aussi leur effet.

Scripts Bash complémentaires

Test des Options et Fichiers

Pour que le bouton “Tester les options et fichiers” aie un effet on va créer le script /usr/local/bin/diapo-test.sh à partir des lignes suivantes :

#!/bin/bash
#
# Script pour tester si des images JPG et un diaporama MPEG existent.
# On traite tous les fichiers.jpg d'un dossier.
 
# Auteur  : Jeanmm
# Date    : août 2006
# Licence : GPL
# Lien    : www.root66.net
 
# 1 paramètre possible :
# - nom du dossier des images et films
 
echo ""
echo "Test si des images et autres fichiers necessaires existent"
echo "----------------------------------------------------------"
echo ""
 
# Dossier des images jpg et des vidéos créées (param 1 si existant)
# -----------------------------------------------------------------
 
if [ ! 0$1 == 0 ] ; then
  cd $1
fi
echo "Dossier des images et videos : $PWD"
 
# Comptage des images
# -------------------
 
countT=0
for ii in `find . -maxdepth 1 -type f -iname "*.jpg"` ; do
  countT=$[$countT + 1]
done
test $countT -eq 0 && echo "Aucune image.jpg dans le dossier ?" || echo "Nombre total d'images : $countT"
 
# Test si image de fond existante
# -------------------------------
 
if [ -f fond720x576.ppm ] ; then
    echo "Le fichier fond720x576.ppm existe"
else
    echo "Le fichier fond720x576.ppm n'existe pas !"
fi
 
# Test si film existant
# ---------------------
 
if [ -f diaporama.mpg ] ; then
    echo "Le fichier diaporama.mpg existe"
else
    echo "Le fichier diaporama.mpg n'existe pas"
fi
 
# Test si musique existante
# -------------------------
 
if [ -f musique.mp2 ] ; then
    echo "Le fichier musique.mp2 existe"
else
    echo "Le fichier musique.mp2 n'existe pas !"
fi

Exemple de résultat :

Test si des images et autres fichiers necessaires existent
----------------------------------------------------------
 
Dossier des images et videos : /home/toto/Diaporama
Nombre total d'images : 2
Le fichier fond720x576.ppm existe
Le fichier diaporama.mpg existe
Le fichier musique.mp2 existe

Effacer un CD-RW

Pour que le bouton “Effacer un CD-RW” aie un effet on va créer le script /usr/local/bin/cd-effacement à partir des lignes suivantes :

#!/bin/bash
 
# Script pour effacer un CD-RW
 
echo "umount /mnt/cdrom"
umount /mnt/cdrom
 
echo "cdrecord blank=fast gracetime=2 dev=/dev/hdc"
cdrecord blank=fast gracetime=2 dev=/dev/hdc

Nota : Pour ce script et les 2 suivants, si le graveur ne se trouve pas en /dev/hdc on adaptera évidemment.

Graver un SVCD

Pour que le bouton “Graver un SVCD” aie un effet on va créer le script /usr/local/bin/cd-gravure-SVCD à partir des lignes suivantes :

#!/bin/bash
 
# Script pour graver un SVCD
 
# argument : le film SVCD à convertir/graver
# ------------------------------------------
 
if [ ! "0$1" == "0" ] ; then
  film=$1
else
  echo "Indiquer le nom du film !"
  exit 1
fi
 
echo "==> vcdimager -q -t svcd -c videocd.cue -b videocd.bin $film"
vcdimager -q -t svcd -c videocd.cue -b videocd.bin $film
 
echo "==> cdrdao write -n --device /dev/hdc --driver generic-mmc videocd.cue"
cdrdao write -n --device /dev/hdc --driver generic-mmc videocd.cue

Nota : ce script va créer les fichiers videocd.cue videocd.bin dans le dossier courant, ne pas s'en inquiéter.

Ejecter un CD

Pour que le bouton “Ejecter le CD” aie un effet on va créer le script /usr/local/bin/cd-ejection à partir des lignes suivantes :

#!/bin/bash
 
# Script pour éjecter un CD
 
umount /dev/hdc
cdrecord -eject dev=/dev/hdc

Script Bash principal 2

Le script bash principal du 2ème outil (configuration de la durée des diapos en nombre d'images (ou “frames”)) est très proche du 1er présenté ci-dessus. On ne répétera donc pas les commentaires.

Pour ce script, on copiera en root le texte suivant dans /usr/local/bin/diapo-Frames.sh :

#!/bin/sh
 
############################################################
# Script pour créer un diaporama MPEG à partir d'images JPEG
############################################################
 
# Particularité : on peut régler la durée de chaque diapo au 25ème de
# seconde près.
 
# On traite tous les fichiers.jpg du dossier courant accessible en écriture.
# (en fait tous fichiers de suffixes .jpg, .jpeg, .JPG et .JPEG)
 
# Auteur  : jeanmm
# Date    : août 2006
# Licence : GPL
# Lien    : www.root66.net
 
# Consommations en fichiers (estimations) :
# - en images cibles de taille maxi :
#   - Ficher.mpg :   0.13 Mo/s, soit 0.67 Mo / image de 5s
# - en images cibles de demi-taille :
#   - Ficher.mpg :   0.12 Mo/s, soit 0.62 Mo / image de 5s
 
# Le script produit les fichiers suivants :
# - diaporama.mpg      : sans audio
# - diaporama-SVCD.mpg : avec audio (si possible)
 
#set -x
 
# Paramètres
# ----------
 
nbframes=150        # durée par défaut en nombre d'images (il en faut 25/seconde)
musique=musique.mp2 # fichier musical optionnel
tronquer=non        # si oui : tronquer la vidéo s'il y a de la musique > durée des diapos
 
# Durée en nombre d'images (paramètre d'appel N° 1) :
 
if [ ! 0$1 == 0 ] ; then
  nbframes=$1
fi
 
# Tronquer la vidéo (paramètre d'appel N° 2) :
 
if [ ! 0$2 == 0 ] ; then
  tronquer=$2
fi
 
# Dossier de travail (paramètre d'appel N° 3) :
 
if [ ! 0$3 == 0 ] ; then
  dossier=$3
  cd $dossier
else
  dossier=$PWD
fi
 
# Taille des images cibles :
# --------------------------
 
# (mettre en commentaire les lignes non souhaitées)
 
# Taille standard SVCD (téléviseurs) = 720x576, avec marges de 10+10
tailleM=720x576
taille=700x556
tailleX=700
tailleY=556
 
# Demi-taille SVCD = 352x288, avec marges de 10+10
#tailleM=352x288
#taille=332x268
#tailleX=332
#tailleY=268
 
# IMPORTANT : le fichier fond$tailleM.ppm doivent exister
# dans le dossier courant, de tailleM exacte ci-dessus.
 
# Test/Résumé des options
# -----------------------
 
echo "Dossier courant : $dossier"
echo "Duree de chaque diapo : $nbframes images"
 
if [ -f fond$tailleM.ppm ]
then
  echo "Image de fond   : fond$tailleM.ppm"
else
    echo "Pas d'image de fond fond$tailleM.ppm trouvee !"
    exit 1
fi
 
if [ -f $musique ]
then
  echo "Fichier musical : $musique"
 
  if [ $tronquer == "oui" ]
  then
    echo "Video tronquee si musique > duree des diapos"
  fi
else
    echo "Pas de diaporama musical car absence du fichier $musique"
fi
 
# Suppression des blancs dans les noms des fichiers
# -------------------------------------------------
 
for a in * ; do
  b=$(echo $a | sed -e 's/[[:blank:]]/_/g')
  if [ ! -e "$b" ] ; then
    echo "mv \"$a\" $b"
    mv "$a" $b
  fi
done
 
# On renomme les fichiers .JPG , .JPEG et .jpeg en .jpg
# -----------------------------------------------------
 
for a in `find . -maxdepth 1 -type f -name "*.JPG"` ; do
  b=$(echo $a | sed -e 's/JPG$/jpg/')
  if [ ! -e "$b" ] ; then
    echo "mv $a $b"
    mv $a $b
  fi
done
 
for a in `find . -maxdepth 1 -type f -name "*.JPEG"` ; do
  b=$(echo $a | sed -e 's/JPEG$/jpg/')
  if [ ! -e "$b" ] ; then
    echo "mv $a $b"
    mv $a $b
  fi
done
 
for a in `find . -maxdepth 1 -type f -iname "*.jpeg"` ; do
  b=$(echo $a | sed -e 's/jpeg$/jpg/')
  if [ ! -e "$b" ] ; then
    echo "mv $a $b"
    mv $a $b
  fi
done
 
 
# Comptage des images et init du traitement
# -----------------------------------------
 
countT=0
for ii in `find . -maxdepth 1 -type f -iname "*.jpg"` ; do
  countT=$[$countT + 1]
done
test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 
rm -f diaporama.log 2>/dev/null
rm -f video*.mpg 2>/dev/null
 
# Boucle sur chaque image
# -----------------------
 
count=0
for ii in `find . -maxdepth 1 -type f -iname "*.jpg" | sort` ; do
    counti=$[$count + 1]
 
    # Conversion d'image : taille + image de fond => tempo2.jpg
 
    echo "Conversion de l'image `printf "%3.3d" $counti`/`printf "%3.3d" $countT` : $ii"
    convert -resize $taille $ii /tmp/tempo1.jpg 2>>diaporama.log
    # calculs pour centrer l'image sur le fond, avec marges +5+5
    x=`identify -format '%w' /tmp/tempo1.jpg`
    y=`identify -format '%h' /tmp/tempo1.jpg`
    dx=$[ ( $tailleX - $x ) / 2 + 10 ]
    dy=$[ ( $tailleY - $y ) / 2 + 10 ]
    #echo " taille : $taille, soit ${x}x$y+$dx+$dy"
    composite -geometry +$dx+$dy /tmp/tempo1.jpg fond$tailleM.ppm /tmp/tempo2.jpg 2>>diaporama.log
 
    # Conversion en film élémentaire => videoXXX.mpg
 
    jpeg2yuv -v 0 -f 25 -n 1 -l $nbframes -I p -j /tmp/tempo2.jpg  2>>diaporama.log | yuvscaler -v 0 -O SVCD 2>>diaporama.log | mpeg2enc -v 0 -a 2 -f 4 -o video`printf "%3.3d" $count`.mpg 2>>diaporama.log
 
    count=$[$count + 1]
done
 
# dernier morceau provisoire si on tronque
if [ $tronquer == "oui" ]
then
  jpeg2yuv -v 0 -f 25 -n 1 -l 25 -I p -j /tmp/tempo2.jpg  2>>diaporama.log | yuvscaler -v 0 -O SVCD 2>>diaporama.log | mpeg2enc -v 0 -a 2 -f 4 -o video`printf "%3.3d" $count`.mpg 2>>diaporama.log
  count=$[$count + 1]
fi
 
# Concaténation des videoXXX.mpg => diaporama.mpg (sans audio)
echo "Creation de la video : diaporama.mpg"
cat video*.mpg >diaporama.mpg
rm -f video*.mpg 2>/dev/null
 
# Ajoût du son
if [ -f $musique ]
then
  echo "Creation de la video sonore : diaporama-SVCD.mpg"
  mplex -f 4 $musique diaporama.mpg -o diaporama-x%3.3d.mpg -v 0 2>>diaporama.log
 
  # suppr du dernier tronçon
  if [ $tronquer == "oui" ]
  then
    rm -f `ls diaporama-x*.mpg | sort | tail -n 1` 2>/dev/null
  fi
 
  # concaténation des portions
  cat diaporama-x*.mpg >diaporama-SVCD.mpg
 
  rm -f diaporama-x*.mpg
fi
 
# Suppression de log si vide
test -s diaporama.log || rm -f diaporama.log
 
ls -latr diaporama*.mpg
echo "Traitement termine"
exit 0

Script Python principal 2

Ce second script Python est tout-à-fait analogue au précédent. Il nécessite le script bash principal N° 2 ci-dessus, plus les mêmes scripts bash complémentaires.

Pour ce script on copiera en root le texte suivant dans /usr/local/bin/diapo-Frames.py :

#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
 
# Ce script Python affiche une fenêtre de paramétrage et de lancement de scripts bash
# qui permettent de créer un diaporama à partir d'images JPG, et éventuellement
# un CD de type SVCD contenant ce diaporama.
#
# Particularité : on peut régler la durée de chaque diapo au 25ème de seconde près :
# on indique le nombre d'images (ou "frames") par diapo, chaque seconde de vidéo
# étant une succession de 25 images.
#
# Auteur  : jeanmm
# Date    : août 2006
# Licence : GPL
# Lien    : www.root66.net
 
import sys, os, string
from   Tkinter import *
import Pmw
import tkMessageBox
from   DialogueDossiersJmm           import DirBrowserDialog
from   DialogueFichiersEtDossiersJmm import PmwFileDialog
 
# Données générales
# -----------------
 
# Titre de la fenetre
MonTitre1  = "Creation de diaporama"
 
# Dossier par défaut
MonDossier = os.path.join(os.getenv('HOME'), 'Diaporama')
 
# Logos pour agrementer la fenetre
MonLogoDossier = '/usr/local/divers/LogoDossier.gif'
MonLogo        = '/usr/local/divers/decor.gif'
 
# Les scripts bash à exécuter
MonScript0 = 'diapo-test.sh'
MonScript1 = 'diapo-Frames.sh'
MonScript2 = 'cd-effacement'
MonScript3 = 'cd-gravure-SVCD'
MonScript4 = 'cd-ejection'
 
# Option générale de listage de numéros de lignes
NumLi = 0 # 0=non, 1=oui
ii=0
 
# Nom de l'option choisie (tronquer le film ou non)
nomOption='non' # 'oui' ==> on ne tronque pas
 
# Dossiers accessibles cycliquement par F3
Dossiers=['','',''] # dossier courant, courant au lancement, et home
NumDos=0
 
 
# Sous-programmes divers
# ======================
 
# Parcours cyclique de 3 noms de dossiers par F3
# ----------------------------------------------
 
def f3(ev=None):
    global NumDos
    NumDos=NumDos+1
    if NumDos==3:
        NumDos=0
    entree1.delete(0,END)
    entree1.insert(END, Dossiers[NumDos])
 
# Parcours de dossiers général par F4
#------------------------------------
 
def f4(ev=None):
    texte2['text']=""
 
    if os.path.isdir(entree1.get()):
        rep=entree1.get()
    else:
        texte2.configure(fg='red', font=('Times', 12, 'bold'))
        texte2['text']="Le Dossier n'existe pas ?!?"
        entree1.focus_set()
        entree1.xview(END)
        return
 
    dirBrowserDialog = DirBrowserDialog(fen1,
        label = '',
        path = entree1.get(),
        title = 'Selection de dossier')
 
    dir = dirBrowserDialog.activate()
    fen1.focus_set()
    #print 'Dossier sélectionné :', dir
    if dir != None:
        entree1.delete(0,END)
        entree1.insert(END, dir)
    entree1.xview(END)
    entree1.focus_set()
 
# Recherche de fichiers JPG par F5
#---------------------------------
 
def f5(ev=None):
    texte2['text']=""
 
    f0=PmwFileDialog(fen1)
    f0.title("Listage des noms d'images.jpg")
    fname=f0.askfilename(directory=entree1.get(), filter='*.jpg')
 
# Rafraichissement de fenêtre en cas de déplacement
# ------------------------------------------------
 
def rafraichissement(ev):
    fen1.update_idletasks()
 
# Lecture d'une ligne de fichier
# ------------------------------
 
# Comme readline, mais en plus de '\n' on teste '\r'.
# Permet de découper les sorties du programme de gravure
# en plusieurs lignes écrites au fur et à mesure, par exemple :
#   Wrote 1 of 4 MB (Buffers 100%  99%).
#   Wrote 2 of 4 MB (Buffers 100%  99%).
#   Wrote ...
# aulieu d'une ligne unique en fin de gravure :
#   Wrote 1 of 4 MB (Buffers 100%  99%).\rWrote 2 of 4 MB (Buffers 100%  99%).\rWrote ...
 
def lecture_ligne():
    global fout      # fichier lu (stdout de script en cours)
    txt=fout.read(1) # lecture/test de chaque caractère
    ligne=''         # ligne couramment lue
    while txt:
        if txt=='\n':
            ligne = ligne + txt
            break
        elif txt=='\r':
            ligne = ligne + '\n'
            break
        else:
            ligne = ligne + txt
        txt=fout.read(1) # caractère suivant
    return ligne
 
# quitter le programme
# --------------------
 
# on simule le clic sur le bouton Quitter quand il est sélectionné + touche entrée
def quitter(ev=None):
    bouton3.invoke()
 
 
# Sous-programmes de Traitement
# =============================
 
# Test des options et fichiers
# ----------------------------
 
def tests_options(ev=None):
 
    global ii        # Numéro de ligne
    global nomOption # Nom de l'option choisie
    global Dossiers  # Noms dossiers
 
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    # Option choisie
    if nomOption=='':
        texte2['text']="Choisissez d'abord une option"
        return
 
    texte2['text']='Tests en cours...'
    fen1.update_idletasks()
 
    # Traitement du dossier
    try:
        os.chdir(entree1.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="Le Dossier n'existe pas !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="Le Dossier n'existe pas ?!?"
        entree1.focus_set()
        return
    Dossiers[0]=entree1.get()
 
    # Durée de chaque diapo
 
    try:
        dureeDiapo = int(entree2.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="Le nombre d'images de chaque diapo est invalide !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="La duree de chaque diapo est invalide ?!?"
        entree2.focus_set()
        return
 
    if dureeDiapo < 1: # Nb >= 1
        dureeDiapo=1
        entree2.delete(0,END)
        entree2.insert(END, '1')
 
    # Lancement du script 0 avec arg dossier
 
    fin,fout=os.popen4(MonScript0 + ' ' + entree1.get())
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
    texte2['text']='OK - '
 
    while txt:
        txt=fout.readline()
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if ligne[0:16]=='Aucune image.jpg':
            texte2['text']='Aucune image.jpg - '
            zoneListage.insert(END, ligne, 'rouge')
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    MonFic=entree1.get()
    if MonFic[-1:0]=='/':
        Pass
    else:
        MonFic = MonFic + '/'
    MonFic = MonFic + 'diaporama.mpg'
 
    if os.path.isfile(MonFic):
        texte2['text']= texte2['text'] + "le film diaporama.mpg existe"
    else:
        texte2['text']= texte2['text'] + "le film diaporama.mpg n'existe pas"
    zoneListage.see(END)
    fen1.update_idletasks()
 
 
# Création de diaporama
# ---------------------
 
def creation_diaporama(ev=None):
 
    global ii        # Numéro de ligne
    global nomOption # Nom de l'option choisie
    global Dossiers  # Noms dossiers
 
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    # Option choisie
    if nomOption=='':
        texte2['text']="Choisissez d'abord une option"
        return
 
    texte2['text']='Creation de diaporama en cours...'
    fen1.update_idletasks()
 
    # Traitement du dossier
    try:
        os.chdir(entree1.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="Le Dossier n'existe pas !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="Le Dossier n'existe pas ?!?"
        entree1.focus_set()
        return
    Dossiers[0]=entree1.get()
 
    # Durée de chaque diapo (en images)
 
    try:
        dureeDiapo = int(entree2.get())
    except:
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        ligne="Le nombre d'images de chaque diapo est invalide !?\n\n"
        zoneListage.insert(END, ligne, 'rouge')
        zoneListage.see(END)
        texte2['text']="Le nombre d'images de chaque diapo est invalide ?!?"
        entree2.focus_set()
        return
    if dureeDiapo < 1: # Nb >= 1
        dureeDiapo=1
        entree2.delete(0,END)
        entree2.insert(END, '1')
 
    # Lancement du script avec args duree + option oui/non + dossier
 
    fin,fout=os.popen4(MonScript1 + ' ' + str(dureeDiapo) + ' ' + nomOption + ' ' + entree1.get())
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=fout.readline()
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if ligne[0:16]=='Aucune image.jpg':
            texte2['text']='Aucune image.jpg dans le dossier ?'
            zoneListage.insert(END, ligne, 'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    texte2['text']='OK - diaporama cree'
    fen1.update_idletasks()
 
 
# Effacement d'un CD-RW
# ---------------------
 
def effacer_cd(ev=None):
 
    global ii        # Numéro de ligne
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    texte2['text']='Effacement de CD-RW en cours...'
    fen1.update_idletasks()
 
    if tkMessageBox.askokcancel("Effacement de CD", "Confirmez ou annulez l'effacement"):
        pass
    else:
        texte2['text']='OK'
        fen1.update_idletasks()
        return
 
    # Lancement du script
 
    fin,fout=os.popen4(MonScript2)
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=fout.readline()
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if txt[0:17]=='cdrecord: No disk':
            texte2['text']='Pas de CD dans le graveur ?'
            txt='Pas de CD dans le graveur ?\n'
            zoneListage.insert(END, txt,'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    ligne='OK - CD efface\n'
    zoneListage.insert(END, ligne)
    zoneListage.see(END)
    texte2['text']='OK - CD efface'
    fen1.update_idletasks()
 
 
# Gravude d'un CD-SVCD
# --------------------
 
def graver_SVCD(ev=None):
 
    global ii        # Numéro de ligne
    global fout      # fichier stdout du script
 
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    MonFic = entree1.get() + '/diaporama-SVCD.mpg'
 
    if os.path.isfile(MonFic):
        pass
    else:
        texte2['text']= "le film " + MonFic + " n'existe pas ?"
        return
 
    texte2['text']='Gravure de SVCD en cours...'
    fen1.update_idletasks()
 
    # Lancement du script
 
    fin,fout=os.popen4(MonScript3 + ' ' + MonFic)
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=lecture_ligne() # lecture perso avec test '\r'
        ii=ii+1
        if NumLi:
            ligne='%04d ' %(ii)
            zoneListage.insert(END, ligne)
        if txt:
            ligne='%s' %(txt)
        else:
            ligne='\n'
        if ligne[0:8]=='++ WARN:':
            pass
        elif ligne[0:23]=='WARNING: Unit not ready':
            texte2['text']='Pas de CD dans le graveur ?'
            ligne='Pas de CD dans le graveur ?\n'
            zoneListage.insert(END, ligne,'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        elif ligne[0:24]=='Disk seems to be written':
            texte2['text']='Le CD semble deja grave ?'
            ligne='Le CD semble deja grave ?\n'
            zoneListage.insert(END, ligne,'rouge')
            zoneListage.see(END)
            fin.close()
            fout.close()
            return
        elif ligne[-2:]=='\\r':
            ligne=ligne[0:-2] + '\n'
            zoneListage.insert(END, ligne)
        else:
            zoneListage.insert(END, ligne)
        zoneListage.see(END)
        fen1.update_idletasks()
    fin.close()
    fout.close()
 
    texte2['text']='OK - CD grave'
    fen1.update_idletasks()
 
 
# Ejection d'un CD
# --------------------
 
def ejecter_CD(ev=None):
 
    global ii        # Numéro de ligne
    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 
    texte2['text']='Ejection de CD en cours...'
    fen1.update_idletasks()
 
    # Lancement du script
 
    fin,fout=os.popen4(MonScript4)
 
    # Boucle de récupération des résultats (txt='' => terminé)
 
    txt='x'   # Contenu de chaque ligne produite (stdout + stderr)
 
    while txt:
        txt=fout.readline()
    ligne='OK, CD ejecte\n'
    zoneListage.insert(END, ligne)
    zoneListage.see(END)
    fin.close()
    fout.close()
    texte2['text']='OK, CD ejecte'
    fen1.update_idletasks()
 
 
# =========================================================
#       ----------- Programme principal -----------
# =========================================================
 
# Instanciation d'une fenêtre Pmw (Python méga-widgets)
# -----------------------------------------------------
 
fen1 = Pmw.initialise()
fen1.title(MonTitre1)
fen1.bind("<Alt-F4>", quitter)
fen1.bind("<Configure>", rafraichissement)
 
# Dossiers pour touche F3
Dossiers[0]=MonDossier
Dossiers[1]=os.getcwd()
Dossiers[2]=os.getenv('HOME')
 
fen1.bind("<F3>", f3)
fen1.bind("<F4>", f4)
fen1.bind("<F5>", f5)
 
 
# creation des widgets de configuration/lancement des scripts
# ===========================================================
 
# Ligne 1
# -------
 
# dossier des images/films
texte1 = Label(fen1, text='  Dossier :')
texte1.grid(row=1, column=1, sticky=E, padx=5, pady=5)
 
 
# Saisie de nom de dossier
# alternatives : f3 pour 3 valeurs prédéfinies, f4 pour dialogue
entree1 = Entry(fen1, width=70, bg='white')
entree1.grid(row=1, column=2, columnspan=2, sticky=W, padx=5, pady=5)
entree1.insert(END, MonDossier)
entree1.focus_set()
 
# Bouton pour dialogue de parcours de dossier (aussi par f4)
logo=PhotoImage(file=MonLogoDossier)
bouton0 = Button(fen1, activebackground='DeepSkyBlue2', image=logo, command=f4)
bouton0.grid(row=1, column=4, sticky=W, padx=0, pady=3)
bouton0.bind("<Return>",f4)
 
# Ligne 2
# -------
 
# durée de chaque diapo en Images (25 par seconde)
 
texte2 = Label(fen1, text='  Images :')
texte2.grid(row=2, column=1, sticky=E, padx=5, pady=5)
 
entree2 = Entry(fen1, width=8, bg='white')
entree2.grid(row=2, column=2, sticky=W, padx=5, pady=5)
entree2.insert(END, '150')
 
texte2b = Label(fen1, text='(25 images par seconde)     ')
texte2b.grid(row=2, column=2, sticky=E, padx=5, pady=5)
 
# Ligne 3
# -------
 
# option Tronquer la vidéo
 
texte3 = Label(fen1, text='   Option :')
texte3.grid(row=3, column=1, sticky=E, padx=5, pady=5)
 
class ZoneRadio(Frame):
    """Utilisation de widgets 'boutons radio'"""
    def __init__(self, boss=None):
        """Création d'un champ d'entrée avec 2 boutons radio"""
        Frame.__init__(self)
        self.pack()
        self.configure(relief=GROOVE, bd=2)
        # Nom français et nom technique des quatre styles de police :
        texteOption =["Ne pas tronquer la video", "Tronquer"]
        valeurOption =["non", "oui"]
        # Le style actuel est mémorisé dans un 'objet-variable' Tkinter ;
        self.opt = StringVar()
        self.opt.set(valeurOption[0])
        # Création des boutons radio
        for n in range(2):
            bout = Radiobutton(self,
                text = texteOption[n],
                variable = self.opt,
                value = valeurOption[n],
                command = self.modifOption)
            bout.pack(side=LEFT, padx=5)
 
    def modifOption(self):
        global nomOption
        nomOption = self.opt.get()
 
zoneradio1=ZoneRadio()
zoneradio1.grid(row=3, column=2, columnspan=2, sticky=W, padx=5, pady=5)
 
# Ligne 4
# -------
 
# messages divers
 
texte2 = Label(fen1, text='Dossier courant : ' + os.getcwd())
texte2.grid(row=4, column=2, columnspan=2, padx=5, pady=5)
 
# Ligne 5
# -------
 
# boutons d'actions pour diaporama et bouton quitter
 
# bouton de lancement de tests
bouton1 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Tester les options et fichiers", command=tests_options)
bouton1.grid(row=5, column=2, padx=5, pady=5)
bouton1.bind("<Return>",tests_options)
 
# bouton de création de diaporama
bouton2 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Creer un Diaporama", command=creation_diaporama)
bouton2.grid(row=5, column=3, padx=5, pady=5)
bouton2.bind("<Return>",creation_diaporama)
 
# bouton pour quitter
bouton3 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=15, text='Quitter', command=fen1.quit)
bouton3.grid(row=5, column=4, columnspan=2, padx=5, pady=5)
bouton3.bind("<Return>",quitter)
 
# Ligne 6
# -------
 
# boutons d'actions pour gravure
 
# bouton pour effacer un CD-RW
bouton4 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Effacer un CD-RW", command=effacer_cd)
bouton4.grid(row=6, column=2, padx=5, pady=5)
bouton4.bind("<Return>",effacer_cd)
 
# bouton pour graver un CD
bouton5 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=30, text="Graver un SVCD", command=graver_SVCD)
bouton5.grid(row=6, column=3, padx=5, pady=5)
bouton5.bind("<Return>",graver_SVCD)
 
# bouton pour éjecter un CD
bouton6 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=15, text="Ejecter le CD", command=ejecter_CD)
bouton6.grid(row=6, column=4, columnspan=2, padx=5, pady=5)
bouton6.bind("<Return>",ejecter_CD)
 
# Logo en bout de lignes 1 à 4
# ----------------------------
 
can1 = Canvas(fen1, width=90, height=106, bg='AntiqueWhite3')
photo = PhotoImage(file=MonLogo)
item = can1.create_image(45, 53, image=photo)
can1.grid(row=1, column=5, rowspan=4, padx=4, pady=4)
 
 
# Zone de listage des résultats du script
# ---------------------------------------
 
# C'est un rectangle de la largeur totale de la fenêtre,
# avec ascenseurs automatiques si nécessaire.
 
zoneListage = Pmw.ScrolledText(fen1,
    text_font   = 'Courier 11 normal', text_bg = 'AliceBlue',
    text_padx   = 10, text_pady = 10, text_wrap = 'none',
    borderframe = 1,
    borderframe_borderwidth = 3,
    borderframe_relief = RIDGE,
    usehullsize = 1,
    hull_width = 710, hull_height = 350)
 
zoneListage.grid(row=7, column=1, columnspan=5, padx=4, pady=4)
zoneListage._textbox['takefocus'] = 0
 
ii=0   # Compteur des lignes insérées
 
# balise pour lignes rouges créées ici (en plus
# des lignes noires générées par le script)
 
zoneListage.tag_configure('rouge', foreground='red')
 
# texte d'explications en début de zone
 
titre = """
Cet outil sert à créer un Diaporama à partir d'images JPG
---------------------------------------------------------
 
Choisissez :
- le dossier de base contenant les images à traiter et les films créés,
- la durée de chaque diapo en nombre d'images (il en faut 25 par seconde),
- si le fichier son (musique.mp2) est plus long que la durée  d'affichage
  des images, on peut choisir de tronquer le film à la fin de la dernière
  diapo.
 
Un 1er bouton permet de tester si un film existe déjà, s'il y a des images
dans le dossier, et aussi si les autres options choisies sont correctes.
Il est donc conseillé de l'actionner systématiquement.
 
Un second bouton permet ensuite de créer effectivement un diaporama
à partir des images contenues dans le dossier.
 
Trois autres boutons permettent de simplifier la manipulation des CD :
- effacement de CD-RW
- gravure d'un SVCD à partir du film-diaporama du dossier courant
- éjection du CD.
\n"""
 
zoneListage.insert(END, titre)
 
 
# Lancement de l'application
# --------------------------
 
fen1.mainloop()

Compléments

Calculer avec Python en mode interactif

Voici une petite astuce pour utiliser Python comme calculette. En effet, Python peut servir à beaucoup de choses, comme construire des applications comme on vient de le voir, mais Python est aussi très pratique pour effectuer des choses simples en mode ligne de commande. Ici on va s'en servir pour calculer les durées des diapos pour l'outil 2.

Supposons qu'on aie un morceau de musique qui dure 7 minutes 44 secondes, et qu'on veuille s'en servir pour créer un diaporama de 72 photos. Voici une façon de calculer la durée de chaque diapo pour que ça tombe pile poil :

python -i
Python 2.4.1 (#2, Aug 25 2005, 18:20:57)
[GCC 4.0.1 (4.0.1-2mdk for Mandriva Linux release 2006.0)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 7*60+44
464
>>> _*25
11600
>>> _/72
161
>>>

Pour démarrer le mode interactif il suffit de taper “python -i”; on peut taper une vraie ligne de code Python après chaque ">>>". Si on ne met pas “nom-de-variable = valeur-ou-formule” mais seulement “valeur-ou-formule”, c'est comme si on avait fait “_ = valeur-ou-formule” (Python affecte le dernier résultat à une variable par défaut appelée “_”). Ici on a donc calculé que la musique dure 464 secondes, soit 11600 images (avec 25 images par seconde), et si on divise par 72 on voit qu'il faudra créer le diaporama en indiquant 161. Avec une telle précision on n'a pas besoin de tronquer; la dernière diapo aura pour durée 161 + le reste de la division de 11600 par 161. On termine Python en tapant Ctrl+Z.

Le même calcul en une seule ligne et avec le reste :

>>> # avec chiffres derrière la virgule :
... (7*60+44)*25/72.0
161.11111111111111
>>> # ou bien : quotient + reste en un seul calcul :
... divmod((7*60+44)*25, 72)
(161, 8)

Créer des icônes sur le bureau

Une fois au point, les 2 outils Python présentés ici peuvent bien sûr être liés à des icônes sur le bureau, sans passer par des appels en ligne de commande.

Bon diaporamas ! ^_^

creer_des_diaporamas_a_partir_d_images_jpeg.txt · Dernière modification : 2021/10/18 16:09 de 127.0.0.1