Comment renommer des photos, compte tenu des données EXIF?

14

Disons que j'ai un tas de photos, toutes avec des informations EXIF ​​correctes, et les photos sont nommées aléatoirement (à cause d'un problème que j'ai eu). J'ai un petit programme appelé jheadqui me donne la sortie ci-dessous:

$ jhead IMG_9563.JPG

File name    : IMG_9563.JPG
File size    : 638908 bytes
File date    : 2011:02:03 20:25:09
Camera make  : Canon
Camera model : Canon PowerShot SX210 IS
Date/Time    : 2011:02:03 20:20:24
Resolution   : 1500 x 2000
Flash used   : Yes (manual)
Focal length :  5.0mm  (35mm equivalent: 29mm)
CCD width    : 6.17mm
Exposure time: 0.0080 s  (1/125)
Aperture     : f/3.1
Focus dist.  : 0.29m
ISO equiv.   : 125
Exposure bias: -1.67
Whitebalance : Manual
Light Source : Daylight
Metering Mode: pattern
Exposure Mode: Manual

Maintenant, je dois renommer toutes les photos du dossier au format suivant:

001.JPG
002.JPG
003.JPG
...

Où le nombre mineur serait l'image la plus ancienne et le maximum la plus récente.

Je ne suis pas un bon script, donc je demande de l'aide.

Je pense qu'un script bash est suffisant, mais si vous vous sentez plus à l'aise, vous pouvez écrire un script python.

J'ai pensé à quelque chose comme:

$ mv IMG_9563.JPG `jhead IMG_9563.JPG | grep date`

mais je ne sais pas comment faire cela pour tous les fichiers à la fois.

Tomas
la source
Je ne comprends pas la phrase mineure / maximale et l'exemple précédent. Pourriez-vous clarifier cela?
maxschlepzig
Ce nom de fichier mineur / maximum est un pas en avant. Parce que, une fois que les fichiers sont nommés d'une manière qu'ils représentent, qui sont plus anciens et plus récents, je peux facilement renommer 001.jpg, 002.jpg, etc. avec un autre programme, bien qu'il serait préférable de le faire avec un autre script.
Tomas
La "table de renommage" serait ls *.JPG | wc > renameEt puis je devrais utiliser un script renommé en XXX.JPG
Tomas
Sory, non wc, j'ai oublié celui à commander par son nom.
Tomas
La commande est triée.
Tomas

Réponses:

10

Vous pouvez le faire pour tous les fichiers en utilisant une boucle for (dans le shell / dans un shell-script):

for i in *.JPG; do
  j=`jhead "$i" | grep date | sed 's/^File date[^:]\+: \(.\+\)$/\1/'`.jpg
  echo mv -i "$i" "$j"
done

Ce n'est qu'un aperçu très basique. Supprimez echolorsque vous avez vérifié que tout fonctionne comme prévu.

maxschlepzig
la source
Merci. Maintenant, grep me donnerait File date : 2011:02:03 20:25:09. Comment filtrer uniquement la deuxième colonne?
Tomas
Je ne renomme donc le fichier que 20:25:09
Tomas
@Tomas, a mis à jour la réponse - si vous ne voulez vraiment que du temps (qu'en est-il des collisions alors?), Vous devez bien sûr modifier l'expression régulière.
maxschlepzig
j=`jhead "$i" | grep date | sed 's/.* //'`.jpgau lieu?
frabjous
@maxshlepzig: Merci, vous avez raté un 'avant `` .jpg`
Tomas
28

Je viens de découvrir ici que jhead peut tout faire pour vous! :)

jhead -autorot -nf%Y-%m-%d_%H-%M-%S *.jpg
Kevin
la source
7
Oui! Mais faites attention à cette chaîne de format particulière, car elle donnera à deux fichiers pris dans la même seconde le même nom. %i(ou %03i, plus précisément) donnera un numéro de séquence, comme demandé dans la question d'origine. La combinaison des deux n'est peut-être pas une mauvaise idée.
mattdm
Juste pour répondre au commentaire de mattdm - le manuel '' jhead '' suggère qu'il ajoutera automatiquement un chiffre ou une lettre supplémentaire (1,2,3 ou a, b, c, etc.) aux doublons (horodatage identique).
John U
0

Si quelqu'un a besoin d'un renommage plus complexe, par exemple pour inclure des valeurs d'exposition clés dans le nom de fichier, voici mon petit script. Il renomme les fichiers jpeg à quelque chose comme ceci: NightSky_2014.08.27_22.30.05_NX20_F2.8_f20.0mm_20s_ISO800.jpg.

#!/bin/bash

for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | \
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;} 
/Exposure time:/ { e=$3; 
                   if (e==int(e)) e=int(e); 
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; } 
                 }
/ISO equiv./     { iso="ISO" $4; } 
/Focal length/   { f="f" $4; } 
/Date.Time /     { d=$3 "_" $4; gsub(":",".",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); } 
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso ".jpg"; }'`

 echo mv $s $x
 mv $s $x
 echo =====
done
Libor
la source
0

J'ai aimé le code publié par maxschlepzig mais j'ai quand même eu des difficultés avec la sortie.

Le problème était l'espace dans le nom de fichier résultant (entre la chaîne de date et la chaîne d'heure). Bien que trivial pour toute personne utilisant une interface graphique, cela rend la gestion des fichiers sur la ligne de commande un peu plus difficile.

