Redimensionar e converter imagens em lote com ImageMagick
Gere versões de cada imagem com 480, 960 e 1.440 pixels de largura, tanto em WebP quanto em JPEG, para um site responsivo. Este script Bash cria um novo lote sem alterar os originais. Uma pequena página HTML permite que o navegador escolha entre os arquivos gerados.
O objetivo aqui é preparar vários tamanhos e um formato alternativo para a mesma imagem de um site. Para criar uma única cópia PNG por JPEG, incluindo pastas aninhadas, use o tutorial de JPEG para PNG.
Verificar as ferramentas e o escopo dos arquivos de entrada
Use Bash 5.3.15 e ImageMagick 7.1.2-31 no Linux com um sistema de arquivos que diferencie maiúsculas
e minúsculas neste tutorial. Execute os blocos de comandos no Bash. As opções de instalação do
ImageMagick 7 estão listadas nos downloads oficiais. Um pacote chamado
imagemagick pode fornecer a versão 6; este tutorial usa o executável
magick da versão 7. Ele não abrange shells nativos do Windows nem o Bash
mais antigo que acompanha o macOS.
bash --version && magick -version && magick -list format
Procure rw na lista de formatos para JPEG,
PNG e WEBP. O script lê arquivos de imagens
estáticas JPEG (.jpg ou .jpeg), PNG e WebP
diretamente em uma única pasta de entrada, incluindo arquivos ocultos e extensões com maiúsculas e
minúsculas misturadas. Ele ignora subdiretórios e links simbólicos. Cada imagem deve ter pelo menos
1.440 pixels de largura após a aplicação dos metadados de orientação. Imagens menores são rejeitadas,
não ampliadas. O script rejeita sequências que o decodificador expõe, incluindo WebP animado. Use
PNGs estáticos: como explicam as notas sobre o formato, o decodificador
PNG lê apenas o primeiro quadro de um PNG animado (APNG).
Este script não preserva animações.
As saídas são imagens opacas de 8 bits. Os pixels transparentes são compostos sobre um fundo branco
em ambos os formatos. A opção -colorspace sRGB do
ImageMagick converte as cores decodificadas antes da composição. Este é um procedimento local para
fotografias comuns da web, não um fluxo de trabalho de prova de cores ICC: arquivos sensíveis a
perfis de cor ou com ampla gama de cores precisam de uma
conversão com -profile apropriada antes da
remoção dos perfis. Guarde seus originais para esse trabalho.
Criar uma entrada reproduzível
Em um diretório de trabalho, crie uma imagem de exemplo dividida em metades azul e vermelha.
O && impede a gravação se input-images já existir.
Você pode usar esse diretório dentro de um projeto existente; os comandos não instalam pacotes nem
alteram a configuração desse projeto.
mkdir input-images &&
magick -size 2400x1600 xc:steelblue -fill tomato \
-draw 'rectangle 1200,0 2399,1599' -depth 8 jpeg:- > input-images/hero.jpg
Para seu próprio lote, coloque imagens compatíveis na pasta de entrada e mantenha-a inalterada
enquanto o script estiver em execução. Use outro diretório de trabalho se você já tiver uma pasta
input-images.
Salvar o script de processamento em lote
Salve o código a seguir em um novo arquivo batch-images.sh ao lado de
input-images. Cada arquivo de origem recebe um diretório com seu nome completo:
hero.jpg e hero.png permanecem distintos. O redirecionamento
do shell alimenta os fluxos padrão do ImageMagick, de modo que espaços,
hífens iniciais, colchetes e padrões % nos nomes dos arquivos sejam
tratados literalmente.
#!/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"
O script aplica -auto-orient
antes de verificar a largura. -resize '480x>'
limita a largura e preserva a proporção; os outros dois tamanhos funcionam da mesma forma. A largura
mínima de entrada garante que as três saídas tenham exatamente as larguras indicadas.
-quality 82 é uma configuração do codificador,
não 82% de qualidade visual nem uma promessa de redução no tamanho do arquivo. Ambas as saídas usam
codificação com perdas. Compare a aparência e o tamanho em bytes dos arquivos antes de escolher uma
configuração de qualidade para fotografias reais.
Executar e inspecionar o lote
bash batch-images.sh input-images web-images
Para o exemplo, uma execução bem-sucedida exibe Created six images for hero.jpg seguido de
Finished processing 1 source image(s) in ./web-images. O diretório contém hero.jpg/480.webp,
hero.jpg/960.webp e hero.jpg/1440.webp, além dos arquivos
.jpg correspondentes.
O original input-images/hero.jpg permanece inalterado. Uma nova execução recusa o diretório
web-images existente; escolha um novo destino para criar outro lote.
O script processa os nomes na ordem da localidade C, para no primeiro erro e retorna um status
diferente de zero, identificando o arquivo de origem.
Os arquivos derivados gerados com sucesso anteriormente permanecem, e um derivado com falha é
removido. Este é um lote parcial, não uma versão publicada: inspecione-o e corrija a origem antes de
executar novamente em um novo diretório.
Além de verificar o status, o script trata mensagens de diagnóstico como falhas, porque
-regard-warnings transforma apenas alguns avisos do
decodificador em erros. Um decodificador ainda pode recuperar conteúdo danificado sem emitir uma
mensagem de diagnóstico; uma conversão bem-sucedida não comprova que a entrada está intacta.
Verifique os seis arquivos derivados do exemplo lendo seus bytes, sem interpretar padrões nos nomes dos arquivos:
(
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
)
O resultado esperado é WEBP 480x320 e JPG 480x320, depois os
mesmos formatos em 960x640 e 1440x960.
Abra também as saídas: confirme que ambas as metades coloridas e as bordas externas estão presentes.
Nas suas próprias imagens, verifique a orientação, os elementos próximos às bordas e o fundo branco
onde havia pixels transparentes. As dimensões, por si só, não comprovam essas propriedades.
Usar os arquivos gerados em uma página responsiva
Salve este documento completo como web-images/preview.html. Ele faz referência às saídas
reais do exemplo; abra esse arquivo diretamente no navegador. Não é necessário um servidor para
esta prévia local das imagens.
<!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>
As regras de picture e srcset
permitem que um navegador compatível com WebP selecione arquivos da primeira fonte;
o img fornece candidatos JPEG e um src padrão.
Cada descritor w é a largura real do arquivo em pixels.
sizes descreve a largura exibida, correspondendo ao limite de 960 pixels do
CSS. Altere os caminhos, o texto alternativo, a proporção
width/height e sizes ao
adaptar o exemplo à sua página. Aplique codificação de URL aos nomes de arquivos com caracteres
especiais: um diretório chamado photo%03d.jpg precisa de
photo%2503d.jpg/480.webp em uma URL.
Para inspecionar o arquivo selecionado, abra o console de desenvolvedor do navegador e execute:
document.querySelector('img').currentSrc
Experimente carregar a página do zero em uma área de visualização estreita e depois em uma mais
larga. A proporção de pixels do dispositivo e a política de seleção do navegador também afetam a
escolha; redimensionar uma página já carregada pode manter uma imagem maior em cache. Remover o
elemento source em uma cópia temporária permite inspecionar a seleção de JPEG
no mesmo navegador. Uma URL WebP inválida não faz com que a alternativa JPEG seja selecionada
automaticamente.
Mantenha o conjunto completo de arquivos derivados junto ao incorporar a marcação ao seu site. A prévia local demonstra a geração dos arquivos e a seleção pelo navegador; faça medições na sua página real se precisar comprovar uma melhoria no tempo de carregamento ou no uso de banda.
