Remove nés quadros de um gif (remova um quadro a cada n quadros)

4

Eu gravei .gif da tela com ffmpeg. Eu usei gifsicle e imagemagick para comprimir um pouco, mas ainda é grande. Minha intenção é torná-lo pequeno, removendo, digamos, um quadro a cada 2 quadros, para que a contagem total de quadros seja reduzida à metade.

Não consegui encontrar uma maneira de fazer isso, nem com gifsicle nem com imagemagick . man páginas não ajudaram.

Como posso remover um quadro de uma animação .gif a cada n frames?

    
por Vittorio Romeo 03.09.2013 / 13:29

2 respostas

6

Provavelmente, existe uma maneira melhor de fazer isso, mas eis o que eu faria

Primeiro, divida sua animação em quadros

convert animation.gif +adjoin temp_%02d.gif

Em seguida, selecione um sobre n quadros com um pequeno loop em que você faz o loop em todos os quadros, verifique se ele é divisível por 2 e, se for o caso, copie-o em um novo arquivo temporário.

j=0; for i in $(ls temp_*gif); do if [ $(( $j%2 )) -eq 0 ]; then cp $i sel_'printf %02d $j'.gif; fi; j=$(echo "$j+1" | bc); done

Se você preferir manter todos os números não divisíveis (e, portanto, se quiser excluir em vez de manter todos os enésimos quadros), substitua -eq por -ne .

E depois de fazer isso, crie sua nova animação a partir dos quadros selecionados

convert -delay 20 $( ls sel_*) new_animation.gif

Você pode criar facilmente um pequeno script convert.sh , o que seria algo assim

#!/bin/bash
animtoconvert=$1
nframe=$2
fps=$3

# Split in frames
convert $animtoconvert +adjoin temp_%02d.gif

# select the frames for the new animation
j=0
for i in $(ls temp_*gif); do 
    if [ $(( $j%${nframe} )) -eq 0 ]; then 
        cp $i sel_'printf %02d $j'.gif; 
    fi; 
    j=$(echo "$j+1" | bc); 
done

# Create the new animation & clean up everything
convert -delay $fps $( ls sel_*) new_animation.gif
rm temp_* sel_*

E depois é só ligar, por exemplo

$ convert.sh youranimation.gif 2 20
    
por 03.09.2013 / 14:09
2

Existe uma versão alternativa da resposta do MBR , como uma função bash:

gif_framecount_reducer () { # args: $gif_path $frames_reduction_factor
    local orig_gif="${1?'Missing GIF filename parameter'}"
    local reduction_factor=${2?'Missing reduction factor parameter'}
    # Extracting the delays between each frames
    local orig_delay=$(gifsicle -I "$orig_gif" | sed -ne 's/.*delay \([0-9.]\+\)s//p' | uniq)
    # Ensuring this delay is constant
    [ $(echo "$orig_delay" | wc -l) -ne 1 ] \
        && echo "Input GIF doesn't have a fixed framerate" >&2 \
        && return 1
    # Computing the current and new FPS
    local new_fps=$(echo "(1/$orig_delay)/$reduction_factor" | bc)
    # Exploding the animation into individual images in /var/tmp
    local tmp_frames_prefix="/var/tmp/${orig_gif%.*}_"
    convert "$orig_gif" -coalesce +adjoin "$tmp_frames_prefix%05d.gif"
    local frames_count=$(ls "$tmp_frames_prefix"*.gif | wc -l)
    # Creating a symlink for one frame every $reduction_factor
    local sel_frames_prefix="/var/tmp/sel_${orig_gif%.*}_"
    for i in $(seq 0 $reduction_factor $((frames_count-1))); do
        local suffix=$(printf "%05d.gif" $i)
        ln -s "$tmp_frames_prefix$suffix" "$sel_frames_prefix$suffix"
    done
    # Assembling the new animated GIF from the selected frames
    convert -delay $new_fps "$sel_frames_prefix"*.gif "${orig_gif%.*}_reduced_x${reduction_factor}.gif"
    # Cleaning up
    rm "$tmp_frames_prefix"*.gif "$sel_frames_prefix"*.gif
}

Uso:

gif_framecount_reducer file.gif 2 # reduce its frames count by 2
    
por 10.10.2014 / 04:44