Recréer les fichiers AVIF corrompus

Cela fait une paire de fois que les images au format AVIF ne s’affichent pas sur SkyMinds et aujourd’hui, on règle le problème une bonne fois pour toute.

Concrètement, à chaque fois que j’uploade une image dans la bibliothèque de média de WordPress, plusieurs images sont créés: les miniatures bien sûr mais aussi un jeu d’images au format WEBP et au format AVIF. Tout se fait de manière automatique avec ShortPixel lors de l’upload.

Or, dernièrement certaines images ne s’affichent plus. Si on retire la source AVIF du DOM du document, le WEBP s’affiche bien, tout comme l’image originale en PNG ou JPG. C’est donc au niveau de la compression AVIF que cela coince.

Procédure de debug

Configuration NginX

Si vous vous souvenez bien, j’ai dans ma configuration NginX des directives pour donner la précédence aux formats AVIF et WEBP sur toutes mes images. Cela permet de servir en priorité les fichiers images aux formats les plus récents, avec un fallback sur les formats plus anciens (JPG, PNG notamment).

J’ai passé la configuration au peigne fin et il n’y a pas de problème à ce niveau. Les fichiers AVIF sont bien servis, le problème se trouve plus au niveau de l’encodage des fichiers.

Tester les images affectées

Lorsque je visionne un article avec une image affectée par le bug, elle ne saffiche pas mais apparait comme une image cassée. Lorsque l’on ouvre l’image dans un nouvel onglet, on obtient l’erreur suivante: “the image cannot be displayed because it contains errors“.

Je ne connais pas le nom des images affectées ni leur nombre (cela inclut aussi les miniatures) donc le plus simple est de dresser la liste des fichiers AVIF sur le site. Ensuite, je veux inspecter chaque image pour vérifier qu’elles possèdent bien les entêtes et bits nécessaires à leur bon affichage.

Commençons par installer les outils nécessaires pour examiner les fichiers AVIF:

apt install libavif-bin libavif13

On lance un test sur un fichier problématique:

avifdec /home/www/example/wp-content/uploads/2021/05/the-handmaids-tale-june-nick.avif /dev/null Code language: JavaScript (javascript)

et voici le résultat:

Decoding with AV1 codec 'dav1d' (1 worker thread), please wait... 
ERROR: Failed to parse image: BMFF parsing failed 
Diagnostics: * Box[meta] does not have a Box[hdlr] as its first child boxCode language: JavaScript (javascript)

L’erreur (“ERROR: Failed to parse image: BMFF parsing failed”), suggère que le fichier est en effet soit corrompu, soit incompatible donc nous allons le recréer.

Un script bash pour recréer tous les fichiers AVIF corrompus

Il est évident que nous n’allons pas tester tous les fichiers un par un. Maintenant que nous avons pu tester un fichier, nous allons créer une boucle pour tester tous les fichiers qui ont été uploadés sur le site : si le fichier est corrompu, nous allons le recréer, sinon on passe au suivant.

Voici le script que j’ai écrit pour récréer les fichiers AVIF:

nano check-avif.shCode language: CSS (css)
#!/bin/bash

# Script Name: Recreate corrupted AVIF images
# Script URI : https://www.skyminds.net/recreer-fichiers-avif-corrompus/
# Author: Matt Biscay
# Author URL: https://www.skyminds.net 

# Directory to search for AVIF files
SEARCH_DIR="/home/www/example/public_html/wp-content/uploads"

# Dry run mode flag
DRY_RUN=0

# Check for --dry-run option
if [ "$1" == "--dry-run" ]; then
  DRY_RUN=1
  echo "Dry run mode enabled. No files will be modified."
fi

# Function to check if AVIF file is corrupted
check_avif() {
  local output
  output=$(avifdec "$1" /dev/null 2>&1)
  local status=$?
  if [ $status -ne 0 ]; then
    if echo "$output" | grep -q -E "ERROR: Failed to decode image|Failed to read image|ERROR: Failed to parse image"; then
      return 1
    fi
  fi
  return 0
}

# Function to convert other image formats to AVIF
convert_to_avif() {
  convert "$1" "$2"
}

