Como posso renomear fotos, dados os dados EXIF?

14

Digamos que eu tenha um monte de fotos, todas com informações EXIF corretas, e as fotos são nomeadas aleatoriamente (devido a um problema que tive). Eu tenho um pequeno programa chamado jhead que me dá a saída abaixo:

$ 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

Agora preciso renomear todas as fotos da pasta no próximo formato:

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

Onde o número menor seria a imagem mais antiga e o máximo o mais recente.

Não sou tão bom em escrever scripts, por isso estou pedindo ajuda.

Eu acho que um script bash é suficiente, mas se você se sentir mais confortável, você pode escrever um script python.

Eu pensei em algo como:

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

mas não sei como fazer isso para todos os arquivos de uma só vez.

    
por Tomas 06.02.2011 / 23:02

7 respostas

11

Você pode fazer isso para todos os arquivos usando um loop for (no shell / em um shell script):

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

Este é apenas um esboço muito básico. Exclua echo quando você verificar que tudo funciona conforme o esperado.

    
por 06.02.2011 / 23:14
27

Acabamos de descobrir aqui que o jhead pode faça tudo por você! :)

jhead -autorot -nf%Y-%m-%d_%H-%M-%S *.jpg
    
por 21.03.2011 / 16:02
0

Se alguém precisar de renomeação mais complexa, por exemplo, para incluir valores-chave de exposição em nome de arquivo, aqui está meu pequeno script. Ele renomeia arquivos jpeg para algo como isto: 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
    
por 02.09.2014 / 15:27
0

Eu gostei do código postado pelo maxschlepzig, mas tive dificuldades com o resultado, no entanto.

O problema era o espaço no nome do arquivo resultante (entre a string de data e a string de tempo). Embora seja trivial para qualquer pessoa que use uma GUI, o manuseio de arquivos na linha de comando é um pouco mais difícil.

Aqui o comando 'sed' foi substancialmente alterado para quatro operações separadas 'sed' em favor do argumento monolítico anterior. Para se adequar a mim mesmo, o seguinte também muda o arquivo para as normais permissões 644.

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
    
por 31.05.2015 / 23:41
0

Por ser mais fácil de lidar com (imho), escrevi para mim mesmo um 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
}

O que isso faz?

  1. Iterar todos os arquivos transmitidos como parâmetros (por exemplo, *.JPG ).

    Eu verifiquei que ele lida com arquivos RAW e vídeos corretamente. Deve funcionar com tudo o que o exiftool pode lidar.

  2. Não faz nada se um arquivo

    • não existe,
    • é um diretório,
    • não tem uma data EXIF ou
    • exiftool informa um erro ou
    • já existe um arquivo com o nome do arquivo de destino.

Isso faz com que seja bastante robusto. Em particular, nenhum arquivo pode desaparecer (silenciosamente) como é o caso de algumas das outras respostas.

    
por 28.05.2016 / 13:56
0

exiv2 seria uma alternativa para manipulação, que permite uma sintaxe muito simples:

exiv2 is a program to read and write Exif, IPTC, XMP metadata and image comments and can read many vendor makernote tags. The program optionally con‐ verts between Exif tags, XMP properties and IPTC datasets

Então, isso renomearia todos os jpegs na pasta atual:

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

Se você também quiser adicionar informações geográficas, poderá usar exivtool :

exiftool '-filename<${gpslatitude;} ${gpslongitude} ${datetimeoriginal}' -d "%Y-%m-%d %H.%M.%S%%-c.%%e" *.JPG
    
por 23.11.2016 / 09:48
0

Eu gosto da solução do Kevin, já que eu queria manter o nome original também (evitando problemas com imagens tiradas no mesmo segundo), aqui está a minha solução:

for i in *.JPG; do jhead -nf%Y%m%d_%H%M%S_"$(basename "$i" .JPG)" "$i" ; done
    
por 20.07.2018 / 17:17