#!/bin/bash appNome="StopMotion Fácil" userPrefDir="$HOME/.stopmotion-facil" userPref="$userPrefDir/conf.txt" [ -d "$userPrefDir" ] || mkdir "$userPrefDir" [ -f "$userPref" ] || touch "$userPref" # Opções para o filme: tamanhoTela=$( grep tamanhoTela "$userPref" | cut -d: -f2 ) [ "$tamanhoTela" = "" ] && tamanhoTela='200x150' gamma=$( grep gamma "$userPref" | cut -d: -f2 ) [ "$gamma" = "" ] && gamma='não' niveisContrast=$( grep niveisContrast "$userPref" | cut -d: -f2 ) [ "$niveisContrast" = "" ] && niveisContrast='0%,100%' frameRate=$( grep frameRate "$userPref" | cut -d: -f2 ) [ "$frameRate" = "" ] && frameRate='30' numCopias=$( grep numCopias "$userPref" | cut -d: -f2 ) [ "$numCopias" = "" ] && numCopias='3' addImgFade=$( grep addImgFade "$userPref" | cut -d: -f2 ) [ "$addImgFade" = "" ] && addImgFade='0' addDirFade=$( grep addDirFade "$userPref" | cut -d: -f2 ) [ "$addDirFade" = "" ] && addDirFade='20' bitrate=$( grep bitrate "$userPref" | cut -d: -f2 ) [ "$bitrate" = "" ] && bitrate='300' # Testa se o festival existe: fest=false #festival -v >/dev/null 2>/dev/null && fest=true festCmd='festival --pipe' bold='\033[00;00;1m' # Formata Bold fimF='\033[m' # Fim Formata $fest && echo '(SayText "Stopmotion Facil!")' | $festCmd #2345678901234567890123456789012345678901234567890123456789012345678901234567890 echo -e " \033[40;30;1m o o | o o o o | o o o o | o o o o | o o o o | o o o o | o o o o | o o o o | o o | | | | | | | v1.0 | | | | \033[40;34;1m S T O P M O T I O N \033[40;30;1m | | | | | | | | | | | o o | o o o o | o o o o | o o o o | o o o o | o o o o | o o o o | o o o o | o o\033[m " function limpaParaFestival() { echo $1 | sed 's/á\|ã/a/gi' | sed 's/é\|ê/e/gi' | sed 's/í/i/gi' | sed 's/ó\|ô\|õ/o/gi'| sed 's/ú/u/gi' | sed 's/[^-a-zA-Z0-9!?$@]/ /g' } function diga() { echo -e "$@" $fest && echo "(SayText \"$( limpaParaFestival "$@" )\")" | $festCmd } # Onde gardar respostas: resp='' function pergunte() { perg='' list1='' list2='' for arg in "$@"; do if [ "$perg" = "" ]; then perg="$arg" else list1="$list1,$arg" list2="$list2$arg" fi done #perg=$( echo "$perg" | sed "s/_\(.\)/\\$bold\1\\$fimF/g" ) echo -ne "$( echo "$perg" | sed "s/_\(.\)/\\$bold\1\\$fimF/g" ) [${list1:1}] " $fest && echo "(SayText \"$( limpaParaFestival "$perg" )\")" | $festCmd resp='' while ! ( echo "$resp" | grep -iq "[$list2]" ); do read -sn1 resp if ! ( echo "$resp" | grep -iq "[$list2]" ); then echo -en "\a" fi done resp=$( echo $resp | tr 'a-z' 'A-Z' ) echo $resp } # Diretorios com fotos para gerar o filme: dirs='' function manipulaListaDirs() { resp='?' while [ $resp = '?' -o $resp = 'A' -o $resp = 'D' ]; do if [ "$newDir" = "" ]; then newDir="$( echo "$dirs" | sed 's/.*:\([^:]\+\)$/\1/' )" echo " >> ... $newDir" [ "$newDir" = "" ] && newDir="$(pwd)" fi echo " >> abrindo $newDir" if [ $resp = 'A' ]; then newDir="$( zenity --file-selection --directory "--filename=$newDir/" --title="$appNome" )" [ "$newDir" != "" ] && dirs="$dirs:$newDir" fi if [ $resp = 'D' ]; then diga -n " Indique o número: " read numDel dirs="$( num=0; vazio=true echo "$dirs" | sed "s/:/\n/g" | while read d; do let num++ if [ "$num" != "$numDel" ]; then echo -n "$( $vazio || echo -n ':' )$d" vazio=false fi done )" fi diga " Diretórios listados:" num=0 echo "$dirs" | sed "s/:/\n/g" | while read d; do if [ "$d" != "" ]; then let num++ diga " $num $d" fi done pergunte " Deseja _Adicionar ou _Deletar um diretório da lista?" A D N done } function redefineTamanhoTela() { diga -n " Defina a Largura: "; read w while ! ( echo $w | grep -q '^[0-9]\+$' ); do diga -n " A Largura deve ser um número inteiro: "; read w done diga -n " Defina a Altura: "; read h while ! ( echo $h | grep -q '^[0-9]\+$' ); do diga -n " A Altura deve ser um número inteiro: "; read h done tamanhoTela=$( echo -n "${w}x$h" ) } function redefineNiveisContrast() { diga " O nível de contraste é definido por dois pontos: * Ponto Negro, que é nulo em 0% * Ponto Branco, que é nulo em 100% " diga -n " Percentual do Ponto Negro: "; read pn while ! ( echo $pn | grep -q '^[0-9]\+$' ); do diga -n " Esse percentual deve ser um número inteiro: "; read pn done diga -n " Percentual do Ponto Branco: "; read pb while ! ( echo $pb | grep -q '^[0-9]\+$' ); do diga -n " Esse percentual deve ser um número inteiro: "; read pb done niveisContrast=$( echo -n "${pn}%,$pb%" ) } function redefineGamma() { diga " Gamma é um valor real (tem prate decimal) que corrige o valor do tom médio de uma imagem. Seus valores úteis estão entre 0.8 e 2.3. Gamma abaixo de 1.0 escurece a imagem e acima ilumina. " diga -n " Valor de Gamma (digite \"n\" para indefinido): "; read gamma while ! ( echo $gamma | grep -q '^[.0-9]\+$\|n' ); do diga -n " Valor invalido, tente novamente: "; read gamma done [ "$gamma" = "n" ] && gamma="não" } function redefineFrameRate() { diga -n " Número de quadros por segundo: "; read frameRate while ! ( echo $frameRate | grep -q '^[0-9]\+$' ); do diga -n " Apenas valores inteiros são aceitos: "; read frameRate done } function redefineNumCopias() { diga -n " Quantas vezes cada fotografia deve ser replicada: "; read numCopias while ! ( echo $numCopias | grep -q '^[0-9]\+$' && [ $numCopias -gt 0 ] ); do diga -n " Apenas valores inteiros e maiores que 0 são aceitos: "; read numCopias done } function redefineAddImgFade() { diga -n " Quantos frames fade devem existir entre cada fotografia: " read addImgFade while ! ( echo $addImgFade | grep -q '^[0-9]\+$' ); do diga -n " Apenas valores inteiros são aceitos: "; read addImgFade done } function redefineAddDirFade() { diga -n " Quantos frames fade devem existir entre cada diretório: " read addDirFade while ! ( echo $addDirFade | grep -q '^[0-9]\+$' ); do diga -n " Apenas valores inteiros são aceitos: "; read addDirFade done } function redefineBitrate() { diga -n " Defina o limite de kbits por segundo do filme: " read bitrate while ! ( echo $bitrate | grep -q '^[0-9]\+$' ); do diga -n " Apenas valores inteiros são aceitos: "; read addDirFade done } function redefineSom() { som="$( zenity --file-selection --title="$appNome - Selecionar arquivo de Som" )" } function finaliza() { [ -e "$dirTrab" ] && rm -rf $dirTrab [ -e "$numFile" ] && rm $numFile $realNumFile if [ "$1" != "" ]; then exit $1 else exit 0 fi } ################################################################################### # Começo... diga " Estamos no diretório $(pwd)" pergunte " Existem fotografias para o filme neste diretório?" s n if [ "$resp" = 'S' ]; then echo ' Ok!' dirs="$(pwd)" else diga " Então, vou abrir uma janela para você selecionar um diretório com fotos..." cd; # Go Home! dirs="$( zenity --file-selection --directory --title="$appNome" )" fi manipulaListaDirs resp='' while [ "$resp" != 'G' -a "$resp" != 'X' ]; do somStrLim=$( if [ "$som" = "" ]; then echo -n nenhum else if [ "${#som}" -gt 34 ]; then echo -n "$som" | sed 's/^.*\(.\{32\}\)$/...\1/' else echo -n "${#som} $som" fi fi ) diga " -= Menu =- 1 - Visualizar e manipular lista de diretórios de fotos 2 - Definir dimensão do filme (Atual: $tamanhoTela) 3 - Definir correção de Contraste (Atual: $niveisContrast) 4 - Definir correção de Gamma (Atual: $gamma) 5 - Definir quadros por segundo (Atual: $frameRate) 6 - Definir número de cópias das fotografias (Atual: $numCopias) 7 - Adicionar transição fade entre as imagens (Atual: $addImgFade) 8 - Adicionar transição fade entre diretórios (Atual: $addDirFade) Q - Definir nível de qualidade do filme (Atual: $bitrate) S - Arquivo de Som para o fundo (Atual: $somStrLim) G - Gerar Filme! X - Sair " pergunte " Qual opção deseja?" 1 2 3 4 5 6 7 8 Q S G X case $resp in 1) manipulaListaDirs ;; 2) redefineTamanhoTela ;; 3) redefineNiveisContrast ;; 4) redefineGamma ;; 5) redefineFrameRate ;; 6) redefineNumCopias ;; 7) redefineAddImgFade ;; 8) redefineAddDirFade ;; Q) redefineBitrate ;; S) redefineSom ;; esac done if [ "$resp" = 'X' ]; then diga "Saindo!" finaliza exit 0 fi ################################################################################### # Gerando... diga " Convertendo Frames..." dirTrab=$( mktemp -d ) frameExt="jpg" if [ "$gamma" = "não" ]; then argGamma='' else argGamma="-gamma $gamma" fi if [ "$niveisContrast" = "0%,100%" ]; then argNiveisContrast='' else argNiveisContrast="-level $niveisContrast" fi # conta frames: totFrames=$( echo "$dirs" | sed "s/:/\n/g" | while read d; do ls -1 "$d/" 2>/dev/null | grep -i '\.\(jpg\|jpeg\|png\|gif\|tif\|tiff\|bmp\|svg\)$' done | wc -l ) function criaFade() { # Recebe 2 números informando as frames que recebem transição fade numFrameIni=$1 numFrameFim=$2 tot=$(( $numFrameFim - $numFrameIni )) imgIni="$dirTrab/frame$numFrameIni.$frameExt" imgFim="$dirTrab/frame$numFrameFim.$frameExt" for numFade in $( seq $(( $numFrameIni+1 )) $(( $numFrameFim-1 )) ); do passo=$(( $numFade - $numFrameIni )) pct1=$(( ( $passo * 100 ) / $tot )) if [ $passo -lt $(( $tot / 2 )) ]; then passoB=$tot else passoB=$(( ( $tot - $passo ) * 2 )) fi pct1=$(( ( $passo * 100 ) / $tot )) pct2=$(( ( $passoB * 100 ) / $tot )) estadoAtual=" Frame: $numFade $pct - Fading de $numFrameIni para $numFrameFim - passo $passo $pct1%" if [ ${#estadoAtual} -gt 80 ]; then estadoAtual="$( echo -n "$estadoAtual" | sed 's/^\(.\{45\}\).*\(.\{30\}\)$/\1 ... \2/' )" fi echo -ne "\r$esp80\r$estadoAtual" newImg="$dirTrab/frame$numFade.$frameExt" composite -dissolve $pct1%x$pct2% $imgFim $imgIni $newImg done } #12345678901234567890 esp80=' ' esp80="$esp80$esp80$esp80$esp80" numFile=$(mktemp) realNumFile=$(mktemp) echo -n 0 > $numFile echo -n 0 > $realNumFile ultimaImg='' echo "$dirs" | sed "s/:/\n/g" | while read d; do num=$( cat $numFile ) realNum=$( cat $realNumFile ) estadoAtual=" ==> Pegando imagens de $d ..." if [ ${#estadoAtual} -gt 80 ]; then estadoAtual="$( echo -n "$estadoAtual" | sed 's/^\(.\{45\}\).*\(.\{30\}\)$/\1 ... \2/' )" fi diga -ne "\r$esp80\r$estadoAtual" primeiraFotoDoDir=true ls -1 "$d/" 2>/dev/null | grep -i '\.\(jpg\|jpeg\|png\|gif\|tif\|tiff\|bmp\|svg\)$' | while read img; do ultimoNum=$num let num++ if [ "$ultimoNum" != 0 ]; then if ( $primeiraFotoDoDir && [ "$addDirFade" -gt 0 ] ); then # Salta na contagem de frames entre um dir e outro: num=$(( $num + $addDirFade )) else num=$(( $num + $addImgFade )) fi fi primeiraFotoDoDir=false let realNum++ pct=$( echo -n $(( ($realNum*1000)/$totFrames )) | sed 's/^\(.*\)\(.\)$/\1.\2%/' ) estadoAtual=" Frame: $num $pct -> $d/$img" if [ ${#estadoAtual} -gt 80 ]; then estadoAtual="$( echo -n "$estadoAtual" | sed 's/^\(.\{45\}\).*\(.\{30\}\)$/\1 ... \2/' )" fi echo -ne "\r$esp80\r$estadoAtual" newImg="$dirTrab/frame$num.$frameExt" ultimaImg="$newImg" convert -resize "$tamanhoTela!" $argNiveisContrast $argGamma "$d/$img" $newImg for cpNum in $( seq 2 $numCopias ); do let num++ cp $newImg "$dirTrab/frame$num.$frameExt" done if [ "$ultimoNum" != 0 ]; then # Cria fade entre as duas ultimas imgs, se houver números vazios entre as duas: criaFade $ultimoNum $(( $num - $numCopias + 1 )) fi echo -n $num > $numFile echo -n $realNum > $realNumFile done done num=$( cat $numFile ) realNum=$( cat $realNumFile ) diga -e "\r$esp80\r Finalizado! $num frames geradas de $realNum imagens." cd $dirTrab # dá espaço: #2345678901234567890123456789012345678901234567890123456789012345678901234567890 diga " ===== Gerando o Filme... =======================================================" i=0 for img in *; do let i++ pct=$( echo -n $(( ($i*1000)/$num )) | sed 's/^\(.*\)\(.\)$/\1.\2%/' ) echo -ne "\r$esp80\r Convertendo tipos... $i de $num - $pct" convert $img $img.png rm $img done echo # -sameq = qualidade total if ffmpeg -b $bitrate -r $frameRate -i frame%d.$frameExt.png \ $( if [ "$som" != "" ]; then echo -n "-i"; else echo "-r"; fi ) \ "$( if [ "$som" != "" ]; then echo -n "$som"; else echo $frameRate; fi )" \ filme.avi; then diga "===== Filme Gerado. ============================================================ " mostrouFilme=false if ! $mostrouFilme; then totem filme.avi 2>&1 >/dev/null && mostrouFilme=true; fi if ! $mostrouFilme; then kaffeine filme.avi 2>&1 >/dev/null && mostrouFilme=true; fi if ! $mostrouFilme; then gxine filme.avi 2>&1 >/dev/null && mostrouFilme=true; fi if ! $mostrouFilme; then mplayer filme.avi 2>&1 >/dev/null && mostrouFilme=true; fi diga " Abrindo diálogo para você salvar o filme gerado..." deskDir="$HOME" if [ -e "$HOME/Desktop" ]; then deskDir="$HOME/Desktop"; fi nomeArq='' while [ "$nomeArq" = "" ]; do i=0; nomeArq="$deskDir/filme.avi" while [ -e "$nomeArq" ]; do let i++; nomeArq="$deskDir/filme-$i.avi"; done nomeArq="$( zenity --file-selection --filename="$nomeArq"\ --save --title="$appNome - Salvar Filme" )" diga " Nome selecionado: $nomeArq" resp='' if [ -e "$nomeArq" ]; then pergunte " Este Arquivo já existe. Deseja Sobreescrever?" S N fi [ "$resp" = 'N' ] && nomeArq='' done else diga " Ups! Algo errado. :-( Diretório de trabalho: $dirTrab Pressione qualquer tecla para terminar." read -sn1 bli finaliza 1 fi mv filme.avi "$nomeArq" [ "$gama" = "" ] && gamma="não" # [ "$niveisContrast" = "" ] && niveisContrast="0%,100%" echo " tamanhoTela:$tamanhoTela gamma:$gamma niveisContrast:$niveisContrast frameRate:$frameRate numCopias:$numCopias addImgFade:$addImgFade addDirFade:$addDirFade bitrate:$bitrate " > "$userPref" finaliza