Ici, la commande «sed» a été substantiellement modifiée en quatre opérations «sed» distinctes en faveur de l'argument monolithique précédent. Pour me convenir, ce qui suit modifie également le fichier en autorisations 644 normales.

for i in *.JPG ; do
  chmod 644 $i
  j=`jhead "$i" | grep ^Date/Time | sed -e 's/^Date\/Time[ ]\+: //;s/:/-/g;s/ /_/g':/-/g;s/ /_/g'`.jpg
  echo mv -i "$i" "$j"
  # mv -i "$i" "$j"
done
endotherme
la source
2
Bienvenue sur Stack Exchange. (1) Je comprends sedassez bien, donc je comprends essentiellement ce que vous essayez de faire. Mais notre objectif à Stack Exchange n'est pas de distribuer des sandwichs au poisson ou d'écrire des milliers de solutions uniques à des questions trivialement distinctes; notre objectif est d'enseigner aux gens comment pêcher (c.-à-d., enseigner aux gens, y compris l'intervenant actuel et les futurs lecteurs, comment résoudre leurs propres problèmes). À cette fin, votre réponse serait meilleure si vous expliquiez ce que vous tentez. (Veuillez ne pas répondre dans les commentaires; modifiez votre réponse pour la rendre plus claire.)… (Suite)
G-Man dit «Réinstalle Monica»
(Suite)… (2) Votre commande échoue car les guillemets ne sont pas équilibrés. Veuillez ne pas publier de code non testé.
G-Man dit «Réinstalle Monica»
0

Parce qu'il est plus facile de gérer (à mon humble avis), je me suis écrit un script Ruby:

require 'fileutils'

ARGV.each { |file|
  if File.exist?(file) && !File.directory?(file)
    exif = `exiftool "#{file}" | grep -E "(Error|Create Date)"`
    if exif.strip.size > 0
      exif = exif.split("\n")[0].split(/\s+/)
      if exif[0] != "Error"
        # Change the target format here
        filename = exif[3].gsub(":", "-") + " " + 
                   exif[4].gsub(":", ".") + 
                   File.extname(file)
        if filename != file && !File.exist?(filename)
          FileUtils::mv(file, File.dirname(file) + "/" + filename)
        end
      end
    end
  end
}

Qu'est-ce que cela fait?

  1. Itère tous les fichiers passés en paramètres (par exemple *.JPG).

    J'ai vérifié qu'il gère correctement les fichiers RAW et les vidéos. Cela devrait fonctionner avec tout ce qui exiftoolpeut être traité.

  2. Ne fait rien si un fichier

    • n'existe pas,
    • est un directeur,
    • n'a pas de date EXIF, ou
    • exiftool signale une erreur, ou
    • un fichier avec le nom de fichier cible existe déjà.

Cela le rend assez robuste. En particulier, aucun fichier ne peut disparaître (en silence) comme c'est le cas pour certaines des autres réponses.

Raphael
la source
0

exiv2 serait une alternative de manipulation, qui permet une syntaxe très simple:

exiv2 est un programme pour lire et écrire des métadonnées Exif, IPTC, XMP et des commentaires d'image et peut lire de nombreuses balises makernote de fournisseurs. Le programme convertit éventuellement les balises Exif, les propriétés XMP et les jeux de données IPTC

Donc, cela renommerait tous les jpeg du dossier actuel:

for i in *.JPG; do exiv2 -v -r '%Y%m%d.%H%M%S.:basename:' rename "$i"; done

Si vous souhaitez également ajouter des informations géographiques, vous pouvez utiliser exivtool:

exiftool '-filename<${gpslatitude;} ${gpslongitude} ${datetimeoriginal}' -d "%Y-%m-%d %H.%M.%S%%-c.%%e" *.JPG
rubo77
la source
0

J'aime la solution de @ Kevin, car je voulais aussi garder le nom d'origine (éviter les problèmes avec les images prises dans la même seconde), voici ma solution:

for i in *.JPG; do jhead -nf%Y%m%d_%H%M%S_"$(basename "$i" .JPG)" "$i" ; done
Giorgio Borgonovo
la source
0

Première publication par un débutant ... Premier script bash ... J'ai aimé la solution Libor / HalosGhost ci-dessus car elle incluait plus de détails dans le renommage. Mais après les tests, les noms de fichiers en double finiraient par perdre des fichiers. J'ai donc ajouté une balise de compteur à la fin du nom de fichier pour faciliter la référence et la prévention des collisions. Je suis sûr que quelqu'un ici peut améliorer cela, mais j'ai pensé que cela pourrait aider.

Mes excuses après avoir affiché le code. J'ai des difficultés avec l'interface, mais si quelqu'un pouvait m'orienter vers une façon correcte de faire les choses, ce serait formidable.

#!/bin/bash

y=1
for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | \
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;}
/Exposure time:/ { e=$3;
                   if (e==int(e)) e=int(e);
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; }
                 }
/ISO equiv./     { iso="ISO" $4; }
/Focal length/   { f="f" $4; }
/Date.Time /     { d=$3 "_" $4; gsub(":","",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); }
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso "_" ; }'`

 echo mv $s "$x${y}.jpg"
 mv $s "$x${y}.jpg"
 y=$((y+1))
 echo =====
done
jgroezin
la source
Merci Stephen pour la retouche. Essayer d'apprendre
jgroezin