# Loop through all AVIF files in the directory
find "$SEARCH_DIR" -type f -iname "*.avif" | while read -r avif_file; do
#  echo "Checking file: $avif_file"

  # Check if AVIF file is corrupted
  if ! check_avif "$avif_file"; then
    echo -e "\033[31mCorrupted AVIF file found: $avif_file\033[0m"  # Marking in red

    # Try to find the original image file
    original_file=$(echo "$avif_file" | sed -e "s/\.avif$//")

    for ext in png jpg jpeg webp; do
      if [ -f "${original_file}.${ext}" ]; then
        original_file="${original_file}.${ext}"
        break
      fi
    done

    # Check if original file exists
    if [ ! -f "$original_file" ]; then
      echo "Original file for $avif_file not found. Skipping."
      continue
    fi

    # Recreate the AVIF file
    if [ $DRY_RUN -eq 0 ]; then
      echo "Recreating AVIF file from $original_file"
      convert_to_avif "$original_file" "$avif_file"
    else
      echo "Would recreate AVIF file from $original_file (dry run)"
    fi
#  else
#    echo "File is valid: $avif_file"
  fi
done

Code language: PHP (php)

Fonctionnement du script

Contexte et configuration initiale

Le script commence par définir un terrain de jeu : le répertoire de recherche. Spécifié comme "/home/www/example/public_html/wp-content/uploads", ce chemin représente le lieu où le script va chercher activement les fichiers AVIF à examiner. Il vous suffit d’éditer la variable SEARCH_DIR pour refléter le chemin de vos fichiers.

Le mode Dry Run : une précaution nécessaire

Avant de plonger dans la réparation des fichiers, le script introduit une option de sécurité : le mode Dry Run. Ce mode, activé par l’option --dry-run, permet au script de s’exécuter sans apporter de modifications réelles aux fichiers. C’est un filet de sécurité pour les utilisateurs qui souhaitent voir les opérations prévues du script sans affecter leurs données réelles.

Identification des fichiers corrompus

Au cœur du script se trouve la fonction check_avif, une méthode astucieuse pour déterminer si un fichier AVIF est corrompu. En utilisant avifdec, le script tente de décoder chaque fichier AVIF vers une destination neutre (/dev/null). Si cette opération échoue avec des messages d’erreur spécifiques, le script reconnaît le fichier comme corrompu. Cette étape est cruciale, car elle assure que seuls les fichiers réellement endommagés sont pris en compte pour la réparation.

Conversion et réparation des fichiers

Pour les fichiers identifiés comme corrompus, le script entreprend une quête pour trouver leur version originale. En retirant l’extension .avif et en cherchant parmi d’autres formats populaires (PNG, JPG, JPEG, WEBP), le script essaie de localiser la source d’origine de l’image corrompue.

Une fois cette image trouvée, le script utilise la fonction convert_to_avif pour recréer le fichier AVIF. Cette méthode garantit que les images sont restaurées à leur état d’origine, préservant ainsi la qualité et l’intégrité des données visuelles.

On peut d’abord lancer le script en mode --dry-run, pour avoir un aperçu des éventuelles recréation de fichiers:

./check-avif.sh --dry-run

Une fois que les tests ont été effectués et que vous avez trouvé des fichiers AVIF corrompus, il ne reste plus qu’à les corriger et les rendre de nouveau opérationnels et visibles dans tous les navigateurs:

./check-avif.sh 

Voilà, un petit script à garder dans sa trousse à outils, cela peut toujours servir!

Vous voulez un site WordPress ou WooCommerce qui soit à la fois rapide et performant? Vous êtes au bon endroit.

Découvrez comment je peux booster votre site »

Articles conseillés :

Matt

Matt Biscay est développeur WordPress et WooCommerce certifié chez Codeable, ainsi que sysadmin qualifié et enseignant-chercheur. Passionné par le code performant et les solutions sécurisées, je m'efforce d'offrir une expérience utilisateur exceptionnelle sur chaque projet.

Vous avez aimé cet article ? Vous avez un projet en tête et vous pensez que je pourrais vous aider à le concrétiser ? N'hésitez pas à me contacter, je serais ravi de discuter avec vous de votre projet !

Opinions