⚠️ Este é um site de tradução não oficial, sem relação com a ImageMagick Studio LLC. Para informações oficiais, consulte a página original (https://usage.imagemagick.org/windows/index.html).

Exemplos do ImageMagick -- Uso no Windows

 [ Introdução](#intro)

Introdução

Para que serve um script do IM no meu PC com Windows?

Os exemplos a seguir presumem, de modo geral, que o IM é executado em um computador desktop com Windows, provavelmente conectado a uma rede. Existem muitos programas de manipulação de imagens prontamente disponíveis, como o Adobe Photoshop, o Paint Shop Pro da Corel, o IrfanView (http://www.irfanview.com/) e até o GIMP (http://www.gimp.org/). Então por que se dar ao trabalho de processar imagens por meio dos programas de linha de comando e dos scripts do IM? A verdadeira vantagem de usar o ImageMagick em vez de uma interface controlada pelo mouse é a possibilidade de automatizar por completo manipulações rotineiras, seja para arquivos individuais, seja para grandes conjuntos de arquivos. Tarefas como:

Conversão de formato em lote
Isso é oferecido por muitos programas de Windows, como o IrfanView. No entanto, a versatilidade do IM no que diz respeito a formatos de imagem é insuperável. É possível, por exemplo, transformar todas as páginas de um PDF em uma série de JPEGs (caso o GhostScript esteja instalado no computador).
Redução e pré-processamento de fotografias digitais
Ao incorporar fotografias digitais em um documento de processador de texto, convém em geral reduzir sua resolução, para que o documento possa ser impresso mais rápido. O mesmo vale ao transformar o documento em um PDF por meio de um driver de impressora PDF como o FreePDF. O pré-processamento também pode incluir rotinas de correção de cor e de lente.

Inserção do seu logotipo em um lote de fotografias digitais

Aplicação de uma série de operações a um lote de fotografias digitais
Depois de ter elaborado uma sequência de passos de trabalho com um programa controlado pelo mouse, pode-se querer automatizar esses passos para o processamento em lote futuro. No entanto, linguagens de script (como o Action Script da Adobe) não são muito comuns nos programas de processamento de imagens do Windows.

Combinação de várias imagens em uma imagem de catálogo

Embora algumas dessas tarefas (em especial a redução em lote) também sejam oferecidas por outros programas gratuitos (sobretudo pelo processamento em lote do IrfanView), nunca há liberdade de escolha quanto aos passos de processamento a aplicar: é preciso conformar-se com aqueles oferecidos pelo programa. Por exemplo, o processamento em lote do IrfanView permite inserir uma cadeia de texto em um lote de fotografias, mas não um logotipo. Também permite alterar o valor de gama, mas o histograma da fotografia não pode ser ceifado em suas extremidades (como faz o "[-contrast-stretch](https://imagemagick.org/command-line-options/#contrast-stretch)" no IM, veja Normalizar e Alongamento de Contraste). Os scripts do IM são especialmente adequados para uso produtivo em uma rede corporativa, pois scripts prontos podem ser aplicados por qualquer pessoa – os usuários finais não precisam necessariamente saber o que acontece nos bastidores. Assim, passos padronizados de fluxo de trabalho sobre imagens podem ser totalmente automatizados (e de fato padronizados). Vários dos scripts apresentados a seguir foram derivados do uso produtivo em nossa pequena empresa (que atua no campo da reconstrução de acidentes). Não sou um programador de scripts de Windows excepcional nem muito familiarizado com as ferramentas de linha de comando do IM. Provavelmente existem abordagens mais elegantes para alguns dos problemas tratados a seguir. Os pontos que se pretende destacar são:

  • demonstrar algumas técnicas básicas de programação de scripts de Windows com as ferramentas de linha de comando do IM.
  • comprovar que o uso de scripts baseados no IM não é arte pela arte nem um passatempo acadêmico.
  • mostrar que as ferramentas de linha de comando do IM podem realizar trabalho real em uma rede local (e não apenas em servidores web).

Como no restante das páginas de Exemplos do IM, usaremos apenas as ferramentas de linha de comando do IM e deixaremos de lado suas diversas interfaces de programação. Os scripts destinam-se a rodar dentro de uma rede local com letras de unidade atribuídas a cada unidade de rede. A maioria dos scripts destina-se a ser executada nos computadores clientes dessa rede; poucos visam ao servidor (de arquivos) da rede.

Ambientes possíveis para as ferramentas de linha de comando do IM

No Windows, comandos simples do IM costumam ser executados no shell de comandos do Windows (um "shell do DOS" iniciado ao executar cmd.exe). Para operações complexas, realizadas em uma linha de comando extensa ou em uma série de linhas de comando, é melhor escrever um script. Para uma série de comandos simples, isso será muito provavelmente um arquivo batch do DOS, executado no shell de comandos do Windows. Essa abordagem, contudo, tem suas limitações, pois o conjunto de comandos dos arquivos batch é bastante restrito em comparação com o dos shells de comando UNIX mais comuns. Ao executar o IM no Windows, há basicamente as seguintes alternativas:

O shell de comandos do Windows ("janela do DOS")
É executado pelo cmd.exe (modo 32 bits) no Windows NT 4.0, no Windows XP e em versões posteriores, e está presente em qualquer computador com Windows. Veja Usando o shell do DOS e arquivos batch, bem como a nota especial sobre A questão do Convert.
Cygwin
Um shell de comandos semelhante ao bash (http://www.cygwin.com/). Ao usar esse shell, os exemplos do IM apresentados no restante desta seção de uso podem ser executados exatamente como são dados, pois há acesso a um shell de linha de comando ao estilo UNIX. Veja Usando o Cygwin mais adiante.
O Windows Script Host
O Windows Script Host baseia-se na tecnologia .COM. Está presente em qualquer computador contemporâneo com Windows, e os scripts do WSH são muito mais poderosos do que simples arquivos batch do DOS. O Windows Script Host oferece várias interfaces de programação, sendo o VBScript (Visual Basic Script) e o JScript (Java Script) as mais comuns. As ferramentas de linha de comando do IM podem ser invocadas usando os comandos Run ou Exec do objeto Shell do shell do DOS. Veja Visual Basic Script (VBS) mais adiante.
O Windows Powershell
O sucessor bem mais poderoso do antigo shell do DOS, baseado na tecnologia .NET 2.0. O Powershell veio junto com o Windows 7 e é executado pelo powershell.exe. Pode ser baixado para o Windows XP e o Vista no site da Microsoft.

Executando scripts de forma eficaz

Suponha que exista um script de Windows perfeito (um arquivo batch do DOS, um VBScript ou qualquer outro) que recebe o nome (ou os nomes) do arquivo de entrada como parâmetro(s) de linha de comando, realiza alguma manipulação e produz o resultado como uma única imagem ou uma série de imagens. Certamente não se vai querer abrir um shell de comandos do DOS (ou uma alternativa) toda vez e informar os nomes dos arquivos ao script digitando-os. Para evitar esses procedimentos trabalhosos, é possível, no essencial, usar Arrastar e Soltar (Drag & Drop) ou SendTo: ao usar Arrastar e Soltar, coloca-se o arquivo batch do DOS ou o VBScript (ou o que for) em um local de fácil acesso, como a área de trabalho ou o diretório que contém os arquivos de imagem a processar. Em seguida, selecionam-se os arquivos a processar no Windows Explorer e basta soltá-los sobre o arquivo de script. Os nomes dos arquivos serão passados ao script como os parâmetros de linha de comando e poderão ser referenciados no script. Como alternativa, pode-se colocar o script (ou um atalho para ele) na pasta SendTo. Os programas dessa pasta aparecem no menu de contexto do Windows Explorer ao clicar com o botão direito no painel de arquivos do Explorer. Novamente, os nomes dos arquivos selecionados são passados ao script como parâmetros de linha de comando. A pasta SendTo chama-se SendTo. Sua localização parece mudar a cada nova versão do Windows. Uma forma infalível de encontrá-la é digitar shell:sendto na caixa de execução.Uma única linha de comando no Windows XP ou posterior pode ter 8192 (= 213) caracteres. Assim, ao invocar uma ferramenta do IM diretamente da linha de comando, seja diretamente, seja por meio de um arquivo batch que nomeia diretamente todos os arquivos necessários, dificilmente se esbarrará nessa limitação. O Arrastar e Soltar, porém, usa a rotina ExecShell, limitada a cadeias de "apenas" 2048 (= 211) caracteres. Como todos os arquivos são passados com nomes totalmente qualificados (isto é, unidade + caminho + nome), isso pode se tornar um problema para arquivos batch e VBScripts executados via WSH quando os nomes de caminho ficam longos demais. Esses erros não podem ser tratados de forma adequada pelo script depois que ocorrem, pois o erro acontece antes de o script ser de fato executado. A solução no Windows XP costuma ser colocar os arquivos em um local onde os nomes de caminho sejam mais curtos.

A questão do Convert

A rotina de instalação do IM no Windows adiciona o diretório de programas do IM ao caminho de busca, de modo que se possa chamar as ferramentas de linha de comando do IM diretamente do prompt de comando, sem informar um nome de caminho. Por padrão, usa-se magick como ferramenta de linha de comando. No entanto, ao selecionar os nomes de programa legados, os nomes das ferramentas de linha de comando do IM são bastante inespecíficos (por exemplo, convert, identify, compare ...), o que provoca conflitos de nome com outros programas. Em especial, convert é uma ferramenta de sistema do Windows, localizada no diretório de sistema do Windows (c:\Windows\system32\convert.exe), que converte o sistema de arquivos FAT32 no agora comum NTFS. Mas há também outros programas chamados "convert.exe", por exemplo o utilitário conversor de relatórios do Delphi.A ferramenta de conversão de FAT → NTFS veio pela primeira vez com o Windows XP e gerou um conflito de nome com a ferramenta de linha de comando "convert" do IM: como o diretório de programas do IM era acrescentado ao final do caminho de busca do DOS (isto é, a variável de ambiente PATH), a ferramenta de sistema era encontrada primeiro e chamadas simples a "magick" em scripts antigos não eram resolvidas corretamente. As versões atuais do programa de instalação do IM no Windows, porém, colocam o diretório de programas do IM no início do caminho de busca, garantindo assim que, em caso de nomes conflitantes, a ferramenta de linha de comando do IM seja em geral encontrada primeiro. Contudo, outros utilitários com o mesmo nome (por exemplo, o conversor de relatórios do Delphi) enfrentaram o mesmo problema e adotaram a mesma solução, isto é, colocar o caminho de seu programa no início da variável de caminho, o que significa que essa solução não é infalível: se o Delphi for instalado depois do IM, uma chamada simples a Convert invocará a ferramenta conversora de relatórios, e não o Convert do IM.A introdução da ferramenta Convert com o Windows XP fez muitos scripts antigos travarem. A solução comum era renomear a ferramenta Convert do IM para outra coisa, como "IMconvert" (Observe que não é possível renomear o comando do sistema, pois o próximo service pack do Windows provavelmente o restauraria, ignorando a versão renomeada.) Essa solução, embora hoje desnecessária, ainda pode ser encontrada por toda a Internet. A melhor solução para evitar possíveis conflitos de nome no futuro é chamar as ferramentas de linha de comando do IM pelo seu caminho completo em qualquer script. Ou seja, armazenar sua localização em uma variável ou constante. Assim, todo arquivo batch deveria começar com linhas como

  SETLOCAL EnableDelayedExpansion
  SET IMCONV="%PROGRAMFILES%\ImageMagick\Convert"
  ...
  %IMCONV% -size 128x128 xc:white test.gif

O código presume que o IM foi instalado em uma pasta chamada "ImageMagick" abaixo da pasta de programas, o que não corresponde à nomeação padrão de sua pasta de instalação. (Veja Instalando o ImageMagick no Windows para detalhes.) %PROGRAMFILES% é uma variável de ambiente que expande para o nome do diretório de programas, isto é, "Program Files" na versão em inglês do Windows e "Programme" na versão em alemão. SETLOCAL limitará a definição de novas variáveis de ambiente (como IMCONV) ao escopo do arquivo batch. EnableDelayedExpansion não é realmente necessário aqui, mas é um bom hábito usar essa opção sempre que se usar SETLOCAL; veja Diretrizes para programação de arquivos batch. para detalhes. Há formas mais sofisticadas e infalíveis de descobrir a pasta de instalação do IM, que serão tratadas em Edição, depuração e teste de erros em tempo de execução. O código VBScript equivalente seria algo como

  Set wsh = WScript.CreateObject("WScript.Shell")
  IMconv = wsh.ExpandEnvironmentStrings("%PROGRAMFILES%") & "\ImageMagick\Convert"

Por questão de simplicidade, não usaremos esse código toda vez a seguir, mas convém tê-lo em mente como um bom hábito. Para um bom resumo alternativo e soluções para esse problema, veja Ron Savage: MS Windows and convert.exe.

Codificação de caracteres

O ImageMagick codifica cadeias em Unicode, mais precisamente em UTF-8. Ao contrário, o DOS usa páginas de código para codificar caracteres (na maioria das vezes em 8 bits). Isso gera problemas ao escrever cadeias em imagens, como ao trabalhar com 'label' ou '-title': ao usar caracteres não ASCII, algo dará errado na abordagem simples. Por exemplo, ao tentar criar um rótulo com tremas alemães como 'ä', 'ö', 'ü', basta usar o seguinte no Linux...

  magick label:äöü test.png

Mas isso não criaria a cadeia desejada no Windows. É possível, porém, ler uma cadeia codificada em UTF-8 a partir de um arquivo de texto:

  magick label:umlauts.txt test.png

e é possível até criar esse arquivo de texto com o uso do "echo, caso se troque a página de código para UTF-8 de antemão:

  CHCP 65001
  ECHO äöü > umlauts.txt
  magick label:umlauts.txt test.png

Mas, ao querer processar a saída de um comando do DOS, por exemplo ao tentar intitular uma folha de índice dos JPEGs contidos em determinado diretório com o nome desse diretório, surgem problemas. Trocar para a página de código 65001 não funcionará com a maioria dos comandos do DOS, sobretudo ao percorrer árvores de diretórios em laço. E alternar a página de código entre, digamos, 1252 (latim da Europa Ocidental) e 65001 em geral também não funciona, ou fica ao menos bastante complicado. A abordagem mais segura é transformar as cadeias quando forem necessárias, usando um programa externo de linha de comando, como o "Iconv.exe", uma ferramenta UNIX também disponível para Windows. Baixe o arquivo de instalação do SourgeForge e instale os arquivos no diretório padrão C:\Program Files\GnuWin32. Em seguida, despeje a saída do comando do DOS em um arquivo de texto no script e transforme esse arquivo em UTF-8 da seguinte forma:

  CHCP 1252
  DIR /B äöü.jpg > temp.txt
  "C:\Program Files\Gnuwin32\bin\iconv.exe" -f ISO-8859-1 -t UTF-8 temp.txt > title.txt
  magick label:@title.txt äöü.jpg -append äöü_labelled.jpg

Os parâmetros dizem ao Iconv para transcodificar de ISO-8859-1 (página de código 1252) para UTF-8. O Iconv escreve sua saída em stdout, de modo que é preciso redirecioná-la para um arquivo a fim de usá-la com 'label'. Observe que despejar a saída em um arquivo de texto é recomendável de qualquer modo, pois isso faz o ImageMagick interpretar o conteúdo do arquivo literalmente, sem tomar a barra invertida do Windows ("\") por um caractere de escape. É claro que o código do exemplo acima não faz muito sentido tal como é apresentado aqui, para fins de demonstração. Em um arquivo batch prático do DOS, o nome do arquivo provavelmente será gerado em um laço FOR. Um exemplo prático é dado adiante (Veja Processamento em lote de uma árvore de (sub)diretórios). Para saber mais sobre o tratamento de UTF, veja os outros exemplos do IM e as informações em Tratamento de texto em formato Unicode ou UTF8.

Instalando o ImageMagick no Windows

O ImageMagick está em constante desenvolvimento; novas versões são lançadas aproximadamente a cada mês. Recomenda-se fortemente usar uma versão atualizada do IM, sobretudo quando o IM não parece realizar uma tarefa exatamente como se espera. Na maioria dos casos, a instalação da versão atual resolverá o problema. O programa de instalação da versão binária atual pode ser encontrado em https://imagemagick.org/script/binary-releases.php#windows.Também é possível baixar uma versão do ImageMagick capaz de HDRI (qualidade em ponto flutuante) e FFT (transformada rápida de Fourier) no Astronomy and Astrophotography Blog. Por padrão, o IM instala-se em um diretório de programas chamado C:\Program Files\ImageMagick x.x.x-x, onde "x.x.x-x" representa seu número de versão. Por padrão, o programa de instalação sugere estender a variável de ambiente PATH quando o IM é instalado pela primeira vez (isto é, "Add application path to your system path" fica marcado). Se esquecer de desinstalar versões antigas, logo se terá uma bela coleção de várias versões do ImageMagick com suas respectivas extensões de PATH.Em nosso escritório, portanto, adotamos o hábito de instalar o IM em C:\Program Files\ImageMagick, instalando as versões mais novas por cima das antigas e deixando a variável de ambiente PATH intacta. Não encontramos nada de errado com esse procedimento em anos de uso. Se de fato se quiser saber o número da versão do IM, pode-se sempre chamar "convert -version", e um script à prova de erros pode avaliar o número da versão caso dependa de uma versão mínima. Veja a seção "Edição, depuração e teste de erros em tempo de execução" para mais informações sobre isso.O ImageMagick escreve algumas chaves de Registro em HKEY Local Machine\Software\ImageMagick. Se lidar com várias versões instaladas do IM, a chave mais importante é HKEY Local Machine\Software\ImageMagick\Current, onde também se encontra o caminho para os binários do IM, chamado BinPath. Pode-se consultar essa entrada do registro no início de qualquer script e, assim, determinar o caminho do programa sem ter de depender da variável de ambiente PATH. Veja a seção "Edição, depuração e teste de erros em tempo de execução" para mais informações sobre isso.O programa de instalação do IM oferece a opção de instalar um objeto COM+ para o ImageMagick por meio da opção Install ImageMagickObject OLE Control for VBscript, Visual Basic, and WSH. A opção não fica marcada por padrão, e a instalação do objeto COM+ não é pré-requisito para usar o IM em um VBScript, como será comprovado a seguir. De todo modo, não convém contar com o objeto COM+ estar instalado em uma máquina alvo do script que não seja a sua.Ao trabalhar com arquivos PostScript, o ImageMagick depende de outro programa, o "Ghostscript", para a leitura e a conversão de arquivos PostScript e PDF em um formato de imagem que ele possa usar. Ou seja, para ler tais documentos, o Ghostscript precisa estar instalado no computador. Sua versão mais recente pode ser baixada no SourceForge. A ordem em que se instalam o GhostScript e o ImageMagick não importa. Não é preciso instalar o GhostScript antes do ImageMagick, e o ImageMagick funcionará bem sem ele estar instalado. Ele só é necessário caso se queira trabalhar com arquivos PostScript ou PDF. O IM determina a localização do Ghostscript em tempo de execução, consultando-a no Registro.

Particularidades e armadilhas

De modo bastante extraordinário para programas de Windows, o IM permite que imagens sejam escritas em stdout e lidas de stdin e, assim, usar encadeamento (piping) para encadear tarefas de processamento de imagem. A operação

  magick -size 128x128 xc:white gif:- | magick - test.gif

é equivalente a

  magick -size 128x128 xc:white test.gif

No primeiro comando do encadeamento, o operador de menos diz ao IM para escrever a imagem em stdout, ao passo que o operador de menos no segundo comando do encadeamento diz ao IM para ler a imagem de stdin. Esse procedimento permite evitar o uso explícito de arquivos temporários. É especialmente útil quando algum comando não oferece certas operações, por exemplo o recorte de bordas (trimming):

  montage -tile 2x2 -geometry 400x300+60+60 1.png 2.png 3.png 4.png miff:- | magick - -trim montage.png

Como consequência desse recurso, a saída textual costuma ser escrita em stderr em vez de stdout. Por exemplo: para redirecionar a saída textual do Compare para um arquivo de texto, seria preciso escrever

  magick compare -metric PSNR 1.png 2.png dif_1_2.png 2>result.txt

Portanto, é preciso redirecionar stderr ("2>") para o arquivo de texto, e não stdout ("1>" ou apenas ">").

Obtendo ajuda

As opções de linha de comando estão amplamente documentadas no site do IM, mas é a seção de Uso do site que realmente demonstra como fazê-las funcionar. Essa seção do site é bastante bem estruturada, permitindo uma abordagem orientada ao problema para a tarefa que se deseja realizar. No entanto, a abordagem rápida e improvisada é uma busca no Google nessa seção do site quanto à opção de linha de comando que se tem em mente. Para fazer uma montagem de várias imagens e descobrir mais sobre a opção -tile, pode-se fazer uma busca no Google por

e logo se descobrirá o essencial. Basta ter em mente que isso revelará código destinado à aplicação em um ambiente UNIX / LINUX, que precisa ser ligeiramente ajustado para ser aplicado no Windows.Outra fonte de informação muito útil é o fórum de discussão do IM, também conhecido como Discourse Server User Forum, que convém incorporar aos favoritos do navegador. Tornar-se membro permite fazer perguntas, que na maioria das vezes são respondidas rapidamente por usuários experientes.

Programas auxiliares e alternativas

Sim, é verdade. Existem certas tarefas que outros programas fazem melhor do que o ImageMagick. Em geral, aquelas projetadas com formatos específicos em mente, em vez da manipulação de imagens genérica que o ImageMagick oferece.

  • O IrfanView é provavelmente o visualizador de imagens mais comum no Windows, que também permite alguma manipulação básica de imagens.
  • Um programa com interface gráfica como o Adobe Photoshop ou o Gimp é mais adequado para a edição direta e o teste de passos complexos de manipulação de imagem.
  • Para manipulações no cabeçalho EXIF de fotografias digitais, o Jhead e o ExifTool são mais versáteis do que o ImageMagick.
  • A extração de fluxos JPEG de PDFs deve ser feita com o xPDF.
  • O processamento de vídeo é melhor feito com o VirtualDub, sobretudo em combinação com o AviSynth e seu editor AvsP.

Isso não quer dizer que o ImageMagick deva ser ignorado para esse tipo de trabalho com imagens. Mas é possível fazer muito mais combinando-os.


Usando o Cygwin

Como se disse acima, o ImageMagick foi projetado pensando em UNIX e Linux, de modo que a abordagem mais fácil é provavelmente instalar um shell Bash no sistema Windows e executar a variedade de scripts do IM já escritos para aquele sistema, por exemplo os scripts de Fred Weinhaus. O Cygwin, nas palavras de seus desenvolvedores, oferece "um ambiente semelhante ao Linux para Windows". Consiste em todas as ferramentas normalmente disponíveis no shell do Linux. Testei alguns dos scripts bash de Fred Weinhaus no shell Bash do Cygwin e constatei que eram plenamente funcionais. Na parte inferior da página raiz do site do Cygwin há um link rotulado Install or update now!, que baixa um instalador inicial chamado Setup.exe. Ao iniciar esse programa, ele oferece uma lista de espelhos do site. Depois de escolher um deles, a rotina apresenta uma visão em árvore das ferramentas que instalará. A seleção padrão me parece razoável, então pode-se simplesmente prosseguir. A rotina de instalação baixará então os pacotes necessários e instalará o Cygwin no computador. Ao instalar, certifique-se de incluir o pacote "bc", que não vem habilitado por padrão. Ele pode ser instalado como opção no painel de instalação do Cygwin. É um utilitário de matemática em ponto flutuante e pode ser vital em scripts do IM, como os usados por Fred Weinhaus.
Ao iniciar o Cygwin, seu shell Bash se parece bastante com uma caixa do DOS, isto é, uma janela de texto com fundo preto. Assim como na janela do DOS, a fonte pode ser escolhida clicando no menu de sistema da janela, situado à esquerda na barra de título. Os comandos básicos são:
  • O diretório atual é alterado com o comando CD, mais ou menos como no DOS. No entanto, a barra invertida ("\") tem de ser substituída pela barra normal ("/"). As unidades também são alteradas com CD, como no DOS. Assim, CD w: mudará para a unidade w:. Ao contrário de um ambiente Unix normal, os nomes de caminho não diferenciam maiúsculas de minúsculas. Caracteres especiais, como tremas, podem ser usados. Para alguns comandos, os nomes de unidade têm de ser passados em uma sintaxe especial, evitando os dois-pontos. Por exemplo /cygdrive/w/test.
  • O Cygwin lê a variável de ambiente PATH do Windows e define seu próprio PATH de acordo. Isso pode ser verificado digitando echo $PATH no shell Bash. Observação: ao contrário do Windows, os nomes das variáveis de ambiente diferenciam maiúsculas de minúsculas, então é preciso usar letras maiúsculas ao referir-se a PATH.
  • Ao contrário do Windows, o diretório atual não está no caminho de busca por padrão! Se, por exemplo, o script de shell "autolevel1" residir em W:\scripts, não basta mudar para esse diretório ao chamar o script de shell. É preciso anexar ao menos uma localização mínima de diretório ao início do script, assim: ./autolevel1 (para o script localizado no diretório atual). Ou o caminho completo do script, assim /cygdrive/w/scripts.
  • Como alternativa, pode-se anexar esse diretório de scripts explicitamente ao caminho de busca com PATH=$PATH:/cygdrive/w/scripts. Como os dois-pontos são usados como separador de caminho, é preciso usar essa nomenclatura especial, como /cygdrive/w/scripts em vez de w:/scripts.

Esta descrição do shell do Cygwin será ampliada em futuras versões desta página. Por ora, as informações acima devem bastar para começar.


Usando o shell do DOS e arquivos batch

Convertendo scripts: do shell UNIX para o DOS do Windows

Ao invocar comandos do IM diretamente do shell de comandos do DOS (usando cmd.exe), é preciso modificar os scripts apresentados no site de Exemplos do IM (caso não venham desta seção), pois a maioria dos exemplos fornecidos (em outras seções) destina-se, em geral, a ser executada em um shell de comandos UNIX ou LINUX. Para executá-los em um shell de comandos do DOS, é preciso fazer as seguintes modificações:

  • Na maioria das vezes, aspas duplas '"' têm de ser usadas no lugar de aspas simples ''' para que os argumentos do comando permaneçam corretos. Atenção a aspas dentro de aspas, como no operador [-draw](https://imagemagick.org/command-line-options/#draw). É possível usar aspas simples dentro de um argumento entre aspas duplas do DOS, pois estas são passadas ao IM para tratamento, e não processadas pelo shell.
  • Barras invertidas '\' que aparecem no final das linhas de exemplo mostradas representam uma 'continuação de linha', que anexa a linha seguinte à mesma sequência de linha de comando. Substitua-as pelo caractere '^' para indicar continuação de linha em arquivos batch do DOS. No DOS, a linha seguinte também precisará começar com um espaço; contudo, isso é prática bastante comum, então não deve causar muitos problemas. Também é possível juntar todas as linhas em uma só e remover essas barras invertidas, embora isso torne a edição, e depois a leitura do comando, muito mais difícil. Por isso, essa prática não é recomendada.
  • Todos os caracteres reservados do shell que não estiverem entre aspas duplas devem ser escapados com um '^' (acento circunflexo) se usados em sentido literal (isto é, sem cumprir sua função habitual). Esses caracteres reservados do shell são: '&', '|', '(', ')', '<', '>', '^'. Isso significa, em especial, que:
    • O caractere especial '>' (usado na geometria de redimensionamento) precisa ser escapado com '^'. Por exemplo "-resize 100x100^>"
    • De modo semelhante, o sinalizador de 'ajuste interno de redimensionamento' '^' precisa ser duplicado para tornar-se '^^'.
  • As barras invertidas de escape do shell UNIX '\' não são necessárias para escapar parênteses '()' nem pontos de exclamação '!'.
  • Fora isso, as barras invertidas de escape do shell UNIX '\' precisarão ser substituídas por um circunflexo '^', quando escaparem caracteres como '<' e '>'.
    Por exemplo: "-resize 100x100\>" tornar-se-á "-resize 100x100^>".
  • Em arquivos batch do DOS, o caractere de porcentagem '%' também tem um significado especial, pois referencia os parâmetros de linha de comando. Por exemplo %1, %2, ... (no shell UNIX, um sinal '$' é usado com o mesmo sentido geral). Em um arquivo batch do DOS, os sinais de porcentagem simples (como aparecem no "comando FOR") precisarão ser duplicados para '%%'. O próprio ImageMagick, em geral, apenas verifica se há um sinal de porcentagem presente, e não se importa se mais de um foi dado. Assim, a menos que faça parte de um rótulo de texto ou de uma cadeia de comentário, duplicar todos os sinais de porcentagem em geral não faz mal.
  • Tenha em mente que os nomes de arquivo do Windows podem conter caracteres de espaço. Espaços também podem ser usados no UNIX, mas não é tão comum. Esses nomes de arquivo que podem conter espaços têm de ser colocados entre aspas duplas "file name.jpg" ou "file name".jpg. Um nome de arquivo passado a um script ou arquivo batch via Arrastar e Soltar ou SendTo como parâmetro de linha de comando merece atenção especial, pois é passado ao script sem aspas se não contiver caracteres de espaço, e com aspas quando contiver.
  • Comentários em scripts de shell UNIX começam com um '#' sem aspas em qualquer ponto de uma linha e continuam até o fim da linha. Definições de cor (como "#FF0000" para a cor vermelha) costumam ser colocadas entre aspas para remover esse significado especial. Essa colocação entre aspas não é necessária no DOS, mas usar aspas duplas '"' ao redor delas não faz diferença e deve ser mantido. No DOS, os comentários só podem aparecer no início de uma linha usando um prefixo 'REM', '@REM' ou '::'. Ainda que também continuem até o fim da linha. Fica a critério de cada um qual método de comentário usar. No entanto, comentar bem em qualquer arquivo batch é sempre recomendável, para que se saiba o que o comando tenta fazer em cada passo, ao retornar ao script meses ou anos depois. Também facilita muito para que outras pessoas o compreendam. Todos os scripts deveriam começar com um comentário mais amplo, explicando o que o script faz e como deve ser usado. Isso é simplesmente boa prática de programação.
  • Ao executar um arquivo batch do DOS, os comandos individuais são ecoados por padrão, isto é, os comandos são exibidos na caixa de saída do DOS. No UNIX, seria preciso, em vez disso, acrescentar um comando ou opção especial para exibir dessa forma os comandos em execução. É possível desativar essa saída 'ecoada' iniciando o script com "@ECHO OFF". O comentário inicial especial "#!/path/to/shell" dos scripts de shell UNIX não é necessário para arquivos batch do DOS. Assim, essa linha pode ser substituída pelo comando "@ECHO OFF" nos arquivos batch do DOS.

Por exemplo, seguindo as regras acima, este script de shell UNIX...

  #!/bin/sh
  # Create a negated rose image and overlay a comment
  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

tornar-se-á algo assim como um arquivo batch do DOS no Windows...

  @ECHO OFF
  :: Create a negated rose image and overlay a comment
  magick -background none -fill red -gravity center  ^
          -font "C:\path\to the\font\candice.ttf"  ^
          -size 140x92   caption:"A Rose by any Name"  ^
          ( rose: -negate -resize 200%% ) +swap -composite  ^
          C:\where\to\save\output.gif

Escrevi um conversor básico de script de shell Linux para arquivo batch do DOS usando o SED (S treaming ED itor). O SED é um programa comum de manipulação de arquivos de texto do UNIX / Linux, também disponível para Windows em http://sed.sourceforge.net/. Assim como o IM é um manipulador de imagens orientado por comandos, o SED é um editor orientado por comandos. O script SED cim.txt que realiza as manipulações necessárias tem esta aparência (depois de retirados quaisquer comentários):

  s/'/\"/g
  s/%/%%/g
  s/\\\([()!]\)/\1/g
  s/\([&|<>]\)/^\1/g
  s/^[ ]*#/::/
  s/\(^.*\)\( #.*$\)/\2\n\1/
  s/\(.:.*\.[a-z,A-Z]*\)[ ]/\"\1\" /g
  s/\\[ ]*$/^/
  s/^[ ][ ]//

É possível baixar a versão totalmente comentada no arquivo sed_script.zip. Se colocar o script SED cim.txt na mesma pasta do script de shell Linux a ser convertido, invoca-se a conversão com:

  %programfiles%\GnuWin32\bin\SED -f  cim.txt linux.scr > windows.bat

Também é possível invocar a conversão via SendTo ou Arrastar e Soltar usando o seguinte arquivo batch:

SET SP=%programfiles%\GnuWin32\bin
%SP%\SED -f %SP%\cim.txt "%~1"> "%~dpn1.bat"

Este arquivo batch presume que se tenha colocado o script SED cim.txt dentro da pasta de programas do SED. Ele recebe o nome do script de shell Linux como único parâmetro de linha de comando e gera um arquivo batch com o mesmo nome, mas com extensão '.bat', na mesma pasta. (A manipulação críptica de nome de arquivo "%~dpn1.bat" é explicada na próxima seção.) Observe: o script SED acima só realiza as substituições rudimentares mencionadas acima. Ele NÃO transformará scripts de shell Linux sofisticados (como os apresentados no site de Fred Weinhaus) no arquivo batch equivalente!

Tratamento de nomes de arquivo em arquivos batch

Como se disse acima, o IM é particularmente útil ao aplicar uma sequência padronizada de passos de processamento a um arquivo de imagem. Nesse caso, o nome do arquivo será passado ao script como parâmetro de linha de comando, seja via Arrastar e Soltar, seja via SendTo. Usando essas técnicas, o nome de arquivo entregue ao arquivo batch do DOS será um nome totalmente qualificado, isto é, incluirá o nome da unidade e o caminho do diretório. Isso pode ser testado soltando um arquivo sobre o seguinte arquivo batch:

ECHO Filename: %1
PAUSE

Por causa da instrução PAUSE, a caixa do DOS permanecerá aberta até o usuário pressionar uma tecla, de modo que se possa inspecionar o resultado. Experimente o acima com um nome de arquivo que contenha espaços e notará que o nome ficará entre aspas duplas.Observe que aqui e em todos os exemplos a seguir presume-se que a qualquer arquivo de rede tenha sido atribuída uma letra de unidade. Na prática, nunca vi diferente em uma rede comercial local. Ao trabalhar com arquivos batch, não convém tentar lidar com nomes UNC: pode-se até fazer o arquivo batch funcionar, mas isso causará muitos problemas desnecessários.Ao usar esse nome de arquivo em uma linha de comando do Convert, esse comportamento pode causar problemas. Vamos realizar uma conversão simples de qualquer outro formato para JPEG. O código mais básico seria:

magick %1 %1.jpg
PAUSE

Isso produzirá um arquivo JPEG (com qualidade e resolução padrão) no mesmo diretório, com uma extensão ".jpg" adicional ao final. O código acima funciona com qualquer nome de arquivo, contenha espaços ou não. Para se livrar da extensão original, as coisas ficam um pouco mais complicadas:

magick %1 "%~dpn1.jpg"
PAUSE

O arquivo batch acima manipula o nome do arquivo por meio do operador ~: %~1 expande %1 removendo quaisquer aspas ao redor (")
%~f1 expande %1 para um nome de caminho totalmente qualificado
%~d1 expande %1 apenas para a letra da unidade
%~p1 expande %1 apenas para o caminho
%~n1 expande %1 apenas para o nome do arquivo
%~x1 expande %1 apenas para a extensão do arquivo
Esses modificadores podem ser combinados, de modo que "%~dpn1" significa "unidade + caminho + nome sem extensão e sem aspas ao redor". Por conseguinte, temos de colocar o nome entre aspas duplas, para que o código também funcione com nomes de arquivo que incluam espaços. (Se não incluírem, as aspas não fazem mal.) A instrução PAUSE serve apenas para fins de teste e pode ser retirada no arquivo batch final. Se quiser apenas testar o código sem de fato invocar o IM, deve-se escrever:
ECHO magick %1 "%~dpn1.jpg"
PAUSE

o que apenas mostrará o resultado da sua manipulação de cadeia.

Processamento em lote de vários arquivos

Laços FOR

O comando FOR do DOS pode ser usado para processar uma série de arquivos de modo semelhante ao que faz no UNIX. Para reduzir em 50% todos os arquivos JPEG do diretório atual, pode-se digitar a seguinte linha em uma caixa do DOS:

  FOR %a in (*.jpg) DO magick %a -resize 50% small_%a

Observe que o sinal de porcentagem não é duplicado. No entanto, ao colocar esse comando em um arquivo batch, será preciso substituí-lo por

  FOR %%a in (*.jpg) DO magick %%a -resize 50%% small_%%a

Novamente, é conveniente invocar essa operação em lote por Arrastar e Soltar ou SendTo, passando um nome de arquivo totalmente qualificado (ou um nome de pasta) a um arquivo batch do DOS possivelmente localizado em outro diretório (como shell:sendto). Nesse caso, devemos, como primeiro passo, tornar o diretório do arquivo o diretório atual:

  %~d1
  CD "%~p1"
  MD small
  FOR %%a in (*.jpg) DO magick %%a -resize 50%% small\%%a
  PAUSE

Neste arquivo batch nós

  • mudamos a unidade fornecendo o nome da unidade (d: ou o que for)
  • tornamos a pasta do arquivo o diretório atual
  • criamos um subdiretório chamado "small"
  • reduzimos todos os arquivos JPEG em 50% e colocamos essas versões reduzidas no novo subdiretório.

Observe: como o til (~) libera o nome de arquivo passado como parâmetro de linha de comando de quaisquer aspas que possam envolvê-lo, normalmente temos de colocar o resultado de qualquer manipulação desse tipo novamente entre aspas. Por isso escrevemos CD "%~p1" no exemplo acima. No caso do comando CD, poderíamos até ter omitido as aspas ao redor, pois esse comando aceita apenas um parâmetro e, portanto, consegue lidar com espaços em branco sem aspas ao redor.Tornar o diretório do arquivo o diretório atual como primeiro passo torna os passos seguintes um pouco mais fáceis, pois as referências a nomes de arquivo ficam um pouco mais fáceis e curtas. Poderíamos, porém, ter escrito igualmente:

  MD "%~dp1small"
  FOR %%a in ("%~dp1*.jpg") DO magick "%%a" -resize 50%% "%%~dpasmall\%%~nxa"
  PAUSE

Isso pode tornar as coisas um pouco mais curtas, mas também bem mais complicadas. Observe que os modificadores de nome de arquivo também funcionam sobre a variável do laço For %%a. Observação dois: a barra invertida final faz parte do nome de caminho. Portanto, deve ser "%~dp1small" e não "%~dp1\small", o que não torna o código mais legível, especialmente no caso de "%%~dpasmall\%%~nxa".Há várias limitações e ressalvas na instrução FOR. Uma delas é que, em essência, executa-se apenas um único comando após DO. É possível, porém, agrupar uma série de comandos do DOS entre parênteses "(", ")" e, assim, executar uma sequência simples de comandos:

  @ECHO OFF
  :: Lighten darker areas of all images in a directory
  %~d1
  CD "%~p1"
  FOR %%a in (*.jpg) DO (
    ECHO Processing file: "%%~nxa"
    magick %%a -blur 30 -negate %%a.miff
    magick composite %%a.miff %%a -compose overlay "%%~dpn1_light"%%~xa
    DEL %%a.miff
  )
  PAUSE

Este arquivo batch processará todas as imagens encontradas no diretório passado como argumento de linha de comando. Primeiro ele desfoca a imagem original e a negativa, armazenando o resultado intermediário em um arquivo com uma extensão ".miff" adicional. Depois superpõe a imagem original sobre essa versão modificada, clareando assim as seções mais escuras da imagem original. Por fim, a imagem intermediária é excluída. Observe que, no exemplo acima, a ênfase deve recair sobre a sequência simples de comandos: não é possível usar saltos GOTO dentro do bloco. Se esse comportamento for necessário, é preciso chamar outro arquivo batch a partir do laço FOR:

  %~d1
  CD %~p1
  MD small
  FOR %%a in (*.jpg) DO CALL "%~dp0process" "%%~fa"

Onde "process.bat" é o arquivo batch que faz o trabalho de fato e que está localizado no mesmo diretório do arquivo batch que o chama. O parâmetro de linha de comando 0 ("%0") é o nome do próprio arquivo batch, de modo que "%~dp0process" chama o arquivo batch process.bat no mesmo diretório. A instrução FOR fornece apenas o nome do arquivo, que é transformado em um nome totalmente qualificado via "%~fa". No presente caso, o código do arquivo batch process.bat seria o mesmo que foi colocado entre os parênteses no exemplo acima:

  magick %%1 -blur 30 -negate %%1.miff
  magick composite %%1.miff %%1 -compose overlay "%%~dpn1_light"%%~x1
  DEL %%1.miff

O uso de um arquivo batch separado, contudo, oferece todas as (limitadas) possibilidades de um arquivo batch do DOS. Isso não faz diferença neste exemplo, mas mostraremos os benefícios dessa abordagem mais adiante. Se não quiser se incomodar com dois arquivos batch, pode-se fazer o script criar o segundo script process.bat (usando ECHO), chamá-lo a partir do laço principal e depois excluí-lo quando a tarefa terminar:

  ECHO magick %%1 -blur 30 -negate %%1.miff >%~dp0process.bat
  ECHO composite %%1.miff %%1 -compose overlay "%%~dpn1_light"%%~x1 >>%~dp0process.bat
  ECHO DEL %%1.miff >>%~dp0process.bat
  %~d1
  CD %~p1
  MD small
  FOR %%a in (*.jpg) DO CALL "%~dp0process" "%%~fa"
  DEL %~dp0process.bat

Ao usar o comando ECHO, temos de escapar quaisquer caracteres especiais do DOS, sobretudo o sinal de porcentagem, uma segunda vez. E sim, o IM poderia ter feito tudo o que foi descrito acima em um único comando de processamento, eliminando a necessidade da imagem intermediária ".miff", mas não é esse o ponto deste exemplo.

Processamento em lote de uma árvore de (sub)diretórios

Há várias técnicas para processar todos os arquivos em uma árvore de (sub)diretórios. A abordagem mais simples é usar o sinalizador "/R" na instrução FOR para fazê-la percorrer em laço todos os arquivos em todos os subdiretórios abaixo do diretório atual. Para transformar em JPEG todos os arquivos TIFF da árvore de subdiretórios, basta então digitar:

  FOR /R %%a IN (*.tif) DO imconv "%%~a" "%%~dpna.jpg"

Ao usar o sinalizador "/R", percorre-se sempre a árvore inteira de subdiretórios, sem opções de ordenação ou filtragem de arquivos. No exemplo seguinte, geraremos folhas de índice de fotos para todos os subdiretórios e as colocaremos no diretório raiz. Isso oferece uma maneira fácil de fazer uma busca visual por determinada fotografia, semelhante à visualização no Windows Explorer, mas sem a necessidade (demorada) de rastrear novamente a árvore inteira de diretórios a cada busca. Para começar, abordamos o problema com a ajuda de dois arquivos batch, um realizando o laço e outro fazendo o trabalho de fato. As folhas de índice serão arquivos JPEG de baixa qualidade chamados IDX_0001.jpg, IDX_0002.jpg, IDX_0003.jpg e assim por diante. Primeiro estabelecemos o laço:

  DEL IDX_????.JPG
  SET COUNT=0
  FOR /F "delims=" %%a in ('DIR /S /B /AD ^|FIND /I "Porsche" ^|SORT') DO CALL c.bat "%%a"
  DEL title.txt

A primeira linha limpa quaisquer resultados de buscas anteriores. Na segunda linha, definimos a variável de ambiente COUNT, que usaremos para gerar os nomes de arquivo IDX_nnnn.JPG. Na terceira linha, estabelecemos uma lista de todos os subdiretórios via DIR /S /B /AD, extraímos aqueles diretórios que contêm a palavra "Porsche" (sem diferenciar maiúsculas de minúsculas com o uso da opção /I) e ordenamos essa lista filtrada. A ordenação garantirá que a ordenação numérica dos arquivos IDX coincida com a ordenação alfabética dos nomes de caminho dos diretórios. A opção "delims=" inibirá o comportamento padrão de truncar as linhas após o primeiro espaço em branco. Ao chamar o arquivo batch C.BAT, colocamos o nome de caminho entre aspas para garantir que os espaços em branco sejam tratados corretamente. Na última linha, excluímos um arquivo temporário criado pelo arquivo batch C.BAT. Chegamos agora ao trabalho de fato:

  CHCP 1252
  DIR %1\*.jpg>nul || GOTO :EOF

  :: Generate IDX filename
  SET /A COUNT+=1
  SET TFILE=000%COUNT%
  SET TFILE=IDX_%TFILE:~-4%.jpg

  :: Generate title without bracketing quotes
  ECHO %~1>temp.txt
  "C:\Program Files\Gnuwin32\bin\iconv.exe" -f ISO-8859-1 -t UTF-8 temp.txt>title.txt

  montage -geometry 210x140+0+5 -tile 6x -title @title.txt %1\*.jpg -quality 30%% %TFILE%
  jhead -cl %1 %TFILE%

Na primeira linha, trocamos a página de código para latim da Europa Ocidental (ISO-8859-1). Na segunda linha, verificamos se o diretório de fato contém alguma fotografia e pulamos o restante do arquivo batch caso não contenha. (Executar o restante do arquivo batch, em vez disso, na verdade não faria mal, pois magick montage simplesmente não geraria saída, mas a contagem dos arquivos IDX deixaria de ser consecutiva.) Desde o Windows XP há um rótulo de destino de GoTo especial :EOF, que permite encerrar a execução sem definir um rótulo adequado.Em seguida, geramos o nome de arquivo "TFILE" do arquivo de índice incrementando "COUNT", acrescentando alguns zeros à esquerda e extraindo os últimos 4 caracteres via %TFILE:~-4%, concatenando-os então para criar um nome de arquivo na forma "IDX_nnnn.jpg". O uso da instrução SET /A para realizar cálculos é explicado em Cálculos usando SET mais adiante. Nas linhas seguintes, liberamos o nome de caminho "PNAME" das aspas e armazenamos o resultado no arquivo intermediário 'temp.txt', que é transcodificado para Unicode (UTF-8) com a ajuda do "Icon.exe" (veja "Codificação de caracteres"). A cadeia Unicode armazenada em 'title.txt' é então lida pelo Montage do IM. Isso garante que a cadeia seja tratada literalmente, de modo que não precisemos escapar as barras invertidas nos nomes de caminho do Windows. O Montage então combina as fotografias em fileiras de seis (-tile 6x) e as intitula com o nome de caminho. A folha de índice resultante terá 1260 pixels de largura e é armazenada com 30% de qualidade JPG a fim de reduzir a demanda de armazenamento. Na última linha, usamos o programa JHEAD para escrever o nome de caminho no comentário do JPEG. Isso oferece a possibilidade de filtrar as folhas de índice dentro do Windows Explorer buscando por texto nos arquivos por certas subcadeias no nome do arquivo. Podemos combinar os dois arquivos batch, colocando o código do "arquivo batch de trabalho" dentro do laço FOR:

  SETLOCAL EnableDelayedExpansion
  SET ICONV="%PROGRAMFILES%\Gnuwin32\bin\iconv.exe" -f ISO-8859-1 -t UTF-8
  CHCP 1252
  DEL IDX_????.JPG
  SET COUNT=0
  FOR /F "delims=" %%a in ('DIR /S /B /AD ^|FIND /I "Porsche" ^|SORT') DO (
    DIR "%%a\*.jpg">nul
    IF !ERRORLEVEL!==0 (
      SET /A COUNT+=1
      SET TFILE=000!COUNT!
      SET TFILE=IDX_!TFILE:~-4!.jpg
      ECHO %%a >temp.txt
      %ICONV% temp.txt>title.txt
      montage  -geometry 210x140+0+5 -tile 6x -title @title.txt "%%a\*.jpg" -quality 30%% !TFILE!
      jhead -cl %%a !TFILE!
    )
  )
  DEL temp.txt
  DEL title.txt

Basicamente, duas modificações têm de ser aplicadas ao código inicial:

  • Temos de habilitar a expansão retardada (delayed expansion) e referenciar as variáveis de ambiente usadas dentro do laço FOR colocando-as entre pontos de exclamação em vez de sinais de porcentagem.
  • Temos de evitar a instrução GOTO, que reiniciaria o processador de comandos.

Por padrão, as variáveis de ambiente dentro de um laço FOR não são avaliadas em tempo de execução. Em vez disso, o código é pré-processado usando a lista dada nos parênteses. Uma referência a %COUNT% dentro do laço FOR, portanto, sempre devolve o mesmo valor. Para habilitar a avaliação em tempo de execução das variáveis de ambiente, é preciso ativar a expansão retardada. Isso pode ser feito ao chamar o processador de comandos via cmd /V:on ou ativado de modo geral no registro, usando o seguinte arquivo REG:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"DelayedExpansion"="1"

[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"DelayedExpansion"="1"

No entanto, a versão à prova de erros consiste em definir essa opção no próprio arquivo batch com o uso de SETLOCAL EnableDelayedExpansion, que também limitará quaisquer alterações às variáveis de ambiente à versão atual do processador de comandos, o que provavelmente é o desejado. As referências aos valores em tempo de execução das variáveis de ambiente dentro do laço agora têm de usar pontos de exclamação em vez de sinais de porcentagem. O uso de instruções GOTO dentro de um laço FOR é uma possível fonte de erros muito sutis e deve, portanto, ser evitado. Em nosso arquivo batch podemos, contudo, trocar facilmente o salto por uma instrução IF que envolve o bloco de código com o código do montage.

Processamento em lote de um número arbitrário de arquivos

Em arquivos batch do DOS, apenas nove parâmetros de linha de comando podem ser endereçados diretamente por %1 a %9. Em versões antigas do Windows, só era possível contornar essa limitação com o comando SHIFT, que causava um deslocamento circular dos parâmetros de linha de comando. Em versões mais novas, os parâmetros de linha de comando podem ser tratados em um laço For:

  FOR %%i in (%*) DO ...

Isso nos permite montar (Montage) um número arbitrário de imagens passadas por Arrastar e Soltar:

  @ECHO OFF
  SETLOCAL EnableDelayedExpansion
  %~d1
  CD "%~p1"
  DEL Files.txt   2>nul:
  DEL FSorted.txt 2>nul:
  FOR %%I in (%*) DO ECHO %%~nxI>>files.txt
  FOR /F "delims=" %%A in ('TYPE files.txt ^| Sort') Do (
  ECHO %%A>>fsorted.txt
  )
  SET MONTAGE=montage -tile 3x
  FOR /F "delims=" %%A in (FSorted.txt) Do (
  SET MONTAGE=!MONTAGE! %%A
  )
  SET MONTAGE=%MONTAGE% result%~x1
  %MONTAGE%
  DEL Files.txt
  DEL FSorted.txt

O código acima presume que os arquivos passados como parâmetros de linha de comando residem no mesmo diretório e têm de ser montados de acordo com a ordem alfanumérica de seus nomes de arquivo. Isso faria sentido, por exemplo, para um índice de fotografias digitais, que assim ficariam ordenadas de acordo com a hora em que foram tiradas. Primeiro tornamos o diretório dos arquivos o diretório atual, o que torna o restante do código bem mais simples. Em seguida, despejamos os nomes dos arquivos em files.txt. Mesmo que os arquivos tenham sido selecionados em ordem alfabética, não podemos confiar que essa ordenação seja preservada quando os nomes dos arquivos são passados ao script. Por isso, ordenamos os arquivos em um segundo passo de trabalho, despejando-os em fsorted.txt. Com base nesse arquivo, construímos então a linha de comando do Montage em outro laço For. O arquivo de saída do Montage usa a mesma extensão do primeiro arquivo de entrada (%~x1). (Presumindo que todos os arquivos compartilhem a mesma extensão.) Observe que o comando Montage final é apenas chamado avaliando-se a variável de ambiente, isto é, %MONTAGE%.Como foi dito em , passar uma grande quantidade de arquivos com nomes (completos) longos pode causar problemas no Windows XP, pois a lista de parâmetros do ShellExecute é limitada a 2048 caracteres. Esse erro não pode ser tratado pelo arquivo batch, pois ocorre antes de o controle ser passado ao arquivo batch. Uma possível solução baseada em script é processar todos os arquivos de imagem do diretório quando apenas um arquivo é passado ao arquivo batch:

 %~d1 & IF EXIST %1\* (CD %1) ELSE CD %~p1
 IF "%2"=="" (
 SET PATTERN=*.jpg
 ) ELSE (
 SET PATTERN=%*
 )
 FOR %%v IN (%PATTERN%) DO (...)

Na primeira linha, verificamos se o segundo parâmetro de linha de comando está presente. Em caso afirmativo, todos os parâmetros de linha de comando (%*) são processados. Se apenas um arquivo é passado ao script, o padrão é definido como todos os arquivos JPEG. Essa correspondência simples de padrão exige que tenhamos mudado para a unidade atual (via %~d1) e para a pasta atual, isto é,

  • CD %1 se um nome de pasta foi passado ao script
  • CD %p1 se um nome de arquivo foi passado ao script.

Obtendo informações do ImageMagick

Reutilizando a saída de um comando do IM

Nas versões recentes do Windows, a instrução FOR tornou-se muito mais poderosa, veja DOS "For" Command Help. Usando a opção "/F", é possível ler a entrada da variável de substituição a partir de um arquivo, de uma cadeia ou da saída de outro comando do DOS ou de outro programa. Este último caso é especialmente útil com o IM. Para ter uma ideia geral do que realmente são os métodos de sobreposição do IM, pode-se usar o seguinte arquivo batch:

  @ECHO OFF
  :: compose two gradients using all compose methods available
  ::
  magick -size 80x80 -flip gradient: compose_src.png
  magick compose_src.png -rotate 90 compose_dst.png
  FOR /F %%A in ('magick -list compose') DO ^
     magick composite compose_src.png compose_dst.png -compose %%A compose_%%A.png

[IM Output]
Src | [IM Output]
Dst | | [IM Output]
Multiply | [IM Output]
Screen | [IM Output]
Overlay
---|---|---|---|---|---

Este script compõe duas imagens de gradiente, usando todos os métodos de composição alfa possíveis disponíveis, para que se veja como os operadores afetam as cores da imagem. Apenas algumas das imagens que ele gera são mostradas acima. Isso é semelhante às imagens geradas para Composition Tables, para que se veja como os operadores afetam as cores da imagem. Como as linhas acima são presumidas como um arquivo batch, temos de duplicar os sinais de porcentagem. O script acima cria primeiro duas imagens em escala de cinza ortogonais (alinhadas em ângulo reto) com gradientes que cobrem toda a faixa de escala de cinza. O comando Convert -list compose do IM nos fornecerá uma lista de opções possíveis, cada uma colocada em uma única linha de saída. Observe que temos de usar aspas simples ao referir-nos a um comando entre parênteses. Usando a opção "/F", o comando FOR processará então cada uma dessas linhas de saída e a passará ao comando executado por DO. Como consequência, as duas imagens de gradiente são superpostas aplicando todos os métodos de sobreposição que o IM conhece. Os arquivos de saída são nomeados de acordo com o método de sobreposição. No próximo exemplo, ilustramos os espaços de cor que o IM oferece. Usamos a mesma técnica de gradiente de antes para gerar as faces de um cubo definido pelas três coordenadas do espaço de cor:

magick -size 256x256 gradient: gy.miff
magick gy.miff -rotate 90 gx.miff
magick -size 256x256 xc:black black.miff

::R + G top left
magick gy.miff gx.miff -flop black.miff -set colorspace %1 -combine ^
        -resize 260x300! -background none -shear 0x-30 ^
        -virtual-pixel Transparent RG.miff

:: R + B top right
magick gy.miff  black.miff gx.miff -set colorspace %1 -combine ^
        -resize 260x300! -background none -shear 0x30 RB.miff

:: G + B bottom
magick black.miff gx.miff gy.miff -set colorspace %1 -combine ^
        -resize  260x300! -background none -shear 0x30 -rotate 120 ^
        -crop 520x300+0+75 GB.miff

magick -set colorspace %1 RG.miff RB.miff +append top.miff
magick -set colorspace %1 -size 520x150 xc:Transparent w.miff
magick top.miff w.miff -append topx.miff

composite -geometry +0+299 GB.miff  topx.miff colorspace_%1.png
DEL *.miff

[IM Output]
colorspace RGB | [IM Output]
colorspace sRGB
---|---
Um exemplo semelhante ao acima usando scripts de shell UNIX é dado em Cubo isométrico usando cisalhamentos.

Este arquivo batch recebe o espaço de cor como parâmetro de linha de comando "%1". Em seguida, gera as três faces do cubo e as cisalha e monta de modo a obtermos uma vista isométrica, na qual o ponto (0,0,0) fica no centro de um hexágono. A imagem final é nomeada conforme o espaço de cor (isto é, "%1") e armazenada como PNG. Agora queremos chamar este arquivo batch (salvo como "cspace.bat") a partir de outro arquivo batch que fornece os nomes dos espaços de cor:

  FOR /F %%A in ('magick -list colorspace') DO CALL cspace %%A

Também podemos filtrar a saída da opção -list encadeando-a no DOS:

  magick -list colorspace | FIND "RGB" >>clist.txt
  FOR /F %%A in (clist.txt) DO CALL cspace %%A
  DEL clist.txt

Neste exemplo, filtramos da saída as linhas que contêm "RGB" e as escrevemos no arquivo clist.txt. Esse arquivo é então usado como entrada para o comando FOR /F. Também podemos fazer isso em uma só execução, evitando o arquivo temporário:

  FOR /F %%A in ('magick -list colorspace ^| FIND "RGB"') DO CALL cspace %%A

Nesse caso, o símbolo de encadeamento "|" tem de ser escapado, pois não está entre aspas duplas (apenas entre as aspas simples necessárias para a instrução FOR) e (ao menos na linha de comando acima) não está no seu sentido habitual.

Processando saída de uma única linha

Essa técnica também pode ser aplicada de forma útil a uma saída de uma única linha. Podemos, por exemplo, aplicar uma correção de gama automática que ajusta aproximadamente o brilho médio de uma imagem para o meio da faixa de quantum (isto é, 127 para uma profundidade de cor de 8 bits) por meio de uma técnica explicada no site de Fred Weinhaus:

  FOR /F %%a in ('identify -format "%%[fx:log(mean)/log(0.5)]" %1') DO ^
  magick %1 -gamma %%a "%~dpn1"_c.%~x1

A este arquivo batch é passado um nome de arquivo totalmente qualificado como parâmetro de linha de comando "%1", muito provavelmente via Arrastar e Soltar ou SendTo. A saída do comando Identify do IM fornece então um valor de gama, que ajustará o brilho médio da imagem para o meio de sua faixa dinâmica. Esse valor é calculado usando uma expressão de formato FX. A saída de uma única linha do comando Identify é salva na variável "%%a" e passada ao comando Convert como argumento para o operador Gamma. O comando FOR parece ser bastante sensível quando se trata de continuações de linha: se as usar, certifique-se de não começar a linha seguinte com espaços.
Este método de correção de gama automática hoje está embutido no IM usando "[-auto-gamma](https://imagemagick.org/command-line-options/#auto-gamma)", e foi adicionado ao IM v6.5.5-1. Mas ele mostra a técnica de reutilizar a saída de um comando para uso em argumentos de comandos posteriores.
--- ---
Com a mesma técnica de FOR, podemos ler a informação EXIF embutida em uma fotografia e escrevê-la no canto superior esquerdo da imagem:
  FOR /F "tokens=1,2" %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize 18 -fill white -gravity northwest ^
    -annotate +0+0 "%%i %%j" "%~dpn1"_dated%~x1

| Fotos costumam ser salvas em formato JPEG. Ler e salvar novamente imagens JPEG causa uma leve degradação da imagem devido à compressão com perdas do JPEG e, por isso, salvar de volta em JPEG não é recomendável.
---|---
No arquivo batch acima, o nome de arquivo da fotografia é fornecido como o único parâmetro de linha de comando, referido como "%1". O comando Identify lê a data e a hora em que a fotografia foi tirada a partir da informação EXIF dentro do arquivo JPEG. O comando FOR passa então essa saída ao Convert, que anota a fotografia de forma correspondente no canto superior esquerdo. A informação EXIF de data e hora é formatada como "yyyy:mm:dd hh:mm:ss", por exemplo "2006:12:26 00:22:38". Assim, data e hora são separadas por um caractere de espaço. Por padrão, a instrução FOR só encontraria o primeiro token ("palavra") em cada linha, com os caracteres de tabulação e espaço como delimitadores padrão. Assim, no exemplo acima, o processamento padrão devolveria apenas a data, mas não a hora. Usando a opção "tokens=1,2" declaramos nosso interesse em ambos os tokens, que são nomeados consecutivamente, isto é, "%x, %y". Podemos, contudo, alterar a formatação bastante inusitada da data com o seguinte código:

  FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize 18 -fill white -gravity northwest ^
    -annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1

Agora definimos os dois-pontos (':') como delimitador adicional, fazendo a data ser dividida nos três tokens "%i", "%j", "%k". O próximo delimitador encontrado é o caractere de espaço que separa data e hora. Com o asterisco ("*") pedimos que o restante da linha seja armazenado no quarto token "%l". Agora podemos formatar a data como quisermos. Escolhemos a notação anglo-americana "mm/dd/yyyy", como no exemplo acima.

Definindo vários valores a partir de um único comando

Uma técnica para definir vários valores a partir de um único comando do ImageMagick é fazer o comando formatar os dados, de modo que se possam definir várias variáveis.

  FOR /F %%L IN ('identify -format "Width=%%w\nHeight=%%h" %1') DO set %%L

Isso resulta em definir ambas as variáveis do DOS 'Width' e 'Height' a partir de uma única chamada do comando do ImageMagick.

Realizando cálculos

O interpretador de comandos do DOS é fraco quando se trata de cálculos. Pode-se usá-lo para realizar aritmética simples com inteiros. Mas, para fazer matemática de ponto flutuante mais complexa, tem-se acesso à expressão de formato FX do IM ou a um programa calculador de DOS de terceiros.

Usando as expressões FX do IM

A expressão de formato FX do IM pode ser usada para matemática de ponto flutuante e pode acrescentar essa matemática a cadeias formatadas maiores, como foi demonstrado acima no primeiro exemplo da seção Processando saída de uma única linha. Com o uso do comando SET, o resultado pode ser armazenado em uma variável de ambiente e usado mais adiante no arquivo batch. Como exemplo simples, podemos querer ajustar o tamanho da fonte da cadeia de data-hora do exemplo acima de acordo com as dimensões da fotografia:

  FOR /F %%i IN ('identify -format "%%[fx:min(w,h)*0.05]" %1') DO SET psize=%%i

  FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize %psize% -fill white -gravity northwest ^
    -annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1

Na primeira linha, avaliamos a menor dimensão da fotografia por "%[fx:min(w,h)]", tomamos 5% desse valor e o armazenamos na variável de ambiente PSIZE. Esse valor é referenciado na instrução seguinte (%psize%) para definir o tamanho da fonte da informação de hora-data. E aqui calculamos um ângulo aleatório como um inteiro entre -15° e +15° para criar uma imagem em miniatura rotacionada.

  FOR /F %%x IN ('magick null: -format "%%[fx:int(rand()*31)-15]" info:') DO SET angle=%%x
  magick %1 -thumbnail x90 -alpha set ^
            -background none -rotate %angle%   "%~dpn1"_rotated.png

As expressões FX não só podem gerar números, mas também gerar vários números, embutidos em uma cadeia maior. Por exemplo, em Borda com canto arredondado elas foram usadas para gerar diretamente uma cadeia de desenho complexa com base na informação de largura e altura da imagem. Esse recurso adicional, junto com evitar qualquer dependência adicional de outros programas externos, torna este método preferível para fazer cálculos no script batch.

Usando o comando SET

O comando SET pode realizar alguma matemática simples com inteiros e alguma manipulação básica de cadeias quando a opção "/A" é invocada. No exemplo a seguir, calculamos aproximadamente a largura da cadeia de hora-data com o uso do comando SET:

  :: Determine the font height
  FOR /F %%i IN ('identify -format "%%[fx:min(w,h)*0.05]" %1') DO SET psize=%%i

  :: The width of the date-time string is roughly 9 times its height
  SET /A pwidth=%psize% * 9

  :: Calculate the average brightness in this section
  :: and choose the text color correspondingly
  FOR /F %%i IN ('identify -format "%%[fx:mean]" -crop %pwidth%x%psize%+0+0 %1') DO SET mean=%%i
  IF %mean% LEQ 0.5 (SET fcolor=white) ELSE SET fcolor=black

  :: Annotate the photograph
  FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize %psize% -fill %fcolor% -gravity northwest ^
    -annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1

Este arquivo batch de exemplo escolhe a cor da cadeia de data-hora de acordo com o brilho médio (%mean%) na área onde ela será colocada. Se a intensidade média de cor for inferior a 50%, a cadeia será branca; caso contrário, será preta. O exemplo também faz uso da instrução IF. Observe que a parte ELSE tem de ser colocada na mesma linha e que o primeiro comando tem de estar entre parênteses.

Usando outras calculadoras externas

Como alternativa, pode-se usar um programa de DOS que ofereça matemática de ponto flutuante, como o EVAL. Ao colocar esse arquivo no diretório de programas do IM ou no diretório de sistema do Windows, é possível realizar cálculos de ponto flutuante em qualquer janela de shell do DOS. Usando o programa EVAL, o comando FOR e variáveis de ambiente, podemos tornar o exemplo do cubo de cores acima um pouco mais flexível e seus diversos cálculos mais transparentes:

  magick -size 256x256 gradient: gy.gif
  magick gy.gif -rotate 90 gx.gif
  magick -size 256x256 xc:black black.gif

  :: Set the dimension of the color cube / hexagon and calculate the various lengths
  SET l1=512
  FOR /F %%i IN ('EVAL "round(cos(degree*30)*%l1%)"') DO SET l2=%%i
  FOR /F %%i IN ('EVAL "2*%l2%"') DO SET l3=%%i
  FOR /F %%i IN ('EVAL "round((1+sin(degree*30))*%l1%/2)"') DO SET l4=%%i
  FOR /F %%i IN ('EVAL "round(%l1%/4)"') DO SET l5=%%i

  magick gy.gif gx.gif -flop black.gif -set colorspace %1 -combine ^
          -resize %l2%x%l1%! -background none -shear 0x-30 ^
          -virtual-pixel Transparent RG.miff

  magick gy.gif  black.gif gx.gif -set colorspace %1 -combine ^
          -resize %l2%x%l1%! -background none -shear 0x30 RB.miff

  magick black.gif gx.gif gy.gif -set colorspace %1 -combine ^
          -resize  %l2%x%l1%! -background none -shear 0x30 -rotate 120 ^
          -crop %l3%x%l1%+0+%l5% GB.miff

  magick -set colorspace %1 RG.miff RB.miff +append top.miff
  magick -set colorspace %1 -size %l3%x%l4% xc:Transparent w.miff
  magick top.miff w.miff -append topx.miff

  magick composite -geometry +0+%l1% GB.miff  topx.miff colorspace_%1.png
  DEL *.miff
  DEL *.gif

Edição, depuração e teste de erros em tempo de execução

Em princípio, os arquivos batch do DOS podem ser escritos em qualquer editor, até no Bloco de Notas do Windows. Convém, porém, usar um editor com destaque de sintaxe para arquivos batch do DOS. Pessoalmente, acho que o Notepad++ é a ferramenta ideal, mas falar de editores tende a deixar as pessoas irritadas. Então: sim, qualquer outro editor serve. Até onde sei, não há no mercado uma IDE (ambiente de desenvolvimento integrado) gratuita para arquivos batch. Poder-se-ia pensar que isso deveria vir com o sistema operacional, mas nunca foi o caso. Até agora escrevi todos os meus arquivos batch com o Notepad++, mas, para quem escreve arquivos batch com regularidade, a IDE de batch Running Steps pode ser de ajuda. É shareware e custa cerca de US$ 80. Explicações abrangentes dos comandos do DOS podem ser encontradas em http://www.computerhope.com/msdos.htm. Como a própria linguagem batch do DOS, depurar arquivos batch é um assunto bastante estranho. Eu testaria qualquer arquivo batch em uma caixa do DOS para começar. Ao testar Arrastar e Soltar ou SendTo, é recomendável encerrar o arquivo batch com uma instrução PAUSE, para que a caixa do DOS permaneça aberta após o término da tarefa em lote. Quanto às mensagens de erro em tempo de execução, a abordagem geral é verificar o ERRORLEVEL do DOS e saltar para uma mensagem de erro correspondente gerada pelo comando ECHO. Constatei que uma das fontes de erro mais prováveis é o programa Convert não ser encontrado corretamente na máquina que executa o script. Assim, se pretender compartilhar seus scripts batch com outras pessoas, deve-se, antes de tudo, verificar se o Convert está acessível:

  @ECHO OFF
  magick -version 1>nul: 2>nul:
  IF NOT %errorlevel%==0 GOTO NoMagick:
  magick ...
  GOTO :EOF
  ...
  :NoMagick
  ECHO ImageMagick (convert.exe) not found.
  PAUSE

Na primeira linha, consultamos a versão do ImageMagick, suprimindo a saída padrão com 1>nul: (ou apenas >nul:) e qualquer mensagem de erro com 2>nul:, isto é, redirecionamos _stdout_ e _stderr_ para nul:. Se a chamada ao Convert do IM falhar, o programa de sistema Convert será chamado em seu lugar, o qual não consegue tratar a opção -version e definirá a variável ERRORLEVEL.Pode-se tentar determinar por que o Convert não é encontrado e tentar corrigir o problema: é possível determinar se o caminho do programa do IM faz parte da variável de ambiente PATH:

  @ECHO OFF
  PATH | FIND /I "ImageMagick"
  IF NOT %errorlevel%==0 GOTO NoPath:
  ...
  :NoPath
  ...

Se o Find (chamado com a opção /I, que não diferencia maiúsculas de minúsculas) não conseguir encontrar a cadeia, ele define o ERRORLEVEL. Em uma abordagem mais sofisticada, pode-se verificar a entrada do Registro em vez disso, não dependendo mais do PATH:

  @ECHO OFF
  FOR /F "tokens=1,2,*" %%A in ^
  ('reg  query "HKCM\Software\ImageMagick\Current" ^| FIND "BinPath"') DO ^
  SET MPATH=%%C
  IF [%MPATH%]==[] GOTO NoMagick:
  "MPATH\convert.exe" ...
  ...
  :NoMagick
  ...

Com este código, consultamos a chave de Registro Current do IM e procuramos a entrada BinPath. A linha decisiva da saída é:LibPath REG_SZ C:\Program Files\ImageMagickAs "palavras" nessa linha de texto são separadas por tabulações (no Windows XP) ou por vários espaços em branco (no Windows Vista). Esses são os delimitadores padrão usados pelo For /F. A terceira "palavra" (%%C) é a que procuramos e a armazenamos na variável de ambiente MPATH, à qual podemos nos referir ao chamar o magick mais adiante no script.Um script pode exigir que uma determinada versão mínima do ImageMagick esteja instalada. Por exemplo, o método de distorção de perspectiva foi implementado pela primeira vez na versão 6.3.5-9 (em setembro de 2007). Assim, se o script lidar com retificação de perspectiva, deve-se testar se a versão instalada do IM é mais recente que essa:

  @ECHO OFF
  SETLOCAL EnableDelayedExpansion
  SET MINVERSION=7.5.3-0
  FOR /F "tokens=1,2,3" %%a in ('magick -version ^|FIND "Version"') DO SET VERSION=%%c
  IF %VERSION% LSS %MINVERSION% GOTO GetNewVersion:
  Goto :EOF
  :GetNewVersion
  ECHO This Script requires et least ImageMagick version %MINVERSION%.
  ECHO Yours is %VERSION%.
  PAUSE
  Goto :EOF

O SETLOCAL restringe quaisquer alterações às variáveis de ambiente ao script atual, de modo que não precisemos temer efeitos colaterais. A opção EnableDelayedExpansion não é realmente necessária aqui, mas é um bom hábito usar essa opção sempre que se usar SETLOCAL. Em seguida, armazenamos a versão mínima exigida na variável de ambiente MINVERSION. Na terceira linha, chamamos o Convert com a opção '-version', extraímos a primeira linha da saída via ^|FIND "Version", obtemos a terceira palavra dessa linha e a armazenamos na variável de ambiente VERSION. Comparamos então essa versão com a versão mínima exigida na quarta linha.

Otimizando o tempo de execução

Para medir o tempo de execução, pode-se exibir o conteúdo da variável de ambiente %TEMP%. O script a seguir testa várias formas de calcular o brilho médio de um arquivo de imagem (grande), digamos uma fotografia digital:

   IF "%1"=="" GOTO :EOF
   ECHO %TIME%
   Identify -verbose %1 | FIND "mean" & ECHO %TIME%
   copy %1 %TEMP%\*.* & ECHO %TIME%
   Identify -verbose %TEMP%\%1 | FIND "mean" & ECHO %TIME%
   Convert %TEMP%\%1  -format %%[fx:mean] info: & ECHO %TIME%
   Convert %TEMP%\%1 -resize 1x1! -format %%[fx:mean] info: & ECHO %TIME%
   DEL %TEMP%\%1

A imagem é passada ao script como o único parâmetro de linha de comando, que é testado na primeira linha do script. A seguir, o tempo de execução de várias abordagens é medido ecoando a variável de ambiente %TIME% antes e depois da instrução. O e comercial & permite colocar vários comandos do DOS em uma linha e é usado apenas para reduzir o espaço necessário para o código aqui. Se a imagem estiver em uma unidade de rede, a transferência para a memória do computador cliente pode consumir uma parcela considerável do tempo de execução. Por isso, o arquivo é copiado para a pasta temporária local, cujo nome é armazenado na variável de ambiente %TEMP%.Verifica-se que o simples comando Convert leva tanto tempo de execução quanto filtrar o resultado do Identify, mas que redimensionar a imagem para um pixel via -resize 1x1! acelera significativamente a operação, sem alterar demais seu resultado.Observe que usamos ECHO %TIME% em vez de TIME /T, pois este último exibe apenas horas e minutos, enquanto o primeiro fornece centésimos de segundo. Ao contrário dos shells de comando UNIX, não há forma direta de medir tempos relativos, isto é, definir um ponto de referência, executar a instrução e depois avaliar o tempo necessário. O cálculo de tempos relativos dentro de um arquivo batch é dificultado pelo fato de os arquivos batch permitirem apenas aritmética com inteiros. Pode-se extrair os segundos com o comando FOR e depois usar o operador fx do IM para realizar a subtração, considerando o transbordo de 60 segundos

   FOR /F "tokens=1,2,* delims=:" %%a in ("%TIME%") DO SET START=%%c
        ... some command(s)...
        FOR /F "tokens=1,2,* delims=:" %%a in ("%TIME%") DO SET STOP=%%c
   Convert null: -format "%%[fx:(%STOP%-%START%<0.0)?%STOP%-%START%+60.0:%STOP%-%START%]" info:

Isso, porém, só funcionará em versões do Windows onde o separador decimal está definido como o ponto decimal, pois a hora é fornecida de acordo com a localidade e o fx realiza seus cálculos de acordo com o esquema dos EUA. Ao contrário do VBScript, não há forma de alterar a localidade dentro de um arquivo batch (a não ser alterá-la para a máquina inteira via registro).Como alternativa, pode-se transformar a hora inteira em centésimos de segundo, o que pode ser feito em aritmética de inteiros, assim como calcular quaisquer diferenças mais tarde. O código básico é

   for /f "tokens=1-4 delims=:., " %%a in ("%TIME%") do ^
        set /a  Start100S=1%%a * 360000 + 1%%b * 6000 + 1%%c * 100 + 1%%d - 36610100

O "1" inserido antes de cada parte do código de hora dividido impede que números com zero à esquerda sejam (mal) interpretados como octais. O "erro de cálculo" introduzido por esse procedimento é depois compensado subtraindo-se 36610100 ao final. O código de exemplo completo (e mais elegante) pode ser encontrado aqui.Outra abordagem é o utilitário TimeIt oferecido pelo Windows 2003 Resource Kit, que pode ser baixado aqui. Oficialmente, porém, ele só suporta o Windows XP.

Diretrizes para programação de arquivos batch

Estas são, em resumo, as regras a seguir ao programar arquivos batch:

  • Comece com SETLOCAL EnableDelayedExpansion
  • Defina uma variável para referenciar a ferramenta Convert do IM: SET IMCONV="%PROGRAMFILES%\ImageMagick"
  • Ao trabalhar com vários arquivos, muitas vezes simplifica o código tornar a pasta que contém os arquivos a pasta atual, isto é,
    • mude para a unidade via %~d1
    • mude para a pasta via CD %~p1
  • Use o iconv.exe das GnuTools para transformar texto em UTF-8 e alimentar texto a partir de um arquivo.
  • Tenha em mente que o Convert e o Montage escrevem a saída textual em stderr, não em stdout.
  • Muitos erros surgem de nomes de arquivo que contêm espaços em branco, portanto verifique em cada arquivo batch se ele trata esses nomes corretamente.
  • Não se esqueça de duplicar cada sinal de porcentagem, por exemplo ao definir a qualidade JPEG.
  • Não se esqueça de escapar os caracteres especiais nas cadeias, por exemplo "^|".
  • Cálculos com inteiros realizados por SET /A tratam qualquer número que comece com zero como octal, portanto coloque um "1" antes de cada número desse tipo.

Resumindo

Os exemplos acima provam que o simples arquivo batch do DOS é surpreendentemente versátil quando combinado com as possibilidades oferecidas pelo ImageMagick. De fato, quase tudo pode ser feito de alguma forma (rudimentar) em um arquivo batch. Uma vez que se passa a pensar nas formas estranhas seguidas no desenvolvimento da linguagem de arquivos batch do DOS, os scripts podem até acabar bastante curtos. Ainda assim, essas poucas linhas de código provavelmente terão consumido horas de experimentos tediosos, a menos que se tenha real familiaridade com a linguagem de arquivos batch. Se o objetivo for mais do que tarefas básicas de processamento de imagem, é provavelmente recomendável usar uma linguagem de script mais sofisticada, pois o desenvolvimento do código será mais simples e mais estruturado.


Visual Basic Script (VBS)

Os recursos de script do Microsoft Windows Script Host (WSH) são mais sofisticados do que os da simples linguagem de arquivos batch. O WSH é independente de linguagem no sentido de que pode fazer uso de diferentes motores de linguagem Active Scripting. Por padrão, ele interpreta e executa arquivos JScript de texto simples (Java Script) e arquivos VBScript (VisualBasic Script). O Windows Script Host é distribuído e instalado por padrão a partir do Windows 98 (pode, no entanto, ter sido desativado em uma possível máquina alvo por questões de segurança). O WSH implementa um modelo de objetos que expõe um conjunto de interfaces COM que permitem endereçar objetos do sistema, em especial o sistema de arquivos. Não discutiremos o Windows Script Host em detalhe aqui, pois isso é feito em outro lugar (e provavelmente melhor); em vez disso, daremos alguns exemplos práticos de como enfrentar problemas típicos. Os exemplos são dados em VisualBasic Script, mas o código JScript seria muito parecido, de modo que deve ser fácil reescrever os exemplos em JScript, caso essa seja a linguagem preferida. Como os arquivos batch, os VBScripts podem ser escritos em qualquer editor, e eu novamente sugeriria o Notepad++ como editor de escolha. Assim como para os arquivos batch, a Microsoft não oferece uma IDE feita sob medida para dar suporte ao desenvolvimento de VBScripts. Havia um Microsoft Script Editor que vinha com o Microsoft Office de 2000 a 2003, mas nunca o experimentei. A Microsoft também oferece o (bastante rudimentar) Microsoft Script Debugger, mas, novamente, não tenho muita experiência pessoal com ele. Há várias IDEs comerciais para VBS oferecidas como shareware a preços razoáveis, como o VbsEdit. Como se disse na seção Instalando o ImageMagick no Windows, em geral não usaremos a interface COM+ do ImageMagick a seguir. As ferramentas do IM, como Convert, Montage e Identify, serão em vez disso executadas diretamente invocando o comando run do shell, com todas as opções e nomes de arquivo necessários, mais ou menos da mesma forma que se faz em arquivos batch. Ao montar a cadeia de comando, porém, aproveitaremos os recursos oferecidos por uma linguagem de programação de verdade.

Um exemplo básico: correção de lente

Como o uso do WSH gera certa sobrecarga, nosso exemplo inicial não é muito básico, a fim de demonstrar as vantagens do VBScript em comparação com um simples arquivo batch. A seguir, corrigiremos a distorção de lente da câmera digital Nikon 995 por meio da distorção de barril do IM. O(s) parâmetro(s) de correção dependem da distância focal, que é consultada primeiro via magick identify. Para a correção da lente da Nikon 995, precisamos apenas do parâmetro b (isto é, a, c = 0), que pode ser calculado a partir da distância focal f por: b = 0.000005142 f ³ - 0.000380839 f ² + 0.009606325 f - 0.075316854 Essa dependência foi encontrada por meio do banco de dados lensfun, que lista os parâmetros de distorção de barril para esta lente. Então aqui está nosso VBScript:

  SetLocale(1033)          ' US, i.e. decimal point
  const strConv = "IMCONV" ' name of the IM Convert program
  const strAdd = "_pt"    ' string attached to the filename
  '
  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  ' names of the in- and output files
  strFileIn = WScript.Arguments(0)
  Pos = InStrRev(strFileIn,".")
  strFileOut = Left(strFileIn,Pos - 1) & strAdd & Mid(strFileIn, Pos)
  '
  ' evaluation of the focal length and calculation of parameter b
  command = "identify -format ""%[EXIF:FocalLength]"" """ & strFileIn & """"
  Set objExec = wsh.Exec(command)
  strf = objExec.StdOut.Readline
  f = eval(strf)
  b =  0.000005142 * f * f * f -0.000380839 * f * f + 0.009606325 * f  -0.075316854
 '
  Command = strConv & " """ & strFileIn _
    &  """ -virtual-pixel black -filter point -distort Barrel   ""0.0 " _
    & b & " 0.0 "" """ & strFileOut & """"
  wsh.run command,7,true

Na primeira linha, definimos a localidade como inglês dos EUA (1033), o que (entre outras coisas) define o separador decimal como o ponto decimal. Do contrário, os valores decimais seriam apresentados de acordo com a localidade, isto é, possivelmente com vírgula decimal em vez de ponto decimal, o que causaria problemas ao passar tais valores ao IM. As duas linhas após a definição das constantes de cadeia são sobrecarga padrão, pois sempre precisamos de um objeto Shell para iniciar os programas do IM via seu método Exec ou Run.O único argumento do script é um nome de arquivo, que normalmente fornecemos via Arrastar e Soltar ou SendTo. Ao nomear o arquivo de saída, acrescentamos "pt" ao nome de arquivo original, tal como o PTlens faria, por exemplo _Photo.JPG → Photo_pt.JPG. O nome do arquivo é armazenado em strFileIn, do qual derivamos o nome do arquivo de saída strFileOut. Em seguida, executamos o programa Identify do IM. O resultado (isto é, o racional EXIF que representa a distância focal) é armazenado em strf. Os racionais EXIF são fornecidos como numerador / denominador, por exemplo 82 / 10 = 8,2 mm. O racional, portanto, tem de ser avaliado antes de usá-lo na fórmula que calcula o parâmetro b. Nas duas últimas linhas, construímos a linha de comando do Convert e executamos a instrução via método Run do objeto Shell. O parâmetro 7 minimiza a janela e TRUE diz ao script para aguardar o resultado. O script acima esboça a estratégia geral ao usar VBScript com as ferramentas de linha de comando do IM (e não o objeto COM+). Estas são chamadas

  • via comando Run do objeto Shell, se nenhuma saída textual é esperada
  • via comando Exec do objeto Shell, se a saída textual tem de ser avaliada, como é o caso típico com o Identify.

Este primeiro VBScript não faz nada que não pudesse ter sido feito por meio de um arquivo batch como

   SETLOCAL EnableDelayedExpansion
   FOR /F %%i in ('identify -format "%%[EXIF:FocalLength]" %1') DO SET FL=%%i
   FOR /F %%i IN ('Convert null: -format "%%[fx:0.000005142*(%FL%)^3 - 0.000380839 * (%FL%)^2 + 0.009606325 * %FL% - 0.075316854]" info:') DO SET B=%%i
   Convert %1 -distort barrel "0.0 !B! 0.0" "%~dpn1_pt%~x1"

mas o código VBS é mais direto, mais fácil de modificar e pode ser facilmente estendido no que diz respeito à verificação de erros e afins. Observe que quebras de linha na segunda instrução FOR são impossíveis, de modo que temos de deixá-la tão longa quanto está.

Trabalhando com vários arquivos

Uma vantagem genuína do VBScript em comparação com os arquivos batch do DOS é que se pode percorrer facilmente em laço um número arbitrário de argumentos de linha de comando. Pode-se, por exemplo, selecionar vários arquivos no Windows Explorer e combinar as imagens selecionadas em uma folha de índice via Montage do IM. O código básico seria:

  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  strInputFiles  = ""
  For EACH Arg IN WScript.Arguments
      strInputFiles = strInputFiles & " """ & Arg & """"
  next
 '
  IndexFile= Left(WScript.Arguments(1),InStrRev(WScript.Arguments(1),"\")) & "index.jpg"
  Command = "montage -geometry 210x140+0+5 -tile 6x " & strInputfiles & " -quality 80% """ & IndexFile & """"
  wsh.run command, 7, true

O script primeiro concatena os nomes de arquivo passados ao script via Arrastar e Soltar. Em seguida, deriva o nome de um arquivo de saída JPEG na mesma pasta por meio de alguma manipulação simples de cadeias. Por fim, o Montage é chamado com os parâmetros apropriados. Para scripts maiores, é conveniente armazenar os nomes dos arquivos em um vetor:

  Dim FName()
  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  NArgs = WScript.Arguments.Count
  Redim FName(NArgs-1)
  FOR i = 0 TO NArgs - 1
    FName(i) = """" & WScript.Arguments(i) & """"
  NEXT

Primeiro definimos um vetor dinâmico via Dim FName() e depois o redimensionamos via Redim FName(NArgs-1). A linha de comando do Montage possivelmente ficará muito longa, pois, na lista de arquivos de entrada, cada arquivo é nomeado por seu nome totalmente qualificado. O comprimento máximo não é o habitual de 8192 caracteres, mas é determinado pelo comprimento máximo permitido para uma chamada da função ShellExecute, que é de apenas 2048 caracteres no Windows XP. Isso pode causar problemas quando o nome do diretório é muito longo. O erro causado não pode ser tratado pelo script, pois ocorre antes de o script ser executado. Uma solução possível é colocar os arquivos em uma pasta local com um nome mais curto. A solução (parcial) baseada em script é a mesma dos arquivos batch: se apenas um nome de arquivo é dado, todas as imagens do diretório pai são processadas. Para processar todos os GIFs dentro de uma pasta, poderíamos fazer algo na linha de:

  Dim fs, folder
  Set fs = CreateObject("Scripting.FileSystemObject")
  If WScript.Arguments.Count <> 1 Then WScript.Quit(1)
  set Folder = fs.getFolder(fs.GetParentFoldername(WScript.Arguments(0)))
  FN=""
  FOR EACH file in folder.files
     If instr(file,"gif") <> 0 THEN FN = FN & File & vbLF
  NEXT
  MsgBox FN

Aqui usamos o objeto FileSystem para determinar o nome da pasta pai. A correspondência da extensão do arquivo, porém, é verificada da forma comum, pois o objeto Files oferece apenas a propriedade Type. Muitas vezes, os nomes dos arquivos terão de ser ordenados alfabeticamente, pois o Arrastar e Soltar ou o SendTo os passará ao script em ordem aleatória. Isso pode ser conseguido com um bubble sort:

  for i = 0 to NArgs - 1
    for j = i + 1 to NArgs - 1
      if FName(i) > FName(j) then
        Temp = FName(i)
        FName(i) = FName(j)
        FName(j) = Temp
      end if
    next
  next

[clip] Uma aplicação mais sofisticada do conceito descrito acima é apresentada à direita: um conjunto de quadros de vídeo foi montado em duas "tiras de filme" paralelas por meio de um VBScript e do ImageMagick. A perfuração dá uma dica visual de que a progressão dos quadros é de cima para baixo, isto é, coluna por coluna, em contraste com o padrão de leitura ocidental habitual, da esquerda para a direita e depois de cima para baixo. O script inteiro que realiza a tarefa pode ser baixado do arquivo strip.zip. Nota marginal: o código de tempo vermelho no canto superior direito de cada quadro foi gerado por um script AVIsynth. Os quadros foram despejados exportando-os do VirtualDub. Com o código de tempo embutido, os quadros não precisam necessariamente ser temporalmente equidistantes, isto é, podem ser escolhidos conforme a necessidade no Windows Explorer e enviados ao script, que é colocado na pasta SendTo.

Trabalhando com arquivos de texto

Ao trabalhar com scripts em um computador cliente, a informação de entrada é em geral fornecida via Arrastar e Soltar ou SendTo, isto é, consiste basicamente em nomes de arquivo que serão processados de uma forma predefinida pelo script. Qualquer informação adicional tem de ser fornecida por interação do usuário em tempo de execução ou fornecida na forma de um arquivo de texto. Basicamente, temos as seguintes opções:

  • O script aceita arquivos de imagem como entrada, acompanhados de um arquivo de texto (possivelmente opcional) que fornece informação adicional.
  • O script aceita um único arquivo de texto como entrada, que lista as imagens a processar bem como qualquer informação adicional necessária.

No primeiro caso, convém colocar o arquivo de texto opcional no mesmo diretório das imagens, atribuindo-lhe um nome padrão. O script pode então derivar o nome do diretório pai a partir das imagens de entrada e abrir o arquivo de texto no mesmo diretório, se presente. Um exemplo dessa abordagem é a "tira de filme" mencionada acima: no início do script provavelmente definiremos alguma ordenação padrão dos quadros, dependendo do número de imagens passadas ao script. Mas pode haver cenários em que queiramos desviar da ordenação padrão dos quadros. Assim, poderíamos colocar um arquivo de texto chamado ordering.txt no diretório dos quadros, o qual, se presente, controlará a ordenação dos quadros:

  strTxtFile="ordering.txt"
  PDir = fs.getParentFolderName(FName(0)) & "\"
  Wsh.CurrentDirectory = PDir

  If fs.FileExists(strTxtFile) then
    Set objFile = fs.OpenTextFile(strTxtFile, 1)
    bCtrlFile = True
    NCols = objFile.ReadLine
    objFile.close
  else
    bCtrlFile = False
  end if

[clip] Uma aplicação útil do segundo conceito pode ser encontrada no mapeamento em perspectiva de uma imagem para um plano alvo, como demonstrado no site de Fred Weinhaus. Poderíamos usar esse conceito para "revestir" uma imagem distorcida em perspectiva sobre uma versão (em sua maior parte) correta em perspectiva, como demonstrado à direita: na parte superior, a imagem à esquerda mostra uma fotografia tirada no local de um pequeno acidente. A fotografia à direita foi tirada em uma visita posterior ao local, de uma posição um tanto elevada. Na parte inferior, a fotografia do acidente (isto é, a superfície plana da via) é mapeada sobre a fotografia alvo por meio de uma transformação de perspectiva. (O objetivo disso é visualizar o ângulo de orientação da tênue marca de derrapagem deixada pelo pneu dianteiro direito do carro preto.) Para realizar essa tarefa, o usuário tem de escolher quatro pontos na imagem de origem e seus pontos alvo na imagem correta em perspectiva. Poderíamos fazer isso à mão, determinando as coordenadas na imagem de origem e na imagem alvo escolhendo os pontos em um visualizador de imagens (como o IrfanView), anotando suas coordenadas e fornecendo-as a uma linha de comando do Convert. Esse trabalho tedioso pode, contudo, ser simplificado pelo programa gratuito WinMorph, que oferece uma interface conveniente para fazer justamente isso: escolher alguns pontos de origem e seus pontos alvo correspondentes a partir de duas imagens. As polilinhas amarelas nas duas fotografias conectam os quatro pontos escolhidos em cada imagem. O próprio algoritmo de morphing, porém, não é adequado para realizar uma correção de perspectiva. (O funcionamento básico desse algoritmo é explicado na parte Distorts da seção de Uso do site do IM. Uma demonstração de sua utilidade para morphing encontra-se no script ShapeMorph de Fred Weinhaus.) O WinMorph armazena sua informação em um arquivo de texto estruturado que contém (entre outras informações) os nomes de arquivo tanto da origem quanto do alvo, bem como as coordenadas dos pontos de origem e alvo. Assim, podemos derivar do arquivo do WinMorph toda a informação necessária para a distorção de perspectiva do IM. É possível baixar uma cópia de todos os arquivos e imagens envolvidos no arquivo wmpr.zip.

Encadeamento (piping)

Até agora invocamos as ferramentas de linha de comando do IM (como Convert, Identify, Montage) diretamente via função Run ou Exec do objeto Shell. Se, porém, quisermos usar os recursos de encadeamento do IM, isto é, alimentar um comando com a saída do anterior, temos de chamar as ferramentas de linha de comando via um ambiente de comando. Por exemplo, para recortar as bordas brancas da folha de índice gerada pelo script acima, o código teria de ser:

  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  strInputFiles  = ""
  For EACH Arg IN WScript.Arguments
      strInputFiles = strInputFiles & " """ & Arg & """"
  next
 '
  IndexFile= Left(WScript.Arguments(1),InStrRev(WScript.Arguments(1),"\")) & "index.jpg"
  Command = "cmd /c montage -geometry 210x140+0+5 -tile 6x " & strInputfiles & " miff:- | magick - -trim """ & IndexFile & """"
  wsh.run command, 7, true

Aqui chamamos o processador de comandos cmd com a opção /c a fim de fechar a caixa de comando automaticamente ao terminar. Para fins de depuração, poderíamos também invocá-lo com a opção /k, que deixa a caixa de comando aberta e nos permite ler possíveis mensagens de erro.

Testando e depurando VBScripts

Basicamente, usamos o VBScript para construir a lista de argumentos das ferramentas de linha de comando do IM, que são então executadas por si mesmas ou dentro de uma caixa do DOS. Isso significa que, antes de tudo, deve-se garantir que

  • a própria linha de comando faz o que esperamos que faça
  • a linha de comando é construída corretamente pelo script.

Assim, para começar, deve-se testar a própria linha de comando dentro de uma caixa do DOS. Ao testar o script pela primeira vez, não se deve executar o comando do IM, mas sim exibir a cadeia de texto em uma caixa de mensagem via MsgBox(strCommand), pois, se a própria linha de comando estiver errada, há pouco que qualquer ferramenta de depuração poderia fazer. A simples caixa de mensagem também é útil ao depurar o script, e nunca senti de fato necessidade de um depurador sofisticado. Quanto ao teste em tempo de execução, deve-se garantir que

  • as ferramentas de linha de comando do IM podem ser acessadas corretamente
  • o usuário selecionou o que se esperava que ele selecionasse, isto é, vários arquivos (possivelmente de certo tipo), um diretório, um arquivo de texto, etc.

Mensagens de erro podem ser facilmente exibidas com o uso de MsgBox(...).


Mais informações

Infelizmente não há tutorial conhecido (além deste) que trate especificamente do uso de comandos do ImageMagick em arquivos batch do DOS. A página web DOS "For" Command Help tem uma explicação melhor sobre o uso do comando "FOR". Também pode ser interessante consultar a página Batch Script de Bonzo.