Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

modifier_des_images_jpeg [2008/05/07 13:13]
127.0.0.1 édition externe
modifier_des_images_jpeg [2017/02/21 15:10] (version actuelle)
Ligne 1: Ligne 1:
 +====== Introduction ======
 +
 +Cet article présente un outil destiné à traiter en batch des **images JPEG** (ou **JPG**), pour :
 +
 +  * Modifier leur nom, par exemple le rendre égal à la date de prise de vue s'il s'agit de photos prises par APN (appareil photo numérique),
 +  * Modifier leur date, par exemple la rendre aussi égale à la date de prise de vue,
 +  * Modifier l'orientation de celles qui ne sont pas dans le bon sens,
 +  * Incruster automatiquement un texte dans l'image (date, heure, nom du fichier, commentaire).
 +
 +Il est utile notamment pour les images JPEG provenant d'APN, sous réserve qu'elles contiennent les **infos EXIF** (date de prise de vue, orientation), et aussi pour toutes images dont on aura modifié manuellement les noms et/ou les commentaires qu'on pourra alors incruster.
 +
 +**Remarque :** pour les pressés qui n'ont vraiment pas le temps de lire les détails ni copier/coller les lignes de code vers des fichiers, essayez de **télécharger et installer le contenu de** {{:modif_images_1.3.tar.gz|:modif_images_1.3.tar.gz}}. D'ailleurs ceux qui sont moins pressés ont aussi le droit d'utiliser ce fichier ... ^_^
 +
 +Exemple de photos provenant d'un APN, avant traitement :
 +
 +{{  :wiki-modif-images1.jpg  |:wiki-modif-images1.jpg}}
 +
 +On voit ici 3 photos qui viennent juste d'être téléchargées d'un APN au moyen de **flphoto2**. On constate que les noms des images ne sont pas du tout intéressants, que les dates sont les mêmes (date du téléchargement) et qu'une des photos a été prise en mode portrait mais apparait couchée.
 +
 +Quand on possède plusieurs centaines, voire plusieurs milliers de photos présentant ces inconvénients ça finit par représenter un vrai problème. D'où l'idée de cet outil qui **permet de modifier l'ensemble des images de toute une arborescence de dossiers en un seul appel**.
 +
 +Article rédigé par Jeanmm 8-)\\
 +Version initiale : 12/6/2006.
 +
 +Version 0.2 le 24/8/2006 : ajoût d'une option pour incruster l'heure dans les images.
 +
 +Version 0.3 le 01/9/2006 : ajoût d'options pour incruster le nom du fichier et un commentaire dans les images, et choisir la taille des caractères incrustés; modification de l'IHM pour rendre toutes les options configurables par ajoût de boutons.
 +
 +Version 1.0 et suivantes depuis le 03/09/2006 : installation simplifiée par mise à disposition d'une archive contenant tous les fichiers + des explications + un script d'installation; voir la liste des évolutions dans l'explication fournie.
 +
 +Dernière version : 1.3 le 01/10/2006.
 +
 +====== Solution proposée ======
 +
 +On va donc proposer ici un jeu de **scripts bash** faisant appel au logiciel de traitement d'images **ImageMagick** et à l'outil **jhead**, ces scripts pouvant être appelés de manière manuelle, ou encapsulés dans un **script Python** pour réaliser une petite application avec IHM graphique. Exemple d'appel de l'application graphique :
 +
 +{{  :wiki-modif-images12.jpg  |:wiki-modif-images12.jpg}}
 +
 +Voici un exemple de résultat pour l'image redressée et une des images en mode paysage (modification des dates, des noms, redressement de l'image couchée, et incrustation de la date de prise de vue directement dans chaque image) :
 +
 +{{  :wiki-modif-images4.jpg  |:wiki-modif-images4.jpg}} {{  :wiki-modif-images5.jpg  |:wiki-modif-images5.jpg}}
 +
 +On voit au-dessus de l'image redressée les noms et les dates modifiés : les noms indiquent directement la date et heure de prise de vue à la seconde près ! La date est visible en bas à gauche de l'image, en double couleur (blanc et noir décalés), donc lisible sur quasiment n'importe quel fond d'image. La taille des caractères incrustés dans les images est proportionnelle à la hauteur effective de chaque image selon le ratio souhaité, ce qui renforce encore leur lisibilité.
 +
 +Autre exemple, avec de plus incrustation de l'heure de prise de vue et d'un commentaire personnel. **Pour le commentaire**, rien de plus simple, par exemple sous konqueror on fait un **clic droit sur l'image, puis Propriétés / Méta-informations**, et on tombe directement dans le champ où on peut taper le texte qu'on veut :
 +
 +{{  :wiki-modif-images8.jpg  |:wiki-modif-images8.jpg}}
 +
 +Le résultat est sympa, avec ici une taille de caractères incrustés plus importante que sur les images précédentes et leur ombre noire doublée :
 +
 +{{  :wiki-modif-images10.jpg  |:wiki-modif-images10.jpg}}
 +
 +**Conseils :**
 +
 +  * Il est vivement conseillé de commencer par lire et appliquer l'article [[http://root66.freecontrib.org/wiki/doku.php?id=scripts_sauvegarde_donnees|Scripts de sauvegarde de données]] , car il contient des explications pour installer quelques logiciels complémentaires nécessaires à cet outil, ainsi que de nombreux conseils qui sont tout-à-fait valables ici; d'ailleurs on remarquera tout de suite les similitudes entre les deux outils, et on verra rapidement que cet outil est nettement plus compliqué que le premier, donc autant se "faire la main" par ordre croissant de difficultés. Ceci étant dit, depuis que l'archive.tar.gz est disponible l'installation est réellement devenue simple.
 +  * Régler la date de son appareil avant de prendre des photos !
 +  * Lors de la mise au point de ses images, les garder dans 2 dossiers séparés si on souhaite réaliser des incrustations, car elles sont irréversibles. Donc dans le 1er dossier on appliquera par exemple les modifs de date du fichier, nom du fichier, rotation et ajoût de commentaires. Dans le second on fera tous les essais d'incrustations complémentaires jusqu'à l'obtention du bon résultat; les ajustements porteront en général sur l'orthographe, la longueur et le contenu du texte et/ou la hauteur des caractères.
 +  * Avant de traiter plusieurs centaines de photos, on commencera par un échantillon représentatif, en combinant par exemple mode portrait et mode paysage, texte court et texte long, format 3/4 standard et image très large ou très étroite...
 +
 +====== Scripts Bash / Imagemagick / Jhead ======
 +
 +Pour **ImageMagick** on trouvera toute info utile directement sur le site [[http://www.imagemagick.org/script/index.php|ImageMagick]] et bien sûr sur bien d'autres; le logiciel est probablement fourni dans votre distribution. Ce logiciel est composé d'un certain nombre d'outils d'analyse et de modification d'images, tous appelables en ligne de commande, donc faciles à insérer dans un script bash ou autre.
 +
 +Nous allons nous servir d'une toute petite partie des immenses possibilités d'ImageMagick pour répondre à nos besoins, d'abord en créant des scripts bash séparés, chacun n'effectuant qu'un seul des traitements souhaités, puis en combinant les appels à ces scripts de manière plus souple à l'aide d'un script Python.
 +
 +A noter aussi l'utilisation de **jhead** ("JPEG Header") qui est un outil de listage des infos EXIF contenues dans les images. Pour lire ces infos EXIF on peut utiliser indifféremment ImageMagick ou Jhead, le second ayant l'avantage de faire ce travail plus rapidement. Si l'outil **jhead** n'existe pas sur le PC, on peut vérifier d'abord si la distribution le fournit, sinon aller voir ici : [[http://freshmeat.net/projects/jhead/|Projet Jhead]] . A noter une fonctionnalité de modification (pas encore) offerte ici :  jhead permet de supprimer les images miniatures parfois contenues dans les entêtes EXIF, ce qui peut représenter un gain de place.
 +
 +Les manipulations qu'on va détailler dans cet article sont celles décrites dans la fenêtre de l'outil présenté ci-dessus. L'utilisateur de ces outils a tout loisir pour rallonger les possibilités de traitements; on pourra par exemple imaginer la création de bordures ou cadres décoratifs, des effets de filtrages, la suppression des miniatures des entêtes EXIF, etc... A partir du moment où une commande de traitement par ImageMagick (ou un autre outil) est bien maîtrisée, il devient facile d'étendre ces scripts modulaires.
 +
 +===== Script Bash principal =====
 +
 +On a choisi d'encapsuler la plupart des scripts de détail dans un script bash principal. Copier les lignes ci-dessous dans un éditeur de texte et l'enregistrer avec pour nom **jpeg-transfos** dans un dossier accessible de tous, par exemple **/usr/local/bin** et ne pas oublier de le rendre exécutable.
 +
 +La première action de ce script consiste à appeler le script **"jpeg-comptage"** présenté plus bas. Ce script va comme son nom l'indique compter les images à traiter, mais aussi appeler le script **"jpeg-suppr-blancs"** qu'on présentera aussi. La raison de ce dernier script est de supprimer tous les blancs (et aussi apostrophes) dans les noms de fichiers; ce contrôle est important car cela évitera que les autres scripts plantent par la suite. De manière générale je conseille de ne jamais utiliser de blancs, accents et autres caractères spéciaux dans les noms de fichiers, à la longue on s'épargne nombre de galères !
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Modifications diverses sur des images JPG.
 +# ------------------------------------------
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +echo ""
 +echo "Modifications/tests d'images JPG"
 +echo "--------------------------------"
 +echo ""
 +if [ $3$4$5$6$7$8$9 -eq 0 ] ; then
 +    echo "Entrez les arguments positionnels suivants :"
 +    echo " 1 : profondeur de parcours des sous-dossiers (1 par defaut)"
 +    echo " 2 : option de niveau de listage d'infos (0, 1 ou 2)"
 +    echo " Puis : options de traitement ( 0/1 si binaire) :"
 +    echo " 3 : 0/1 Date fichier = date de prise de vue"
 +    echo " 4 : 0/1 Rotation si necessaire"
 +    echo " 5 : Nom du fichier :"
 +    echo "    0 : 'inchange'"
 +    echo "    1 : 'JJMMAA-HHMMSS.jpg'"
 +    echo "    2 : 'AAMMJJ-HHMMSS.jpg'"
 +    echo "    3 : 'JJMMAA-nom-ancien.jpg'"
 +    echo "    4 : 'AAMMJJ-nom-ancien.jpg'"
 +    echo " 6 a 10 : Incrustations :"
 +    echo "    6 : 0/1 'JJ/MM/AA'"
 +    echo "    7 : 0/1 'HHhMM'"
 +    echo "    8 : 0/1 'Nom'"
 +    echo "    9 : 0/1 'Commentaire'"
 +    echo "    10: Rapport hauteur d'image / hauteur caracteres, 30 par defaut"
 +    exit 0
 +fi
 +echo "Dossier : $PWD"
 +
 +# Si un 1er argument est present c'est la profondeur du find
 +# ----------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +echo "Profondeur maximale de parcours des dossiers : $max"
 +
 +# 2eme argument : liste d'infos
 +# -----------------------------
 +
 +bavard=$2
 +
 +# Les arguments suivants sont les options de traitement
 +# -----------------------------------------------------
 +
 +if [ "0$3" == "0" ] ; then
 +    echo "Il faut au moins 1 option de traitement en argument 3"
 +    exit 1
 +fi
 +
 +# Comptage ==> supprime au passage les blancs et apostrophes dans les noms
 +# Puis renomme les fichiers .JPG , .JPEG et .jpeg en .jpg
 +# ----------------------------------------------------------------------------
 +
 +jpeg-comptage $max
 +if [ $? -ne 0 ] ; then
 +    exit 1
 +fi
 +
 +for a in `find . -maxdepth $max -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 $max -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 $max -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
 +
 +# Traitement des options choisies
 +# -------------------------------
 +
 +if [ "0$3" -eq "01" ] ; then
 +    jpeg-date $max $bavard
 +fi
 +
 +if [ "0$4" -eq "01" ] ; then
 +    jpeg-rotation $max $bavard
 +fi
 +
 +if [ "0$5" -eq "01" ] ; then
 +    jpeg-nom-JJMMAA-HHMMSS $max $bavard
 +elif [ "0$5" -eq "02" ] ; then
 +    jpeg-nom-AAMMJJ-HHMMSS $max $bavard
 +elif [ "0$5" -eq "03" ] ; then
 +    jpeg-prefixe-nom-JJMMAA $max $bavard
 +elif [ "0$5" -eq "04" ] ; then
 +    jpeg-prefixe-nom-AAMMJJ $max $bavard
 +fi
 +
 +if [ "0$6" == "01" ] ; then
 +    zz="1"
 +else
 +    zz="0"
 +fi
 +if [ "0$7" == "01" ] ; then
 +    zz="$zz 1"
 +else
 +    zz="$zz 0"
 +fi
 +if [ "0$8" == "01" ] ; then
 +    zz="$zz 1"
 +else
 +    zz="$zz 0"
 +fi
 +if [ "0$9" == "01" ] ; then
 +    zz="$zz 1"
 +else
 +    zz="$zz 0"
 +fi
 +
 +if [ ! "$zz" == "0 0 0 0" ] ; then
 +    shift
 +    if [ 0$9 -eq 0 ] ; then
 +        tc=30
 +    else
 +        tc=$9
 +    fi
 +    jpeg-incrustations $max $zz $tc $bavard
 +fi
 +</code>
 +
 +===== Script de modification des dates =====
 +
 +Le script ci-dessous détermine la date de création et modifie la date de fichier de chaque image à partir de l'info "**EXIF**" correspondante contenue dans le fichier. On propose 2 possibilités de commandes, l'une étant mise en commentaire :
 +  * par **ImageMagick** et sa commande **identify -format "%[EXIF:DateTime]"**,
 +  * par **jhead**; en fait cette seconde méthode est ici plus rapide.
 +
 +Pour trouver les images on utilise la commande **find** qui parcourt le 1er dossier spécifié, et éventuellement les sous-dossiers de niveau souhaité (paramètre **maxdepth**). Attention : la commande find ne marche pas si des noms de fichiers contiennent des blancs.
 +
 +L'info de date extraite de chaque image est mise au format nécessaire pour la commande **touch** grâce à l'éditeur **awk**. Pour le détail se reporter à la doc de ces 2 outils. C'est la commande **touch** qui effectue la modification de date effective.
 +
 +Copier les lignes ci-dessous dans un éditeur de texte et l'enregistrer avec pour nom **jpeg-dates** dans le même dossier accessible de tous,  et le rendre exécutable.
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Modif des dates d'images JPG
 +# ----------------------------
 +#
 +# Transformations telles que les dates des fichiers
 +# soient celles des infos Exif Date/Time.
 +#
 +# les suffixes jpeg, JPEG et JPG sont transormes en jpg.
 +#
 +# Boucle sur les seules images jpg du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee optionnellement en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Si un 1er argument est present c'est la profondeur find
 +# -------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +
 +# Si un 2eme argument est present on liste des infos en +
 +# -------------------------------------------------------
 +
 +if [ 0$2 -ne 0 ] ; then
 +    bavard=$2
 +else
 +    bavard=0
 +fi
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +    countT=$[$countT + 1]
 +done
 +
 +test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $countT -lt 2 ] ; then
 +        echo "Modif des dates d'images : $countT image trouvee"
 +    else
 +        echo "Modif des dates d'images : $countT images trouvees"
 +    fi
 +    cc=0
 +fi
 +
 +# Traitement des dates
 +# --------------------
 +
 +for i in `find . -maxdepth $max -type f -iname "*.jpg" | sort` ; do
 +    # Lecture de la date par ImageMagick-identify ou par jhead
 +    #Madate=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,3,2) substr($1,6,2) substr($1,9,2) substr($2,1,2) substr($2,4,2) "." substr($2,7,2)}'`
 +    Madate=`jhead "$i" | awk ' $1=="Date/Time" {print substr($3,1,4) substr($3,6,2) substr($3,9,2) substr($4,1,2) substr($4,4,2) "." substr($4,7,2) }' `
 +    if test -n "$Madate"; then
 +        if [ "$Madate" != "." ] ; then
 +            # mise de la date exif
 +            touch -t $Madate "$i" || echo "$i : date invalide ?"
 +            if [ $bavard -eq 1 ] ; then
 +                ls -la "$i"
 +                cc=$[$cc + 1]
 +            fi
 +        fi
 +    fi
 +done
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $cc -lt 2 ] ; then
 +        echo "Modif des dates d'images : $cc date modifiee"
 +    else
 +        echo "Modif des dates d'images : $cc dates modifiees"
 +    fi
 +fi
 +</code>
 +
 +===== Scripts de changement des noms de fichiers =====
 +
 +==== AAMMJJ-HHMMSS.jpg ====
 +
 +Le script qu'on va appeler **jpeg-nom-AAMMJJ-HHMMSS** permet de convertir tous les noms de fichiers en **AAMMJJ-HHMMSS.jpg**. Cette forme fait que le tri par noms de fichiers sera égal au tri par dates.
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Modif de noms d'images JPG
 +# ---------------------------
 +#
 +# Transformations telles que les noms des fichiers
 +# soient conformes aux infos Exif Date/Time :
 +#
 +#      AAMMJJ-HHMMSS.jpg
 +#
 +# les suffixes jpeg, JPEG et JPG sont transormes en jpg.
 +#
 +# Boucle sur les seules images jpg du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee optionnellement en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Si un 1er argument est present c'est la profondeur find
 +# -------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +
 +# Si un 2eme argument est present on liste des infos en +
 +# -------------------------------------------------------
 +
 +if [ 0$2 -ne 0 ] ; then
 +    bavard=$2
 +else
 +    bavard=0
 +fi
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +    countT=$[$countT + 1]
 +done
 +
 +test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $countT -lt 2 ] ; then
 +        echo "Modif des noms d'images : $countT image trouvee"
 +    else
 +        echo "Modif des noms d'images : $countT images trouvees"
 +    fi
 +    cc=0
 +fi
 +
 +# Traitement des dates
 +# --------------------
 +
 +for i in `find . -maxdepth $max -type f -iname "*.jpg" | sort` ; do
 +
 +    # Lecture de la date par ImageMagick-identify
 +    #Madate=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,3,2) substr($1,6,2) substr($1,9,2) "-" substr($2,1,2) substr($2,4,2) substr($2,7,2)}'`
 +    Madate=`jhead "$i" | awk ' $1=="Date/Time" {print substr($3,3,2) substr($3,6,2) substr($3,9,2) "-" substr($4,1,2) substr($4,4,2) substr($4,7,2) }' `
 +
 +    if test -n "$Madate"; then
 +        if [ "$Madate" != "-" ] ; then
 +            if [ "./$Madate.jpg" != "$i" ] ; then
 +                # mise de la date exif
 +                mv "$i" "$Madate.jpg"
 +                if [ $bavard -eq 1 ] ; then
 +                    echo "$i renommee en ./$Madate.jpg"
 +                    cc=$[$cc + 1]
 +                fi
 +            fi
 +        fi
 +    fi
 +done
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $cc -lt 2 ] ; then
 +        echo "Modif des noms d'images : $cc nom modifie"
 +    else
 +        echo "Modif des noms d'images : $cc noms modifies"
 +    fi
 +fi
 +</code>
 +
 +==== JJMMAA-HHMMSS.jpg ====
 +
 +Le script qu'on va appeler **jpeg-nom-JJMMAA-HHMMSS** permet de convertir tous les noms de fichiers en **JJMMAA-HHMMSS.jpg**. Cette forme crée des dates plus conformes aux habitudes françaises ^_^
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Modif de noms d'images JPG
 +# ---------------------------
 +#
 +# Transformations telles que les noms des fichiers
 +# soient conformes aux infos Exif Date/Time :
 +#
 +#      JJMMAA-HHMMSS.jpg
 +#
 +# les suffixes jpeg, JPEG et JPG sont transormes en jpg.
 +#
 +# Boucle sur les seules images jpg du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee optionnellement en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Si un 1er argument est present c'est la profondeur find
 +# -------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +
 +# Si un 2eme argument est present on liste des infos en +
 +# -------------------------------------------------------
 +
 +if [ 0$2 -ne 0 ] ; then
 +    bavard=$2
 +else
 +    bavard=0
 +fi
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +    countT=$[$countT + 1]
 +done
 +
 +test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $countT -lt 2 ] ; then
 +        echo "Modif des noms d'images : $countT image trouvee"
 +    else
 +        echo "Modif des noms d'images : $countT images trouvees"
 +    fi
 +    cc=0
 +fi
 +
 +# Traitement des dates
 +# --------------------
 +
 +for i in `find . -maxdepth $max -type f -iname "*.jpg" | sort` ; do
 +
 +    # Lecture de la date par ImageMagick-identify
 +    #Madate=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,9,2) substr($1,6,2) substr($1,3,2) "-" substr($2,1,2) substr($2,4,2) substr($2,7,2)}'`
 +    Madate=`jhead "$i" | awk ' $1=="Date/Time" {print substr($3,9,2) substr($3,6,2) substr($3,3,2) "-" substr($4,1,2) substr($4,4,2) substr($4,7,2) }' `
 +
 +    if test -n "$Madate"; then
 +        if [ "$Madate" != "-" ] ; then
 +            if [ "./$Madate.jpg" != "$i" ] ; then
 +                # mise de la date exif
 +                mv "$i" "$Madate.jpg"
 +                if [ $bavard -eq 1 ] ; then
 +                    echo "$i renomme en ./$Madate.jpg"
 +                    cc=$[$cc + 1]
 +                fi
 +            fi
 +        fi
 +    fi
 +done
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $cc -lt 2 ] ; then
 +        echo "Modif des noms d'images : $cc nom modifie"
 +    else
 +        echo "Modif des noms d'images : $cc noms modifies"
 +    fi
 +fi
 +</code>
 +
 +==== AAMMJJ-ancien-nom.jpg ====
 +
 +Le script qu'on va appeler **jpeg-prefixe-nom-AAMMJJ** permet de convertir tous les noms de fichiers en ajoutant le préfixe **"AAMMJJ-"** aux noms courants. Cette forme peut être utile si on n'a pas réellement envie de modifier les noms existants qui peuvent avoir une vraie signification, on se contente de leur préfixer la date.
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Modif de noms d'images JPG
 +# ---------------------------
 +#
 +# Transformations telles que les noms des fichiers
 +# aient des prefixes conformes aux dates Exif :
 +#
 +#    nom.jpg ==> AAMMJJ-nom.jpg
 +#
 +# les suffixes jpeg, JPEG et JPG sont transormes en jpg.
 +#
 +# Boucle sur les seules images jpg du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee optionnellement en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Si un 1er argument est present c'est la profondeur find
 +# -------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +
 +# Si un 2eme argument est present on liste des infos en +
 +# -------------------------------------------------------
 +
 +if [ 0$2 -ne 0 ] ; then
 +    bavard=$2
 +else
 +    bavard=0
 +fi
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +    countT=$[$countT + 1]
 +done
 +
 +test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $countT -lt 2 ] ; then
 +        echo "Modif des noms d'images : $countT image trouvee"
 +    else
 +        echo "Modif des noms d'images : $countT images trouvees"
 +    fi
 +    cc=0
 +fi
 +
 +# Traitement des dates
 +# --------------------
 +
 +for i in `find . -maxdepth $max -type f -iname "*.jpg" | sort` ; do
 +
 +    # Lecture de la date par ImageMagick-identify
 +    #Madate=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,3,2) substr($1,6,2) substr($1,9,2) "-"}'`
 +    Madate=`jhead "$i" | awk ' $1=="Date/Time" {print substr($3,3,2) substr($3,6,2) substr($3,9,2) "-"}' `
 +    Madate2=`echo "$i" | awk '{print substr($1,3,7)}'`
 +    i2=`echo "$i" | awk '{print substr($1,3)}'`
 +    if test -n "$Madate"; then
 +        if [ "$Madate" != "-" ] ; then
 +            if [ "$Madate2" != "$Madate" ] ; then
 +                # mise de la date exif
 +                mv "$i" "$Madate$i2"
 +                if [ $bavard -eq 1 ] ; then
 +                    echo "$i renomme en ./$Madate$i2"
 +                    cc=$[$cc + 1]
 +                fi
 +            fi
 +        fi
 +    fi
 +done
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $cc -lt 2 ] ; then
 +        echo "Modif des noms d'images : $cc nom modifie"
 +    else
 +        echo "Modif des noms d'images : $cc noms modifies"
 +    fi
 +fi
 +</code>
 +
 +==== JJMMAA-ancien-nom.jpg ====
 +
 +Le script qu'on va appeler **jpeg-prefixe-nom-JJMMAA** permet de convertir tous les noms de fichiers en ajoutant le préfixe **JJMMAA-** aux noms courants. Cette forme est identique à la précédente, avec des dates de nouveau au format français ^_^
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Modif de noms d'images JPG
 +# ---------------------------
 +#
 +# Transformations telles que les noms des fichiers
 +# aient des prefixes conformes aux dates Exif :
 +#
 +#    nom.jpg ==> JJMMAA-nom.jpg
 +#
 +# les suffixes jpeg, JPEG et JPG sont transormes en jpg.
 +#
 +# Boucle sur les seules images jpg du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee optionnellement en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Si un 1er argument est present c'est la profondeur find
 +# -------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +
 +# Si un 2eme argument est present on liste des infos en +
 +# -------------------------------------------------------
 +
 +if [ 0$2 -ne 0 ] ; then
 +    bavard=$2
 +else
 +    bavard=0
 +fi
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +    countT=$[$countT + 1]
 +done
 +
 +test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $countT -lt 2 ] ; then
 +        echo "Modif des noms d'images : $countT image trouvee"
 +    else
 +        echo "Modif des noms d'images : $countT images trouvees"
 +    fi
 +    cc=0
 +fi
 +
 +# Traitement des dates
 +# --------------------
 +
 +for i in `find . -maxdepth $max -type f -iname "*.jpg" | sort` ; do
 +
 +    # Lecture de la date par ImageMagick-identify
 +    #Madate=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,9,2) substr($1,6,2) substr($1,3,2) "-"}'`
 +    Madate=`jhead "$i" | awk ' $1=="Date/Time" {print substr($3,9,2) substr($3,6,2) substr($3,3,2) "-"}' `
 +    Madate2=`echo "$i" | awk '{print substr($1,3,7)}'`
 +    i2=`echo "$i" | awk '{print substr($1,3)}'`
 +    if test -n "$Madate"; then
 +        if [ "$Madate" != "-" ] ; then
 +            if [ "$Madate2" != "$Madate" ] ; then
 +                # mise de la date exif
 +                mv "$i" "$Madate$i2"
 +                if [ $bavard -eq 1 ] ; then
 +                    echo "$i renomme en ./$Madate$i2"
 +                    cc=$[$cc + 1]
 +                fi
 +            fi
 +        fi
 +    fi
 +done
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $cc -lt 2 ] ; then
 +        echo "Modif des noms d'images : $cc nom modifie"
 +    else
 +        echo "Modif des noms d'images : $cc noms modifies"
 +    fi
 +fi
 +</code>
 +
 +===== Script d'Incrustations dans l'image =====
 +
 +Le script qu'on va appeler **jpeg-incrustations** permet d'incruster 1 à 4 choses dans chaque image selon les options cochées dans la fenêtre de l'outil :
 +
 +  * la date de prise de photo, sous forme : **JJ/MM/AA**, par exemple 21/05/06,
 +  * l'heure de prise de photo, sous forme : **HHhMM**, par exemple 15h22,
 +  * le nom du fichier, seulement le nom simple et sans le suffixe ".jpg" (et avec les éventuels "_" remplacés par des blancs), par exemple une image appelée "Jour_de_soleil.jpg" donnera "Jour de soleil",
 +  * le commentaire associé à l'image, tel qu'on l'aura créé dans les propriétés de l'image. A noter que certains logiciels peuvent mettre un commentaire par défaut, par exemple "Created with The Gimp".
 +
 +La taille des caractères est calculée pour être proportionnelle à la hauteur de chaque image, selon le nombre qu'on aura indiqué dans la fenêtre (l'outil forcera une valeur > 4). Par exemple la valeur par défaut de 30 signifie que pour une image de 15 cm de haut les caractères feront 0,5 cm. Les calculs sont optimisés pour que sur un écran de format 4/3 les images affichées en mode plein-écran aient les textes toujours affichés avec la même hauteur, peu importe la proportion largeur/hauteur effective de chaque image.
 +
 +On inscrit le texte si possible 3 fois , 1 fois en blanc et 2 fois en noir, légèrement décalés afin que ce soit visible sur quasiment n'importe quelles couleurs de fond.
 +
 +L'outil **convert** utilisé pour réaliser ce travail fait partie de la suite **ImageMagick**.
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Incrustation de la date, de l'heure, du nom de fichier et/ou du commentaire dans des images JPG
 +# -----------------------------------------------------------------------------------------------
 +#
 +# D'apres les infos Exif Date/Time/Comment et le nom xxxx.jpg, on incruste :
 +#
 +#  JJ/MM/AA HHhMM xxxx commentaire
 +#
 +# en noir/blanc en bas a gauche de l'image.
 +#
 +# Toutes les combinaisons sont possibles en option
 +#
 +# les suffixes jpeg, JPEG et JPG sont transormes en jpg.
 +#
 +# Boucle sur les seules images jpg du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Les arguments doivent etre numeriques et sont tous positionnels;
 +# les noms de fichiers doivent etre sans blancs.
 +
 +# 1er argument : profondeur du find
 +# ---------------------------------
 +
 +if [ ! 0$1 -eq 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +
 +# Les 5 arguments suivants sont dans l'ordre les champs optionnels :
 +# - date
 +# - heure
 +# - nom de fichier
 +# - commentaire
 +# - taille caracteres (ratio hauteur d'image / taille des caracteres)
 +# avec 0 : absence, 1 : present (sauf taille)
 +# valeurs par defaut : 0 0 0 0 30
 +
 +if [ 0$2$3$4$5 -eq 0 ] ; then
 +    echo "Aucune incrustation demandee ?!?"
 +    exit 1
 +fi
 +
 +blabla=""
 +
 +if [ 0$2 -eq 0 ] ; then
 +    Date=0
 +else
 +    Date=$2
 +    blabla="$blabla Date"
 +fi
 +
 +if [ 0$3 -eq 0 ] ; then
 +    Heure=0
 +else
 +    Heure=$3
 +    blabla="$blabla Heure"
 +fi
 +
 +if [ 0$4 -eq 0 ] ; then
 +    Nom=0
 +else
 +    Nom=$4
 +    blabla="$blabla Nom"
 +fi
 +
 +if [ 0$5 -eq 0 ] ; then
 +    Comm=0
 +else
 +    Comm=$5
 +    blabla="$blabla Commentaire"
 +fi
 +
 +# rapport taille image / taille car >= 5; 30 par defaut
 +if [ 0$6 -eq 0 ] ; then
 +    tcc=30
 +else
 +    if [ 0$6 -lt 5 ] ; then
 +        tcc=5
 +    else
 +        tcc=$6
 +    fi
 +fi
 +
 +# Si un 7eme argument est present on liste des infos en +
 +# -------------------------------------------------------
 +
 +if [ 0$7 -eq 0 ] ; then
 +    Bavard=0
 +else
 +    if [ $7 -gt 1 ] ; then
 +        set -x
 +    fi
 +    Bavard=$7
 +fi
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +    countT=$[$countT + 1]
 +done
 +
 +test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 +
 +if [ $Bavard -eq 1 ] ; then
 +    if [ $countT -lt 1 ] ; then
 +        echo "Incrustation de texte : aucune image trouvee"
 +        exit 0
 +    elif [ $countT -lt 2 ] ; then
 +        echo "Incrustation avec ratio hauteur-image/texte de $tcc : $countT image trouvee"
 +    else
 +        echo "Incrustation avec ratio hauteur-image/texte de $tcc : $countT images trouvees"
 +    fi
 +fi
 +
 +# Traitement
 +# ----------
 +
 +cc=0 # compteur d'images traitees
 +
 +for i in `find . -maxdepth $max -type f -iname "*.jpg" | sort` ; do
 +
 +    # Lecture de la date
 +    d1=""
 +    d2=""
 +    d3=""
 +    if [ $Date -ne 0 ] ; then
 +        # Lecture de date par ImageMagick-identify
 +        #d1=" "`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,9,2)}'`"/"
 +        # ou lecture par jhead (laisser l'une des 2 en commentaire)
 +        d1=" "`jhead "$i" | awk ' $1=="Date/Time" {print substr($3,9,2) }' `"/"
 +        #d2=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,6,2)}'`
 +        d2=`jhead "$i" | awk '$1=="Date/Time" {print substr($3,6,2)}'`"/"
 +        #d3=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($1,3,2)}'`
 +        d3=`jhead "$i" | awk '$1=="Date/Time" {print substr($3,3,2)}'`
 +        if [ $d1 == "/" ] ; then
 +            d1=""
 +        fi
 +        if [ $d2 == "/" ] ; then
 +            d2=""
 +        fi
 +    fi
 +
 +    # Lecture de l'heure
 +    d4=""
 +    d5=""
 +    if [ $Heure -ne 0 ] ; then
 +        #d4=" "`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($2,1,2)}'`"h"
 +        d4=" "`jhead "$i" | awk '$1=="Date/Time" {print substr($4,1,2)}'`"h"
 +        #d5=`identify -format "%[EXIF:DateTime]" "$i" | awk '{print substr($2,4,2)}'`
 +        d5=`jhead "$i" | awk '$1=="Date/Time" {print substr($4,4,2)}'`
 +        if [ $d4 == "h" ] ; then
 +            d4=""
 +        fi
 +    fi
 +
 +    # Lecture du nom de fichier, sans prefixe ni suffixe ni "_"
 +    nn=""
 +    if [ $Nom -ne 0 ] ; then
 +        xx=$i
 +        yy=${xx##*/}
 +        zz=${yy%.*}
 +        nn=" $(echo "$zz" | tr "_" " ")"
 +    fi
 +
 +    # Lecture du commentaire
 +    co=""
 +    if [ $Comm -ne 0 ] ; then
 +        # il semble que identify soit plus fiable pour le commentaire
 +        co=" "`identify -format "%c" "$i"`
 +        #co=" "`jhead "$i" | awk '$1=="Comment" {print substr($0,16,length($0)-15)}'`
 +        # protection des apostrophes avec un "\" : chaque "'" donne "\'"
 +        #co=$(echo "$zz" | sed "s/'/\\\'/g")
 +    fi
 +
 +    # Lecture de la largeur et hauteur de l'image
 +    #x=`identify -format '%w' "$i"`
 +    #y=`identify -format '%h' "$i"`
 +    x=`jhead "$i" | awk ' $1=="Resolution" {print $3}' `
 +    y=`jhead "$i" | awk ' $1=="Resolution" {print $5}' `
 +    #set -x
 +
 +    # Calcul jc = taille du jeu de caracteres selon les proportions de l'image
 +    # $tcc = rapport de base en entree tel que jc = y/tcc si y/x=3/4
 +    jcmin=20 # taille minimale absolue; par ailleurs tcc >= 5 deja vrai
 +
 +    # Pour avoir le meme aspect d'affichage quelle que soit l'image, on a :
 +    # si y/x >= 3/4 : jc = y/tcc
 +    # sinon        : jc = y/tcc * (3/4) / (y/x) (l'image affichee diminue en hauteur,
 +    #                il faut donc compenser en augmentant la taille des caracteres)
 +    # autrement dit :
 +    # si 4y >= 3x  : jc = y/tcc
 +    # sinon        : jc = y/tcc * 3x / 4y = 3x /tcc /4
 +    # En fait la distinction points/pixels introduit un second rapport 4/3, et on aura :
 +    # si 4y >= 3x  : jc = 4/3 * y/tcc
 +    # sinon        : jc = 4/3 * y/tcc * 3x / 4y = x /tcc
 +
 +    t1=$[$y * 4]
 +    t2=$[$x * 3]
 +    if [ $t1 -ge $t2 ] ; then
 +        jc=$[$y * 4 / $tcc / 3]
 +    else
 +        jc=$[$x / $tcc]
 +    fi
 +
 +    if [ $jc -lt $jcmin ] ; then
 +        jc=$jcmin
 +    fi
 +
 +    # positions des 2 ou 3 textes
 +    # (1 ou 2 inscriptions noires + 1 blanche)
 +    dc=$[($jc + 2) / 10] # decalage
 +    if [ $dc -lt 2 ] ; then
 +    dc=2
 +    fi
 +    if [ $dc -ge 2 ] ; then
 +        dc2=$[$dc / 2]
 +    else
 +        dc2=0
 +    fi
 +    x=$[$y/45]
 +    y1=$[$y-$x+$dc]
 +    y1b=$[$y-$x+$dc2]
 +    y2=$[$y-$x]
 +    x1=$x
 +    x1b=$[$x-$dc2]
 +    x2=$[$x-$dc]
 +    # Commandes d'incrustation des 2 textes
 +    if [ $dc2 -gt 0 ] ; then
 +        convert -font helvetica -fill black -pointsize $jc -draw "text $x1,$y1 \"$d1$d2$d3$d4$d5$nn$co\"" $i /tmp/tempo2.jpg
 +        convert -font helvetica -fill black -pointsize $jc -draw "text $x1b,$y1b \"$d1$d2$d3$d4$d5$nn$co\"" /tmp/tempo2.jpg /tmp/tempo.jpg
 +        convert -font helvetica -fill white -pointsize $jc -draw "text $x2,$y2 \"$d1$d2$d3$d4$d5$nn$co\"" /tmp/tempo.jpg $i.jpg
 +        rm -f /tmp/tempo2.jpg
 +    else
 +        convert -font helvetica -fill black -pointsize $jc -draw "text $x1,$y1 \"$d1$d2$d3$d4$d5$nn$co\"" $i /tmp/tempo.jpg
 +        convert -font helvetica -fill white -pointsize $jc -draw "text $x2,$y2 \"$d1$d2$d3$d4$d5$nn$co\"" /tmp/tempo.jpg $i.jpg
 +    fi
 +    #set +x
 +
 +    # remise de la date d'origine
 +    touch -r "$i" "$i.jpg" && rm -f "$i" && mv "$i.jpg" "$i"
 +    rm -f /tmp/tempo.jpg
 +    if [ $Bavard -eq 1 ] ; then
 +    echo "Incrustation de$blabla dans $i"
 +    cc=$[$cc + 1]
 +  fi
 +done
 +
 +if [ $Bavard -eq 1 ] ; then
 +    if [ $cc -lt 2 ] ; then
 +        echo "Incrustation de$blabla : $cc image modifiee"
 +    else
 +        echo "Incrustation de$blabla : $cc images modifiees"
 +    fi
 +fi
 +</code>
 +
 +===== Script de Rotations =====
 +
 +Le script qu'on va appeler **jpeg-rotation** permet de tourner les images qui n'ont pas la bonne orientation. Le travail le plus courant consiste à redresser des images prises en mode portrait et qui apparaissent en mode paysage, mais toutes les corrections sont possibles, soit 7 corrections sur 8 orientations possibles en tout.
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Rotation d'images JPG
 +# ---------------------
 +#
 +# Transformations telles que : orientation Exif = 1
 +#
 +# Les dates des fichiers sont preservees, et les
 +# suffixes jpeg, JPEG et JPG sont transormes en jpg.
 +#
 +# Boucle sur les seules images jpg du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee optionnellement en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Si un 1er argument est present c'est la profondeur find
 +# -------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +    max=$1
 +else
 +    max=1
 +fi
 +
 +# Si un 2eme argument est present on liste des infos en +
 +# -------------------------------------------------------
 +
 +if [ 0$2 -ne 0 ] ; then
 +    bavard=$2
 +else
 +    bavard=0
 +fi
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +  countT=$[$countT + 1]
 +done
 +test $countT -eq 0 && echo "Aucune image.jpg a traiter ?" && exit 0
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $countT -lt 2 ] ; then
 +        echo "Orientation d'images : $countT image trouvee"
 +    else
 +        echo "Orientation d'images : $countT images trouvees"
 +    fi
 +    cc=0
 +fi
 +
 +# Traitement de l'orientation
 +# ---------------------------
 +
 +for i in `find . -maxdepth $max -type f -iname "*.jpg" | sort` ; do
 +
 +    # Lecture de l'orientation par ImageMagick-identify
 +    orientation=`identify -format "%[EXIF:Orientation]" $i `
 +
 +    # Test si orientation presente et != 1
 +    if test -n "$orientation"; then
 +        if [ "$orientation" != "1" ] ; then
 +            # on tourne l'image et remet l'info d'orientation a 1
 +            if [ $bavard -eq 1 ] ; then
 +                echo "Rotation de l'image $i (orientation exif = $orientation)"
 +                cc=$[$cc + 1]
 +            fi
 +            cp "$i" "$i.tmp.jpg"
 +            jhead -autorot "$i.tmp.jpg" >/dev/null
 +            # remise de la date d'origine
 +            touch -r "$i" "$i.tmp.jpg" && rm -f "$i" && mv "$i.tmp.jpg" "$i" 
 +        fi
 +    fi
 +done
 +
 +if [ $bavard -eq 1 ] ; then
 +    if [ $cc -lt 2 ] ; then
 +        echo "Orientation d'images : $cc image tournee"
 +    else
 +        echo "Orientation d'images : $cc images tournees"
 +    fi
 +fi
 +</code>
 +
 +===== Script de Comptage =====
 +
 +Le script qu'on va appeler **jpeg-comptage** permet de compter le nombre d'images dans le dossier et les éventuels sous-dossiers souhaités. Il appelle aussi le script **jpeg-suppr-blancs** de renommage des fichiers qui comportent des blancs dans leurs noms.
 +
 +<code bash>
 +#!/bin/sh
 +#
 +# Comptage d'images JPG
 +# ---------------------
 +#
 +# les suffixes jpg, jpeg, JPG et JPEG sont traites.
 +#
 +# Boucle sur les seules images du dossier courant
 +# ou plusieurs niveaux de sous-dossiers selon la variable
 +# max passee optionnellement en 1er argument du script.
 +#
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# Si un 1er argument est present c'est la profondeur find
 +# -------------------------------------------------------
 +
 +if [ 0$1 -ne 0 ] ; then
 +  max=$1
 +else
 +  max=1
 +fi
 +
 +# On supprime au prealable les blancs et apostrophes dans les noms de fichiers
 +# ----------------------------------------------------------------------------
 +
 +jpeg-suppr-blancs $max
 +
 +# Comptage des images
 +# -------------------
 +
 +countT=0
 +
 +for ii in `find . -maxdepth $max -type f -iname "*.jpg"` ; do
 +  countT=$[$countT + 1]
 +done
 +
 +for ii in `find . -maxdepth $max -type f -iname "*.jpeg"` ; do
 +  countT=$[$countT + 1]
 +done
 +
 +test $countT -eq 0 && echo "Aucune image trouvee !" && exit 1
 +echo "Nombre total d'images : $countT"
 +exit 0
 +</code>
 +
 +====== Script de renommage des fichiers ======
 +
 +Le script qu'on va appeler **jpeg-suppr-blancs** permet de renommer les fichiers qui comportent des blancs dans leurs noms. Au passage on supprime aussi les apostrophes, mais on pourrait encore l'enrichir pour ôter les accents et autres caractères parasites. Pour notre outil le contrôle de l'absence de blancs est déjà suffisant mais nécessaire, sinon les commandes "find" des autres outils auraient des effets inattendus.
 +
 +<code bash>
 +#!/bin/sh
 +# Suppression des blancs et apostrophes dans les noms des fichiers;
 +# Les fichiers modifies sont listes.
 +
 +# Auteur  : Jeanmm
 +# Date    : aout 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +# S'il y a 1 seul argument c'est la profondeur find;
 +# s'il y a 0 argument, la profondeur find est mise a 1.
 +# On constitue ensuite un script intermediaire avec tous les
 +# fichiers identifies et on l'execute.
 +
 +if [ $# -lt 2 ] ; then
 +    if [ $# -eq 1 ] ; then
 +        max=$1
 +    else
 +        max=1
 +    fi
 +    # jpeg-suppr-blancs.txt = liste des fichiers
 +    # jpeg-suppr-blancs-tempo.sh  = script
 +    rm -f jpeg-suppr-blancs.txt
 +    echo "#!/bin/sh" >jpeg-suppr-blancs-tempo.sh
 +    find . -maxdepth $max -type f -iname "*" >>jpeg-suppr-blancs.txt
 +    cat jpeg-suppr-blancs.txt | awk '{x = "\"" $0  "\""; gsub (" ","_",$0); y = "\"" $0  "\""; print "jpeg-suppr-blancs ", x, y >>"jpeg-suppr-blancs-tempo.sh"}'
 +    echo "exit 0" >>jpeg-suppr-blancs-tempo.sh
 +    sh jpeg-suppr-blancs-tempo.sh
 +    rm -f jpeg-suppr-blancs.txt jpeg-suppr-blancs-tempo.sh
 +    exit 0
 +
 +# Appel avec 2 arguments ==> c'est le nom du fichier a renommer et le nom avec des "_" a la place des blancs
 +else
 +    # Conversion des apostrophes en "_" au passage,
 +    # et factorisation des "_".
 +    b=$(echo $2 | tr "'" "_" | tr -s _ _ )
 +
 +    # On renomme finalement le fichier
 +    if [ "$1" != "$b" ] ; then
 +        echo "mv \"$1\" $b"
 +        mv "$1" $b
 +    fi
 +fi
 +</code>
 +
 +====== Scripts Python ======
 +
 +Ah ! On va enfin donner le script principal qui va faire appel à tous les scripts ci-dessus pour créer notre petite application. Mais avant ça il est vivement conseillé de lire l'article [[http://root66.freecontrib.org/wiki/doku.php?id=scripts_sauvegarde_donnees|Scripts de sauvegarde de données]] afin d'y apprendre tout à propos de **Python**, **Pmw** et **TkInter** : l'environnement général est en effet le même, et si Pmw ou TkInter manque ça ne marchera pas. On y lira aussi les recommandations pour créer/insérer une image décorative et effectuer les premiers tests.
 +
 +En plus de ces conseils préliminaires indispensables on aura besoin ici de deux petits outils complémentaires, ceux qui affichent les fenêtres de fichiers et de dossiers quand on clique sur le bouton "Lister les images" ou la petite icône de dossier. D'ailleurs il faudra aussi se procurer une image représentant cette icône. Les outils complémentaires ont été empruntés à d'autres sources sur le web, preuve du caractère diversifié de ce logiciel, et de la souplesse de Python pour fédérer des briques de toutes origines.
 +
 +===== Script Python principal =====
 +Commençons déjà par le **script Python** principal :
 +
 +<code python>
 +#!/usr/bin/python
 +# -*- coding: iso-8859-1 -*-
 +
 +# Ce script affiche une fenetre de parametrage et de
 +# lancement de scripts bash qui permettent plusieurs
 +# manips sur des images jpeg (rotation, incrustations...).
 +
 +# Un script bash est termine quand il n'y a plus de fichier
 +# stdout/stderr associe, les sorties eventuelles dans ces 2
 +# fichiers etant captees et affichees dans une zone de texte
 +# deroulante sous la zone de parametrage.
 +
 +# Auteur  : Jeanmm
 +# Version : 1.3
 +# Date    : 1er octobre 2006
 +# Licence : GPL
 +# Lien    : http://www.root66.net
 +
 +import sys, os, string
 +from  Tkinter    import *
 +from  FileDialog import *
 +import Pmw
 +from  DialogueDossiersJmm          import DirBrowserDialog
 +from  DialogueFichiersEtDossiersJmm import PmwFileDialog
 +
 +#===========================================
 +# Debut de la partie a adapter a ses besoins
 +#===========================================
 +
 +# Titre de la fenetre
 +MonTitre1  = "Modifications sur images jpg"
 +
 +# Les scripts Bash a executer;
 +# tout passe quasiment par un script unique qui se charge de dispatcher
 +# a d'autres scripts secondaires selon les traitements a realiser
 +MonScript1 = 'jpeg-transfos'
 +MonScript2 = 'jpeg-comptage'
 +
 +# Logos pour agrementer la fenetre
 +MonLogoDossier = '/usr/local/divers/LogoDossier.gif'
 +MonLogoLinux  = '/usr/local/divers/LogoRoot66.gif'
 +
 +# Options de traitement (mettre 0/1 pour oui/non)
 +# Ou modifier le contenu du fichier /home/nom/.root66/jpeg-transfos.txt
 +MonDossier=os.path.join(os.getenv('HOME'), 'Images')
 +sousDossiers=1
 +dateFichier=1
 +rotationImage=1
 +#nomFichier='inchange'
 +nomFichier='JJMMAA-HHMMSS.jpg'
 +#nomFichier='AAMMJJ-HHMMSS.jpg'
 +#nomFichier='JJMMAA-nom-ancien.jpg'
 +#nomFichier='AAMMJJ-nom-ancien.jpg'
 +incrustationDate=0
 +incrustationHeure=0
 +incrustationNom=0
 +incrustationComm=0
 +tailleCar=32
 +
 +# titre facultatif en debut de zone deroulante
 +
 +titre = """
 +Cet outil sert a modifier des images JPG en fonction de leurs infos EXIF
 +------------------------------------------------------------------------
 +
 +Choisissez :
 +- le dossier de base contenant les images a traiter (F3 permet de naviguer
 +  entre le dossier mis par defaut, le dossier courant de l'utilisateur et son home;
 +  F4 affiche la fenetre de navigation comme quand on clique sur le logo de dossier),
 +- le nombre de niveaux de sous-dossiers qu'il faut traiter
 +  (1 par defaut ==> seul le dossier choisi sera traite),
 +- au moins une des options parmi celles proposees,
 +puis appuyez sur le bouton de traitement.
 +A noter aussi :
 +- F5 agit comme quand on clique sur le bouton Compter / Lister,
 +- Alt+F4 termine le programme comme le bouton Quitter,
 +- Les options par defaut sont modifiables dans .root66/jpeg-transfos.txt de son home.
 +\n"""
 +
 +#===========================================
 +# Fin de la partie a adapter a ses besoins
 +#===========================================
 +
 +# Option generale de listage de numeros de lignes
 +NumLi = 0 # 0=non, 1=oui
 +
 +# Dossiers accessibles cycliquement par F3
 +Dossiers = ['','',''] # dossier courant, courant au lancement, et home
 +NumDos = 0
 +
 +# Sous-programmes generaux
 +# ========================
 +
 +# Parcours de 3 dossiers predefinis par F3
 +# ----------------------------------------
 +
 +def f3(ev=None):
 +    global Dossiers, NumDos
 +    NumDos = NumDos + 1
 +    if NumDos == 3:
 +        NumDos = 0
 +    entree1.delete(0,END)
 +    entree1.insert(END, Dossiers[NumDos])
 +
 +# Parcours de dossiers general 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']="Nom de dossier invalide ?"
 +        entree1.focus_set()
 +        entree1.xview(END)
 +        return
 +
 +    dirBrowserDialog = DirBrowserDialog(fen1,
 +        label = '',
 +        path = rep,
 +        hidedotfiles = 1,
 +        title = 'Selection de dossier')
 +
 +    dir = dirBrowserDialog.activate()
 +    fen1.focus_set()
 +    if dir != None:
 +        entree1.delete(0,END)
 +        entree1.insert(END, dir)
 +    entree1.focus_set()
 +    entree1.xview(END)
 +
 +# Comptage/Listage de noms de fichiers JPG par bouton ou F5
 +#----------------------------------------------------------
 +# On les compte d'abord, avec listage d'infos sommaires,
 +# puis on affiche une fenetre de parcours.
 +
 +def f5(ev=None):
 +    global ii        # Numero de ligne
 +    texte2['text'] = ""
 +
 +    if os.path.isdir(entree1.get()):
 +        rep=entree1.get()
 +    else:
 +        texte2.configure(fg='red', font=('Times', 12, 'bold'))
 +        texte2['text'] = "Nom de dossier invalide ?"
 +        entree1.focus_set()
 +        entree1.xview(END)
 +        return
 +
 +    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 +
 +    fen1.update_idletasks()
 +
 +    # Traitement du dossier
 +    try:
 +        os.chdir(entree1.get())
 +    except:
 +        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()
 +
 +    # Argument 1 : Pofondeur de parcours des sous-dossiers
 +    # (1 par defaut = seulement le dossier courant)
 +
 +    try:
 +        NbDos = int(entree2.get())
 +    except:
 +        ii += 1
 +        if NumLi:
 +            ligne = '%04d ' %(ii)
 +            zoneListage.insert(END, ligne)
 +        ligne = "Le nombre de sous-dossiers est invalide ?!?\n\n"
 +        zoneListage.insert(END, ligne, 'rouge')
 +        zoneListage.see(END)
 +        texte2['text']="Le nombre de sous-dossiers est invalide ?!?"
 +        entree2.focus_set()
 +        return
 +    if NbDos < 1: # Nb >= 1
 +        NbDos = 1
 +        entree2.delete(0,END)
 +        entree2.insert(END, '1')
 +
 +    # Lancement du script de comptage
 +
 +    fin,fout = os.popen4(MonScript2 + ' ' + str(NbDos))
 +
 +    # Boucle de recuperation des resultats (txt='' => termine)
 +
 +    txt = 'x'  # Contenu de chaque ligne produite (stdout + stderr)
 +
 +    while txt:
 +        txt=fout.readline()
 +        ii += 1
 +        if NumLi:
 +            ligne = '%04d ' %(ii)
 +            zoneListage.insert(END, ligne)
 +        if txt:
 +            ligne = '%s' %(txt)
 +        else:
 +            ligne = '\n'
 +        if ligne[0:12] == 'Aucune image':
 +            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()
 +
 +    if texte2['text'][0:12] == 'Aucune image':
 +        pass
 +    else:
 +        texte2['text'] = ''
 +
 +        # Affichage de fenetre de parcours des dossiers
 +        f0 = PmwFileDialog(fen1,
 +            info = "(nota : les dossiers debutant avec un '.' ne seront pas traites)")
 +        f0.title("Listage des images.jpg")
 +        fname = f0.askfilename(directory=rep, filter='*.jpg')
 +
 +# Actionnement des boutons radio
 +# ------------------------------
 +
 +def modifBoutonUnique(tag, etat):
 +    """
 +    fonction appelee quand un bouton flipflop est modifie
 +    - tag = nom du bouton
 +    - etat = etat enfonce (si vrai) ou non
 +    """
 +    global dateFichier, rotationImage, incrustationDate
 +    global incrustationHeure, incrustationNom, incrustationComm
 +    if tag == "Date fichier = date de prise de vue":
 +        dateFichier = etat
 +    elif tag == "Rotation si necessaire":
 +        rotationImage = etat
 +    elif tag == "JJ/MM/AA":
 +        incrustationDate = etat
 +    elif tag == "HHhMM":
 +        incrustationHeure = etat
 +    elif tag == "nom de fichier":
 +        incrustationNom = etat
 +    elif tag == "Commentaire":
 +        incrustationComm = etat
 +
 +def modifBoutonMultiple(tag):
 +    """
 +    fonction appelee quand un bouton de choix parmi un groupe est modifie
 +    - tag = nom du bouton
 +    """
 +    global nomFichier
 +    if tag == 'inchange':
 +        nomFichier = 0
 +    elif tag == 'JJMMAA-HHMMSS.jpg':
 +        nomFichier = 1
 +    elif tag == 'AAMMJJ-HHMMSS.jpg':
 +        nomFichier = 2
 +    elif tag == 'JJMMAA-nom-ancien.jpg':
 +        nomFichier = 3
 +    elif tag == 'AAMMJJ-nom-ancien.jpg':
 +        nomFichier = 4
 +
 +
 +# Rafraichissement de fenetre en cas de deplacement
 +# -------------------------------------------------
 +
 +def rafraichissement(ev):
 +    fen1.update_idletasks()
 +
 +# quitter le programme
 +# --------------------
 +
 +# on simule le clic sur le bouton quand il est selectionne + touche entree
 +def quitter(ev=None):
 +    bouton2.invoke()
 +
 +
 +# Sous-programmes de Traitement principal
 +# ---------------------------------------
 +
 +def traiter_les_images(ev=None):
 +
 +    global ii        # Numero de ligne
 +    global Dossiers  # Noms dossiers
 +    global tailleCar # Taille des caracteres a incruster
 +
 +    texte2.configure(fg='red', font=('Times', 12, 'bold'))
 +
 +    texte2['text'] = 'Traitement en cours...'
 +    fen1.update_idletasks()
 +
 +    # Traitement du dossier
 +    try:
 +        os.chdir(entree1.get())
 +    except:
 +        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()
 +
 +    # Argument 1 : Pofondeur de parcours des sous-dossiers
 +    # (1 par defaut = seulement le dossier courant)
 +
 +    try:
 +        NbDos = int(entree2.get())
 +    except:
 +        ii += 1
 +        if NumLi:
 +            ligne = '%04d ' %(ii)
 +            zoneListage.insert(END, ligne)
 +        ligne = "Le nombre de sous-dossiers est invalide ?!?\n\n"
 +        zoneListage.insert(END, ligne, 'rouge')
 +        zoneListage.see(END)
 +        texte2['text'] = "Le nombre de sous-dossiers est invalide ?!?"
 +        entree2.focus_set()
 +        return
 +    if NbDos < 1: # Nb >= 1
 +        NbDos = 1
 +        entree2.delete(0,END)
 +        entree2.insert(END, '1')
 +
 +    mesOptions = str(NbDos)
 +
 +    # Argument 2 : Listage d'infos
 +    mesOptions = mesOptions + ' 1'
 +
 +    # Argument 3 : Date fichier
 +    mesOptions = mesOptions + ' ' + str(dateFichier)
 +
 +    # Argument 4 : Rotation
 +    mesOptions = mesOptions + ' ' + str(rotationImage)
 +
 +    # Argument 5 : Modification du nom de fichier
 +    mesOptions = mesOptions + ' ' + str(nomFichier)
 +
 +    # Argument 6 : Incrustation Date
 +    mesOptions = mesOptions + ' ' + str(incrustationDate)
 +
 +    # Argument 7 : Incrustation Heure
 +    mesOptions = mesOptions + ' ' + str(incrustationHeure)
 +
 +    # Argument 8 : Incrustation Nom de fichier
 +    mesOptions = mesOptions + ' ' + str(incrustationNom)
 +
 +    # Argument 9 : Incrustation Commentaire
 +    mesOptions = mesOptions + ' ' + str(incrustationComm)
 +
 +    # Argument 10 : Hauteur des incrustations (rapport hauteur image / taille caracteres)
 +    try:
 +        tailleCar = int(entree3.get())
 +    except:
 +        ii += 1
 +        if NumLi:
 +            ligne = '%04d ' %(ii)
 +            zoneListage.insert(END, ligne)
 +        ligne = "Le rapport hauteur image / taille caracteres est invalide ?!?\n\n"
 +        zoneListage.insert(END, ligne, 'rouge')
 +        zoneListage.see(END)
 +        texte2['text'] = "Le rapport hauteur image / taille caracteres est invalide ?!?"
 +        entree2.focus_set()
 +        return
 +    if tailleCar < 5: # Nb >= 5
 +        tailleCar = 5
 +        entree3.delete(0,END)
 +        entree3.insert(END, '5')
 +    mesOptions = mesOptions + ' ' + str(tailleCar)
 +
 +    # Lancement du script
 +    fin,fout=os.popen4(MonScript1 + ' ' + mesOptions)
 +
 +    # Boucle de recuperation des resultats (txt='' => termine)
 +
 +    txt='x'  # Contenu de chaque ligne produite (stdout + stderr)
 +
 +    while txt:
 +        txt = fout.readline()
 +        ii += 1
 +        if NumLi:
 +            ligne = '%04d ' %(ii)
 +            zoneListage.insert(END, ligne)
 +        if txt:
 +            ligne = '%s' %(txt)
 +        else:
 +            ligne = '\n'
 +        if ligne[0:12] == 'Aucune image':
 +            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()
 +
 +    if texte2['text'][0:12] == 'Aucune image':
 +        pass
 +    else:
 +        texte2['text'] = 'OK - traitement termine'
 +
 +# =============== Programme principal =================
 +
 +# Lecture du fichier de configuration ~/.root66/jpeg-transfos.txt
 +# ---------------------------------------------------------------
 +
 +d1=os.path.join(os.getenv('HOME'), '.root66')
 +f1=os.path.join(d1, 'jpeg-transfos.txt')
 +if os.path.isfile(f1):
 +    try:
 +        fo1=open(f1, 'r')
 +        t=""
 +        while 1:
 +            # Lecture d'une ligne
 +            t=fo1.readline()
 +            # Ligne vide => fin de fichier
 +            if t=='': break
 +
 +            # Suppression des caracteres de fins de lignes
 +            if t[-1]=='\n': # 'new-line'
 +                t=t[0:-1]
 +
 +            # Separation et analyse des champs : parametre = z[0], valeur = z[1]
 +            z=string.split(t,'=')
 +
 +            if z[0] == 'MonDossier' and z[1] != '':
 +                MonDossier = z[1]
 +            elif z[0] == 'sousDossiers' and z[1] != '':
 +                sousDossiers = int(z[1])
 +            elif z[0] == 'dateFichier' and z[1] != '':
 +                dateFichier = int(z[1])
 +            elif z[0] == 'rotationImage' and z[1] != '':
 +                rotationImage = int(z[1])
 +            elif z[0] == 'nomFichier' and z[1] != '':
 +                nomFichier = z[1]
 +            elif z[0] == 'incrustationDate' and z[1] != '':
 +                incrustationDate = int(z[1])
 +            elif z[0] == 'incrustationHeure' and z[1] != '':
 +                incrustationHeure = int(z[1])
 +            elif z[0] == 'incrustationNom' and z[1] != '':
 +                incrustationNom = int(z[1])
 +            elif z[0] == 'incrustationComm' and z[1] != '':
 +                incrustationComm = int(z[1])
 +            elif z[0] == 'tailleCar' and z[1] != '':
 +                tailleCar = int(z[1])
 +        fo1.close()
 +    except:
 +        print "Fichier de config invalide", t, "?"
 +else:
 +    # On essaie de creer le dossier .root66 et le fichier
 +    if not os.path.isdir(d1):
 +        try:
 +            os.makedirs(d1)
 +        except:
 +            print "Impossible de creer le dossier " + d1
 +            sys.exit(1)
 +    try:
 +        fo1=open(f1, 'w')
 +        fo1.write("# Fichier de configuration de l'outil jpeg-transfos.py\n")
 +        fo1.write("#\n")
 +        fo1.write("# Options de traitement :\n")
 +        fo1.write("# - mettre 1/0 pour oui/non,\n")
 +        fo1.write("# - mettre un '#' devant les lignes inutiles,\n")
 +        fo1.write("# - et pas de blancs autour des '='.\n")
 +        fo1.write("#\n")
 +        fo1.write("MonDossier=%s\n"    %MonDossier)
 +        fo1.write("sousDossiers=%d\n"  %sousDossiers)
 +        fo1.write("#\n")
 +        fo1.write("dateFichier=%d\n"  %dateFichier)
 +        fo1.write("rotationImage=%d\n" %rotationImage)
 +        fo1.write("#\n")
 +        if nomFichier=='inchange':
 +            fo1.write("nomFichier=inchange\n")
 +        else:
 +            fo1.write("#nomFichier=inchange\n")
 +        if nomFichier=='JJMMAA-HHMMSS.jpg':
 +            fo1.write("nomFichier=JJMMAA-HHMMSS.jpg\n")
 +        else:
 +            fo1.write("#nomFichier=JJMMAA-HHMMSS.jpg\n")
 +        if nomFichier=='AAMMJJ-HHMMSS.jpg':
 +            fo1.write("nomFichier=AAMMJJ-HHMMSS.jpg\n")
 +        else:
 +            fo1.write("#nomFichier=AAMMJJ-HHMMSS.jpg\n")
 +        if nomFichier=='JJMMAA-nom-ancien.jpg':
 +            fo1.write("nomFichier=JJMMAA-nom-ancien.jpg\n")
 +        else:
 +            fo1.write("#nomFichier=JJMMAA-nom-ancien.jpg\n")
 +        if nomFichier=='AAMMJJ-nom-ancien.jpg':
 +            fo1.write("nomFichier=AAMMJJ-nom-ancien.jpg\n")
 +        else:
 +            fo1.write("#nomFichier=AAMMJJ-nom-ancien.jpg\n")
 +        fo1.write("#\n")
 +        fo1.write("incrustationDate=%d\n"  %incrustationDate)
 +        fo1.write("incrustationHeure=%d\n" %incrustationHeure)
 +        fo1.write("incrustationNom=%d\n"  %incrustationNom)
 +        fo1.write("incrustationComm=%d\n"  %incrustationComm)
 +        fo1.write("tailleCar=%d\n"        %tailleCar)
 +        fo1.close()
 +    except:
 +        print "Impossible de creer le fichier",f1
 +
 +# Instanciation d'une fenetre Pmw (Python mega-widgets)
 +# -----------------------------------------------------
 +
 +fen1 = Pmw.initialise()
 +fen1.title(MonTitre1)
 +fen1.monOption = IntVar()
 +
 +# 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)
 +
 +fen1.bind("<Alt-F4>", quitter)
 +fen1.bind("<Configure>", rafraichissement)
 +
 +
 +# creation des widgets de configuration/lancement du script
 +# =========================================================
 +
 +# Ligne 1
 +# -------
 +
 +texte1 = Label(fen1, text='  Dossier :')
 +texte1.grid(row=1, column=1, sticky=E, padx=2, pady=5)
 +
 +# Saisie de nom de dossier
 +# alternatives : f3 pour 3 valeurs predefinies, f4 pour dialogue
 +entree1 = Entry(fen1, width=74, bg='white', fg='dark blue')
 +entree1.grid(row=1, column=2, columnspan=4, sticky=EW, padx=2, pady=5)
 +entree1.insert(END, MonDossier)  # valeur par defaut
 +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=6, padx=0, pady=3)
 +bouton0.bind("<Return>",f4)
 +
 +# Ligne 2
 +# -------
 +
 +texte2 = Label(fen1, text='Sous-Dossiers :')
 +texte2.grid(row=2, column=1, sticky=E, padx=2, pady=5)
 +
 +entree2 = Entry(fen1, width=4, bg='white', fg='dark blue')
 +entree2.grid(row=2, column=2, sticky=W, padx=2, pady=5)
 +entree2.insert(END, str(sousDossiers)) # valeur par defaut
 +
 +# Ligne 3
 +# -------
 +
 +# widget RadioSelect pour 'Date fichier = date de prise de vue'
 +zz = Pmw.RadioSelect(fen1,
 +    buttontype = 'checkbutton',
 +    labelpos = None,
 +    command = modifBoutonUnique,
 +    hull_borderwidth = 2,
 +    hull_relief = 'ridge',
 +    selectmode = 'multiple',
 +    )
 +zz.grid(row=3, column=2, columnspan=2, sticky='ew', padx=3, pady=3)
 +zz.add('Date fichier = date de prise de vue')
 +
 +if dateFichier:
 +    zz.invoke('Date fichier = date de prise de vue')
 +
 +# widget RadioSelect pour 'Rotation si necessaire'
 +zz = Pmw.RadioSelect(fen1,
 +    buttontype = 'checkbutton',
 +    labelpos = None,
 +    command = modifBoutonUnique,
 +    hull_borderwidth = 2,
 +    hull_relief = 'ridge',
 +    selectmode = 'multiple',
 +    )
 +zz.grid(row=3, column=4, columnspan=2, sticky='ew', padx=3, pady=3)
 +
 +# Ajout bouton
 +zz.add('Rotation si necessaire')
 +if rotationImage:
 +    zz.invoke('Rotation si necessaire')
 +
 +# Lignes 4 a 9
 +# ------------
 +
 +# widget RadioSelect vertical, avec les choix de noms de fichiers
 +# sur 2 colonnes du cote gauche
 +zz = Pmw.RadioSelect(fen1,
 +    buttontype = 'radiobutton',
 +    orient = 'vertical',
 +    labelpos = 'n',
 +    command = modifBoutonMultiple,
 +    label_text = 'Nom de fichier',
 +    hull_borderwidth = 2,
 +    hull_relief = 'ridge',
 +    )
 +zz.grid(row=4, rowspan=6, column=2, columnspan=2, sticky='ew', padx=3, pady=3)
 +zz.add('inchange')
 +zz.add('JJMMAA-HHMMSS.jpg')
 +zz.add('AAMMJJ-HHMMSS.jpg')
 +zz.add('JJMMAA-nom-ancien.jpg')
 +zz.add('AAMMJJ-nom-ancien.jpg')
 +zz.invoke(nomFichier)
 +
 +# widget Group sur 2 colonnes du cote droit
 +# pour englober tout ce qui touche aux incrustations
 +gi = Pmw.Group(fen1,
 +    ring_borderwidth = 2,
 +    ring_relief = 'ridge',
 +    tag_pyclass = None
 +    )
 +gi.grid(row=4, rowspan=6, column=4, columnspan=2, sticky='ew', padx=3, pady=3)
 +
 +# widget RadioSelect vertical, avec les choix d'incrustations
 +zz = Pmw.RadioSelect(gi.interior(),
 +    buttontype = 'checkbutton',
 +    orient = 'vertical',
 +    labelpos = 'n',
 +    command = modifBoutonUnique,
 +    label_text = "Incrustations dans l'image",
 +    selectmode = 'multiple',
 +    )
 +zz.grid(row=1, column=1, columnspan=2, sticky='ew', padx=3, pady=3)
 +zz.add('JJ/MM/AA')
 +zz.add('HHhMM')
 +zz.add('nom de fichier')
 +zz.add('Commentaire')
 +if incrustationDate:
 +    zz.invoke('JJ/MM/AA')
 +if incrustationHeure:
 +    zz.invoke('HHhMM')
 +if incrustationNom:
 +    zz.invoke('nom de fichier')
 +if incrustationComm:
 +    zz.invoke('Commentaire')
 +
 +texte3 = Label(gi.interior(), text="hauteur d'image / taille des caracteres :")
 +texte3.grid(row=2, column=1, sticky='e', padx=3, pady=3)
 +
 +entree3 = Entry(gi.interior(), width=4, bg='white', fg='dark blue')
 +entree3.grid(row=2, column=2, sticky='w', padx=3, pady=3)
 +entree3.insert(END, str(tailleCar)) # valeur par defaut
 +
 +# Ligne 10
 +# --------
 +
 +texte2 = Label(fen1, text='Dossier courant : ' + os.getcwd())
 +texte2.grid(row=10, column=2, columnspan=4, padx=3, pady=5)
 +
 +# Fins de Lignes 7 a 9
 +# --------------------
 +
 +# Bouton pour lister les images
 +bouton1a = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=14, text="Compter / Lister", command=f5)
 +bouton1a.grid(row=7, column=6, columnspan=2, padx=3, pady=3)
 +bouton1a.bind("<Return>",f5)
 +
 +# Bouton pour traiter les images
 +bouton1b = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=14, text="Traiter", command=traiter_les_images)
 +bouton1b.grid(row=8, column=6, columnspan=2, padx=3, pady=3)
 +bouton1b.bind("<Return>",traiter_les_images)
 +
 +# Bouton pour quitter
 +bouton2 = Button(fen1, bg='DeepSkyBlue4', activebackground='DeepSkyBlue2', fg='white', width=14, text='Quitter', command=fen1.quit)
 +bouton2.grid(row=9, column=6, columnspan=2, padx=3, pady=3)
 +bouton2.bind("<Return>",quitter)
 +
 +# Logo en bout de lignes 1 a 3
 +# ----------------------------
 +# decoratif et facultatif
 +can1 = Canvas(fen1, width=90, height=100, bg='AntiqueWhite3')
 +photo = PhotoImage(file=MonLogoLinux)
 +item = can1.create_image(45, 50, image=photo)
 +can1.grid(row=1, column=7, rowspan=3, padx=3, pady=4)
 +
 +# Ligne 11 : Zone de listage des resultats des scripts
 +# ----------------------------------------------------
 +
 +# C'est un rectangle de la largeur totale de la fenetre,
 +# avec ascenseurs automatiques si necessaire;
 +# hauteur max : limitee selon taille d'ecran, pour que
 +# toute la fenetre soit totalement visible (important pour
 +# les ecrans de 600 ou 768 pixels).
 +
 +h = fen1.winfo_screenheight() - 426 - 48
 +if h > 400:
 +    h = 400
 +elif h < 100:
 +    h = 100
 +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 = 780, hull_height = h)
 +
 +zoneListage.grid(row=11, column=1, columnspan=7, padx=4, pady=4)
 +zoneListage._textbox['takefocus'] = 0
 +
 +ii = 0  # Compteur des lignes inserees
 +
 +# balise pour lignes rouges creees ici (en plus
 +# des lignes noires generees par le script)
 +zoneListage.tag_configure('rouge', foreground='red')
 +zoneListage.insert(END, titre)
 +
 +# Lancement de l'application
 +# --------------------------
 +
 +fen1.mainloop()
 +</code>
 +
 +==== Explications ====
 +
 +Les seules lignes à modifier se situent entre :
 +
 +<code python>
 +#===========================================
 +# Debut de la partie a adapter a ses besoins
 +#===========================================
 +</code>
 +
 +et
 +
 +<code python>
 +#===========================================
 +# Fin de la partie a adapter a ses besoins
 +#===========================================
 +</code>
 +
 +On peut spécifier le titre de la fenêtre :
 +<code python>
 +# Titre de la fenetre
 +MonTitre1  = "Modifications sur images jpg"
 +</code>
 +
 +Le nom du script bash principal est indiqué ici :
 +<code python>
 +# Le(s) script(s) bash a executer
 +MonScript1 = 'jpeg-transfos'
 +MonScript2 = 'jpeg-comptage'
 +</code>
 +
 +Les deux logos de la fenêtre sont donnés ici :
 +<code python>
 +# Logos pour agrementer la fenetre
 +MonLogoDossier = '/usr/local/divers/LogoDossier.gif'
 +MonLogoLinux  = '/usr/local/divers/LogoRoot66.gif'
 +</code>
 +Le fichier **LogoDossier.gif** est une petite image de 23x20 points obtenue par capture dans une autre application. Le pingouin **LogoRoot66.gif** est un fichier de 100x102 points; on peut mettre toutes sortes de décors d'environ 100x100 points.
 +
 +On peut modifier les options affichées par défaut :
 +<code python>
 +# Options de traitement (mettre 0/1 pour oui/non)
 +# Ou modifier le contenu du fichier /home/nom/.root66/jpeg-transfos.txt
 +MonDossier=os.path.join(os.getenv('HOME'), 'Images')
 +sousDossiers=1
 +dateFichier=1
 +rotationImage=1
 +#nomFichier='inchange'
 +nomFichier='JJMMAA-HHMMSS.jpg'
 +#nomFichier='AAMMJJ-HHMMSS.jpg'
 +#nomFichier='JJMMAA-nom-ancien.jpg'
 +#nomFichier='AAMMJJ-nom-ancien.jpg'
 +incrustationDate=0
 +incrustationHeure=0
 +incrustationNom=0
 +incrustationComm=0
 +tailleCar=32
 +</code>
 +
 +**Attention :** Les options par défaut ci-dessus ne sont valables qu'une seule fois. Dès le 1er lancement l'outil crée le fichier **/home/nom/.root66/jpeg-transfos.txt** s'il n'existait pas. Le fichier est créé à partir des options ci-dessus, et c'est dans ce fichier qu'on pourra ensuite fixer ses options perso de manière stable, même si on installe ultérieurement une nouvelle version de l'outil.
 +
 +On peut suggérer de spécifier un dossier par défaut également connu du logiciel de téléchargement des images d'APN, ce qui simplifie grandement l'utilisation de l'outil. Après modifications les images peuvent alors être déplacées vers des dossiers de classement définitifs autres.
 +A noter que le script Python a été programmé pour modifier cette zone de 3 façons :
 +  * par **saisie directe**,
 +  * par la fenêtre liée au **Logo Dossier**, qu'on peut aussi afficher par **touche F4**,
 +  * par **touche F3**, qui permet de passer cycliquement du dossier par défaut au dossier courant et au dossier home.
 +
 +A noter aussi que la **touche F5** a le même effet que le bouton **"Compter / Lister les images"**.
 +
 +On pourra mettre toute explication utile en début de zone déroulante, bien visible au lancement de l'outil :
 +<code python>
 +# titre facultatif en debut de zone deroulante
 +
 +titre = """
 +Cet outil sert a modifier des images JPG en fonction de leurs infos EXIF
 +------------------------------------------------------------------------
 +
 +Choisissez :
 +- le dossier de base contenant les images a traiter (F3 permet de naviguer
 +  entre le dossier mis par defaut, le dossier courant de l'utilisateur et son home;
 +  F4 affiche la fenetre de navigation comme quand on clique sur le logo de dossier),
 +- le nombre de niveaux de sous-dossiers qu'il faut traiter
 +  (1 par defaut ==> seul le dossier choisi sera traite),
 +- au moins une des options parmi celles proposees,
 +puis appuyez sur le bouton de traitement.
 +...etc...\n"""
 +</code>
 +
 +**Remarques**
 +
 +L'outil démarre en lisant le fichier **/home/nom/.root66/jpeg-transfos.txt** (sauf la toute 1ère fois). Si on veut personnaliser l'outil, le mieux est de se le copier dans son espace perso, et de lancer cet outil perso, donc sans modifier l'outil commun. Seul le fichier jpeg-transfos.py serait à dupliquer, les autres pourront rester inchangés dans /usr/local/bin. On pourra par exemple prévoir un 1er outil qui soit préconfiguré pour les manips de base au téléchargement d'images APN (renommage, rotation, date), et un second outil qui soit préconfiguré pour les manips d'incrustations les plus usuelles. On peut se créer autant d'outils perso que souhaité. Pour un outil perso on conseille à minima de remplacer toutes les occurrences du fichier de configuration **jpeg-transfos.txt** par un nom différent, comme ça chaque outil disposera de sa propre configuration indépendante des autres.
 +
 +Pour le reste des explications on se reportera à l'article sur l'outil de sauvegarde de fichiers. On conseille notamment d'effectuer les premiers tests en lançant l'outil en ligne de commande afin de visualiser et corriger d'éventuelles erreurs (paquetages non trouvés, dossiers inexistants, scripts non exécutables...).
 +
 +===== Script pour Dialogue Dossiers =====
 +
 +Ce code a été emprunté à source@mvista.com, mais on pourra trouver d'autres variantes ailleurs pour un résultat analogue. Si on utilise Python 2.4 on mettra par exemple ce script à un endroit acccessible par défaut par Python, par exemple ici : **/usr/lib/python2.4/DialogueDossiersJmm.py** .
 +
 +L'objectif de ce script est de gérer une fenêtre de navigation dans des dossiers pour en sélectionner un; on pourra s'en servir comme brique de base dans d'autres outils. Exemple de présentation :
 +
 +{{  :wiki-modif-images6.jpg  |:wiki-modif-images6.jpg}}
 +
 +<code python>
 +#!/usr/bin/python
 +# -*- coding: iso-8859-1 -*-
 +#
 +#  Le fichier d'origine a été modifié par : Jeanmm
 +#  Date    : 6/3/2005
 +#  Modifs  : Traduction en Français + corrections de focus
 +#  Licence : GPL
 +#
 +#  FILE: DirBrowser.py
 +#
 +#  DESCRIPTION:
 +#    This file provides a generic Directory browser selection widget.
 +#
 +#  AUTHOR:  MontaVista Software, Inc. <source@mvista.com>
 +#
 +#  Copyright 2001 MontaVista Software Inc.
 +#
 +#  This program is free software; you can redistribute  it and/or modify it
 +#  under  the terms of  the GNU General  Public License as published by the
 +#  Free Software Foundation;  either version 2 of the  License, or (at your
 +#  option) any later version.
 +#
 +#  THIS  SOFTWARE  IS PROVIDED  ``AS  IS'' AND  ANY  EXPRESS OR IMPLIED
 +#  WARRANTIES,  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
 +#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 +#  NO  EVENT  SHALL  THE AUTHOR  BE    LIABLE FOR ANY  DIRECT, INDIRECT,
 +#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 +#  NOT LIMITED  TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
 +#  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 +#  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
 +#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 +#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 +#
 +#  You should have received a copy of the  GNU General Public License along
 +#  with this program; if not, write  to the Free Software Foundation, Inc.,
 +#  675 Mass Ave, Cambridge, MA 02139, USA.
 +#
 +
 +import os
 +import Tkinter
 +import Pmw
 +
 +class DirBrowserDialog(Pmw.MegaToplevel):
 +    "Fenêtre de parcours de dossiers"
 +    def __init__(self, parent = None, **kw):
 +        cwd = os.getcwd()
 +        # Define the megawidget options.
 +        INITOPT = Pmw.INITOPT
 +        optiondefs = (
 +            ('path',              cwd,            None),
 +            ('hidedotfiles',      1,              INITOPT),
 +            ('label',              None,            INITOPT),
 +            #('labelmargin',        0,              INITOPT),
 +            #('labelpos',          None,            INITOPT),
 +            ('borderx',            20,              INITOPT),
 +            ('bordery',            20,              INITOPT),
 +            )
 +
 +        self.defineoptions(kw, optiondefs)
 +
 +        # Initialise the base class (after defining the options).
 +        Pmw.MegaToplevel.__init__(self, parent)
 +
 +        interior = self.interior()
 +        self.transient(parent)
 +        self.ppath=os.sep # previous path for loop, and root path
 +
 +        self.childframe = self.createcomponent('childframe', (), None,
 +                                              Tkinter.Frame,
 +                                              (interior,),
 +                                              borderwidth = 1,
 +                                              relief = 'raised',
 +                                              )
 +        self.childframe.pack(expand = 1,
 +                            fill = 'both',
 +                            )
 +
 +        self.labelframe = self.createcomponent('labelframe', (), None,
 +                                                Tkinter.Frame,
 +                                                (self.childframe,),
 +                                                borderwidth = 2,
 +                                                relief = 'groove',
 +                                                )
 +        self.labelframe.pack(padx = 10, pady = 10, expand = 1, fill = 'both')
 +       
 +        if self['label']:
 +            self.label = self.createcomponent('label', (), None,
 +                                                Tkinter.Label,
 +                                                (self.childframe,),
 +                                                text = self['label'],
 +                                                )
 +            self.label.place(x = (10 + self['borderx']), y = 10, anchor = 'w')
 +
 +
 +        self.workframe = self.createcomponent('workframe', (), None,
 +                                                Tkinter.Frame,
 +                                                (self.labelframe,),
 +                                                #borderwidth = 2,
 +                                                #relief = 'groove',
 +                                                )
 +        self.workframe.pack(padx = self['borderx'],
 +                            pady = self['bordery'],
 +                            expand = 1,
 +                            fill = 'both',
 +                            )
 +
 +        self.buttonframe = self.createcomponent('buttonframe', (), None,
 +                                                Tkinter.Frame,
 +                                                (interior,),
 +                                                borderwidth = 1,
 +                                                relief = 'raised',
 +                                                )
 +        self.buttonframe.pack(expand = 0,
 +                              fill = 'x',
 +                              )
 +
 +        self.optbox = self.createcomponent('optbox', (), None,
 +                                            Pmw.OptionMenu,
 +                                            (self.workframe,),
 +                                            command = self.setpath,
 +                                            )
 +        self.optbox.bind('<Configure>', self._setMinimumSize)
 +
 +        self.listbox = self.createcomponent('listbox', (), None,
 +                                            Pmw.ScrolledListBox,
 +                                            (self.workframe,),
 +                                            dblclickcommand = self._select,
 +                                            )
 +
 +        path = self['path']
 +       
 +        self.entry = self.createcomponent('entryfield', (), None,
 +                                            Pmw.EntryField,
 +                                            (self.workframe,),
 +                                            value = path,
 +                                            entry_bg = 'white',
 +                                            command = self.enteredpath,
 +                                            labelpos = 'nw',
 +                                            label_text = 'Dossier courant :',
 +                                            )
 +
 +        #self.createlabel(self.workframe, childCols = 1, childRows = 3)
 +
 +        self.buttonbox = self.createcomponent('buttonbox', (), None,
 +                                            Pmw.ButtonBox,
 +                                            (self.buttonframe,),
 +                                            )
 +        self.buttonbox.add('OK', text = 'OK',
 +                          command = self.okbutton)
 +        self.buttonbox.add('Annuler', text = 'Annuler',
 +                          command =  self.cancelbutton)
 +        self.buttonbox.add('Nouveau Dossier', text = 'Nouveau Dossier',
 +                          command =  self.newdirbutton)
 +       
 +        self.buttonbox.alignbuttons()
 +        self.buttonbox.pack(expand = 1, fill = 'x')
 +
 +        self.optbox.grid(row = 2, column = 2, sticky = 'ew')
 +        self.listbox.grid(row = 3, column = 2, sticky = 'news')
 +        self.entry.grid(row = 5, column = 2, sticky = 'ew')
 +        self.workframe.grid_rowconfigure(3, weight = 1)
 +        self.workframe.grid_rowconfigure(4, minsize = 20)
 +        self.workframe.grid_columnconfigure(2, weight = 1)
 +
 +        self.setpath(self['path'])
 +
 +        # Check keywords and initialise options.
 +        self.initialiseoptions()
 +
 +    def setpath(self, path):
 +        path = os.path.abspath(os.path.expanduser(path))
 +       
 +        if os.path.isfile(path):
 +            path = os.path.dirname(path)
 +
 +        dirlist = []
 +        hidedotfiles = self['hidedotfiles']
 +        try:
 +            posix = (os.name == 'posix')
 +            for entry in os.listdir(path):
 +                entryPath = path + os.sep + entry
 +                if hidedotfiles and entry[0] == '.':
 +                    # skip dot files if desired
 +                    continue
 +                if not os.path.isdir(entryPath):
 +                    # skip files
 +                    continue
 +                if not os.access(entryPath, os.R_OK | os.X_OK):
 +                    # skip directories we can't enter any way
 +                    continue
 +                dirlist.append(entry)
 +        except:
 +            self.entry.setentry(self['path'])
 +            return
 +
 +        self.entry.setentry(path)
 +       
 +        self['path'] = path
 +
 +        pathlist = []
 +        self.ppath='' # previous path (to stop loop, good for linux & windows)
 +        while path != self.ppath:
 +            pathlist.append(path)
 +            self.ppath=path
 +            path = os.path.dirname(path)
 +        # self.ppath = root path after loop
 +        self.optbox.setitems(pathlist, 0)
 +       
 +        dirlist.sort()
 +        if self['path'] != self.ppath:
 +            dirlist.insert(0, '..')
 +        self.listbox.setlist(dirlist)
 +
 +    def _setMinimumSize(self, event):
 +        # If the optionmenu changes width, make sure it does not
 +        # shrink later.
 +        owidth = self.optbox.winfo_width()
 +        self.workframe.grid_columnconfigure(2, minsize = owidth)
 +
 +    def _select(self):
 +        sel = self.listbox.getcurselection()
 +        if self['path'] == self.ppath:
 +            self['path'] = ''
 +        if len(sel) > 0:
 +            if sel[0] == '..':
 +                self.setpath(os.path.dirname(self['path']))
 +            else:
 +                self.setpath(self['path'] + os.sep + sel[0])
 +
 +
 +    def getcurpath(self):
 +        return self['path']
 +
 +    def enteredpath(self):
 +        self.setpath(self.entry.get())
 +
 +    def okbutton(self):
 +        self.deactivate(self['path'])
 +
 +    def cancelbutton(self):
 +        self.deactivate(None)
 +
 +    def newdirbutton(self):
 +        CreateDirectoryPopup(self.interior(), self['path'])
 +        self.setpath(self['path'])
 +
 +
 +       
 +class CreateDirectoryPopup:
 +    def __init__(self, parent, path):
 +        self.path = path
 +        self.parent = parent
 +        self.newdirpopup = Pmw.PromptDialog(parent,
 +                                            buttons = ('OK', 'Annuler'),
 +                                            defaultbutton = 'OK',
 +                                            title = 'Nouveau Dossier',
 +                                            entryfield_labelpos = 'nw',
 +                                            label_text = 'Création de nouveau dossier dans\n%s\n' %self.path,
 +                                            command = self._buttonpress
 +                                            )
 +
 +        self.newdirpopup.transient(parent)
 +        self.newdirpopup.activate()
 +        self.parent.focus_set()
 +
 +
 +    def _buttonpress(self, button):
 +        if button == 'OK':
 +            newdirname = self.newdirpopup.get()
 +            dirlist = os.listdir(self.path)
 +            if newdirname in dirlist:
 +                ErrorPopup(self.parent,
 +                          'Erreur: "%s" existe déjà !'%newdirname)
 +            else:
 +                try:
 +                    os.mkdir(self.path + os.sep + newdirname)
 +                except:
 +                    ErrorPopup(self.parent,
 +                              'Erreur: création impossible de "%s"' %newdirname)
 +                else:
 +                    self.newdirpopup.deactivate()
 +        else:
 +            self.newdirpopup.deactivate()
 +           
 +
 +def ErrorPopup(parent, message):
 +    error = Pmw.MessageDialog(parent, title = 'Erreur',
 +                              message_text = message,
 +                              defaultbutton = 0,
 +                              )
 +    error.activate()
 +    self.parent.focus_set()
 +   
 +if __name__ == '__main__':
 +
 +    rootWin = Tkinter.Tk()
 +    Pmw.initialise()
 +    rootWin.title('Demo')
 +
 +    def buildBrowser():
 +        # Create the hierarchical directory browser widget
 +        dirBrowserDialog = DirBrowserDialog(rootWin,
 +                                            #labelpos = 'nw',
 +                                            label = '',
 +                                            title = 'Sélection de dossier',
 +                                            #path = '~',
 +                                            #hidedotfiles = 0,
 +                                            )
 +        dir = dirBrowserDialog.activate()
 +
 +        rootWin.focus_set()
 +        print 'Dossier selectionne :', dir
 +
 +    dirButton = Tkinter.Button(rootWin, text="Choisir un dossier", command=buildBrowser)
 +    dirButton.pack(side = 'left', padx = 10, pady = 10)
 +
 +    exitButton = Tkinter.Button(rootWin, text="Quitter", command=rootWin.quit)
 +    exitButton.pack(side = 'left', padx = 10, pady = 10)
 +
 +    rootWin.mainloop()
 +</code>
 +
 +
 
 
Sauf mention contraire, le contenu de ce wiki est placé sous la licence suivante:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki