Quand on fait de la préservation numérique appliquée, on doit souvent intervenir sur des fichiers. Que ce soit pour rectifier une structure de format incorrecte, pour créer une copie de préservation dans un format préféré ou même pour créer une copie de diffusion conforme à nos standards de qualité, il est très utile de pouvoir comparer deux fichiers, l’original et le transformé.

Je vous propose donc ci-dessous quelques-unes de mes méthodes pour évaluer la distance entre la source et la cible d’une transformation (étant entendu que cette transformation a pour but d’être la moins destructive qui soit, donc n’affecter strictement que ce qu’on souhaite changer).

Cet article, comme les autres, a vocation à être enrichi au fur et à mesure de mes découvertes. Donc il commence petit mais il espère devenir plus conséquent ! Par ailleurs, si vous avez des méthodes similaires à me conseiller, je les prends avec avidité et gourmandise.

Un peu de méthode d’abord

Protéger les fichiers sources

Ce que je fais quand j’ai un ou plusieurs fichier(s) à transformer, c’est que je crée un dossier dédié dans un répertoire de test. Je suis donc assuré de n’avoir là que ce qui concerne ma petite affaire.

Ensuite, je fais la chose suivante : après y avoir collé tous les fichiers sources, je lance la ligne de commande suivante dans le répertoire :

chmod a-w *

Cette ligne de commande invoque la commande chmod, qui change les droits d’accès, d’écriture et d’exécution des fichiers. Dans ce cas précis, elle enlève à tous les utilisateurs (a pour all) le droit d’écrire (-w) sur tous les fichiers qui se trouvent dans le répertoire courant (*).

Pourquoi fais-je cela ? Rappelez-vous, dans mon billet sur le tact, je disais que l’informatique est conçue pour faciliter la modification des données. Pour éviter qu’une de vos manipulations n’affecte les fichiers sources, je les mets donc en lecture seule. (Vous pouvez faire pareil en sélectionnant les fichiers sources dans Windows > clic droit > Propriétés > Lecture seule.)

Mutanda, Immutanda, Observanda

Seconde étape : lorsque je dois intervenir sur un fichier, je fais trois petites listes de propriétés.

Mutanda : ce qui est à changer

(Désolé pour le snobisme de latiniste, mais le français n’a pas d’adjectif verbal exprimant l’obligation, alors que c’est exactement de cela que j’ai besoin.)

La première liste contient les propriétés que je veux changer dans mon fichier, et la nouvelle valeur que ces propriétés doivent avoir. Par exemple, si je veux réempaqueter un flux audio d’un conteneur AIFF vers un conteneur WAVE, je vais identifier comme propriété à changer le type MIME. Sa valeur d’origine est audio/x-aiff et sa valeur dans le fichier cible devra être audio/x-wav.

Autre exemple : pour un fichier à déchiffrer, je sélectionnerai la propriété de chiffrement (avec Apache TIka, cette propriété est appelée pdf:encrypted), et la valeur devra passer de true à false.

Assez souvent, une seule propriété est à changer, mais il peut arriver qu’il y en ait plusieurs.

Immutanda : les propriétés à conserver

J’avais déjà évoqué la notion de « propriété signifiante » dans mon billet sur le tact. Ici, il s’agit de caractéristiques du fichier original dont je souhaite conserver la valeur dans le fichier cible, parce qu’elles correspondent à des propriétés que mon institution s’est engagée à garder en l’état (par exemple la qualité du signal audio). Si je reprends mon premier exemple, cela serait notamment l’intégrité du signal audio (dans le cas d’un réempaquetage, on est en droit d’attendre que le signal audio ait strictement la même empreinte numérique), mais aussi, si le format conteneur cible les supporte, les métadonnées internes, la présence d’une vignette, etc.

Observanda : les propriétés à regarder de près

Certaines propriétés peuvent changer sans que l’on ait d’idée préconçue de leur valeur dans le fichier cible. On peut néanmoins vouloir vérifier et comparer les valeurs avant et après pour identifier d’éventuelles dérives. Dans cette catégorie, je place essentiellement le poids du fichier. En effet, si l’on reprend notre cas de réempaquetage AIFF vers WAVE, on s’attend à une petite variation de poids entre les deux. Si en revanche on constate une division par quatre, par exemple, on sera alerté du fait que la transformation a eu un effet imprévu.

Contrôle et évaluation de la dérive : solutions génériques

Passons maintenant au cœur de notre sujet. Nous avons réalisé notre transformation, et nous disposons donc de deux fichiers, l’original et le transformé, à comparer (appelés ci-dessous respectivement monFichierSource et monFichierCible).

Je commence par des méthodes qui peuvent s’appliquer à tout type de contenu, avant de passer aux méthodes qui ne fonctionnent que pour un type spécifique.

Contrôler l’effet de la transformation sur les propriétés des fichiers avec Exiftool

L’outil Exiftool est évidemment un incontournable, je commence donc par lui. Il est capable d’extraire et de calculer les propriétés de très nombreux types de fichiers. Ce que l’on va faire ici est de comparer la sortie de l’outil pour le fichier source et le fichier cible de la manière suivante :

exiftool monFichierSource > proprietesSource.txt
exiftool monFichierCible > proprietesCible.txt
diff proprietesSource.txt proprietesCible.txt

La commande diff compare les deux fichiers et renvoie uniquement les lignes qui changent d’un fichier à l’autre. On s’attendra à y trouver les propriétés à changer, et, le cas échéant, les propriétés à observer, mais non les propriétés à conserver, bien sûr.

Identifier les zones affectées par une modification ponctuelle

Dans le cas où l’on a réalisé une rectification très minime du fichier, avec un éditeur hexadécimal par exemple, on peut identifier quelles lignes ont été affectées avec la commande suivante :

diff <(hexdump monFichierSource) <(hexdump monFichierCible)

Ici, on réutilise diff mais on lui demande de comparer une représentation hexadécimale de chaque fichier. Néanmoins, cette méthode ne marche que si la taille du fichier n’a pas été modifiée (si vous avez remplacé un octet par un autre), sinon tout sera décalé et la commande vous renverra tout le contenu qui suit l’intervention.

Ci-dessus, la capture d’écran de la sortie sur un PDF où j’ai fait deux modifications très localisées pour corriger la valeur de deux attributs /Size et /Length fautifs.

Lorsque je réalise ce genre d’intervention chirurgicale, j’intègre la sortie de la commande ci-dessus dans les métadonnées de provenance du paquet afin d’assurer la réversibilité complète de mon opération.

Comparer deux fichiers, octet par octet

Un autre utilitaire Unix, qui fait comme diff partie de diffutils, est cmp. Cet utilitaire, au lieu de comparer des lignes, travaille octet par octet et vous renverra tous les octets qui ont changé avec l’option -verbose.

cmp -verbose monFichierSource monFichierCible

De ce fait, vous pouvez calculer le nombre d’offsets différents ainsi (la commande wc -l compte les lignes, donc les offsets où un résultat différent a été trouvé) :

cmp -verbose monFichierSource monFichierCible | wc -l

Contrôle et évaluation de la dérive : solutions spécifiques à un type de contenu

Passons maintenant aux méthodes spécifiques à des types de contenu particuliers.

Image fixe

Pour les images fixes, Image Magick dispose de commandes très utiles. Ainsi, la commande identify, qui renvoie de nombreuses propriétés des fichiers (surtout couplée avec l’option -verbose), peut renvoyer exclusivement une empreinte numérique du flux image :

magick identify -quiet -format "%#" monFichierSource
magick identify -quiet -format "%#" monFichierCible

Ainsi, si vous avez altéré uniquement le conteneur ou les métadonnées internes, et que vous voulez vérifier que votre intervention n’a pas affecté le flux image, les commandes ci-dessus devraient renvoyer le même résultat avec le fichier source et le fichier cible.

Dans cette commande, "%#" est un raccourci qui demande de ne renvoyer que la « signature ». Pour plus de détails sur les propriétés renvoyées par Image Magick et leur petit nom, je vous renvoie à cette page.

Image Magick dispose aussi d’une fonction compare qui, comme son nom l’indique, compare des images selon différentes métriques. Cette méthode est efficace dans le cas où le flux image a été affecté, par une compression par exemple. Je ne suis pas spécialiste de ces métriques comme PSNR, qu’on utilise souvent pour évaluer une compression TIFF vers JPEG 2000 (voir par exemple ce billet de blog, un peu ancien cela dit), et j’ai donc du mal à évaluer ce qui est une valeur acceptable, mais j’utilise souvent la métrique AE (pour Absolute Error) qui compte les différences pixel par pixel, et espère que la commande suivante renverra « 0 », qui signifie « aucune différence ».

compare -quiet -metric AE monFichierSource monFichierCible null:

Pour plus de détails sur cette commande, il y a une page très complète sur le site d’ImageMagick.

Documents PDF

Il est possible de comparer deux PDF à l’aide de l’outil comparepdf. L’outil dispose de deux options : -ct pour comparer le contenu textuel et -ca pour comparer l’aspect visuel.

