segunda-feira, 1 de dezembro de 2014

Recuperando fotos do celular

Inadvertidamente apaguei todas as fotos do celular. A qualidade das fotos não é das melhores, mas eu tinha fotos dos meus filhos que não gostaria de perder.

Encontrei um programa muito bom para recuperar fotos: PhotoRec. Ele sugou milhares de fotos da imagem que criei da memória do meu celular (um modesto Galaxy Pocket). Eram tantas imagens, que tive que recorrer a um pouco de código para ajudar na seleção.

Em primeiro lugar, gerei uma imagem da memória. Conectei o celular ao computador e copiei toda a memória:

dd if=/dev/sdb of=pocket


O celular apareceu como /dev/sdb e o comando copiou toda a memória para o arquivo pocket. Essa imagem tem exatamente o tamanho da memória, porque é uma cópia bit a bit.

Depois, rodei o PhotoRec, que tem uma interface textual, mas simples.

Então, identifiquei todas as fotos obviamente minhas (as outras podem ser de aplicativos que baixem imagens, como o navegador ou o WhatsApp). Olhando os metadados das imagens JPG,  descobri que as imagens interessantes são as que têm um valor que começa com S5300 - identificador do aparelho - no campo "Software"). Para isso, usei o módulo Image::MetaData::JPEG do Perl.

use Image::MetaData::JPEG;
use File::Find;
use File::Copy;

find(\&wanted, $ARGV[0]);

sub wanted {
  if(/jpg$/) {
    my $image=new Image::MetaData::JPEG($File::Find::name);
    if($image) {
      my $image_data = $image->get_Exif_data('IMAGE_DATA', 'TEXTUAL');
      my $software=$image_data->{'Software'}->[0];
      if($software=~/^S5300/) {
        print "$software $File::Find::name\n";
        move($File::Find::name, $ARGV[1]);
      }
    }
  }
}

Esse script recebe como parâmetros o nome da pasta onde vai procurar imagens e o nome da pasta para onde vai copiar os selecionados. Depois, eliminei todas as imagens pequenas (com menos de 500 pontos na vertical ou na horizontal). Os aplicativos de notícias que eu uso guardam milhares dessas fotinhos. Para isso, usei o módulo Image::Info.

use Image::Info qw(image_info dim);
use File::Find;
use File::Copy;

find(\&wanted, $ARGV[0]);

sub wanted {
  if(/jpg$/) {
    my $image_info=image_info($_);
    my $width=$image_info->{width};
    my $height=$image_info->{height};
    if($width<500 || $height<500) {
      print "$software $File::Find::name\n = $width $height\n";
      move($File::Find::name, $ARGV[1]);
    }
  }
}

Esse programa recebe como parâmetros o nome da pasta onde vai procurar imagens e o nome da pasta para onde vai copiar as imagens pequenas (não joguei nada fora).

Restaram muitas imagens duplicadas. Algumas tinham pequenas diferenças, mas outras eram idênticas. Então, usei mais um programa para eliminar as repetições.

use Digest::MD5 ;
use File::Copy;

%seen = ();
while( <*> ){
    -d and next;
    $filename="$_"; 
    #print "doing .. $filename\n";
    $md5 = getmd5($filename) ."\n";    
    if ( ! defined( $seen{$md5} ) ){
        $seen{$md5}="$filename";
    }else{
        print "Duplicate: $filename and $seen{$md5}\n";
        move($filename, '../duplicates/');
    }
}
sub getmd5 {
    my $file = "$_";            
    open(FH,"<",$file) or die "Cannot open file: $!\n";
    binmode(FH);
    my $md5 = Digest::MD5->new;
    $md5->addfile(FH);
    close(FH);
    return $md5->hexdigest;
}

Ou melhor, o programa coloca as cópias na pasta "duplicates", para não correr o risco de perder nada.

Ainda foi preciso fazer uma inspeção manual, mas os scripts facilitaram muito o trabalho.