Redimensionnement et conversion d’images en lot avec ImageMagick
Générez des versions de 480, 960 et 1 440 pixels de chaque image, en WebP et en JPEG, pour un site web responsive. Ce script Bash écrit un nouveau lot sans modifier les originaux. Une petite page HTML laisse ensuite le navigateur choisir parmi les fichiers générés.
Il s’agit ici de préparer plusieurs tailles et un format de repli pour une même image de site web. Pour obtenir une seule copie PNG par JPEG, y compris dans des dossiers imbriqués, suivez le tutoriel de conversion JPEG vers PNG.
Vérifier les outils et le périmètre des entrées
Pour cette recette, utilisez Bash 5.3.15 et ImageMagick 7.1.2-31 sous Linux, avec un système de
fichiers sensible à la casse. Exécutez les blocs de commandes dans Bash. Les options d’installation
d’ImageMagick 7 sont répertoriées dans les téléchargements officiels.
Un paquet nommé imagemagick peut fournir la version 6 ; cette recette utilise
l’exécutable magick de la version 7. Elle ne couvre ni les shells Windows
natifs ni l’ancien Bash système de macOS.
bash --version && magick -version && magick -list format
Vérifiez que rw figure dans la liste des formats pour JPEG, PNG et WEBP. Le script lit les
fichiers d’images fixes JPEG (.jpg ou .jpeg), PNG et WebP placés directement dans un même dossier
d’entrée, y compris les fichiers cachés et les extensions en casse mixte. Il ignore les
sous-répertoires et les liens symboliques. Chaque image doit mesurer au moins 1 440 pixels de
large une fois les métadonnées d’orientation appliquées. Les images plus petites sont rejetées au
lieu d’être agrandies. Le script rejette les séquences exposées par le décodeur, y compris les WebP
animés. Utilisez des PNG fixes : comme l’expliquent les
notes sur les formats, le décodeur PNG ne lit que la première image
d’un PNG animé (APNG).
Ce script ne préserve pas l’animation.
Les sorties sont des images opaques en 8 bits. Les pixels transparents sont composités sur fond
blanc dans les deux formats. L’option -colorspace sRGB
d’ImageMagick convertit les couleurs décodées avant la composition. Il s’agit d’une recette locale
pour des photographies web ordinaires, et non d’un flux d’épreuvage ICC : les ressources sensibles
aux profils ou à large gamut nécessitent une
conversion -profile appropriée avant la
suppression des profils. Conservez vos originaux pour ce travail.
Créer une entrée reproductible
Dans un répertoire de travail, créez une image d’exemple divisée en deux moitiés, bleue et rouge.
Avec &&, l’écriture s’arrête si input-images existe déjà. Vous pouvez utiliser ce répertoire au sein
d’un projet existant ; les commandes n’installent aucun paquet et ne modifient pas la
configuration de ce projet.
mkdir input-images &&
magick -size 2400x1600 xc:steelblue -fill tomato \
-draw 'rectangle 1200,0 2399,1599' -depth 8 jpeg:- > input-images/hero.jpg
Pour votre propre lot, placez des images prises en charge dans le dossier d’entrée et ne le
modifiez pas pendant l’exécution du script. Utilisez un autre répertoire de travail si vous avez
déjà un dossier input-images.
Enregistrer le script de traitement par lots
Enregistrez le contenu suivant dans un nouveau fichier batch-images.sh à côté de input-images. Chaque source
obtient un répertoire nommé d’après son nom de fichier complet : hero.jpg et hero.png restent
distincts. La redirection du shell alimente les flux standard
d’ImageMagick, si bien que les espaces, les tirets initiaux, les crochets et les motifs %
dans les noms de fichiers restent littéraux.
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
shopt -s nullglob dotglob
if (( $# != 2 )); then
printf 'Usage: bash batch-images.sh INPUT_DIR NEW_OUTPUT_DIR\n' >&2
exit 1
fi
# A final slash preserves directory names ending in newlines during command substitution.
input_argument=$1
[[ "$input_argument" == /* ]] || input_argument="./$input_argument"
input=$(cd -P -- "$input_argument" && printf '%s/' "$PWD")
input=${input%/}
output=$2
[[ "$output" == /* ]] || output="./$output"
files=()
for file in "$input"/*; do
[[ -f "$file" && ! -L "$file" ]] || continue
case ${file,,} in
*.jpg|*.jpeg|*.png|*.webp) files+=("$file") ;;
esac
done
if (( ${#files[@]} == 0 )); then
printf 'No supported images in %s\n' "$input" >&2
exit 1
fi
# mkdir refuses existing destinations, including existing symbolic links.
mkdir -- "$output"
stage="$output/.source.miff"
diagnostics="$output/.diagnostics"
trap 'rm -f -- "$stage" "$diagnostics"' EXIT
fail_image() {
printf 'Could not process: %s\n' "$file" >&2
cat -- "$diagnostics" >&2
exit 1
}
for file in "${files[@]}"; do
name=${file##*/}
case ${file,,} in
*.jpg|*.jpeg) coder=jpeg ;;
*.png) coder=png ;;
*.webp) coder=webp ;;
esac
# Normalize once, before resizing or discarding the source metadata.
if ! magick -regard-warnings "$coder:-" -auto-orient -colorspace sRGB \
-background white -alpha remove -alpha off -strip -depth 8 miff:- \
< "$file" 2> "$diagnostics" > "$stage" || [[ -s "$diagnostics" ]]; then
fail_image
fi
if ! dimensions=$(magick -regard-warnings miff:- -format '%n %w %h\n' info: \
< "$stage" 2> "$diagnostics") || [[ -s "$diagnostics" ]]; then
fail_image
fi
if [[ ! "$dimensions" =~ ^1\ ([0-9]+)\ ([0-9]+)$ ]]; then
printf 'Expected one still image: %s\n' "$file" >&2
exit 1
fi
if (( BASH_REMATCH[1] < 1440 )); then
printf 'Image must be at least 1440 pixels wide after orientation: %s\n' "$file" >&2
exit 1
fi
mkdir -- "$output/$name"
for width in 480 960 1440; do
for format in webp jpg; do
target="$output/$name/$width.$format"
if ! magick -regard-warnings miff:- -resize "${width}x>" -quality 82 "$format:-" \
< "$stage" 2> "$diagnostics" > "$target" || [[ -s "$diagnostics" ]]; then
rm -f -- "$target"
fail_image
fi
done
done
printf 'Created six images for %s\n' "$name"
done
printf 'Finished processing %s source image(s) in %s\n' "${#files[@]}" "$output"
Le script applique -auto-orient
avant de vérifier la largeur. -resize '480x>'
limite la largeur tout en préservant les proportions ; les deux autres tailles fonctionnent de la
même façon. La largeur minimale en entrée garantit que les trois sorties ont exactement les
largeurs annoncées.
-quality 82 est un réglage de l’encodeur,
et non une qualité visuelle de 82 % ni une promesse de réduction de la taille des fichiers. Les
deux sorties utilisent un encodage avec pertes. Comparez l’apparence des fichiers et leur taille en
octets avant de choisir un réglage de qualité pour de vraies photographies.
Exécuter et inspecter le lot
bash batch-images.sh input-images web-images
Pour l’exemple, une exécution réussie affiche Created six images for hero.jpg suivi de
Finished processing 1 source image(s) in ./web-images. Le répertoire contient hero.jpg/480.webp,
hero.jpg/960.webp et hero.jpg/1440.webp, ainsi que les fichiers .jpg correspondants.
L’original input-images/hero.jpg reste inchangé. Une nouvelle exécution refuse le répertoire web-images
existant ; choisissez une nouvelle destination pour créer un autre lot.
Le script traite les noms dans l’ordre de la locale C, s’arrête à la première erreur et renvoie un
statut non nul en indiquant le fichier source.
Les dérivés déjà réussis sont conservés, et un dérivé en échec est supprimé. Il s’agit d’un lot
partiel, et non d’une version publiée : inspectez-le et corrigez la source avant de relancer le
script vers un nouveau répertoire. En plus de vérifier le statut, le script traite les diagnostics
comme des échecs, car -regard-warnings ne transforme
que certains avertissements du décodeur en erreurs. Un décodeur peut tout de même récupérer un
contenu endommagé sans émettre de diagnostic ; une conversion réussie ne prouve pas qu’une entrée
est intacte.
Vérifiez les six dérivés de l’exemple en lisant leurs octets, ce qui évite d’interpréter les noms de fichiers comme des motifs :
(
set -e
for width in 480 960 1440; do
for format in webp jpg; do
file="web-images/hero.jpg/$width.$format"
printf '%s: ' "$file"
magick "$format:-" -format '%m %wx%h\n' info: < "$file"
done
done
)
Vous devriez obtenir WEBP 480x320 et JPG 480x320, puis les mêmes formats en 960x640 et 1440x960.
Ouvrez aussi les sorties : vérifiez que les deux moitiés colorées et les bords extrêmes sont
présents. Avec vos propres images, vérifiez l’orientation, les sujets proches des bords et le fond
blanc là où les pixels étaient transparents. Les dimensions seules ne permettent pas d’établir ces
propriétés.
Utiliser les fichiers générés dans une page responsive
Enregistrez ce document complet sous le nom web-images/preview.html. Il fait référence aux sorties réelles de
l’exemple ; ouvrez ce fichier directement dans votre navigateur. Aucun serveur n’est nécessaire
pour cet aperçu local des images.
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Responsive image preview</title>
<style>
body { margin: 0; }
img { display: block; width: 100%; max-width: 960px; height: auto; }
</style>
<picture>
<source type="image/webp"
srcset="hero.jpg/480.webp 480w, hero.jpg/960.webp 960w, hero.jpg/1440.webp 1440w"
sizes="(max-width: 960px) 100vw, 960px">
<img src="hero.jpg/960.jpg"
srcset="hero.jpg/480.jpg 480w, hero.jpg/960.jpg 960w, hero.jpg/1440.jpg 1440w"
sizes="(max-width: 960px) 100vw, 960px"
width="1440" height="960" alt="Blue and red halves of a sample image">
</picture>
</html>
Les règles picture et srcset
permettent à un navigateur qui prend en charge WebP de choisir dans la première source ; img fournit
les candidats JPEG et un src par défaut. Chaque descripteur w correspond à la largeur réelle du
fichier en pixels. sizes décrit la largeur affichée, conforme à la limite CSS de 960 pixels.
Modifiez les chemins, le texte alternatif, le rapport width/height et sizes lorsque vous adaptez cet
exemple à votre propre page. Appliquez l’encodage URL aux noms de fichiers comportant des caractères
spéciaux : un répertoire nommé photo%03d.jpg nécessite photo%2503d.jpg/480.webp dans une URL.
Pour inspecter le fichier sélectionné, ouvrez la console de développement du navigateur et exécutez :
document.querySelector('img').currentSrc
Testez une page fraîchement chargée avec une fenêtre d’affichage étroite, puis avec une fenêtre plus
large. Le ratio de pixels de l’appareil et la politique de sélection du navigateur influent aussi
sur le choix ; redimensionner une page déjà chargée peut conserver une image plus grande en cache.
Supprimer l’élément source dans une copie temporaire vous permet d’inspecter la sélection JPEG dans le
même navigateur. Une URL WebP cassée n’entraîne pas automatiquement la sélection du repli JPEG.
Conservez l’ensemble complet des dérivés lorsque vous intégrez le balisage à votre site web. L’aperçu local illustre la génération des fichiers et la sélection par le navigateur ; mesurez votre page réelle si vous devez démontrer une amélioration du temps de chargement ou de la bande passante.
