Redimensionamento sensível ao conteúdo com PHP e ImageMagick
Use Imagick::liquidRescaleImage() para alterar as proporções de uma imagem sem esticar
uniformemente todos os objetos. Este guia produz um JPEG de 400 × 300 a partir de uma imagem local
em PHP. O seam carving pode remover espaços vazios ao redor de um objeto, mas também pode distorcer
o próprio objeto.
O que é redimensionamento sensível ao conteúdo?
O redimensionamento sensível ao conteúdo, ou seam carving, remove ou insere caminhos conectados de pixels chamados de costuras. Ele favorece caminhos com menor variação visual. Um objeto com textura sobre um fundo uniforme pode manter sua forma enquanto o fundo encolhe; já um rosto liso sobre um fundo com muitos detalhes pode ser distorcido. O algoritmo não reconhece qual objeto importa para você.
Pré-requisitos
A configuração abaixo se destina ao Debian 13 com PHP 8.4, Imagick 3.8 e ImageMagick 7. As versões testadas foram PHP 8.4.26, Imagick 3.8.0, ImageMagick 7.1.1-43 e liblqr 0.4.2. Use as atualizações mantidas pela distribuição dentro dessas linhas de versão; os números das versões de correção descrevem a configuração testada, sem representar um requisito mínimo intrínseco. O PHP 8.4 tem suporte.
Como root no Debian 13, instale os pacotes da CLI e da extensão:
apt-get update &&
apt-get install -y --no-install-recommends php8.4-cli php8.4-imagick imagemagick liblqr-1-0
O Debian fornece php8.4-imagick.
Os exemplos usam um JPEG RGB confiável, íntegro e de quadro único chamado
input.jpg em um diretório de trabalho com permissão de escrita. Guarde o
original. A validação de uploads, a animação e a conversão de perfis de cor estão fora do escopo
deste exemplo local de CLI.
Pré-requisitos adicionais
Instalar apenas a liblqr não basta: a biblioteca ImageMagick vinculada à extensão Imagick do PHP precisa ter sido compilada com ela. Antes de salvar os scripts, teste a operação pelo próprio PHP:
php -r '
$im = new Imagick();
$im->newImage(16, 16, "white");
$im->liquidRescaleImage(12, 16, 1, 0);
echo "Liquid rescale available\n";
'
Continue somente se o processo terminar com sucesso e imprimir Liquid rescale available.
A ausência da extensão ou de um delegado causa uma falha antes dessa mensagem. Se a instalação ou
esta verificação falhar, resolva o pré-requisito e repita essa etapa; nenhum arquivo de saída deste
artigo foi criado ainda.
Como usar liquid rescale em PHP
Salve este código como resize.php ao lado de input.jpg.
As duas dimensões de destino são medidas em pixels; altere-as conforme a saída de que você precisa.
<?php
$image = new Imagick();
try {
$image->readImage('input.jpg');
$targetWidth = 400;
$targetHeight = 300;
$deltaX = 1; // Maximum sideways step of a seam
$rigidity = 0; // Penalty for bending a seam
$image->liquidRescaleImage($targetWidth, $targetHeight, $deltaX, $rigidity);
$image->writeImage('output.jpg');
printf("Saved output.jpg (%d x %d)\n", $image->getImageWidth(), $image->getImageHeight());
} catch (ImagickException $e) {
fwrite(STDERR, "Image resizing failed.\n");
$failed = true;
} finally {
$image->clear();
}
if (isset($failed)) {
exit(1);
}
Execute-o nesse diretório:
php resize.php
Uma execução bem-sucedida imprime Saved output.jpg (400 x 300) e grava um JPEG de 400 × 300.
Abra-o ao lado do original: as dimensões confirmam o tamanho de destino, mas não confirmam a
preservação do objeto. Execuções bem-sucedidas substituem output.jpg.
Se ocorrer uma ImagickException, o script termina com status 1 e pode deixar uma saída
anterior no lugar, então confira o status de término antes de usar o arquivo.
Ajuste fino dos parâmetros
A operação liquid rescale é controlada por dois parâmetros principais:
- deltaX: Deslocamento lateral máximo de uma costura. Zero produz costuras retas; valores maiores dão às costuras mais liberdade para contornar o conteúdo da imagem.
- rigidity: Uma penalidade não negativa para a curvatura das costuras. Zero não adiciona penalidade; valores maiores favorecem costuras mais retas. Isso não garante a preservação de um rosto ou de outra característica importante.
Esses significados vêm da documentação dos parâmetros do Imagick. Inspecione o resultado em imagens representativas ao escolher os valores.
Considerações sobre desempenho
Se o original for grande, você pode reduzir a quantidade de pixels que entram no seam carving
fazendo primeiro um redimensionamento convencional. Salve esta versão separada como
resize-small.php. Ela ajusta imagens de entrada grandes demais para caberem em
800 × 600, preservando sua proporção, e depois aplica seam carving para chegar a 400 × 300. Ela pula
o redimensionamento inicial para imagens menores; sem essa condição, bestfit: true
pode ampliá-las, conforme descrito na
documentação de resizeImage.
<?php
$image = new Imagick();
try {
$image->readImage('input.jpg');
if ($image->getImageWidth() > 800 || $image->getImageHeight() > 600) {
$image->resizeImage(800, 600, Imagick::FILTER_LANCZOS, 1, true);
}
$image->liquidRescaleImage(400, 300, 1, 0);
$image->writeImage('optimized-output.jpg');
printf("Saved optimized-output.jpg (%d x %d)\n", $image->getImageWidth(), $image->getImageHeight());
} catch (ImagickException $e) {
fwrite(STDERR, "Image resizing failed.\n");
$failed = true;
} finally {
$image->clear();
}
if (isset($failed)) {
exit(1);
}
php resize-small.php
Este script imprime Saved optimized-output.jpg (400 x 300) em caso de sucesso, com o mesmo comportamento de
substituição e de falha do primeiro script. O redimensionamento inicial também reduz o objeto,
então as duas saídas podem ter aparências diferentes. Se a imagem ajustada tiver largura inferior
a 400 pixels ou altura inferior a 300, a operação final amplia essa dimensão. Compare os resultados
antes de escolher essa combinação de vantagens e limitações; ela não garante processamento mais
rápido nem melhor qualidade.
Problemas comuns e soluções
Erros de alocação de memória
O memory_limit do PHP não limita de forma confiável as alocações nativas do
ImageMagick. Configure os
limites de recursos e a política de segurança do ImageMagick,
incluindo memória, cache em disco, dimensões e tempo de processamento, conforme sua carga de
trabalho. Informe as falhas causadas por limites de recursos em vez de tentar processar a mesma
imagem grande demais indefinidamente.
Ausência de suporte a liblqr
Inspecione a versão vinculada à extensão com:
php --ri imagick
A CLI independente do ImageMagick pode usar uma compilação diferente. Um delegado listado por
magick ou pelo convert do ImageMagick 6 não comprova
que o PHP pode usá-lo. Repita a operação em PHP da seção “Pré-requisitos adicionais” após instalar
uma compilação compatível. Reinicie todos os processos executores PHP de longa duração que usam a
biblioteca antiga. Os scripts salvos informam Image resizing failed. e terminam com status 1
quando a chamada a liquid rescale falha.
Preservação da qualidade
A decodificação de JPEG pode recuperar parte de um arquivo danificado e ainda produzir uma saída. Estes scripts não verificam a integridade da entrada; use um original íntegro e inspecione todo o resultado, incluindo a borda inferior.
Inspecione rostos, letras, bordas retas e padrões repetidos. Os exemplos de seam carving do ImageMagick explicam por que fundos com muitos detalhes podem fazer o algoritmo remover pixels do primeiro plano. Nem uma rigidez maior nem o aumento da nitidez protegem um objeto específico. Para fotos em que a forma importa, compare com o redimensionamento proporcional ou com um recorte explícito e escolha o resultado que mantém o conteúdo de que você precisa.
Conclusão
Experimente o script em algumas imagens da sua própria carga de trabalho antes de aplicá-lo a um lote. Para redimensionamento de imagens e conversão de formatos em um serviço hospedado, explore a API de processamento de imagens da Transloadit.
