Scanner un magazine A3 et le remettre en A4

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écéssite donc de les conserver ad vitam eternam 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:

  • Bash pour la progammation
  • pdftk pour produire le PDF
  • convert et identify d'ImageMagick
  • pdfimages de xpdf (pour le script spécifique aux PDF)

Pour la numérisation, j'ai scanné le magazine en enlevant les agrafes centrales et en placant 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:

  • Fichier n°0 (recto): page de gauche=page 50 | page de droite = 51
  • Fichier n°1 (verso): page de gauche=page 52 | page de droite = 49
  • Fichier n°3 (recto): page de gauche=page 48 | page de droite = 53
  • Fichier n°4 (verso): page de gauche=page 54 | page de droite = 47
  • et ainsi de suite...

A 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:

  • Déterminer les bons numéros de page en fonction des noms de fichier.
  • Découper les images en leur milieu en leur donnant un nom adapté;
  • Assembler toutes les images dans l'ordre dans un seul fichier PDF.

Voici le 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-.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