Fiz um programa em bash para colocar aquela estampa de data (
timestamp) em arquivos com base na última modificação do arquivo. Muitas vezes acontece de você ter a foto em si, mas não ter programado a câmera para gerar automaticamente esse carimbo na foto. Ou, como foi meu caso, achar que não tinha importância a data e, depois, começar a querer colocar, além de que os aplicativos padrão de Câmera de celular não terem essa funcionalidade (pelo menos eu nunca tive contato com um que tivesse, somente aplicativos instalados a mais, como o Camera360).
Para quem quiser pegar o programa, pode fazer o
download, mas, aqui, vou explicar o que fiz, deixando o
código e que referências de consulta usei. É bom para aprender um pouquinho de Bash e alguns comandos de Linux e, para quem quiser, modificar o programa para outros propósitos (Filosofia do Código Aberto ;) ).
O primeiro passo do programa é testar a entrada do programa. Eu quero que o programa receba apenas uma entrada, portanto, se a chamada ao programa for diferente de 1 argumento, devo dar uma mensagem de erro e sair.
Para obter a data da última modificação do arquivo, usamos o comando
stat. Consultando o manual, vemos que a opção -c corresponde a: "
use the specified FORMAT instead of the default; output a newline after each use of FORMAT". Ou seja, se usarmos o stat sozinho, ele dará uma série de informações sobre o arquivo, mas só nos interessa a data da modificação, então usamos a opção -c e pedimos o formato que queremos, que é obtido usando %y.
%y Time of last modification, human-readable
Trecho do manual sobre a opção %y
Usando o comando stat -c %y [
referência], obteremos algo do tipo:
2014-02-25 15:37:46.000000000 -0300
Mas só nos interessa a data, que vem no formato yyyy-mm-dd. Então, usando uma
manipulação de string, localizamos o espaço e pegamos o conteúdo até onde ele ocorrer. Usamos o operador %% seguido do caracter desejado, no caso, o espaço e um asterisco ($string=${string%%-*} - substituí o espaço por um traço para ficar mais palpável). Note que o comando verificará a primeira ocorrência do marcador, mesmo que a string pode tenha o mesmo marcador depois. Entretanto, se usarmos o operador % (simples), ele localizará a última ocorrência, que é o que queremos nesse instante: separar a substring que vem antes do espaço.
O operador ##, por outro lado obtém o que estiver depois do marcador, sendo que a ordem entre o marcador e o asterisco se inverte ($string=${string##*-}). Servirá para obter a extensão do arquivo, como será visto ao longo deste texto. Não quis me alongar muito nessa explicação para não perder o objetivo principal do post, mas tem exemplos
aqui,
aqui e o
meu exemplo (
link no GitHub).
Voltando à data, vamos usar o operador "%% *" para obter o pedaço "2014-02-25" da saída obtida com o comando stat. Segue o trecho do código responsável:
#obtem data de ultima modificacao do arquivo
data=$(stat -c %y $1)
data=${data%% *}
No programa, eu gerei um nome de saída para o arquivo com a data com base no nome de entrada, adicionando a ele a data e hora em que foi gerado. Para isso, temos que pegar o nome do arquivo (que é dado pelo usuário ao rodar o programa, ou seja, é o argumento 1 - $1 - da chamada via linha de comando, por exemplo ./datarFoto
lago.jpg), obter todo o nome até o último ponto (usando o tratamento de substrings que eu expliquei acima) e também guardar a extensão, que usará o operador ## para guardar a substring depois do marcador. Para concatenar duas strings, basta colocá-las lado a lado depois do sinal de =, como na última linha do trecho abaixo:
#gerar nome do arquivo de saida
nomeSaida=$1
extensao=${nomeSaida##*.}
nomeSaida=${nomeSaida%.*}
nomeSaida=$nomeSaida$(date +"_%y%m%d_%H%M")
Faltou explicar o funcionamento do date [
referência]. O sinal de + indica o formato que eu quero que a data seja exibido. O comando date sozinho dá a data atual, usando os operadores +"_%y%m%d_%H%M", a data será exibida no tipo _140131_1251, onde 14 é o ano (2014), 01, o mês e 31 o dia. Os sublinhados foram escolha minha, você podia botar outros caracteres para separar, mas , como estamos lidando com nome de arquivo, não seria legal colocar certos caracteres como barra e dois pontos.
Para mudar o formato da data (a ser carimbada na foto e não no nome do arquivo de saída) para o nosso formato tradicional (dd/mm/yyyy), também usamos o comando date. Mas, dessa vez, damos como entrada a data obtida pelo stat. Para isto, usamos a opção --date= que indica ao date que é para usar determinada data e não a do dia de hoje.
#converte o formato da data de yyyy-mm-dd para dd/mm/yyyy
texto=$(date --date=$data +"%d/%m/%y")
Por fim, vamos carimbar a foto. Usamos o comando convert. Como não consegui rodar o comando de uma vez, coloquei o comando numa string e mandei a string ser rodada, através do eval. As opções do convert que merecem destaque são a gravity (mais informações
aqui), que serve para mudar a origem das coordenadas. A opção draw diz em que posições vertical e horizontal vai ser colocado o texto. Usando a opção gravity Southeast, essas posições são dadas com relação à ponta inferior direita, sendo assim, independente do tamanho, o carimbo sempre vai ser dado neste canto.
#usar o formato para usar o comando convert
executar="convert -pointsize 20 -fill yellow -gravity Southeast -draw 'text 20,20 \"$texto\"' $1 $nomeSaida.$extensao"
eval $executar
Referências:
http://www.instructables.com/id/Add-text-to-images-with-Linux-convert-command/2/?lang=pt
http://www.linuxquestions.org/questions/programming-9/get-file-modification-date-time-in-bash-script-163731/
http://www.cyberciti.biz/faq/linux-unix-formatting-dates-for-display/
http://www.win.tue.nl/~aeb/linux/misc/convert/convert-draw-text.html
http://tldp.org/LDP/abs/html/string-manipulation.html