Script em bash para redimensionar e renomear imagens

O script a seguir usa o programa ImageMagick para redimensionar imagens através do comando “convert”. O parâmetro “-resize” redimensiona para uma largura (em pixels) informada – se quiser definir a altura, coloca-se um “x” na frente do valor. Além disso, recebe o nome do arquivo de entrada a ser convertido e o nome do arquivo de saída. Veja mais sobre o ImageMagick no post Edição de Imagens no Linux.

Além de simplesmente redimensionar, esse script considera uma padronização de nomes dos arquivos envolvidos. Desse modo, eliminam-se espaços em branco, pontos e caracteres incomuns, além de deixar o nome mais curto e manter os arquivos em ordem cronológica (geralmente os dispositivos que geram as fotos nomeiam ordenadamente os arquivos). O nome de cada arquivo fica com um número sequencial e com zeros à esquerda, permitindo um bom ordenamento ao listá-los.

Para esse trabalho, considere que todas as imagens estão em um mesmo diretório. O nome dele é importante para gerar os nomes dos arquivos, devendo ser definido pelo local (pode alternar maiúsculas e minúsculas, mas sem espaço) e data (qualquer formato, desde que não separe usando traço), separados por um traço. Uma sugestão: NomeDoLocal-YYYYmes, onde “YYYY” é o ano com 4 dígitos e “mes” é a abreviação do mês em português com 3 caracteres.

O script (nomeado como resize_images.sh) deve estar um nível acima da pasta a ser trabalhada. O nome dessa pasta deve ser informada como argumento da execução desse script, conforme segue (lembre-se de mudar sua permissão de execução através de “chmod +x resize_images.sh”):

./resize_images.sh Teste-2017nov

#!/bin/bash
# Script para renomear/redimensionar imagens

# Recebe nome do diretório que contém as imagens a serem editadas
dir=$1
# Renomear diretório (ou não)
echo "Diretório a ser trabalhado:" $dir
while true; do
    read -p "O diretório tem nome padrão (NomeDoLugar-YYYYmes)?" sn
    case $sn in
        [Ss]* ) echo "Iniciando script..."; break;;
        [Nn]* ) echo "Renomeie o diretório e execute novamente o script, alterando o argumento de entrada"; exit;;
        * ) echo "Responder (s)im ou (n)ao.";;
    esac
done
cd $dir

# Substituir espaços em branco por underlines
rename 'y/ /_/' *

# Iniciar contador
cont=0
# Loop para listar arquivos (se quiser em ordem inversa, acrescentar parâmetro "-r" no ls abaixo)
for original in $(ls | egrep '\.jpg$|\.JPG$|\.jpeg$|\.gif$|\.GIF$|\.png$|\.PNG$'); do
	echo $original
	# Obter nome e extensão
	nome=$(echo $original | rev | cut -d"." -f2-  | rev)
	ext=$(echo $original | awk -F"." '{print $NF}')
	
	# Caso tenha compressão JPG, mudar extensão de JPG/jpeg para jpg (se for o caso)
	if [ "$ext" == "JPG" ] || [ "$ext" == "jpeg" ]; then
		#echo "Mudando extensão"
		ext='jpg'
		novo_nome1=$nome'.'$ext
		mv $original $novo_nome1
	else
		#echo "Sem mudança de extensão"
		novo_nome1=$original
	fi
	
	# Mudar nome do arquivo para padrão com base no nome do diretório
	lugar=$(echo $dir | awk -F"-" '{print $1}')
	# Número de dígitos (acrescenta zeros à esquerda)
	ndigitos=3
	contador=$(printf "%0*d\n" $ndigitos $cont)
	novo_nome2=$contador'-'$lugar'.'$ext
	echo "Mudando nome para" $novo_nome2
	mv $novo_nome1 $novo_nome2
	nome_arq=$novo_nome2
	
	# Redimensionar imagem se largura (ou altura) for maior que 800 px
	largura=$(convert $nome_arq -print "%w" /dev/null)
	altura=$(convert $nome_arq -print "%h" /dev/null)
	#convert $nome_arq -print "Tamanho original: %wx%h\n" /dev/null
	if [ "$largura" -gt "800" ] || [ "$altura" -gt "800" ]; then
		nome_temporario=$nome_arq'_temp'
		if [ "$largura" -gt "800" ]; then
			# Define valor máximo de largura, mantendo a razão de aspecto
			convert -resize "800" $nome_arq $nome_temporario
		elif [ "$altura" -gt "800" ]; then
			# Define valor máximo de altura, mantendo a razão de aspecto
			convert -resize "x800" $nome_arq $nome_temporario
		fi
		# Somente atualizar arquivo se tiver tamanho menor
		tamanho_original=$(du -b $nome_arq | awk -F" " '{print $1}')
		tamanho_novo=$(du -b $nome_temporario | awk -F" " '{print $1}')
		if [ "$tamanho_novo" -lt "$tamanho_original" ]; then
		  mv $nome_temporario $nome_arq
		else
		  rm $nome_temporario
		fi		
	else
		echo "Não redimensionar - largura e altura menores ou iguais que 800px"
	fi
	
	# Atualizar contador
	cont=$((cont+1))
	#exit
done

Ao recebe o nome do diretório, uma clásula “case” dentro de um “while” é utilizada para perguntar ao usuário se o diretório está com um nome padrão. Se estiver, basta teclar “s” (de “sim”) e ENTER; caso contrário, tecle “n” e renomeie o diretório de modo a conter um único traço com pelo menos 1 caractere antes desse traço.

Primeiramente, são substituídos os espaços em branco por “underlines” (_) nos nomes de todos os arquivos, já que o Linux não se dá muito bem com esses caracteres. É feito um loop para todos os arquivos que tenham as seguintes extensões: jpg, JPG, jpeg, gif, GIF, png e PNG.

Para cada arquivo, o script primeiro deve renomear as extensões JPG (maiúscula) e jpeg para jpg. Depois, renomeia cada arquivo com três dígitos ordenados (000 a 999) e o nome do local (obtido pelo nome da pasta), separados por um traço. Os números vem de um contador e podem conter mais ou menos de 3 dígitos: basta alterar a variável “ndigitos”.

Para executar o redimensionamento, primeiro é verificada a seguinte condição: o arquivo deve ter largura ou altura maior que 800 pixeis. Se for o caso, um arquivo temporário é gravado com a devida conversão. Se o arquivo convertido tiver um tamanho menor que o original, então a substituição é concluída renomeando-se esse arquivo para o nome original, de modo a substitui-lo.