Scanner un magazine A3 et le remettre en A4 đź”—

Posted by MĂ©dĂ©ric Ribreux 🗓 In blog/Sysadmin/

#code #dev #shell

J'ai la chance d'avoir accès à un copieur équipé d'un très bon scanner A3 avec un chargeur automatique. J'ai quelques magazines que je souhaite conserver sous forme numérique histoire d'occuper moins de place dans ma bibliothèque ou sur mon bureau. Ce sont des magazines techniques et je les consulte une fois de temps en temps. Rien qui nécessite donc de les conserver ad vitam æternam sous format papier. Une cinquantaine de magazine occupe quand même un sacré volume… Le plus simple serait de toujours les avoir au format numérique au moment de l'achat mais ce n'est pas forcément facile. Par exemple, le magazine GNU/Linux Magazine France pourrait très bien être vendu dans un format numérique mais, pour des questions que je ne maîtrise pas, ce n'est pas le cas (même s'ils y pensent sérieusement).

Le scan en masse du magazine produit par défaut un fichier "PDF" qui est le reflet du magazine mais avec des pages en bordel. En fait, ce n'est pas un vrai fichier PDF mais plutôt une encapsulation d'images dans un document PDF: il n'y a pas d'OCR ni de vectorisation des graphiques. Sachant cela, il vaut donc mieux partir d'une source sous forme d'images si le scanner le permet et produire un fichier PDF avec les pages dans l'ordre. Dans mon cas, le format JPEG est présent.

J'ai donc scanné en masse tout un magazine en recto verso A3. Le résultat est un ensemble de fichiers images qu'il va falloir découper et assembler pour former un export PDF en A4 et dans l'ordre de lecture des pages.

Pour cela, j'ai utilisé quelques outils:

Pour la numérisation, j'ai scanné le magazine en enlevant les agrafes centrales et en plaçant les pages du milieu vers le haut. La numérisation débute donc par les doubles pages du milieu. Comme nous sommes en A3, il y a donc deux pages par image. De plus, il y a le coup du recto-verso qui vient modifier l'ordre d'apparition des pages. Voici l'ordre pour un magazine de 100 pages:

À noter que j'aurais pu découper les pages A3 en deux pour former un tas de pages A4. La numérisation aurait été sans doute plus rapide mais cette étape de découpe physique est non seulement fastidieuse mais également, le temps de scan sera plus long, car il est plus rapide de scanner une feuille A3 que deux feuilles A4 à cause des opérations de vérification lors du chargement automatique.

Le code (shell) qui suit s'occupe de récupérer les fichiers images produits pour fabriquer un fichier PDF, le tout, en une seule commande. Voici un résumé des actions du script:

Voici le code source:

#!/bin/bash
# Script de remodelage de document JPG scanné A3 recto-verso vers A4.

# On récupère le nombre de pages:
# Les fichiers sont nommés DOC<quelquechose>.jpg
nb_page=$(ls -l DOC*.jpg | wc -l)

echo "Nombre de pages extraites: $nb_page"
# Pour chaque fichier ppm produit,on extrait les pages qu'on nomme correctement:
for f in DOC*.jpg
do
  # Récupération de l'indice de la page:
  num=${f:10:4}
  num=$(echo $num | sed 's/0*//')
  let num=$num-1
  echo "Traitement de la page n° $num"

  # Récupération de la géométrie de l'image:
  width=$(identify $f | cut -d " " -f3 | cut -d "x" -f1)
  height=$(identify $f | cut -d " " -f3 | cut -d "x" -f2)
  let semi_width=$width/2
  let semi_heigth=$height/2

  let paire=$num%2
  if [ "$paire" -eq "0" ]
  then
    # Si on est sur une page paire:
    let g=$nb_page-2*$num/2
    let d=$g+1+4*$num/2
    echo "Page n° $num (paire): gauche=$g | droite=$d"
  else
    # Si on est sur une page impaire:
    let nnum=$num-1
    let gb=$nb_page-2*$nnum/2
    let db=$gb+1+4*$nnum/2
    let g=$gb+$num*2
    let d=$db-$num*2
    echo "Page n° $num (impaire): gauche=$g | droite=$d"
  fi
  # On créée les images qui vont bien:
  convert -crop ${semi_width}x$height+0+0 $f $g.jpg
  convert -crop ${semi_width}x$height+$semi_width+0 $f $d.jpg
  rm $f
done

# enfin, on assemble le tout en pdf avec pdftk:
rm out.pdf
for f in $(ls *.jpg | sort -n)
do
  name=${f%.jpg}.pdf
  convert -compress Jpeg $f $name
done

# Assemblage final !
pdftk $(ls *.pdf | sort -n) cat output output.pdf
exit 0

Je suis loin d'être un dieu du shell et ce script peut forcément être amélioré. En plus, il est assez spécifique: il faut que les fichiers du magazine soient tous situés dans un seul répertoire et qu'ils soient nommés DOC<quelquechose>-<un nombre d'indice>.jpg . Mais les utilisateurs éclairés trouveront bien comment modifier tout ça ! Je suis sûr que l'algorithme de calcul des pages peut être simplifié…

Le code qui suit fait la même chose pour un fichier PDF assemblé pas comme il faut (contient les mêmes images A3 Recto/Verso mais dans un seul fichier PDF). Globalement, c'est le même principe sauf qu'on exporte les images à partir du PDF initial.

#!/bin/bash
# Script de remodelage de document PDF scanné A3 recto-verso vers A4.

# On récupère le nom du fichier pdf à traiter:
fichier_pdf=$1
# On extrait toutes les images
pdfimages $1 p

# On récupère le nombre de pages:
nb_page=$(ls -l p-*.ppm | wc -l)

echo "Nombre de pages extraites: $nb_page"
# Pour chaque fichier ppm produit,on extrait les pages qu'on nomme correctement:
for f in p-*.ppm
do
  # Récupération de l'indice de la page:
  num=${f:2:3}
  num=$(echo $num | sed 's/0*//')
  let num=$num+0
  echo "Traitement de la page n° $num"

  # Récupération de la géométrie de l'image:
  width=$(identify $f | cut -d " " -f3 | cut -d "x" -f1)
  heigth=$(identify $f | cut -d " " -f3 | cut -d "x" -f2)
  let semi_width=$width/2
  let semi_heigth=$height/2

  let paire=$num%2
  if [ "$paire" -eq "0" ]
  then
    # Si on est sur une page paire:
    let g=$nb_page-2*$num/2
    let d=$g+1+4*$num/2
    echo "Page n° $num (paire): gauche=$g | droite=$d"
  else
    # Si on est sur une page impaire:
    let nnum=$num-1
    let gb=$nb_page-2*$nnum/2
    let db=$gb+1+4*$nnum/2
    let g=$gb+$num*2
    let d=$db-$num*2
    echo "Page n° $num (impaire): gauche=$g | droite=$d"
  fi
  # On créée les images qui vont bien:
  convert -crop ${semi_width}x$height+0+0 $f $g.ppm
  convert -crop ${semi_width}x$height+$semi_width+0 $f $d.ppm
  rm $f
done

# enfin, on assemble le tout en pdf avec pdftk:
rm *.pdf
for f in $(ls *.ppm | sort -n)
do
  name=${f%.ppm}.pdf
  convert -compress Jpeg $f ${f%.ppm}.pdf
done
pdftk $(ls *.pdf | sort -n) cat output output.pdf
exit 0