Redimensionado y conversión de imágenes por lotes con ImageMagick
Genera versiones de 480, 960 y 1.440 píxeles de ancho de cada imagen, tanto en WebP como en JPEG, para un sitio web adaptable. Este script de Bash escribe un lote nuevo sin modificar los originales. Una pequeña página HTML permite luego que el navegador elija entre los archivos generados.
La tarea consiste en preparar varios tamaños y un formato alternativo para una misma imagen web. Para obtener una sola copia PNG por cada JPEG, incluidas las carpetas anidadas, usa la guía de conversión de JPEG a PNG.
Comprueba las herramientas y el alcance de las entradas
Usa Bash 5.3.15 e ImageMagick 7.1.2-31 en Linux con un sistema de archivos que distinga mayúsculas
de minúsculas para esta guía.
Ejecuta los bloques de comandos en Bash. Las opciones de instalación de ImageMagick 7 aparecen en las
descargas oficiales. Un paquete llamado imagemagick puede
proporcionar la versión 6; esta guía usa el ejecutable magick de la versión 7.
No cubre los intérpretes de comandos nativos de Windows ni la versión antigua de Bash del sistema macOS.
bash --version && magick -version && magick -list format
Busca rw en la lista de formatos para JPEG, PNG y WEBP.
El script lee archivos de imágenes estáticas JPEG
(.jpg o .jpeg), PNG y WebP ubicados directamente en una carpeta de entrada,
incluidos los archivos ocultos y las extensiones que combinan mayúsculas y minúsculas.
Omite los subdirectorios y los enlaces simbólicos. Cada imagen debe tener al menos
1.440 píxeles de ancho después de aplicar los metadatos de orientación. Las imágenes más pequeñas
se rechazan en lugar de ampliarse. El script rechaza las secuencias que expone el decodificador,
incluido WebP animado. Usa imágenes PNG estáticas: como explican las
notas sobre el formato, el decodificador de PNG
solo lee el primer fotograma de un PNG animado (APNG).
Este script no conserva la animación.
Los resultados son imágenes opacas de 8 bits. Los píxeles transparentes se componen sobre un fondo
blanco en ambos formatos.
La opción -colorspace sRGB de ImageMagick convierte
los colores decodificados antes de la composición. Esta es una guía local para fotografías web
comunes, no un flujo de trabajo de pruebas de color ICC: los activos sensibles a los perfiles o con
una gama de colores amplia necesitan una
conversión con -profile adecuada antes de eliminar
los perfiles. Conserva los originales para ese trabajo.
Crea una entrada reproducible
En un directorio de trabajo, crea una imagen de ejemplo dividida en mitades azul y roja.
&& impide la escritura si input-images ya existe.
Puedes usar este directorio dentro de un proyecto existente;
los comandos no instalan paquetes ni cambian la configuración de ese proyecto.
mkdir input-images &&
magick -size 2400x1600 xc:steelblue -fill tomato \
-draw 'rectangle 1200,0 2399,1599' -depth 8 jpeg:- > input-images/hero.jpg
Para tu propio lote, coloca imágenes compatibles en la carpeta de entrada y mantenla sin cambios
mientras se ejecuta el script. Usa otro directorio de trabajo si ya tienes una carpeta
input-images.
Guarda el script de procesamiento por lotes
Guarda lo siguiente como un archivo nuevo batch-images.sh junto a input-images.
Cada archivo de origen recibe un directorio con su nombre completo:
hero.jpg y hero.png siguen siendo distintos.
La redirección del intérprete de comandos alimenta los
flujos estándar de ImageMagick, de modo que los espacios,
los guiones iniciales, los corchetes y los patrones % en los nombres de archivo
se mantienen literales.
#!/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"
El script aplica -auto-orient
antes de comprobar el ancho. -resize '480x>'
limita el ancho y conserva la relación de aspecto; los otros dos tamaños funcionan de la misma
manera. El ancho mínimo de entrada garantiza que los tres resultados tengan exactamente los anchos
indicados.
-quality 82 es un ajuste del codificador,
no un 82 % de calidad visual ni una reducción prometida del tamaño del archivo. Ambos resultados usan
codificación con pérdida. Compara el aspecto y los tamaños en bytes de los archivos antes de elegir
un ajuste de calidad para fotografías reales.
Ejecuta e inspecciona el lote
bash batch-images.sh input-images web-images
Para el ejemplo, una ejecución correcta imprime Created six images for hero.jpg seguido de
Finished processing 1 source image(s) in ./web-images. El directorio contiene hero.jpg/480.webp,
hero.jpg/960.webp y hero.jpg/1440.webp, además de los archivos .jpg correspondientes.
El original input-images/hero.jpg no se modifica. Una nueva ejecución rechaza el directorio
web-images existente; elige un destino nuevo para crear otro lote.
El script procesa los nombres según el orden de la configuración regional C, se detiene ante el
primer error y devuelve un estado distinto de cero que identifica el archivo de origen.
Los derivados anteriores generados correctamente se conservan, y cualquier derivado que falle se
elimina. Este es un lote parcial, no una versión publicada: inspecciónalo y corrige el archivo de
origen antes de volver a ejecutar el script con un directorio nuevo.
Además de comprobar el estado, trata los mensajes de diagnóstico como fallos, porque
-regard-warnings solo convierte algunas
advertencias del decodificador en errores. Un decodificador aún puede recuperar contenido dañado sin
emitir un diagnóstico; una conversión correcta no demuestra que una entrada esté intacta.
Comprueba los seis derivados del ejemplo leyendo sus bytes, sin interpretar patrones en los nombres de archivo:
(
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
)
Deberías obtener WEBP 480x320 y JPG 480x320, y luego los mismos formatos a 960x640 y 1440x960.
Abre también los resultados: confirma que aparezcan ambas mitades de color y los bordes exteriores.
Con tus propias imágenes, comprueba la orientación, los sujetos cercanos a los bordes y el fondo
blanco donde los píxeles eran transparentes. Las dimensiones por sí solas no permiten confirmar
esas propiedades.
Usa los archivos generados en una página adaptable
Guarda este documento completo como web-images/preview.html. Hace referencia a los archivos
reales generados en el ejemplo; abre ese archivo directamente en tu navegador. No se necesita un
servidor para esta vista previa local de imágenes.
<!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>
Las reglas de picture y srcset
permiten que un navegador compatible con WebP seleccione entre los archivos de la primera fuente;
img proporciona candidatos JPEG y un src predeterminado.
Cada descriptor w es el ancho real del archivo en píxeles.
sizes describe el ancho mostrado, que coincide con el límite CSS de 960 píxeles.
Cambia las rutas, el texto alternativo, la relación
width/height y sizes al adaptar esto a tu propia página.
Aplica codificación de URL a los nombres de archivo con caracteres especiales: un directorio llamado
photo%03d.jpg necesita photo%2503d.jpg/480.webp en una URL.
Para inspeccionar el archivo seleccionado, abre la consola de desarrollo del navegador y ejecuta:
document.querySelector('img').currentSrc
Prueba una página recién cargada en una ventana de visualización estrecha y luego en una más ancha.
La relación de píxeles del dispositivo y la política de selección del navegador también influyen
en la elección; al cambiar el tamaño de una página ya cargada, puede conservarse una imagen más
grande en caché. Eliminar el elemento source en una copia temporal te permite
inspeccionar la selección de JPEG en el mismo navegador. Una URL de WebP rota no hace que se
seleccione automáticamente la alternativa JPEG.
Mantén todo el conjunto de derivados junto al trasladar el marcado a tu sitio web. La vista previa local demuestra la generación de archivos y la selección del navegador; mide tu página real si necesitas confirmar una mejora en el tiempo de carga o en el uso del ancho de banda.
