Typescript to gif - convertir une capture terminal vers un gif animé

Comment utiliser la commande "script" et un peu de bash + imagemagick pour en faire une animation en GIF (ou pourquoi pas une vidéo par la suite)

Cette semaine, un administrateur système m'a montré une commande que je ne connaissais pas du tout... "script". Ce petit utilitaire permet d'enregistrer le flux terminal vers un fichier afin d'être relu. En grattant dans le "man" j'ai découvert deux options intéressantes, l'une d'elle permet de garder les "temps" de commande + le nombre de caractères à lire... On peut alors utiliser "scriptreplay" pour relire la session ou bien, comme moi, jouer avec et créer une animation

Prenons le temps de comprendre. Si je tape la commande:

script --timing=/tmp/timing /tmp/script

alors commence une session enregistrée dans le fichier /tmp/script.

Tapons alors des commandes, par exemple

echo "hello world"

Puis pressez CTRL+D. La session "script" s'arrête. Vous pouvez rejouer la session (qui ne va pas rejouer les commandes, mais les afficher avec les résultats de l'époque...) en utilisant "cat"

cat /tmp/script

Or... on a besoin de voir "à la replay" la commande. Soit:

scriptreplay -t /tmp/timing /tmp/script

Et là, c'est déjà plus joli. Mais voilà, pour partager une capture de ce genre en vidéo (ou en gif animé) ce format ne nous convient pas encore. On va donc réfléchir recréer une belle vidéo de tout ce beau monde.

Première option, on fait un screencast (avec ffmpeg) mais bon... la souris peut apparaître... et puis pour en faire un gif c'est pas encore ça.

Seconde option, celle qu'on va mettre en place, est de faire ceci: - relire le fichier /tmp/timing - prendre séquence par séquence le texte depuis le typescript (fichier généré par la commande script) - afficher ça dans le terminal et faire une capture du terminal avec la commande "import" - relire une fois de plus le timing et cette fois ci: lire les temps d'attente - utiliser "convert" avec l'option -delay pour mettre frame à frame les images dans le gif animé.

Voilà... bon je vais pas passer par 4 chemins, le but n'est pas de vous apprendre à faire du bash mais au moins vous parler des "soucis" que j'ai dut régler: - lire un fichier d'un certain endroit à un autre: on utilise "dd" - créer des images numérotées avec 5 chiffres pour être à l'aise: printf

Le reste coule presque de source... Voilà le script:

#!/bin/bash
 
TIMING=$1
SCRIPT=$2
W=$WINDOWID
 
rm -rf /tmp/script-replay-gifs/
mkdir /tmp/script-replay-gifs/
 
t=$(mktemp)
cp $SCRIPT $t
 
#remove first line
sed -i '1d' $t
 
#clear screen
clear
 
#read timing file one by one
curr=0
i=0
while read line
do
    #capture time and chars to read
    cols=($line)
    chars=${cols[1]}
 
    #read from current char the number of chars to read
    dd if=$t bs=1 skip=$curr count=$chars 2>/dev/null
 
    #convert to gif frame with a nice frame-number
    n=$(printf "%010d" $i)
    import -window $WINDOWID /tmp/script-replay-gifs/$n.gif
 
    #and move to next position
    curr=$((curr+chars))
    i=$((i+1))
done <$TIMING
rm -f $t
 
#now, set gif with delay per frame
i=1
while read line
do
    cols=($line)
    timing=${cols[0]}
    #get next image
    file=$(ls -1 /tmp/script-replay-gifs/ | head -n $i | tail -n 1)
    timing=$(echo "$timing*100" | bc -l | awk '{print int($0)}')
    command=$command" -delay $timing /tmp/script-replay-gifs/$file"
 
    i=$((i+1))
done < $TIMING
 
convert $command /tmp/anim-notoptim.gif
convert /tmp/anim-notoptim.gif -coalesce -layers Optimize /tmp/anim.gif
 
rm -f /tmp/anim-notoptim.gif
rm -rf  /tmp/script-replay-gifs/

Ce script est très très lent à cause de "import" qui prend près d'une seconde par capture... de ce fait pour le moment c'est pas un modèle du genre... et en plus, vous ne pouvez pas quitter le bureau dans lequel vous être pour créer l'animation sous peine de messages d'erreur. Notez que ce n'est un qu'un petit test

Cela donne: Animation terminal

Pour le coup, j'ai quand même posé un petit coup de "gimp" pour optimiser le gif animé. Je vous laisse maître de me faire des remarques et pourquoi pas (si vous le demandez) je créerai un dépôt git quelque part pour qu'on le fasse évoluer.

Update: j'ai ajouté une opération d'optimisation de taille à la fin du script

Commentaires

1. Le mercredi, mai 30 2012, 15:56 par Jean-Yves

juste une erreur de frappe

import -window .... (il manque un "d")

Merci pour l'article

2. Le jeudi, août 2 2012, 12:00 par Metal3d

Merci, corrigé :)