Je vous renvoie à ce billet que j’ai écrit, et qui donne un exemple de l’utilisation concrète de l’outil. Vous y lirez que, confronté à un retour qui concluait à une différence d’aspect visuel, j’ai vérifié ce retour en produisant une version matricielle de chaque page avec la fonction PDFToImage de pdfbox et en comparant les pages deux par deux avec Image Magick compare. Cela marche très bien !

Son

Il est possible de comparer les flux audio contenus dans un fichier sonore en ne prenant en compte que le signal sonore et non le contenant et ses métadonnées. Certains fichiers stockent l’empreinte interne de ce flux ; c’est le cas du format FLAC. Il est possible alors d’extraire cette information avec la ligne de commande suivante :

metaflac --show-md5sum monFichier.flac

Pour les autres formats, il est nécessaire de calculer l’empreinte du seul flux audio. L’outil ffmpeg permet de le faire de la manière suivante :

ffmpeg -i monFichierSource.aiff -loglevel error -map a:0 -f md5 -
ffmpeg -i monFichierCible.wav -loglevel error -map a:0 -f md5 -

Les options sont les suivantes :

  • -i (pour input) introduit le fichier source ;
  • -loglevel error ne renvoie que la valeur produite par le processus (le retour par défaut de ffmpeg est toujours assez verbeux) ;
  • -map a:0 sélectionne uniquement le premier flux audio – la valeur de cette option est donc à modifier si vos fichiers ont plusieurs flux audio ;
  • -f md5 (pour format) demande comme format de sortie une simple somme de contrôle MD5 ;
  • Le tiret final remplace un nom de fichier cible, paramètre obligatoire pour ffmpeg : au lieu de renvoyer le résultat dans un fichier, la valeur est affichée dans le terminal.

Mais on peut également vouloir comparer des flux audio avant et après compression. Dans ce cas, évidemment, les empreintes numériques ne seront pas les mêmes. On va donc plutôt utiliser un outil qui calcule l’empreinte d’une représentation visuelle du son. J’ai pour le moment repéré deux programmes qui font ça (il y en a sans doute plein d’autres) :

  • xCorrSound, développé au début des années 2010 pour le projet Scape et maintenu (ou plutôt hébergé, parce qu’il n’y a plus de mises à jour depuis douze ans) par l’OPF. Personnellement, je n’ai pas réussi à le faire fonctionner (mais j’avoue que je n’y ai pas mis beaucoup d’effort) et me suis rapidement reporté sur le suivant ;
  • Chromaprint, dont le fonctionnement est décrit ici. Le problème, c’est que cet outil ne permet pas de comparer aisément deux empreintes numériques produites par lui1. Du coup, j’ai utilisé audio-compare qui s’appuie sur le précédent (sous le nom fpcalc) et fournit un pourcentage de similarité.

Image animée

Pour l’image animée, outre la méthode de calcul de MD5 du flux vidéo avec ffmpeg, on peut aller plus loin en générant une empreinte MD5 par frame, c’est-à-dire par image2 :

ffmpeg -i monFichierSource.mov -f framemd5 md5_mov.txt
ffmpeg -i monFichierCible.avi -f framemd5 md5_avi.txt
diff md5_mov.txt md5_avi.txt

Si toutes les frames ont la même empreinte d’un fichier à l’autre, cette dernière commande ne renverra rien. Il est possible d’ajouter l’option -s à la commande diff pour avoir un message explicite, même quand les résultats sont les mêmes.

Il faut ajouter que l’empreinte MD5 est alors calculée sur l’image une fois décodée (= décompressée). Par conséquent, cette méthode est pertinente même pour deux flux vidéo dont l’un est compressé avec un algorithme de compression sans perte.

Concernant les méthodes de comparaison de similarité perceptuelle, je nous signale également cette commande de ffmpeg, que je n’ai pas assez testée. Je développerai quand je l’aurai essayée !

Remerciements

Une fois de plus, cette page est une compilation de méthodes de contrôle signalées par Micky Lindlar, Johan van der Knijff, Juha Lehtonen, Dave Rice, Kris Dekeyser, Jordan de La Houssaye. Qu’iels en soient toustes remercié·e·s !!!

  1. Pour les raisons pour lesquelles les empreintes numériques renvoyées par la commande fpcalc de Chromaprint ne sont pas comparables telles quelles, vous pouvez vous reporter à cette réponse du développeur. ↩︎
  2. Plus de détails sur cette méthode sont disponibles dans le billet de blog de Dave Rice « Reconsidering the Checksum for Audiovisual Preservation », accessible sur <https://dericed.com/papers/reconsidering-the-checksum-for-audiovisual-preservation/>. ↩︎