Exemplos do ImageMagick -- API e Scripts
- Windows e DOS
- PHP
- PHP usando comandos de shell
- PHP Imagick (a API ImageMagick para PHP)
-
PerlMagick (scripts Perl Magick)
-
Metacaracteres em nomes de arquivo
Dicas para melhores scripts de shell/PHP com ImageMagick Por que usar vários comandos "magick" Tornando o IM mais rápido (em geral) Compilando o ImageMagick a partir do código-fonte
- ImageMagick a partir do código-fonte no Ubuntu
- ImageMagick no MacOSX
- Compilando versões HDRI do IM
- Criando uma instalação pessoal do ImageMagick
A interface de linha de comando (CLI) do ImageMagick, de que estes exemplos tratam, é apenas um dos métodos para usar, modificar e controlar imagens com a biblioteca central de funções do ImageMagick (MagickCore). Trata-se basicamente da interface de API do 'shell'. Existem muitas outras interfaces de programação de aplicações (APIs) que podem ser usadas de forma mais direta a partir de diversas linguagens de programação; veja ImageMagick APIs. Aqui são examinadas formas de aprimorar os scripts e a programação com o IM, as diferenças entre a criação de scripts no Windows e no Unix, além dos fundamentos do uso do IM a partir de outras APIs e linguagens de programação.
APIs e outros métodos de uso do IM
As APIs (interfaces de programação de aplicações) para o processamento de imagens em si não são, na verdade, mais rápidas do que usar os comandos da CLI (como o "magick", que por si só representa um tipo de API de shell). A mesma biblioteca 'central' é usada para todo o processamento de imagens no IM. Portanto, ao realizar uma tarefa complexa, como a distorção de uma imagem, usar uma API em vez do "magick" do shell faz muito pouca diferença em termos de 'velocidade' geral do processamento. Então por que usar uma API em vez da linha de comando? Um shell 'bifurca' constantemente muitos comandos diferentes (não apenas comandos "magick" do IM, embora os shells tenham alguns 'embutidos'), cada um dos quais precisa ser carregado e inicializado toda vez que é executado. Todo comando do IM também precisa reinicializar seus arquivos de configuração, analisar os argumentos da linha de comando, reler quaisquer imagens com que se esteja trabalhando e, muitas vezes, salvar os resultados de volta no disco. Tudo isso leva tempo, tornando-os mais lentos. Ou seja, todos esses passos extras consomem tempo e capacidade de processamento; portanto, quando isso é feito com frequência, uma API começa a fazer sentido. Uma API também permite fazer outras coisas que a linha de comando não permite.
- Se a API já estiver em execução, o tempo de configuração é mínimo ou nulo.
- Manter na memória um vetor com muitas listas de imagens que podem ser processadas em qualquer ordem desejada. Por exemplo, há um programa que lê centenas de imagens, gerando miniaturas de 32x32 pixels à medida que as lê e, então, comparando todas elas em pares, um par de cada vez com o magick (9.900 comparações para 100 imagens). Outro exemplo seria ordenar as imagens na memória pela cor geral!
- É possível conduzir muitas linhas distintas de processamento de imagens, em qualquer ordem. Não é necessário 'terminar' uma sequência de processamento antes de trabalhar na próxima imagem ou etapa. Por exemplo, imagine um programa que resolve um quebra-cabeça!
- É possível obter informações das imagens e usar essas informações de maneiras complexas para modificar o processamento sem ter de reinicializar o processamento de imagens (relendo configurações e imagens) repetidas vezes. Por exemplo, obter o tamanho da imagem antes de determinar os requisitos de enquadramento dela.
- Percorrer as imagens em laço, fazendo algo bem diferente com cada uma delas! Por exemplo, gerar uma sequência de animação com cada quadro distorcido de uma forma ligeiramente diferente.
- Acesso direto e completamente aleatório aos dados da imagem. Por exemplo, procurar um 'rosto' em uma imagem.
Mas, para a maioria das tarefas que não envolvem grandes quantidades de imagens, ou o processamento geral de imagens de maneiras bem definidas, a linha de comando é praticamente igual de rápida. Ainda assim, é possível economizar bastante tempo e reprocessamento ao... * Fazer uso do salvamento de imagens MPC (para releituras mais rápidas) de imagens intermediárias. Veja o script divide_vert * Processamento paralelo usando encadeamento por pipes (até mesmo usando máquinas diferentes para etapas diferentes!), para aproveitar melhor o processador e evitar salvar imagens intermediárias no disco. Veja o enlarge_image como exemplo de script encadeado, em que uma etapa envia por pipe a(s) imagem(ns) para a próxima etapa (às vezes opcional) da sequência. * Usar um laço para processar cada imagem individualmente, antes de enviar por pipe um fluxo de imagens resultantes para uma etapa final que 'mescla tudo'. Há muitos scripts assim... Veja o posicionamento programado de imagens em camadas para um exemplo desse tipo de script.
É claro que, em uma API, também há técnicas diferentes e mais rápidas que poderiam ser usadas para uma tarefa de processamento especial que exigisse acesso à imagem. E, à medida que essas técnicas são descobertas e há tempo disponível, elas costumam ser incorporadas à biblioteca central. As distorções de imagem e as várias expressões de FX são um exemplo disso.
Windows e DOS
Os exemplos sobre a criação de scripts no Windows e no DOS usando a API da CLI foram movidos para Uso no Windows.
PHP (comandos do IM a partir das funções "system()")
Os usuários de PHP têm três maneiras de usar o ImageMagick,
- A "
imagickinterface PECL - A interface "
MagicWand" - Usar as funções "system()" e "exec()" para executar o comando "
magick" da CLI.
Por causa da existência dos Exemplos do IM, este último método (e o primeiro, que será visto a seguir) tornou-se, nos últimos anos, a forma mais comum de usar o IM a partir do PHP. É claro que, para algumas tarefas, pode não ser o melhor método (veja acima), caso em que as interfaces de API estão disponíveis, embora possam exigir que um administrador de sistema as disponibilize no ambiente PHP.
PHP usando comandos de shell
A melhor fonte de informações específicas sobre o uso desta técnica é o usuário do fórum do IM Bonzo e o seu site RubbleWebs. Observe que o PHP executa o "magick" em um ambiente diferente, e provavelmente até como um usuário diferente, do que se obteria a partir da linha de comando. Assim, o que funciona na linha de comando pode exigir alguns ajustes para funcionar a partir de um script PHP acionado pela web. O procedimento a seguir é o recomendado para os testes iniciais da interface de linha de comando do IM de um provedor, supondo que não haja acesso direto ao 'shell' de linha de comando no sistema remoto. Ou seja, só é possível enviar arquivos web para execução. Portanto, a primeira coisa a fazer é tentar localizar o comando "magick" no sistema, saber qual versão está instalada e conhecer o ambiente em que o PHP é executado. Em um serviço web Linux, envie este script PHP para o servidor web do provedor e acesse-o...
<?php
header('Content-Type: text/plain');
system("exec 2>&1; pwd");
system("exec 2>&1; type magick");
system("exec 2>&1; locate */magick");
system("exec 2>&1; magick -version");
system("exec 2>&1; magick -list type"); <!-- before IM v6.3.5-7 -->
system("exec 2>&1; magick -list font");
print("------ENVIRONMENT VARIABLES-------\n");
system("exec 2>&1; env");
?>
Isso executa uma boa quantidade de comandos para verificar como é o ambiente. O primeiro, "pwd", indica o diretório atual em que o script PHP foi executado. Esse diretório pode ou não ser aquele onde o script PHP está localizado, e talvez não seja possível gravar nele a partir do script PHP. Os dois comandos seguintes indicam, usando "type", se o "magick" está disponível no PATH de comandos padrão e, em caso afirmativo, onde ele está. O comando "locate" deveria encontrar todos os comandos "magick" que existem no servidor (supondo que seja um servidor linux), mas pode encontrar também outros comandos, arquivos e diretórios "magick" que não sejam do ImageMagick. Será preciso interpretar os resultados. Os três comandos seguintes supõem que o "magick" está no PATH de comandos e pedem que ele informe o número da versão e quais fontes o IM julga ter acesso. Qual comando informa quais fontes depende de quão antiga é a versão instalada do IM. Se aparecerem apenas erros, então o "magick" não está no caminho da linha de comando, e o provedor NÃO inicializou corretamente o "PATH" e o "LD_LIBRARY_PATH" do servidor web para incluí-lo. Veja a saída do comando "env" para saber o que foi definido. Nesse caso, será preciso descobrir exatamente onde ele está localizado e usar algo como o script PHP a seguir. Isso torna o script menos portável, pois fica embutido de forma fixa para aquele provedor específico. Por exemplo, suponha que o comando "magick" esteja em "/opt/php5extras/ImageMagick/bin"; então é possível definir uma variável para especificar sua localização. Isso costuma ser feito como parte do processo de configuração e instalação da aplicação, para scripts PHP usados em diferentes hosts de provedores),
<?php
$im_path="/opt/php5extras/ImageMagick/bin"
header('Content-Type: text/plain');
system("exec 2>&1; $im_path/magick -version");
system("exec 2>&1; $im_path/magick -list type");
system("exec 2>&1; $im_path/magick -list font");
?>
Se ocorrerem erros de biblioteca do "ldd", o "LD_LIBRARY_PATH" está incorreto, e o provedor certamente falhou na tarefa durante a instalação; é preciso relatar o erro e pedir que corrijam a configuração da variável de ambiente "LD_LIBRARY_PATH" do servidor web, ou que reinstalem o ImageMagick. Em vez de definir a localização do comando magick, também é possível ajustar a variável de ambiente PATH com uma linha como esta no início. No entanto, esse método costuma ser 'negado' por padrão pela configuração típica de sistema do PHP...
putenv("PATH=" . $_ENV["PATH"] . ":/opt/php5extras/ImageMagick/bin");
putenv("LD_LIBRARY_PATH=" . $_ENV["LD_LIBRARY_PATH"] .
":/opt/php5extras/ImageMagick/lib");
Depois disso, experimente alguns dos exemplos mais simples dos Exemplos do IM e tente fazê-los funcionar. Por exemplo, para enviar a imagem 'rose' do IM como um arquivo de imagem JPEG de volta ao usuário da web...
<?php
header( 'Content-Type: image/jpeg' );
passthru("magick rose: jpg:-");
?>
Se for necessário definir a localização do comando magick, é possível usar...
<?php
header( 'Content-Type: image/jpeg' );
$magick="/opt/php5extras/ImageMagick/bin/magick"
passthru("$magick rose: jpg:-");
?>
ou, se houver problemas de biblioteca, é possível tentar algo como...
<?php
header( 'Content-Type: image/jpeg' );
$magick="/opt/php5extras/ImageMagick/bin/magick";
$libs="LD_LIBRARY_PATH=\'" . $_ENV["LD_LIBRARY_PATH"] .
":/opt/php5extras/ImageMagick/bin/magick\'";
system("$libs $magick rose: jpg:-");
?>
Se ainda assim nada aparecer, consulte o arquivo bruto Dicas e truques de PHP para obter informações sobre técnicas de redirecionamento de mensagens de erro.
Quando esse script básico estiver funcionando, é possível experimentar uma das fontes listadas pelos scripts de teste PHP (modifique o exemplo a seguir conforme o seu servidor PHP). Por exemplo, em um servidor Solaris disponível na época, notou-se que o conjunto de fontes 'Utopia' estava disponível, o que permitiu tentar criar um rótulo com essa fonte...
<?php
header('Content-Type: image/gif');
passthru("magick -pointsize 72 -font Utopia-Italic label:'Font Test' gif:-");
?>
Exemplo de conversão de shell para PHP
Aqui está um comando ImageMagick bastante típico...
magick -background none -fill red -gravity center \
-font Candice -size 140x92 caption:"A Rose by any Name" \
\( rose: -negate -resize 200% \) +swap -composite output.gif
Ao convertê-lo para PHP, ele se torna algo como...
<?php
header('Content-Type: image/gif');
$color="red";
$image="rose:";
$scale="200%";
$size="140x96";
$string="A Rose by any Name";
passthru( "magick -background none -fill '$color' -gravity center" .
" -font Candice -size '$size' caption:'$string'" .
" \\( '$image' -negate -resize '$scale' \\) +swap -composite" .
" gif:-" );
?>
Observe como a longa linha de comando do "magick" ainda é dividida para tornar a sequência de processamento de imagem mais fácil de acompanhar e de editar depois. Isso foi feito com concatenação de strings em PHP, em vez da continuação de linha do shell usada em scripts de shell. Note também o espaço extra no início das linhas seguintes, e a duplicação das demais barras invertidas que existiam no comando original. Como alternativa, é possível proteger essas opções usando aspas simples em vez de barras invertidas. Também foram usadas algumas variáveis PHP para facilitar o ajuste da imagem gerada pelo script PHP e ter melhor controle dos resultados. No entanto, ao inserir essas opções no "magick", usaram-se aspas simples para protegê-las de novas modificações pelo shell. Mas cuidado com aspas simples dentro dessas strings inseridas! Essas opções poderiam se tornar argumentos de entrada do PHP, permitindo gerar uma imagem para qualquer texto de entrada passado a partir de uma requisição web. Também é possível executar vários comandos de shell dentro da mesma string de chamada de system. Na verdade, uma única chamada de system pode conter um script de shell completo, se desejado! Assim, é possível fazer laços de shell e vários comandos (com limpezas) tudo em uma única chamada de system. Algo que poucas pessoas percebem ser possível. Basicamente, com cuidado, é possível aproveitar bem a matemática fornecida pelo PHP e os recursos de scripting do shell. Tudo ao mesmo tempo. Apenas atente para as aspas. Para vários exemplos de chamada de comandos ImageMagick a partir do PHP, veja Rubble Web, escrevendo código IM em PHP, que descreve cerca de quatro técnicas diferentes.
Atenção às aspas extras
Note que, normalmente, os comandos do IM em PHP são envolvidos por um conjunto extra de aspas (geralmente aspas duplas); por isso, é preciso ter cuidado para acomodar o uso desse nível adicional de aspas. Lembre-se de que, quando o PHP executa uma string.... o PHP faz suas substituições de aspas, barras invertidas e variáveis; o Shell então divide os argumentos e faz suas próprias substituições de variáveis e aspas. Ele também executa quaisquer redirecionamentos de descritores de arquivo do tipo "2>&1", se presentes. O ImageMagick recebe um vetor de argumentos, mas também realiza seu próprio tratamento de metacaracteres de nome de arquivo especificamente para o DOS (o ambiente dos não trata metacaracteres) e para argumentos como coder:*.gif[50x50], que o shell não consegue expandir por causa do prefixo coder: ou do modificador de leitura [...]. Ou seja, MUITA análise de argumentos! O que pode significar muito tratamento de aspas e barras invertidas. Cautela e previsão são necessárias. Recomenda-se ler, no mínimo, os manuais do PHP sobre funções de execução de programas, que incluem: PHP exec(), system() e passthru(). Veja também o operador de crase. É especialmente importante compreender o que exatamente é retornado (geralmente apenas a última linha) e o que é repassado ao cliente que faz a chamada (todo o restante).
Segurança em PHP
Lembre-se...
_Na internet, os únicos usuários em quem se pode confiar como não
potencialmente hostis são aqueles que são *ativamente* hostis.
-- Programming Perl - Camel Book, r3_
É preciso verificar minuciosamente todos os argumentos de entrada passados pelo usuário a um comando do IM. Certifique-se de que o argumento seja exatamente o esperado. É muito melhor ser restritivo demais do que de menos ao lidar com a World Wide Web. Algumas coisas comuns a observar incluem
- Caracteres binários no argumento — uma técnica comum de invasores
- Espaços, tabulações, quebras de linha e retornos inesperados nos argumentos.
- Barras invertidas (separadores de diretório) e caminhos '
..'. Além disso, no windows, '\' e ';' em nomes de arquivo. - Metacaracteres de expansão de arquivos, incluindo "
~*?[]{}<>", além do metacaractere especial "@" específico do ImageMagick. - Outros metacaracteres de shell, incluindo "
$#;", e os três caracteres de aspas ''', '"', '```' - O argumento não corresponde ao que o ImageMagick espera. Use "
[-list](https://imagemagick.org/command-line-options/#list)" para ver quais tipos de argumento o IM entende para opções específicas. Por exemplo, uma opção "[-gravity](https://imagemagick.org/command-line-options/#gravity)" informada pelo usuário tem apenas 10 configurações diferentes. - E assim por diante...
Para qualquer tipo de trabalho de programação web, é vital compreender a segurança e como invasores podem usar argumentos especialmente elaborados para subverter os comandos chamados. Não apenas no PHP, mas também no Shell e no ImageMagick. O IM exige cuidado especial, pois pode, por exemplo, ler um arquivo de senhas e transformá-lo em uma imagem a ser retornada. Novamente... é muito melhor ser excessivamente restritivo do que abrir uma brecha de segurança imprevista quando a web está envolvida.
Gravando no sistema de arquivos
Como mencionado acima, e caso o procedimento inicial descrito tenha sido seguido, sabe-se com certeza que o PHP geralmente é executado como um usuário diferente e mais restrito no servidor. Por isso, normalmente NÃO será possível gravar no diretório que contém o script (ou onde quer que ele esteja de fato em execução). Por motivos de segurança, em geral não é desejável gravar nesse diretório! Se realmente for preciso que o PHP grave arquivos, faça-o salvar a imagem (ou os dados) com um nome de arquivo único em "/tmp" e, acima de tudo, faça a limpeza depois, tanto na saída normal quanto em QUALQUER erro. É impressionante a rapidez com que se pode encher um disco com arquivos temporários deixados por uma aplicação que não faz a limpeza adequada. Se os arquivos salvos (imagens) precisarem ser visíveis pelo servidor web, crie um subdiretório especial de 'gravação por programa' para esses arquivos. Como deveria ser feito. A maioria das aplicações PHP, na verdade, evita gravar qualquer coisa no sistema de arquivos usando um banco de dados como backend. Ou seja, cookies, tokens, dados de usuário, imagens e assim por diante são todos gravados em um banco de dados, como (em ordem de complexidade e escala) SQLite, PostgresSQL, MySQL e Oracle. Nada é salvo no sistema de arquivos. Os programadores de sistema normalmente configuram a aplicação PHP com essas informações quando a aplicação é instalada. As imagens costumam ser reproduzidas pelo mesmo script PHP, ou por um separado, que busca o 'blob' da imagem e o envia ao cliente. As imagens podem ser enviadas como imagens 'inline' junto com o próprio HTML (veja o formato "[inline:](files.html#inline)", que traz uma demonstração de imagens HTML inline), ou como uma única imagem múltipla 'tudo em um', de modo que o HTML/JAVA do cliente faça apenas uma requisição de imagem em vez de 20 requisições separadas. Um último ponto. Deve sempre existir algum método de limpeza de dados antigos. Um usuário que não faz login há 2 anos provavelmente deveria ter seus dados excluídos.
Obtendo a saída de erros
Experimente um destes métodos...
<?php
exec("/usr/local/bin/magick -version",$out,$returnval);
print_r($out[0]);
?>
ou
<?php
exec("/usr/local/bin/magick -list",$out,$returnval);
print_r($out);
?>
ou use shell_exec da seguinte forma
<?php
$IM_version=shell_exec("/usr/local/bin/magick -version");
echo $IM_version
?>
Para incluir a saída de STDERR...
<?php
$array=array();
echo "<pre>";
exec("magick read_test.png write_test.png 2>&1", $array);
echo "<br>".print_r($array)."<br>";
echo "</pre>";
?>
O exemplo acima vem da discussão no fórum de usuários do IM... Como mostrar informações de erro do IM em php?. Veja também as anotações do próprio autor sobre registro de erros de depuração em PHP. Elas remetem ao Manual do PHP sobre registro de erros tratamento e registro de erros em PHP; observe especialmente a seção de exemplos.
Comandos ImageMagick mais seguros...
O ideal, por motivos de segurança, seria evitar usar o shell para dividir uma única string longa em comando e argumentos separados. É melhor fazer isso por conta própria! Isso significa fornecer os argumentos do comando como um vetor de strings separadas, em vez de uma única string analisada pelo shell. Assim, evitam-se a possibilidade de erros de sintaxe do shell, o ônus extra de aspas exigido pelo shell e a possibilidade de algum invasor quebrar o comando do shell e executar o próprio comando (muito ruim). Por outro lado, perdem-se o scripting do shell, os pipes e o redirecionamento de arquivos, mas isso normalmente não é uma grande perda quando já se usa PHP ou outra linguagem que atue como invólucro. No PHP, a única função encontrada que permite chamar um comando diretamente sem um shell é a função pcntl_exec(). Ela basicamente evita o shell e chama o comando diretamente. No entanto, trata-se de uma verdadeira chamada de sistema 'execl()', que substitui o processo atual pelo comando fornecido. Ou seja, ela não faz o 'fork()' nem as ligações de descritores de arquivo necessárias para executá-lo como um subprocesso. Assim, a pcntl_exec() é, na verdade, de nível baixo demais para uso geral, e implementar um comando 'sem shell' pode ficar bastante complexo. Surpreende que uma chamada de comando 'sem shell' mais simples e segura ainda não tenha sido fornecida pela interface do PHP. Mas, por outro lado, o autor não é programador de PHP. O Perl, por sua vez, oferece vários métodos para chamar subcomandos e processos com segurança, o que muitas vezes o torna preferível ao PHP como interface web. Alguém com conhecimento de segurança em PHP se dispõe a esclarecer ou indicar mais informações?
API 'IMagick' do PHP
Para testar se o módulo PHP PECL Imagick está realmente funcionando, envie uma imagem de teste simples "image.jpg" e este script PHP para o mesmo diretório acessível pela web.
<?php
$handle = imagick_readimage( getcwd() . "image.jpg" );
if ( imagick_iserror( $handle ) ) {
$reason = imagick_failedreason( $handle ) ;
$description = imagick_faileddescription( $handle ) ;
print "Handle Read failed!<BR>\n";
print "Reason: $reason<BR>\n";
print "Description: $description<BR>\n";
exit ;
}
header( "Content-type: " . imagick_getmimetype( $handle ) );
print imagick_image2blob( $handle );
?>
Há um livro sobre PHP IMagick disponível online, e mais exemplos de uso do IMagick podem ser encontrados no blog do Mikko. O único problema do IMagick é que ele não vem sendo mantido nem atualizado, de modo que pode haver várias funções que não funcionam ou que estão ausentes. Certifique-se de usar a v3.x do IMagick e uma versão atual do IM. Ele funciona e, para a maioria das tarefas, funciona bem, mas, se for preciso fazer outras coisas, outros métodos do PHP podem ser uma opção melhor.
'MagickWand' do PHP
É possível verificar se o módulo PHP MagickWand faz parte da instalação do PHP usando...
<?php
if (extension_loaded('magickwand')) {
echo "PHP MagickWand is available!\n";
} else {
echo "PHP MagickWand is NOT available!\n";
}
?>
Mas, para verificar se ele está realmente funcionando corretamente, envie alguma imagem de teste "image.png" e este script...
<?php
$image = NewMagickWand();
if( MagickReadImage( $image, 'image.png' ) ) {
header( 'Content-Type: image/jpeg' );
MagickSetImageFormat( $image, 'JPEG' );
MagickEchoImageBlob( $image );
} else {
echo "Error in MagickReadImage()";
echo MagickGetExceptionString($image);
}
?>
Não há garantias quanto ao exemplo acima, mas comentários são bem-vindos. Em geral, o autor não programa em PHP, mas usou o exemplo acima para testar uma instalação de teste SunONE-PHP5 (com os três métodos: linha de comando, magick e MagickWand).
Scripts PHP complexos...
Se for preciso gerar e enviar tanto HTML quanto IMAGENS, considere projetar o script PHP de modo que requisições HTML ou opções de entrada separadas gerem as várias partes necessárias no documento web, a partir do mesmo script PHP ou de scripts diferentes. Ou seja, um script PHP de nível superior pode gerar HTML com as tags apropriadas, que chamam a si mesmo (ou outro script PHP) com as opções apropriadas para criar ou modificar as imagens exibidas pelo primeiro script PHP de nível superior. É isso que muitos scripts PHP de álbuns de fotos e de gráficos fazem. Tudo controlado pelas extensões GET e PATH_INFO das chamadas de URL. Note que não é possível usar POST dentro de uma tag IMG. Procedendo dessa forma, deve ser possível evitar completamente a necessidade de gerar, salvar e limpar imagens temporárias para páginas web geradas por PHP. Essa é uma solução cheia de problemas, como limitações de recursos e coleta de lixo, o que a torna uma técnica de programação muito ruim. Essa técnica é abordada em ambos os livros do ImageMagick, embora o ImageMagick de fato usado ali esteja ficando um pouco datado.
Scripts Perl Magick
A API do PerlMagick é uma boa forma de converter comandos "magick" em um script que também pode lidar com bancos de dados, grandes quantidades de imagens ou processamentos de imagem mais complexos do que seria viável de outro modo. A melhor ajuda é examinar os scripts 'demo' do PerlMagick, que estão tanto no código-fonte quanto, normalmente, instalados na área de documentação do PerlMagick. Em um determinado sistema, ficavam em "/usr/share/doc/ImageMagick-perl-*/demo/". Nesse diretório há um número crescente de exemplos simples de leitura, escrita e processamento de várias imagens. Também está presente o script "demo.pl", que lista praticamente todas as opções comuns de processamento de imagem e como usá-las. Ao converter um comando "magick" de linha de comando para perl, há algumas coisas a lembrar.
- A primeira coisa a lembrar é que o PerlMagick não exclui automaticamente as novas imagens que foram processadas. Muitos operadores criam uma nova imagem modificada a partir da imagem antiga, enquanto outros modificam diretamente uma imagem existente.
- Além disso, muitos operadores não aplicam uma operação específica a toda uma lista de imagens, mas apenas à primeira imagem da lista fornecida. Isso significa que será preciso percorrer em laço a própria sequência de imagens (vetor perl).
- É possível ter muitas sequências de imagens. Na verdade, normalmente cada imagem é lida em sua própria sequência de imagens separada, em vez de ter de se contentar com uma única sequência, como acontece na linha de comando.
- Além disso, com a imagem na memória, é fácil extrair o tamanho da imagem existente. Isso significa que se pode simplesmente criar novas telas sem precisar clonar e limpar uma imagem existente, como se faz na linha de comando. No entanto, clonar uma imagem também copia os metadados dela, de modo que pode ser conveniente acompanhar esses metadados para imagens como fotos digitais.
- Verifique os erros de imagem (como mostrado na página do PerlMagick) após cada processo importante, especialmente ao ler imagens.
Para converter uma linha de comando em perl, basicamente realizam-se exatamente as mesmas operações, na mesma sequência. No entanto, como as imagens em geral não são excluídas e várias sequências de imagens são comuns, o uso de parênteses e de operações extras de clonagem nos comandos "magick" normalmente não é um problema. A parte mais difícil da conversão de scripts costuma ser mapear uma opção de linha de comando para uma chamada de função do PerlMagick. A forma mais rápida encontrada é obter o código-fonte do IM, examinar o arquivo "MagickWand/mogrify.c" e procurar a opção de linha de comando específica que está causando dificuldade. Por exemplo, para a opção -threshold, procure por "threshold", incluindo as aspas. Haverá duas correspondências: uma para uma análise sintática rápida, que garante que todas as opções sejam encontradas, e a segunda com as chamadas internas efetivas para essa opção. Ali se encontra o nome da função de biblioteca usada, que normalmente mapeia diretamente para a função Perl. Neste caso... BilevelImageChannel()
Avisos de segurança
Ao escrever um script para uso público, especialmente um script PHP baseado na web que QUALQUER PESSOA no mundo possa executar, é de importância vital verificar tudo o que possa ter vindo de um usuário desconhecido (ou até conhecido). E isso significa TUDO: argumentos, nomes de arquivo, URLs e também imagens. Até que um argumento de entrada seja validado, ele pode conter letras, números, espaços, pontuação ou até caracteres 'nulos' e de controle. Enquanto não for verificado a fundo, deve ser tratado como suspeito e não deve ser usado. Não importa que se esteja usando algum formulário de entrada controlado pela web. Uma pessoa com um pouco de conhecimento pode facilmente chamar o PHP com os próprios argumentos, sem usar esse formulário. E não acredite que não farão isso: há robôs por aí, lendo formulários de entrada e criando os próprios argumentos 'hackeados' para tentar invadir scripts aleatórios.
Metacaracteres em nomes de arquivo
Como questão de segurança, deve-se ter atenção especial a nomes de arquivo que contenham espaços, aspas, pontuação, caracteres de controle ou outros metacaracteres, pois tanto o IM quanto os shells podem tentar expandi-los. O problema é que um arquivo chamado '*?@${&) .jpg' é, na verdade, um nome de arquivo perfeitamente válido no UNIX, mas MUITOS programas terão dificuldade para lidar com ele se esse programa (como o shell e o IM) também fizer expansão de nomes de arquivo. Lembre-se de que, mesmo que se impeça o shell de fazer a expansão de metacaracteres de 'glob', o próprio IM também faz essa expansão (para uso no DOS). Assim, impedir todos esses caracteres (e gerar um erro) é provavelmente sensato. Como medida de segurança, muitas vezes é uma boa ideia gerar um erro e abortar se um nome de arquivo tiver QUAISQUER caracteres desconhecidos ou incomuns, ou seja, algo que não sejam letras, números ou o sufixo esperado. Antes de passar tal nome de arquivo para um comando de shell ou para o IM. É melhor ser MUITO mais restritivo e impedir situações do que ser permissivo e deixar passar algo ruim.
Dicas para melhores scripts de shell/PHP com ImageMagick
Estes são alguns pontos básicos de programação de scripts levantados a respeito de um script de shell contribuído, enviado à lista de e-mails do IM para uso de outras pessoas. Eles foram originalmente enviados ao autor de forma privada (que permanecerá anônimo), que se mostrou grato. Nem todos são específicos do IM, mas devem ser aplicados de qualquer forma, como prática padrão de programação. Especialmente se houver a intenção de que outra pessoa use, examine e/ou corrija o programa ou script. Isso, por sua vez, tornará o script mais útil.
- Coloque a 'ajuda' ou 'documentação' no início dos scripts e programas. Isso facilita muito para que outras pessoas descubram o que um determinado programa faz sem precisar instalar ou executar o script. Muitas vezes o próprio autor descarta um programa que não tenha um comentário claro sobre sua finalidade, em vez de tentar compilar ou executar um script desconhecido. Na verdade, já se viram grandes projetos em que o primeiro arquivo README nem sequer diz o que o projeto enorme e complexo faz! O programador simplesmente presume que, se você o baixou, deve saber o que ele faz! Garanta também que uma 'opção inválida', como '-?', imprima uma sinopse não apenas das opções, mas também um breve resumo do que o programa faz, ou de onde encontrar essa ajuda. Não aponte apenas para um site remoto, que pode desaparecer daqui a 10 anos! Para um exemplo de script que imprime os próprios 'comentários de abertura', veja o script "jigsaw" na área de scripts do IM. O Perl pode usar POD para autodocumentação (veja o módulo perl "
Pod::Usage"). Por exemplo, veja o script contribuído dpx_timecode.pl. Ter a ajuda como um 'here file' na primeira sub-rotina também é aceitável e funciona na maioria das linguagens. Mas mantenha essa sub-rotina NO TOPO, não no fim ou no meio do script ou programa. - Certifique-se de limpar o código, removendo código e comentários antigos e obsoletos, deixando tudo tão organizado quanto possível. Seja conciso, com etapas comentadas de forma simples (se possível). Veja novamente o script "jigsaw".
- Certifique-se de que os arquivos temporários sejam limpos ao final. Use o comando de shell "trap" para removê-los na saída ou interrupção. É claro que se pode reutilizar um único arquivo temporário várias vezes, de modo que não são necessários muitos, especialmente com os comandos magick do IM v6. Veja novamente o script "jigsaw" e procure por "trap".
- Além disso, nem todos usam o sistema X, ainda que possa parecer que sim. Não faça referência a requisitos de sistema específicos, nem a métodos para corrigir o problema. O que funciona para você pode ser completamente inadequado para o sistema e a configuração de outra pessoa. Ela pode nem ter acesso à Internet! Diga apenas que o comando "
magick" do ImageMagick não foi encontrado. Se quiser acrescentar requisitos de instalação ou sugestões, faça-o como parte de uma documentação separada e mais extensa. - Verifique se o IM em uso tem uma versão suficientemente alta, ou acrescente alterações compatíveis com versões anteriores. Nos exemplos do IM são incluídas propositalmente notas de 'aviso de versão' sobre quando vários recursos especiais foram adicionados, justamente com esse propósito. Isso facilita a criação de scripts com uma única verificação mínima de versão. Aqui está uma forma simples de obter um único número de versão para fins de teste em um script de shell. Ela extrai os 4 números da versão e insere a quantidade certa de zeros para que cada número tenha 2 dígitos, produzindo um número simples de 8 dígitos.
IM_VERSION=`magick -list configure | \ sed '/^LIB_VERSION_NUMBER /!d; s//,/; s/,/,0/g; s/,0*\([0-9][0-9]\)/\1/g'`
Por exemplo, o IM v6.3.5-10 gera "06030510", enquanto a versão imediatamente seguinte, IM v6.3.6.0, produz "06030600". Uma versão em PHP do exemplo acima está disponível na página de exemplos RubbleWeb, lista de fontes. A string resultante pode ser testada, usando um teste numérico simples ou de string, para descobrir se a versão disponível do ImageMagick é moderna o suficiente para o que o script pretende fazer. Por exemplo...
if [ "$IM_VERSION" -lt '06030600' ]; then
echo >&2 "The perspective distortion operator is not available."
echo >&2 "Sorry your installed ImageMagick is too old -- ABORTING"
exit 10
fi
Note também como é exibido ao usuário o motivo exato do aborto e, especificamente, qual(is) recurso(s) especial(is) motivou(aram) a verificação de versão. Do contrário, é possível esquecer mais tarde por que aquela versão específica (ou superior) era necessária. Também é possível modificar o comportamento do IM conforme a versão. Por exemplo, suponha que se queira obter uma lista das fontes disponíveis. Antes da versão v6.3.5-7 do IM, a configuração "type" da "[-list](https://imagemagick.org/command-line-options/#list)" retornava a lista de 'fontes conhecidas'. Em versões posteriores, é preciso usar a configuração "font" em vez dela. Assim, aqui é possível fazer uma verificação de versão para usar a configuração correta e obter as informações necessárias.
if [ "$IM_VERSION" -lt '06030507' ];
then font_list="type";
else font_list="font";
fi
avail_fonts=`magick -list $font_list | cut -d\ -f1 |\
egrep -v '^($|----|Path:|Name$)'`
AVISO: no PERL, uma string que começa com '0' pode ser interpretada como um número octal!!! No entanto, a comparação de dois números octais ainda sai correta, desde que o primeiro dígito continue sendo '0'. Recomenda-se cautela e a verificação do teste de versão. Outra alternativa para testar a versão é usar "expr" em vez do teste "['...
if expr + "$im_version" \>= "06030507" >/dev/null; then
...
AVISO: o '+' extra no exemplo acima normalmente não é necessário, ao menos para este teste, mas é necessário se a variável puder conter a palavra-chave especial 'match", que causaria problemas ao "expr", especialmente quando usado para trabalho com strings ou substrings.
* Também é possível usar a saída de informações da "[-list](https://imagemagick.org/command-line-options/#list)" para verificar se algum recurso especial foi adicionado ao ImageMagick atualmente instalado.
magick -list distort | grep 'Arc' >/dev/null 2>&1
if [ "$?" -ne 0 ]; then
echo >&2 "Arc distortion method not available."
echo >&2 "Sorry your installed ImageMagick is too old -- ABORTING"
exit 10
fi
No entanto, atente para o fato de que muitas vezes um novo método, como "[-distort](https://imagemagick.org/command-line-options/#distort) Arc", pode surgir durante o desenvolvimento do IM antes de estar devidamente pronto para uso geral. Assim, uma verificação de versão ainda pode ser a melhor ideia. É por isso que, nos Exemplos do IM, procura-se anotar (observe os símbolos) a versão do IM em que um novo recurso se tornou estável o suficiente para uso geral.
* Não use linhas únicas muito, muito longas. Especialmente em comandos 'convert' complexos. Divida-as usando métodos de continuação de linha (mostrados acima), como '\' no UNIX, '^' no DOS e a concatenação de strings '.' no PHP. No entanto, isso não significa colocar CADA configuração e operação em uma linha separada. Faça uma operação ou etapa principal por linha: criar nova imagem, modificar imagem, mesclar com outras imagens, etc. Coloque todas as configurações operacionais necessárias para um operador específico logo antes desse operador. Pense em cada linha como uma única etapa de processamento. Isso permite separar as linhas de modo a facilitar a leitura e a compreensão de cada etapa de processamento. Quanto mais clara a separação dos operadores, mais fácil é acompanhar um processo de imagem complexo. Usar parênteses adicionais, indentar as linhas ao longo das várias etapas ou até acrescentar linhas em branco entre grandes blocos de processamento pode tornar ainda mais fácil enxergar as principais etapas de uma operação grande e longa. Essas técnicas são usadas por toda parte nos exemplos do IM, para torná-los mais fáceis de acompanhar e entender; então basta observar! Por fim, comentários extras sobre o que um comando específico faz podem fazer uma grande diferença para quem for ler e entender o script (inclusive você mesmo, 2 meses depois). Pena que, atualmente, não seja possível inserir comentários em uma linha de comando longa!
* Procure não depender de muitos programas externos, ou use-os apenas se estiverem disponíveis (com possíveis alternativas). Outras pessoas provavelmente não terão aquele programa, ou preferirão usar outra coisa. Se o uso de um programa puder ser opcional, torne-o opcional, seja sob controle do usuário, seja de uso automático quando encontrado. Procure não torná-lo um requisito obrigatório, sempre que possível. Por exemplo, é possível usar "pngcrush", "optipng" e "pngnq" para comprimir PNG melhor do que o IM normalmente faria (o IM foi projetado para ser geral, não específico). Da mesma forma, "gifsicle", "intergif" e outros otimizadores de compressão LZW para animações GIF têm pontos positivos e negativos. Apenas não os torne um requisito obrigatório para que um script funcione. Como exemplo prático, uma versão mais antiga do "gif2anim" não usava o "magick identify" do ImageMagick para consultar metadados específicos de GIF, mas dependia de uma versão modificada do "[giftrans](http://www.ict.griffith.edu.au/anthony/software/#giftrans)". Esse requisito depois deixou de ser necessário graças a melhorias no "magick identify" do ImageMagick, então ele foi removido para tornar o script mais amplamente utilizável. O próprio ImageMagick tem MUITOS requisitos opcionais, como o "ghostscript" para a leitura de documentos postscript e PDF, ou o "librsvg" para o tratamento correto de imagens vetoriais SVG. O IM funciona tranquilamente quando eles estão disponíveis. O IM trata essas bibliotecas como opcionais, precisando delas apenas para processar imagens desses formatos. Aqui está um trecho de código que pode ser usado para verificar as dependências de um script (especialmente útil em um ambiente cygwin muito minimalista)...
# Check Dependencies to scripts correct working
DEPENDENCIES="sed awk grep tr bc magick identify" # adjust to suit
for i in $DEPENDENCIES; do
type $i >/dev/null 2>&1 ||
Usage "Required program dependency \"$i\" missing"
done
- Levando o ponto anterior adiante. Se for preciso fazer cálculos de ponto flutuante em um script de shell que usa o IM, é possível usar o próprio IM para esse cálculo, em vez de depender de outro programa, como '
awk' ou 'bc', que pode não estar disponível (especialmente no cygwin no windows). Por exemplo, aqui calcula-se o sin() de um ângulo específico dado em graus, usando o 'magick' para fazer o trabalho...angle=-20 sine=`magick xc: -format "%[fx:sin( $angle *pi/180)]" info:` echo $sine
O exemplo acima exibiria o valor '-0.34202'. É possível ajustar o número de casas decimais usando o controle operacional de precisão. Por padrão, está definido em 6 dígitos.
* Deixe o usuário decidir quais formatos de imagem de entrada/saída usar. O ImageMagick é, antes de tudo, um conversor de imagens, capaz de usar muitos formatos diferentes. Ele pode gerar saída para a tela, para postscript, para impressoras, ou enviar a imagem por pipe para outro comando para processamento adicional. Não limite o usuário a um formato específico. Por exemplo, os scripts "jigsaw" e "gif_anim_montage" permitem que o usuário especifique qualquer imagem de entrada ou saída. Dessa forma, os usuários podem encadear imagens por pipe para dentro ou para fora desse script, possibilitando processamento adicional com outros programas e scripts. Por exemplo, é comum usar um comando como...
gif_anim_montage animation.miff show:
para exibir o resultado do script na tela, em vez de salvá-lo em um arquivo. Na verdade, em muitos scripts, se a saída estiver ausente, o padrão é usar "show:". A entrada não foi limitada APENAS a um arquivo de animação GIF, nem a saída foi restringida apenas aos formatos GIF, PNG ou JPEG; em vez disso, o script foi feito para ler e processar qualquer formato que o ImageMagick consiga tratar. De fato, o IM pode ler de arquivos, de pipelines, da tela atual, ou até da World Wide Web usando um formato de entrada "URL:" ou "HTTP:". Não limite essas possibilidades, a menos que isso se torne uma preocupação de segurança (como no uso web).
* Leia as imagens de entrada e gere as imagens de saída apenas UMA VEZ! Se o usuário fornecer o nome de um arquivo de pipeline ou uma URL, não se deve tentar ler essas imagens mais de uma vez, ou as coisas podem dar errado. Use um arquivo temporário, imagens clonadas, ou salve uma cópia da imagem de entrada com "[MPC:](files.html#mpc)" quando for preciso referir-se a essa imagem várias vezes. Se for possível lidar com várias imagens vindas do pipeline, melhor ainda. Veja novamente o script "jigsaw" para um exemplo de como salvar as imagens de entrada em um arquivo temporário, quando é necessário processar a imagem de entrada várias vezes, ou em uma ordem diferente da que os argumentos do programa sugerem.
Em essência, essas práticas dão a quem usa o programa mais liberdade para fazer o que ELE quer, em vez do que VOCÊ acha que ele quer. Não limite os usuários nem a si mesmo fazendo suposições sobre o uso do script. Obs.: a principal especialidade do autor é a escrita de scripts UNIX, em muitas arquiteturas e 'variantes' diferentes de UNIX, LINUX e outros sistemas semelhantes ao UNIX, com mais de 25 anos de experiência. Portanto, ele deve saber do que fala em relação ao acima exposto.
Por que usar vários comandos "magick"
- Willem, em qua, 25 de out de 2006, escreveu...
- Fiquei pensando; às vezes vejo nos seus exemplos que você invoca o Convert mais de uma vez para obter o resultado desejado. Em geral, eu esperaria que invocar o magick mais de uma vez não fosse necessário; deveria ser tudo possível em 1 invocação (mas o comando ficaria mais complexo). Você concorda com essa afirmação?
Concordo totalmente. Embora, antes da versão 6 do IM, isso fosse de fato impossível, pois o IM, na época, não era projetado para fazer mais de uma ou talvez duas operações por comando. No entanto, o IMv7 deveria permitir realizar todo o processamento em um único comando. Mas, infelizmente, nem isso é sempre possível. Há vários motivos possíveis para usar vários comandos. Normalmente, nas páginas de exemplo, isso é feito para poder exibir o resultado da imagem intermediária e demonstrar melhor as etapas intermediárias de processamento envolvidas. Mais adiante, na mesma área de exemplo, o processo pode ser repetido com um único comando, talvez um pouco mais complexo. Assim, em princípio, sim, um único comando pode fazer todo o processamento de imagem. É perfeitamente possível combinar todas as técnicas de processamento de imagem em um único comando. O próprio autor faz isso o tempo todo. A exceção ocorre nos casos em que é preciso extrair uma informação e depois inseri-la no comando seguinte. Um exemplo disso é a técnica de recorte difuso, que exige extrair os resultados de um recorte feito sobre uma cópia borrada da imagem. Esse resultado é então usado para recortar a imagem original. O mesmo foi feito na atualização do exemplo de cantos arredondados de miniatura, em que o próprio IM foi usado para gerar um comando de desenho a partir do tamanho de uma imagem para o comando seguinte. No entanto, há propostas que permitirão gerar opções diretamente a partir de imagens previamente lidas para a memória. Em scripts, como o script 'jigsaw' (veja Técnicas avançadas, peças de quebra-cabeça), é comum acabar usando vários comandos por um motivo diferente -- o processamento opcional. Isso permite que várias opções de entrada fornecidas pelo usuário selecionem etapas adicionais na sequência de processamento de imagem. Assim, para o processamento opcional, também costumam-se usar comandos separados para cada etapa. Nesse caso, um arquivo temporário é basicamente inevitável. No entanto, normalmente são necessárias no máximo uma ou duas imagens temporárias, e cada etapa processa a imagem de volta para o mesmo nome de arquivo temporário (ou o anterior), para que a próxima etapa de processamento opcional continue. Por exemplo, processar a imagem substituindo a imagem de origem.
magick /tmp/image1.png ..operations.. /tmp/image1.png
Nesse caso, um arquivo MPC pode acelerar a leitura de arquivos intermediários para quase instantânea na etapa de processamento seguinte, pois a imagem é simplesmente despejada da memória para o disco e depois 'paginada' de volta pelo comando seguinte. Isso evita que o IM precise formatar e analisar um formato de arquivo de imagem, embora torne o arquivo temporário maior, por ser simplesmente memória não comprimida. Outra alternativa usada para evitar arquivos temporários é encadear por pipe a(s) imagem(ns) de trabalho de um comando de shell (if-then-else-fi ou laço while) para outro. Isso é conhecido como pipelines de imagem e é demonstrado em vários exemplos. Um exemplo disso é apresentado em streaming de imagens MIFF, em que várias imagens são geradas uma após a outra no mesmo pipeline de saída, para serem recolhidas pelo comando seguinte, que as mescla todas na imagem final. E, por fim, pode ser preciso mudar o estilo de processamento com base nos resultados de etapas anteriores. Por exemplo, em comparações de imagens, muitas vezes é preciso descobrir alguma informação para uso em etapas posteriores, ou mudar como a imagem deve ser processada em fases posteriores. Comparar um diagrama ou desenho pode exigir uma técnica de comparação bem diferente da usada em uma foto da vida real. Se o uso de vários comandos estiver se tornando um problema, talvez seja hora de passar para uma interface de API como o PerlMagick, em que várias sequências de imagens podem ser mantidas na memória, evitando E/S de disco desnecessária.
Tornando o IM mais rápido (em geral)
Há muitas maneiras de fazer o IM trabalhar mais rápido. Aqui estão os aspectos mais importantes a ter em mente. À medida que se desce na lista, o ganho de velocidade fica menor, ou exige mudanças mais complexas na instalação do IM.
- O IM Q8 (ou seja, 8 bits por valor de cor, 3 a 4 bytes por pixel) é bem mais rápido (3 a 4 vezes mais rápido) do que o padrão IM Q16, com sua maior resolução de cor. Se um Q16 não for necessário para as imagens, talvez seja o caso de substituir o IM por uma versão Q8. Atenção, porém: usar apenas 8 bits de qualidade interna pode afetar o processamento geral das imagens, pois as imagens intermediárias perdem informação. Veja HDRI para o oposto disso.
- Use um único comando "
magick", se possível, com todo o processamento necessário para uma imagem. Isso economiza na inicialização, na criação de arquivos temporários ou de pipelines entre comandos, e até na codificação/decodificação para formatos de arquivo de imagem desses pipelines e na E/S de disco. É claro que, às vezes, ainda é preciso usar vários comandos para permitir etapas opcionais de processamento de imagem, como cálculos que envolvem o tamanho da imagem, cores ou etapas de processamento opcionais. O scripting do IMv7 ajudará nesse aspecto. - Os scripts de shell são inerentemente lentos. São interpretados, exigem várias etapas e manipulação extra de arquivos em disco. Isso, é claro, melhorou graças ao novo tratamento de opções do IM v6, que permite realizar um grande número de operações de processamento de imagem em um único comando. Ainda assim, raramente é possível fazer tudo em um único comando "
magick", de modo que muitas vezes é preciso usar vários comandos para conseguir o que se deseja. Assim, uma API como perl, ruby ou um módulo magick de PHP é mais rápida, pois elimina todos os aspectos de interpretação tanto do shell quanto da API de linha de comando do IM. Ela também reduz as etapas de inicialização pelas quais o IM passa ao ler as definições de fontes e cores. - Uma API também pode manter todas as imagens, ou até várias listas de imagens, durante toda a vida do programa (desde que haja memória suficiente para isso). Isso significa que se pode alternar livremente quais imagens estão sendo trabalhadas, sem precisar embaralhar e fazer malabarismos com as imagens, como se faz na linha de comando. Isso é especialmente útil quando também é preciso fazer cálculos extras com base em etapas anteriores de processamento.
- Escrever no formato de arquivo de imagem GIF é lento. O IM precisa se esforçar para reduzir (quantizar) as cores de uma imagem de modo a caber no conjunto limitado de cores do formato. Mesmo assim, muitas vezes é preciso trabalho extra para acertar, especialmente em animações GIF. PNG e JPEG são mais rápidos, mas ao custo do tamanho no caso do PNG e da perda de qualidade no caso do JPEG. Ainda que, na verdade, as imagens GIF sejam piores em termos de qualidade!
- Preparar e armazenar em cache antecipadamente imagens como planos de fundo, sobreposições, molduras e máscaras, ou pré-gerar tabelas de consulta de cores, mapas de distorção, modelos, máscaras, etc. Todas essas coisas podem fazer grandes diferenças no tempo de processamento. Pense no que pode ser feito de antemão. Uma grande biblioteca de imagens pré-geradas pode ser bem mais rápida do que tentar criar as imagens conforme a necessidade. Veja também o uso do "MPC:" para imagens intermediárias e em cache. Trata-se de imagens mapeadas em memória no disco, que têm, essencialmente, tempo de leitura zero, mas são inúteis para qualquer outra finalidade ou em outras máquinas. Elas só devem ser criadas no início de um processo importante de manipulação de imagens e não devem ser armazenadas por muito tempo, pois qualquer mínima atualização de software ou de sistema as invalidará e provavelmente causará falhas de segmentação.
- Evite usar o FX, o operador de imagem de efeitos especiais, se em vez disso for possível usar a composição alfa, o mais simples Evaluate, operações matemáticas simples, ou outras técnicas. Se realmente for preciso usá-lo, procure restringir seu uso à menor imagem possível, ou a um único canal da imagem (ao lidar com tons de cinza).
- Evite usar desfoques de imagem de tamanho grande quando alguns menores podem ser mais rápidos. Faça alguns testes de tempo para ver o que é mais rápido. O mesmo vale para outros operadores de morfologia e de convolução, como os operadores gaussiano e de sombra.
- Use subimagens menores, ou regiões, para o processamento complexo de áreas pequenas. Por exemplo, encontrar e extrair os olhos de uma pessoa (usando regiões), antes de mascarar e recolorir, pode resultar em um enorme ganho de velocidade em comparação com processar a versão grande e completa de uma imagem. Quanto maior a diferença, maior a economia.
- Ao ler imagens grandes ou até um grande número de imagens, é melhor usar um modificador de leitura para redimensioná-las ou recortá-las imediatamente após a leitura de cada imagem, reduzindo assim o requisito total de memória. Para JPEG, é possível usar o modificador de biblioteca especial '
[jpeg:size](formats.html#jpg_read)' para evitar até a alocação da memória. Isso, por sua vez, previne o 'disk thrashing' (que deixa os computadores MUITO lentos). Especialmente quando muitas imagens grandes estão envolvidas, como ao gerar um índice de diretório em montagem ou outras colagens de múltiplas imagens. - Para imagens realmente descomunais que precisam ser processadas a partir do disco, pode ser melhor processá-las em blocos menores.
- Também para imagens grandes... Se você tiver um SO Windows de 64 bits, use a distribuição de 64 bits do ImageMagick. Ela usa um espaço de endereçamento maior e consegue acomodar na memória imagens maiores do que o Windows de 32 bits.
- Por padrão, o IM usa várias threads para operações individuais de processamento de imagem. Isso significa que um computador com dois ou mais 'núcleos' geralmente processará imagens mais rápido do que uma máquina de CPU única. Para imagens grandes, os recursos de multithreading do OpenMP podem produzir uma vantagem de velocidade clara, pois usam mais CPUs para concluir as operações individuais de processamento de imagem. Note que, dentro do IM, apenas as operações individuais de processamento de imagem são paralelizadas. Portanto, a economia é maior no processamento de imagens grandes, e não ao processar grandes quantidades de imagens (veja a seguir).
- Para imagens pequenas, usar os recursos de multithreading do IM não trará muita vantagem. Nesse caso, executar vários converts simultaneamente em imagens diferentes pode produzir mais vazão. Isso também pode ocorrer em situações em que várias requisições web PHP poderiam disparar vários comandos "magick" de imagem. Em qualquer dessas situações, ter o multithreading habilitado pode ser altamente prejudicial por causa da contenção de CPU, sendo melhor desabilitar o OpenMP definindo a variável de ambiente '
MAGICK_THREAD_LIMIT' como '1'. Veja a discussão no fórum do IM Threading slows down 'convert'. Também pode ser interessante examinar oMAGICK_THROTTLE, para fazer o ImageMagick ceder o controle das CPUs com mais frequência, em pontos mais apropriados. - Se você estiver fazendo muitas operações pequenas em imagens (como desenho), procure não usar nomes de cores. Especifique as cores usando cores em hexadecimal, como "
#00AA99", ou números rgb, como "rgb(0,160,100)", para evitar que o IM tenha de carregar as tabelas de nomes de cores (que são bem grandes!). Também é possível tentar remover ou reduzir os arquivos de definição da lista de 'fontes' do sistema (do "type.xml"). Ou remover esses arquivos completamente e especificar as fontes diretamente pelo nome do arquivo. Basicamente, reduza o carregamento das informações extras de configuração, que o IM lê e inicializa quando necessário para um processamento de imagem específico. Portanto, ou não as use, ou reduza o tamanho e o impacto dos arquivos de configuração. - Compilar o ImageMagick como biblioteca compartilhada (o padrão) pode reduzir bastante o tempo de carregamento. As bibliotecas e os módulos codificadores são carregados apenas conforme a necessidade, de modo que uma versão dinâmica do IM não carrega nada que não precise usar durante o processamento de imagem. Além disso, as bibliotecas compartilhadas tendem a permanecer disponíveis, podendo não precisar ser recarregadas em uma segunda execução.
- Se você chamar o ImageMagick como parte de um módulo do Apache, isso também reduzirá o tempo de inicialização, pois algumas partes serão carregadas uma vez e mantidas disponíveis para múltiplos usos, em vez de precisarem ser recarregadas repetidamente. Isso pode se tornar mais prático no futuro, com um processo IM 'daemon' em execução permanente.
Compilando o ImageMagick a partir do código-fonte
Compilando RPMs do ImageMagick para linux a partir de SRPMs
NÃO é preciso ser root para de fato compilar os RPMs, embora seja preciso ser root para instalá-los. Este procedimento é usado para gerar e instalar o IM em sistemas Fedora Linux, mas também há relatos de que funciona em sistemas CentOS 5.4 (Enterprise Redhat) Linux (veja notas mais específicas em IM no CentOS). Primeiro, obtenha a versão mais recente do RPM de código-fonte em RPMs de código-fonte para Linux. Primeiro, certifique-se de que a máquina tenha todos os compiladores e ferramentas necessários.
sudo yum groupinstall "Development Tools"
sudo yum install rpmdevtool libtool-ltdl-devel
| O "sudo" é um programa para executar comandos como root, se você tiver permissão; caso contrário, use um shell de root e remova a parte "sudo" do exemplo acima.
---|---
Para sistemas mais antigos, como o CentOS 5.5, parece que também são necessários estes pacotes
sudo yum compat-libstdc++ gcc-c++ gcc-objc++ libstdc++ libstdc++-devel
Em seguida, também é preciso instalar os pacotes de desenvolvimento das bibliotecas de que o IM precisa para compilar. A forma simples de obter os mais comuns é instalar primeiro a versão de desenvolvimento do IM, ainda que depois seja compilada uma nova para substituí-la.
sudo yum install ImageMagick-devel
Também é preciso garantir que estes pacotes e suas dependências (como as bibliotecas de desenvolvimento jpeg e png) estejam instalados:
freetype-devel ghostscript-devel libwmf-devel jasper-devel lcms-devel bzip2-devel librsvg2 librsvg2-devel liblpr-1 liblqr-1-devel libtool-ltdl-devel autotrace-devel
Alguns exemplos em "ImageMagick examples" também podem usar programas fornecidos por estes pacotes e bibliotecas opcionais, mas eles não são necessários para o processo de compilação.
gnuplot autotrace
Em geral, todos esses pacotes são opcionais, mas, se não estiverem instalados, os 'coders' e operadores que usam essas bibliotecas podem não ser compilados automaticamente. Por exemplo, o módulo "liblqr" é necessário para habilitar o operador Liquid Rescale. Agora, baixe um pacote SRPM (RPM de código-fonte) a partir do qual compilar seus RPMs binários. OU compile um SRPM a partir de um download TAR ou SVN existente usando...
rm config.status config.log
nice ./configure
rm *.src.rpm
make srpm
Note que, uma vez com o SRPM, é possível compilar os RPMs propriamente ditos para instalação.
nice rpmbuild --nodeps --rebuild ImageMagick*.src.rpm
Isso cria um subdiretório "rpmbuild" no seu diretório pessoal, no qual serão extraídas as fontes do SRPM e compilada a versão em pacote RPM do IM. |
Em versões mais antigas do Fedora e do Redhat, isso era feito em "/usr/src", que geralmente é restrito apenas ao root. No entanto, é possível tornar esse diretório de sua propriedade ou gravável por você, para ainda conseguir fazê-lo sem precisar de acesso total de root para a compilação. |
|---|---|
| Agora, pegue os RPMs recém-compilados no diretório de compilação. Isto pega apenas os pacotes ImageMagick Core e PerlMagick; você pode querer pegar mais do que esses dois, mas isso fica a seu critério... |
cp -p ~/rpmbuild/RPMS/*/ImageMagick-[6p]*.i[36]86.rpm .
Limpe e apague as áreas de compilação (incluindo as que possam ter sido criadas para você)...
rm -rf /var/tmp/rpm-tmp.* ~/rpmbuild
Agora é possível instalar os pacotes RPM que você compilou. Para isso, será preciso ser root (veja a nota sobre o comando "sudo" acima)...
sudo rpm -ihv --force --nodeps ImageMagick-*.i[36]86.rpm
O "--nodeps" costuma ser necessário por causa de algumas dependências incomuns que às vezes existem em sistemas Linux. Para atualizar uma instalação existente, geralmente faz-se assim (como root).
sudo rpm -Uhv --force --nodeps ImageMagick-*.i[36]86.rpm
Se quiser ir além, recomenda-se consultar o guia avançado de instalação a partir do código-fonte no Unix no site do IM.
Para remover o IM depois, basta remover o pacote, assim (novamente como root)...
sudo rpm -e --nodeps ImageMagick\*
Às vezes, deseja-se apenas limpar e apagar completamente todos os vestígios do IM do sistema. Para isso, primeiro usa-se o comando anterior para remover o pacote em si do sistema (uma variação é mostrada abaixo). Em seguida, executam-se os comandos de remoção a seguir. NOTA: não há garantias quanto a isto, e convém verificar os comandos a fundo de antemão, para assegurar que não removam algo que não deveriam. Se algo tiver sido esquecido, ou se algo indevido tiver sido removido, avise para que isto possa ser atualizado.
rpm -e --nodeps `rpm -q ImageMagick ImageMagick-perl`
rpm -e --nodeps `rpm -q ImageMagick-devel`
rm -rf /usr/lib/ImageMagick-*
rm -rf /usr/lib/lib{Magick,Wand}*
rm -rf /usr/share/ImageMagick-*
rm -rf /usr/share/doc/ImageMagick-*
rm -rf /usr/include/{ImageMagick,Magick++,magick,wand}
rm -rf /usr/lib/perl5/site_perl/*/i386-linux-thread-multi/Image/Magick*
rm -rf /usr/lib/perl5/site_perl/*/i386-linux-thread-multi/auto/Image/Magick*
rm -rf /usr/share/man/man?/*Magick*
rm -f /usr/lib/pkgconfig/ImageMagick.pc
Aviso: outros pacotes podem precisar de um IM instalado; portanto, se você o remover, sugere-se atualizar imediatamente os pacotes do seu sistema, para que ele instale novamente a versão original (e geralmente bastante antiga) do ImageMagick fornecida para o seu sistema Linux. Isso geralmente envolve usar um pacote de 'atualização de software com GUI' ou o comando "yum upgrade". Aproveite.
ImageMagick a partir do código-fonte no Ubuntu
Para obter todas as bibliotecas de desenvolvimento necessárias para compilar o ImageMagick, use o seguinte
sudo apt-get install imagemagick libmagick++-dev
Uma página web de "Shane" descreve como instalar o ImageMagick a partir do código-fonte no Ubuntu 8.04. Esse procedimento não foi testado, mas instalou o IM diretamente em "/usr/local" usando "make". Ele não gera um pacote de instalação 'DEB', o que não é uma solução ideal. Se alguém souber como criar um pacote 'DEB' para o Ubuntu, avise. Talvez usando Introdução ao empacotamento Debian
Compilando no MacOSX
A forma mais fácil de instalar o ImageMagick no MacOSX é usar o MacPorts. Mas o que segue são indicações de informações sobre a compilação para o MacOSX. Não se sabe se funciona ou se será útil, pois nunca foi usado. Mas veja instalar o ImageMagick sem Fink nem MacPorts e instalar o ImageMagick no Snow Leopard. O texto acima foi parafraseado de uma discussão no fórum de usuários do IM.
Compilando versões HDRI do IM
Para informações sobre a compilação de uma versão HDRI do IM, veja habilitando o HDRI no ImageMagick no site principal do IM; para informações específicas sobre Windows e Ubuntu Linux, veja também a discussão de anúncio das transformadas de Fourier nos fóruns de usuários.
Criando um ImageMagick pessoal
Nem sempre se tem o luxo de ter acesso de superusuário à máquina em que se faz o trabalho com imagens, e muitas vezes quem tem esse acesso não quer atualizar sua instalação do ImageMagick. Talvez por questões de gerenciamento de pacotes, ou por problemas de compatibilidade. Se você tiver acesso à linha de comando (por exemplo, via SSH), nem tudo está perdido. É possível instalar e usar uma versão pessoal do ImageMagick. A má notícia é que ainda será preciso que os administradores de sistema instalem os compiladores e os pacotes de desenvolvimento (veja acima), mas muitas vezes eles já estarão presentes, de modo que nem sempre é um problema. Primeiro, decida em qual subdiretório instalar a sua versão do IM. Um diretório dedicado é a melhor escolha, pois basta apagar esse diretório inteiro para remover a instalação. Neste caso, a instalação será feita no subdiretório "apps/im" do diretório pessoal.
export MAGICK_HOME=$HOME/apps/im
Agora, para instalar uma versão pessoal, baixe, descompacte e entre no diretório das fontes do ImageMagick. Depois, configure-o como uma versão 'não instalada'.
rm config.status config.log
nice ./configure --prefix=$MAGICK_HOME --disable-installed \
--enable-shared --disable-static --without-modules --with-x \
--without-perl --without-magick-plus-plus --disable-openmp \
--with-wmf --with-gslib --with-rsvg --with-xml \
CFLAGS=-Wextra \
;
nice make clean
nice make
nice make install
O importante na definição acima é o "--disable-installed" com o "--prefix". As outras partes desabilitam a compilação de aspectos mais opcionais da sua versão pessoal do ImageMagick. Modifique-as como quiser. Agora, para usar a sua própria versão instalada, em vez da versão normal do sistema, basta definir as seguintes variáveis de ambiente.
export MAGICK_HOME=$HOME/apps/im
export PATH="$MAGICK_HOME/bin:$PATH"
export LD_LIBRARY_PATH="$MAGICK_HOME/lib:$LD_LIBRARY_PATH"
Agora, ao digitar
magick -version
vê-se, por padrão, a versão mais atualizada do IM que você acabou de instalar. Note que a variável "$MAGICK_HOME" precisa estar definida para um ImageMagick criado com a opção "--disable-installed". As outras duas variáveis de ambiente garantem o uso da versão pessoal, em vez de qualquer versão de sistema que também possa estar instalada.
AVISO: não misture as variáveis acima. Ou defina todas elas, ou não as tenha definidas dessa forma. O executável do IM que você usa DEVE usar também as mesmas bibliotecas, coders e arquivos de configuração com que esse executável foi compilado. Misturar a versão do sistema e a sua versão pessoal provavelmente causará falhas de segmentação e de memória.
É possível mover a localização do seu IM pessoal sem recompilar, mas será preciso não apenas modificar as variáveis de ambiente acima, como também alterar (ou remover) os caminhos fixos para o programa "magick display" usado pelo delegado "[show:](files.html#show)" na sua versão pessoal instalada do arquivo "delegate.xml". Veja delegados para mais informações sobre esse aspecto do IM.
Para facilitar a alternância entre a versão instalada no sistema e várias versões pessoais do IM, normalmente não se definem as variáveis acima. Em vez disso, chama-se um script que define essas variáveis antes de invocar a versão específica do IM. Por exemplo, há uma versão pessoal do IM compilada com HDRI, usada apenas para exemplos específicos dos Exemplos do ImageMagick. Normalmente não se quer usar essa versão, preferindo-se a versão sem HDRI instalada no sistema para a maior parte do trabalho com imagens. Assim, instalou-se uma versão 'HDRI' do IM na área pessoal "$HOME/apps/im_hdri" e criou-se um script chamado "hdri" contendo...
#!/bin/sh
#
# hdri imagemagick_command....
#
# Run the HDRI version of imagemagick (or other personal installed IM)
#
# Where is the HDRI version of IM stored
export MAGICK_HOME=$HOME/apps/im_hdri
# Set the other two environment variables
export PATH="$MAGICK_HOME/bin:$PATH"
export LD_LIBRARY_PATH="$MAGICK_HOME/lib:$LD_LIBRARY_PATH"
# Execute the HDRI version of the command
exec "$@"
Agora, ao digitar...
hdri magick -version
Vê-se que foi executada a versão de qualidade HDRI do ImageMagick, mas apenas quando necessário. Sem o prefixo "hdri" no comando acima, seria executada a versão normal do IM do sistema. AVISO: se a sua versão pessoal do IM não for encontrada pelo script, ele reverterá silenciosamente para a versão do sistema. A verificação de 'versão' acima é um teste importante para garantir que se está realmente usando a versão pessoal, e não a do sistema. Também é possível verificar exatamente qual comando magick o script está tentando executar usando o 'which'.
hdri which convert
Ou seja, o script é flexível o bastante para que não seja preciso executar "magick"; pode-se executar qualquer comando, como scripts de shell do ImageMagick, de modo que esse script use o magick HDRI em vez do convert normal do sistema.
hdri some_im_script image.png image_result_hdri.png
![[IM Text]](../static/img/api/hdri_version.txt.gif)