⚠️ 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/draw/index.html).

Exemplos do ImageMagick -- Desenhando

Desenhar no IM é a maneira de adicionar novos elementos a uma imagem existente. Embora boa parte do desenho de texto seja abordada na página de exemplos de Efeitos de Fonte Compostos e em Anotação de Imagens, esta página trata dos demais aspectos mais gerais do operador "[-draw](https://imagemagick.org/command-line-options/#draw)". O comando draw começou como um meio de criar imagens simples. Mas, com o tempo, expandiu-se até se tornar a interface para a conversão de gráficos vetoriais em imagens rasterizadas.


Comandos de Desenho do ImageMagick As imagens em computadores geralmente são salvas de duas formas diferentes. A primeira e mais comum, que você viu ao longo destas páginas de exemplos, é conhecida como Gráficos Rasterizados. Nessa abordagem, as imagens são armazenadas como um arranjo retangular de pixels. A outra forma é menos comum e menos modificável, mas, em outro sentido, mais versátil: os Gráficos Vetoriais de Objetos. Nessa forma, a imagem é descrita em termos de linhas, arcos, preenchimentos de cor e, às vezes, profundidade. Isso é útil porque você pode escalar essas imagens para praticamente qualquer tamanho desejado e elas ainda serão exibidas perfeitamente. Também é possível descrever imagens muito grandes e complexas em uma quantidade de espaço muito pequena quando comparada ao equivalente no formato rasterizado. Exemplos de imagens em gráficos vetoriais incluem o postscript e o novo SVG -- Scalable Vector Graphics. As fontes True-Type também são exemplos de gráficos vetoriais, pois isso permite que as descrições individuais dos caracteres sejam usadas em qualquer escala. O operador de imagem "[-draw](https://imagemagick.org/command-line-options/#draw)" é uma janela para as funções de desenho vetorial do ImageMagick e forma um conjunto de comandos bastante separado dos operadores de imagem normais da linha de comando do IM. | _Existem apenas alguns poucos formatos de arquivo de gráficos vetoriais em uso geral, pois cada um desses formatos costuma ser muito diferente dos demais. O resultado é que há muito pouco compartilhamento de código possível.

Por essa razão, o ImageMagick está mais preocupado com o uso de gráficos vetoriais para desenhar imagens no formato SVG. Os gráficos de postscript e de fontes true-type são passados a outras bibliotecas e aplicativos 'delegados' externos, muito mais adequados para desenhar esses tipos de formatos de gráfico vetorial.

Isso não significa que não haja delegados disponíveis para SVG. Um exemplo é a biblioteca RSVG ou a biblioteca GTK SVG, disponíveis em tempo de compilação. O IM se vinculará a essas bibliotecas para renderizar o SVG em vez de tentar fazê-lo por conta própria._
---|---

Primitivas de Comandos de Desenho

Vamos começar com as primitivas de desenho mais antigas, simples e comuns do operador de imagem "[-draw](https://imagemagick.org/command-line-options/#draw)" dos comandos MVG. Observe que todos os argumentos são tratados como ponto flutuante e não precisam ser inteiros, como costumo usar nestes exemplos. |

  # Single Pixel Draw  (two ways -- these have been enlarged)

  # Point 'paints' the color pixel
  magick -size 10x6 xc:skyblue  -fill black \
          -draw 'point 3,2'         -scale 100x60   draw_point.gif

  # Color Point 'replaces' the color pixel
  magick -size 10x6 xc:skyblue  -fill black \
          -draw 'color 6,3 point'   -scale 100x60   draw_color_point.gif

[IM Output]
[IM Output]
Esses dois métodos de point produzem resultados diferentes quando cores semitransparentes estão envolvidas, conforme o comentário apresentado. Veja Primitivas de Preenchimento de Cor abaixo para os detalhes. |

  # Rectangle  /  Rounded Rectangle  /  Rectangular Arc

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "rectangle 20,10 80,50"       draw_rect.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "roundrectangle 20,10 80,50 20,15"  draw_rrect.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "arc  20,10 80,50  0,360"     draw_arc.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "arc  20,10 80,50 45,270"     draw_arc_partial.gif

[IM Output]
[IM Output]
[IM Output]
[IM Output]
A primitiva de desenho 'arc' é listada junto com os retângulos porque, na verdade, é apenas uma 'ellipse' ajustada dentro do 'rectangle' definido pelas duas coordenadas. Arcos parciais raramente são usados, pois pode ser difícil determinar os pontos de extremidade a menos que os ângulos sejam limitados a múltiplos de noventa graus.
As primitivas 'circle' e 'ellipse' envolvem a coordenada do 'centro' junto com uma coordenada de 'borda' ou, respectivamente, valores de 'tamanho' e 'ângulo'. |

  # Circle  /  Ellipse    (centered on a point)

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "circle 50,30 40,10"          draw_circle.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "ellipse 50,30 40,20 0,360"   draw_ellipse.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "ellipse 50,30 40,20 45,270"   draw_ellipse_partial.gif

[IM Output]
[IM Output]
[IM Output]
Você também pode conferir Empilhar/Desempilhar Contexto para um exemplo de como criar uma elipse rotacionada. |

  # Line / Polyline / Polygon / Bezier

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "line   20,50 90,10"                 draw_line.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "polyline 40,10 20,50 90,10 70,40"   draw_polyline.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "polygon  40,10 20,50 90,10 70,40"   draw_polygon.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "bezier   40,10 20,50 90,10 70,40"   draw_bezier.gif

[IM Output]
[IM Output]
[IM Output]
[IM Output]
Um método melhor para desenhar linhas e curvas é usar o Desenho de Caminho SVG, que pode ser muito mais versátil e permite até o 'desenho de linha relativo'. |

  # text drawing  / image

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -font Candice -pointsize 40 -gravity center \
          -draw "text 0,0 'Hello'"   draw_text.gif

  magick -size 100x60 xc:skyblue -gravity center \
          -draw "image over 0,0 0,0 'terminal.gif'"   draw_image.gif

[IM Output]
[IM Output]
Estas duas últimas operações do tipo preenchimento são atualmente as únicas operações de draw afetadas por "[-gravity](https://imagemagick.org/command-line-options/#gravity)". Outros modificadores dessas operações incluem: "[-fill](https://imagemagick.org/command-line-options/#fill)", "[-tile](https://imagemagick.org/command-line-options/#tile)", "[-origin](https://imagemagick.org/command-line-options/#origin)", "[-stroke](https://imagemagick.org/command-line-options/#stroke)", "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)", "[-font](https://imagemagick.org/command-line-options/#font)", "[-pointsize](https://imagemagick.org/command-line-options/#pointsize)", "[-box](https://imagemagick.org/command-line-options/#box)". Há outros modificadores, mas estes estão relacionados à mais avançada linguagem Magick Vector Graphics.

Primitiva Bezier

A primitiva 'bezier' é usada para desenhar curvas. Cada comando desenhará apenas um segmento de curva. Normalmente são fornecidos 4 pontos (8 números): um ponto inicial 'nó', dois pontos de controle e um ponto final 'nó'. Os dois pontos de controle definem a direção e a rapidez com que a curva se afasta dos pontos 'nó' de extremidade associados. Para unir duas curvas suavemente, o ponto de controle a partir da extremidade deve ser espelhado através do 'nó' para formar o ponto de controle na próxima curva de Bezier. Por exemplo, aqui desenho duas curvas de bezier que se unem suavemente. Observe como as linhas e os pontos de controle (também desenhados) se espelham em linha reta através da coordenada de junção, tanto no ângulo quanto no comprimento. Isso é importante, caso contrário a curva não será suave. |

  points="10,10 30,90   25,10 50,50   50,50 75,90   70,10 90,40"
  clines=`echo "$points" | sed 's/   /\n/g' |\
             while read line; do echo "line $line"; done`
  symbols=`echo path "'"; for point in $points; do
             echo "M $point   l -2,-2 +4,+4 -2,-2   l -2,+2 +4,-4 -2,+2"
           done;  echo "'"`
  magick -size 100x100 xc:skyblue -fill none \
          -draw "stroke gray $clines    stroke blue $symbols " \
          -draw "stroke red  bezier 10,10 30,90   25,10 50,50 " \
          -draw "stroke red  bezier 50,50 75,90   70,10 90,40 " \
          draw_bezier_joined.gif

[IM Output]
Se eu mover um dos pontos de controle de modo que ele NÃO seja 'refletido' através do 'nó' associado a partir do outro ponto de controle do mesmo 'nó', então a curva será descontínua. |

  points="10,10 30,90   25,10 50,50   50,50 80,50   70,10 90,40"
  clines=`echo "$points" | sed 's/   /\n/g' |\
             while read line; do echo "line $line"; done`
  symbols=`echo path "'"; for point in $points; do
             echo "M $point   l -2,-2 +4,+4 -2,-2   l -2,+2 +4,-4 -2,+2"
           done;  echo "'"`
  magick -size 100x100 xc:skyblue -fill none \
          -draw "stroke gray $clines    stroke blue $symbols " \
          -draw "stroke red  bezier 10,10 30,90   25,10 50,50 " \
          -draw "stroke red  bezier 50,50 80,50   70,10 90,40 " \
          draw_bezier_disjoint.gif

[IM Output]
Se o ponto de controle for movido novamente de modo a coincidir com o 'nó' relacionado, a linha virá diretamente daquele ponto, sem nenhuma 'curva'. |

  points="10,10 30,90   25,10 50,50   50,50 50,50   70,10 90,40"
  clines=`echo "$points" | sed 's/   /\n/g' |\
             while read line; do echo "line $line"; done`
  symbols=`echo path "'"; for point in $points; do
             echo "M $point   l -2,-2 +4,+4 -2,-2   l -2,+2 +4,-4 -2,+2"
           done;  echo "'"`
  magick -size 100x100 xc:skyblue -fill none \
          -draw "stroke gray $clines    stroke blue $symbols " \
          -draw "stroke red  bezier 10,10 30,90   25,10 50,50 " \
          -draw "stroke red  bezier 50,50 50,50   70,10 90,40 " \
          draw_bezier_no_curve.gif

[IM Output]
Se ambos os pontos de controle forem definidos em seus respectivos 'nós', será gerada uma linha reta. |

  points="10,10 10,10   50,50 50,50   50,50 50,50   90,40 90,40"
  clines=`echo "$points" | sed 's/   /\n/g' |\
             while read line; do echo "line $line"; done`
  symbols=`echo path "'"; for point in $points; do
             echo "M $point   l -2,-2 +4,+4 -2,-2   l -2,+2 +4,-4 -2,+2"
           done;  echo "'"`
  magick -size 100x100 xc:skyblue -fill none \
          -draw "stroke gray $clines    stroke blue $symbols " \
          -draw "stroke red  bezier 10,10 10,10   50,50 50,50 " \
          -draw "stroke red  bezier 50,50 50,50   90,40 90,40 " \
          draw_bezier_lines.gif

[IM Output]
A primitiva 'bezier' não é realmente útil sem especificar todos os 4 pontos. Apenas o primeiro e o último ponto são classificados como 'nós', pelos quais a curva passará (ou terminará). Todos os demais pontos intermediários são considerados puramente pontos de controle, afetando a curva na sequência dada; quanto mais distante estiver o ponto de controle, maior será seu efeito naquele segmento da curva. |

  points="10,10 30,90   25,10    75,90   70,10 90,40"
  symbols=`for point in $points; do
             echo "M $point   l -2,-2 +4,+4 -2,-2   l -2,+2 +4,-4 -2,+2"
           done`
  magick -size 100x100  xc:skyblue  -fill none \
          -draw "stroke gray  polyline $points " \
          -draw "stroke red   bezier $points " \
          -draw "stroke blue  path '$symbols' " \
          draw_bezier_multi.gif

[IM Output]
Não é recomendado usar mais ou menos que 4 pontos por segmento de curva 'bezier', para manter as coisas simples. Na verdade, recomendo que você não use a primitiva 'bezier' de forma alguma, mas sim o Bezier Cúbico de Caminho SVG para gerar curvas. Ele tem uma função especial de continuação de curva 'S" que faz automaticamente a 'reflexão' apropriada do ponto de controle para gerar segmentos de curva que se unem suavemente e reduz o número de pontos de controle que você precisa usar. Você também pode definir pontos relativos ao último ponto final do path.

Primitivas de Preenchimento de Cor

Além das primitivas 'simples' acima, o "[-draw](https://imagemagick.org/command-line-options/#draw)" também fornece um conjunto de primitivas de preenchimento ou modificação de cor. Essas modificam a(s) cor(es) na imagem a partir do ponto especificado, de acordo com o método escolhido. Esses métodos de preenchimento não são, na verdade, verdadeiros comandos de 'draw', mas funções de substituição de cor. Foram adicionados ao draw por ser o lugar mais fácil de inserir suas operações no ImageMagick em uma versão muito inicial do programa. Assim como acima, a cor usada é definida pela configuração de cor "[-fill](https://imagemagick.org/command-line-options/#fill)", mas, se definida, a imagem "[-tile](https://imagemagick.org/command-line-options/#tile)" será usada em seu lugar. As demais opções de configuração acima não são usadas e não têm efeito nessas operações. Duas configurações extras também se aplicam a essas primitivas: as configurações de "[-bordercolor](https://imagemagick.org/command-line-options/#bordercolor)" e do fator "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)". No entanto, essas configurações NÃO podem ser definidas dentro da linguagem 'MVG', portanto só podem ser definidas antes de usar o operador "[-draw](https://imagemagick.org/command-line-options/#draw)". A primeira delas, 'color point', você já viu como alternativa à primitiva de desenho 'point' nos exemplos acima. Se olhar com atenção, verá o único pixel branco que definimos em nossa imagem de teste.

|

  magick color_test.png   -fill white \
          -draw 'color 30,20 point'      color_point.png

[IM Output]
Entretanto, ao desenhar cores transparentes e semitransparentes, essas funções não são iguais. Aqui temos uma imagem vermelha de três pixels (ampliada); no segundo pixel, ou pixel do meio, usamos a função 'point' para pintar sobre o pixel vermelho com uma cor azul semitransparente, resultando em roxo. Se, porém, usarmos a função 'color point' (último pixel, ou pixel da direita), a cor vermelha é completamente substituída pelo pixel azul semitransparente. Ela não é sobreposta. |

  magick -size 3x1 xc:red -alpha on -fill '#00F8' \
          -draw 'point 1,0' \
          -draw 'color 2,0 point'   -scale 33x33  draw_points.png

[IM Output]
Todas as funções 'color' fazem substituição total de cor, enquanto todas as outras primitivas de cor 'pintam' a cor sobre a imagem. Assim, você pode usar 'color' para desenhar a cor transparente. A função de desenho 'color replace' substituirá todas as ocorrências da cor exata informada na localização especificada. E, como você pode ver, as áreas não precisam estar conectadas. |

  magick color_test.png   -fill white \
          -draw 'color 30,20 replace'      color_replace.png


  magick color_test.png   -fill white   -fuzz 13%\
          -draw 'color 30,20 replace'      color_replace_fuzz.png

[IM Output]

[IM Output]
Entretanto, como você pode ver no primeiro resultado, alguns pixels ao longo das bordas não foram substituídos. Esses pixels não têm exatamente a mesma cor do pixel selecionado, então foram ignorados. Adicionar um pequeno fator de fuzz também incluirá cores semelhantes à cor original, como mostrado no segundo exemplo acima. É claro que um 'fator de fuzz' não é uma ótima solução, pois não capturará todos esses pixels de borda. Este é um problema recorrente em todos esses métodos de 'preenchimento de cor', e um que não tem solução geral. Se você quiser substituir uma cor específica conhecida, em vez de selecionar uma cor da própria imagem, então o operador de imagem "[-opaque](https://imagemagick.org/command-line-options/#opaque)" pode ser usado no lugar. Essa função também usa a configuração do fator "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" para aumentar a faixa de cores que correspondem à cor informada. O método 'floodfill' também é bastante simples, pois apenas preencherá toda a área ao redor do ponto selecionado e não selecionará nenhuma outra área de cores semelhantes que não esteja conectada de alguma forma. Você também pode expandir a área a ser preenchida usando "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" para incluir cores semelhantes. Neste caso, escolhemos um valor alto o suficiente para incluir também a borda em cruz, permitindo que o preenchimento por inundação 'vaze' para o outro lado da imagem. |

  magick color_test.png   -fill white \
          -draw 'color 30,20 floodfill'      color_floodfill.png


  magick color_test.png   -fill white   -fuzz 15%   \
          -draw 'color 30,20 floodfill'      color_floodfill_fuzz.png

[IM Output]

[IM Output]
Preencher áreas por inundação com uma cor não é isento de problemas. A cor pode vazar através de um limite fino, para áreas onde não era desejada (veja GIFs sobre um padrão de fundo como demonstração disso). Ou pode não preencher a área selecionada até a borda (veja Problemas de Anti-Aliasing e Preenchimento por Inundação). Mas funciona. O 'filltoborder' é como o 'floodfill', exceto que você especifica uma cor que delimita a área a ser preenchida, em vez da cor a ser substituída pelo processo de preenchimento. É claro que um fator de fuzz também é recomendado para incluir 'cores semelhantes' nessa seleção da cor de borda, a fim de limitar ainda mais o floodfill. |

  magick color_test.png   -fill white  -bordercolor royalblue \
          -draw 'color 30,20 filltoborder'   color_filltoborder.png


  magick color_test.png   -fill white  -bordercolor blue \
          -draw 'color 30,20 filltoborder'   color_filltoborder2.png


  magick color_test.png   -fill white  -bordercolor blue  -fuzz 30% \
          -draw 'color 30,20 filltoborder'   color_filltoborder_fuzz.png

[IM Output]
[IM Output]
[IM Output]
O último método de cor do draw é o 'reset', que simplesmente substitui, ou redefine, toda a imagem para a cor de preenchimento. Neste caso, o pixel realmente selecionado não tem influência alguma sobre os resultados. |

  magick color_test.png   -fill white \
          -draw 'color 30,20 reset'      color_reset.png

[IM Output]
Isso é, na verdade, muito útil, pois oferece uma maneira simples de gerar uma tela de cor sólida (ou de imagem em mosaico) a partir de uma imagem existente. (Veja Telas Dimensionadas para uma Imagem Existente) para essa e outras formas de fazer o mesmo. FUTURO: Usar um padrão "[-tile](https://imagemagick.org/command-line-options/#tile)" para preencher a área.

Primitivas de Preenchimento de Alpha

A primitiva de desenho 'alpha' funciona exatamente da mesma forma que a primitiva 'color' descrita acima, exceto que não substituirá a cor das áreas selecionadas, apenas o canal 'alpha' das áreas selecionadas. (Isto é, apenas o canal 'alpha' é ajustado por essas funções de preenchimento). Assim como na função de preenchimento 'color', o valor 'alpha' usa a cor de preenchimento (a menos que "[-tile](https://imagemagick.org/command-line-options/#tile)" seja a fonte do 'valor de alpha' a usar). Aqui usamos o mesmo exemplo 'color floodfill' acima, mas aqui ajustamos apenas o canal alfa para tornar as partes preenchidas totalmente transparentes. Ou seja, a cor original ainda está presente, apenas transparente! |

  magick color_test.png   -fill none \
          -draw 'alpha 30,20 floodfill'      matte_floodfill.png


  magick color_test.png   -fill none   -fuzz 15%   \
          -draw 'alpha 30,20 floodfill'      matte_floodfill_fuzz.png

[IM Output]

[IM Output]
A função 'alpha reset' também pode ser usada para tornar uma imagem inteira semitransparente. É claro que, neste caso, devemos gerar a saída em PNG, que pode aceitar cores semitransparentes nas imagens. |

  magick color_test.png   -fill '#00000080' \
          -draw 'alpha 30,20 reset'      matte_reset.png

[IM Output]
Observe que o componente de cor 'black' não foi usado nas operações, apenas o componente alfa da cor. A cor original da imagem é mantida como está. FUTURO: Usar o padrão "[-tile](https://imagemagick.org/command-line-options/#tile)" para um efeito interessante de alpha. Tanto 'color' quanto 'alpha' são funções de substituição total de cor, que sempre produzirão um tipo de substituição de cor booleano (tudo ou nada). Como tal, as bordas dessas áreas sempre mostrarão efeitos de Aliasing. Por causa disso, esses geralmente não são bons operadores de imagem para o desenvolvimento geral de imagens, exceto para definir as áreas transparentes de imagens GIF (que também são booleanas). Nem tudo está perdido, no entanto, como pode ser visto nos exemplos de Remoção de Fundo.


Detalhes sobre os Comandos de Desenho

Coordenadas de Pixel

O comando "[-draw](https://imagemagick.org/command-line-options/#draw)" (e muitos outros no IM) usa o que se chama de "Coordenadas de Pixel". Ou seja, a coordenada '10,10 é o centro do pixel 10 pixels abaixo e à esquerda a partir do canto superior esquerdo. Nesse sistema de coordenadas 0,0 é o centro do pixel superior esquerdo, e w-1,h-1 é o centro do canto inferior direito. As bordas reais ficam em -0.5,-0.5 e w-0.5,h-0.5 e o pixel central (se a imagem tiver tamanho ímpar) fica em '(w-1)/2,(h-1)/2'. No entanto, quando você processa uma imagem matematicamente (como ao usar distort) os pixels reais não têm significado real, e por isso usa-se "Coordenadas de Imagem". Nesse sistema a borda real da imagem está em '0,0' e 'w,h'. E o centro da imagem (que pode ou não ser o centro de um pixel) está em 'w/2,h/2'. Para converter 'coordenadas de pixel' em coordenadas de imagem, some ½. Assim o centro do pixel superior esquerdo é '0.5,0.5' e o pixel inferior direito é 'w-0.5,h-0.5'. Exemplo: centro de um círculo em uma imagem pequena

Desenho com Correção de Gama e Espaço de Cor

Como em quase todas as operações do ImageMagick, "[-draw](https://imagemagick.org/command-line-options/#draw)" é um operador linear, e como tal trabalha em um espaço de cor RGB linear. Isso significa que, para obter bordas bem suaves, pode ser necessário fazer alguma correção de gama nas imagens antes de salvá-las, de modo que sejam armazenadas usando o espaço de cor sRGB não linear (com correção de gama). Por exemplo, se você desenhar um círculo grande e simplesmente salvá-lo... |

  magick -size 81x81 xc:black -fill white -draw 'circle 40,40 40,3' \
          circle_raw.png

[IM Output]
Observe as bordas do círculo: elas não parecem realmente muito suaves. É possível ver efeitos de escada significativos. Isso ocorre porque você desenhou o círculo no espaço de cor RGB linear. Mas então salvou a imagem como se ela realmente estivesse no espaço de cor sRGB! Para corrigir isso precisamos adicionar uma correção de gama à imagem antes de salvá-la. |

  magick -size 81x81 xc:black -fill white -draw 'circle 40,40 40,3' \
          -gamma 2.2 circle_gamma.png

[IM Output]
Agora as bordas do círculo realmente parecem suaves e arredondadas, exatamente como deveriam ser. Se você quiser fazer isso corretamente, deveríamos de fato aplicar a correção usando espaço de cor. No entanto, como o IM assume que RGB é o espaço de cor padrão para salvar, você precisa de um tratamento um tanto delicado para fazê-lo funcionar corretamente. |

  magick -size 81x81 xc:black -set colorspace RGB \
          -fill white -draw 'circle 40,40 40,3' \
          -colorspace sRGB circle_sRGB.png

[IM Output]
| Observe que o espaço de cor sRGB (que é a maneira correta de salvar imagens) não é exatamente o mesmo que simplesmente aplicar uma correção de gama 2.2. No entanto, as diferenças nos resultados entre os dois são pequenas e visíveis apenas em imagens muito muito escuras.
---|---
| Antes do IM v6.7.5-1 os nomes de espaço de cor 'sRGB' e 'RGB' (linear-RGB) estavam na verdade invertidos. Assim, em versões mais antigas do IM os dois rótulos acima devem ser trocados.
---|---
Para desenhar corretamente (ou fazer qualquer processamento de imagem 'linear') usando uma imagem real (no IMv7) você precisa primeiro remover qualquer gama existente, processar a imagem e então restaurar essa correção de gama. Veja Redimensionando com Correção de Espaço de Cor para mais detalhes. Aqui está um exemplo de desenho sobre uma imagem real... Primeiro sem nenhuma correção de cor (raw), e depois com correções de gama e de espaço de cor. |

  magick rose: -fill none -stroke white -draw 'line 5,40 65,5'  rose_raw.png

[IM Output]
|

  magick rose: -gamma .454545 \
          -fill none -stroke white -draw 'line 5,40 65,5' \
          -gamma 2.2 rose_gamma.png

[IM Output]
|

  magick rose: -colorspace RGB \
          -fill none -stroke white -draw 'line 5,40 65,5' \
          -colorspace sRGB rose_sRGB.png

[IM Output]
Como você pode ver, ao usar a correção de gama ou de espaço de cor, a linha fica com aparência bem suave, sem o efeito de serrilhado 'em escada', que pode ser visto ao desenhar diretamente. (Você precisa de um monitor muito bom para vê-lo) | A linha acima foi desenhada usando uma cor "[-stroke](https://imagemagick.org/command-line-options/#stroke)". Você pode desenhar a linha usando "[-fill](https://imagemagick.org/command-line-options/#fill)" e obter os mesmos resultados, mas então você não terá controle da espessura da linha usando "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)". Veja Configuração da Cor de Stroke abaixo para mais informações.
---|---
| _Os nomes de cores são na verdade definidos usando valores para o espaço de cor 'sRGB', MAS são aplicados por draw como se a imagem estivesse no espaço de cor linear-RGB. Assim, usar a correção de gama acima com cores nomeadas (que não sejam 'white' ou 'black') fará com que essas cores fiquem distorcidas. Nesses casos pode ser melhor não usar correção de gama ou de espaço de cor, para que as cores nomeadas sejam mapeadas corretamente.

O mapeamento correto das cores nomeadas 'sRGB' para o espaço de cor da imagem em que se desenha será corrigido como parte do desenvolvimento do IMv7.

_
---|---

Interação entre Stroke, StrokeWidth e Fill

As opções "[-stroke](https://imagemagick.org/command-line-options/#stroke)" e "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" são usadas ao desenhar um contorno ao redor da borda de uma fonte. Essas opções são comumente usadas com "[-fill](https://imagemagick.org/command-line-options/#fill)" para tornar o texto mais interessante, com muito pouco esforço.

    magick -size 380x70 xc:lightblue -pointsize 50 -font Chisel \
            -fill green  -stroke black  -draw 'text 10,55 "Black Border"' \
            stroke_font.jpg

[IM Output]

As configurações padrão são "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth) 1" e "[-stroke](https://imagemagick.org/command-line-options/#stroke) None". Mas isso torna o traço do contorno invisível, deixando apenas a cor "[-fill](https://imagemagick.org/command-line-options/#fill)", e você não o verá. O único efeito que "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" tem quando o "[-stroke](https://imagemagick.org/command-line-options/#stroke)" está 'invisível' é sobre os atributos de tamanho da fonte, o que significa que ele ainda pode afetar o posicionamento da fonte e o tamanho da geração de uma imagem de Label e Caption. Caso contrário, a largura não tem efeito visível até você tornar o traço visível. Para ver como "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" realmente afeta a aparência de uma fonte (quando tornado visível), aqui desenhei alguns textos com várias larguras, de 'desligado' até maiores.

    magick -size 320x420 xc:lightblue -pointsize 70 -font Vademecum \
      -fill red -stroke none                 -draw 'text 30,80  "Stroke -"' \
      -fill red -stroke black -strokewidth 0 -draw 'text 30,160 "Stroke 0"' \
      -fill red -stroke black -strokewidth 1 -draw 'text 30,240 "Stroke 1"' \
      -fill red -stroke black -strokewidth 2 -draw 'text 30,320 "Stroke 2"' \
      -fill red -stroke black -strokewidth 3 -draw 'text 30,400 "Stroke 3"' \
      stroke_table.jpg

[IM Output]

Note pelos exemplos acima que definir um "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" de '0' NÃO é o mesmo que definir a cor "[-stroke](https://imagemagick.org/command-line-options/#stroke)" como 'none' (o padrão). O primeiro cria um contorno de traço muito muito fino, enquanto o segundo efetivamente o desliga. Em ambos os casos o traço ainda é desenhado. No entanto, você também deve notar que mesmo com um "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" de '0' o contorno da imagem será expandido muito muito ligeiramente além do de uma imagem simplesmente 'preenchida' (usando uma cor "[-stroke](https://imagemagick.org/command-line-options/#stroke)" de 'none'. Essencialmente, usar qualquer largura menor que '1.0' não funciona corretamente. E você deve ter cautela nos casos em que isso pode importar. Lembre-se, porém, de que "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" também é uma configuração de ponto flutuante. Ou seja, uma largura de traço de '0.5' também é válida. No entanto, geralmente isso só é importante quando você tenta desenhar Círculos Finos em Bitmap com o Anti-Aliasing desligado.
Aqui está um exemplo de uso de uma largura de traço extremamente grande.

   magick -size 320x100 xc:lightblue -font Candice -pointsize 72 -fill white \
           -stroke black -strokewidth 15 -draw "text 25,65 'Anthony'" \
           stroke_thick.jpg

[IM Output]

Note que "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" expande as linhas tanto para dentro quanto para fora. Aqui está o mesmo exemplo, mas com a fonte redesenhada, sem o contorno do traço, para remover a parte interna do traço muito grosso.

   magick -size 320x100 xc:lightblue -font Candice -pointsize 72 -fill white \
           -stroke black -strokewidth 15 -draw "text 25,65 'Anthony'" \
           -stroke none                  -draw "text 25,65 'Anthony'" \
           stroke_outline.jpg

[IM Output]

Para mais exemplos de uso de stroke veja Efeitos Compostos de Fonte. Dê uma atenção especial ao "Efeito Balão".

Desenhando Linhas (Stroke)

O desenho de linha padrão no IM tem alguns comportamentos estranhos que vale a pena conhecer. Aqui está o desenho de linha padrão... |

  magick -size 100x40 xc:lightblue \
          -draw "line 5,35 95,5" \
          line_default.jpg

[IM Output]
Você pode definir a cor da linha com uma opção "[-fill](https://imagemagick.org/command-line-options/#fill)". |

  magick -size 100x40 xc:lightblue \
          -fill white -draw "line 5,35 95,5" \
          line.jpg

[IM Output]
Você também pode tornar uma linha ligeiramente mais grossa definindo a cor "[-stroke](https://imagemagick.org/command-line-options/#stroke)". |

  magick -size 100x40 xc:lightblue \
          -fill white -stroke black -draw "line 5,35 95,5" \
          line_stroke.jpg

[IM Output]
Mas o que aconteceu com a cor branca que especificamos com a opção "[-fill](https://imagemagick.org/command-line-options/#fill)"? Este é o aspecto delicado de desenhar linhas no ImageMagick. O que o programa faz é, na verdade, considerar a linha como um objeto preenchido de cerca de 1 pixel de largura. Isso é natural, pois normalmente várias linhas são usadas para varrer uma área que será preenchida. Assim, tal como quando usamos stroke com fontes na seção anterior, o IM desenha a linha (ou objeto) usando a cor de preenchimento e, em seguida, desenha em volta dela com a cor de stroke. O resultado é que a linha com a cor de stroke acima agora está ligeiramente mais grossa, com a cor de preenchimento completamente escondida por baixo. Se você tornar a cor de stroke semitransparente, poderá tornar essa cor de preenchimento visível novamente. Em resumo, as linhas parecerão ser desenhadas com a cor "[-fill](https://imagemagick.org/command-line-options/#fill)", mas essa opção não tem consequência alguma uma vez que a cor "[-stroke](https://imagemagick.org/command-line-options/#stroke)" tenha sido definida como algo diferente das cores padrão "none" ou "transparent". | A opção "-linewidth" é na verdade apenas um alias para "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)", e não deve ser usada.
---|---
Por exemplo, você provavelmente pensaria que este comando produziria uma linha muito grossa. E produz, mas como a cor "[-stroke](https://imagemagick.org/command-line-options/#stroke)" é invisível você não pode vê-la. Você vê apenas o 'preenchimento' interno da área de um pixel de largura da linha. |

  magick -size 100x40 xc:lightblue \
          -fill white -strokewidth 3 -draw "line 5,35 95,5" \
          line_fill_3.jpg

[IM Output]
| O resultado acima eu considero na verdade um bug. Nada deveria ter sido desenhado, pois não há 'área' a ser preenchida, e nenhuma 'cor de stroke' da linha foi definida. A razão pela qual o IM atualmente faz isso é evitar confusão para novos usuários, mas na verdade apenas causa problemas para usuários avançados. VejaLimites de Preenchimento no Desenho para mais detalhes.
---|---
Mas se a cor de stroke também for definida, você obterá a linha grossa solicitada... |

  magick -size 100x40 xc:lightblue \
          -stroke black -strokewidth 3 -draw "line 5,35 95,5" \
          line_stroke_3.jpg

[IM Output]
Se a configuração "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" for definida como um, a linha acima será completamente coberta. |

  magick -size 100x40 xc:lightblue \
          -stroke black -strokewidth 1 -draw "line 5,35 95,5" \
          line_stroke_1.jpg

[IM Output]
Claro, munido desse conhecimento, você pode usá-lo para ser criativo, assim como pode com o desenho de fontes. |

  magick -size 100x40 xc:lightblue \
          -stroke black -strokewidth 5 -draw "line 5,35 95,5" \
          -stroke white -strokewidth 2 -draw "line 5,35 95,5" \
          line_multi.jpg

[IM Output]
Aqui usei a configuração de "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" mais fina, de '0', assim como fiz para as fontes acima. |

  magick -size 100x40 xc:lightblue \
          -fill white -stroke black -strokewidth 0 -draw "line 5,35 95,5" \
          line_stroke_0.jpg

[IM Output]
Isso produz o resultado muito estranho de uma linha pontilhada, composta por pontos pretos e segmentos cinza. Esse é o resultado de uma estranha "frequência de batimento de cor" entre as cores de stroke, fill e de fundo. Aqui está uma visão ampliada da linha... |

  magick -size 25x10 xc:lightblue \
          -fill white -stroke black -strokewidth 0 -draw "line 2,8 22,1" \
          -scale 400%    line_stroke_0_white.jpg

[IM Output]
| O efeito de "frequência de batimento de cor" não é diferente do "batimento sonoro" que você obtém quando tem dois violões muito levemente desafinados. Nesse caso você obtém um ponto preto onde a cor de stroke sobrepõe completamente a cor de fill subjacente e obtém um ponto cinza onde a cor de stroke se mistura com AMBAS as cores de fill e de fundo. A mistura de cores é uma consequência natural dos processos de anti-aliasing que o IM usa para tentar melhorar a aparência das linhas e de outros objetos de desenho. Para mais informações veja minha página de discussão e exemplos Anti-Aliasing no IM.
---|---
Note que esse efeito só aparece em linhas inclinadas, não em linhas puramente horizontais ou verticais, onde o aliasing não tem efeito e, portanto, não há efeitos de "frequência de batimento de cor". |

  magick -size 100x40 xc:lightblue \
          -fill white -stroke black -strokewidth 0 -draw "line 5,20 95,20" \
          line_stroke_horz.jpg

[IM Output]
Aqui usei diferentes cores de fill subjacentes na visão ampliada, para que você possa ver como a cor altera o batimento resultante. |

  magick -size 25x10 xc:lightblue \
          -fill none -stroke black -strokewidth 0 -draw "line 2,8 22,1" \
          -scale 400%     line_stroke_0_none.jpg

[IM Output]
|

  magick -size 25x10 xc:lightblue \
          -fill red -stroke black -strokewidth 0 -draw "line 2,8 22,1" \
          -scale 400%    line_stroke_0_red.jpg

[IM Output]
|

  magick -size 25x10 xc:lightblue \
          -fill black -stroke black -strokewidth 0 -draw "line 2,8 22,1" \
          -scale 400%    line_stroke_0_black.jpg

[IM Output]
Vamos comparar isso com um stroke de none... |

  magick -size 25x10 xc:lightblue \
          -fill black -stroke none -draw "line 2,8 22,1" \
          -scale 400%    line_stroke_-_black.jpg

[IM Output]
Como você pode ver, ao desenhar linhas muito finas, você pode reduzir esse 'batimento' usando as mesmas cores de fill e stroke, OU definindo uma das cores como none para desligá-la. Embora a última seja a melhor ideia, a primeira pode ser mais prática para suas necessidades específicas de programação. Note que a espessura da linha de fill é '0'. Mas a linha de stroke pode ter uma espessura maior. Também é um valor de ponto flutuante! Uma linha de 2.5 pixels de largura é perfeitamente válida. | Esses resultados são causados não apenas por uma largura de stroke 0 com bug, causando um batimento de cor, mas também pela 'cor de fill' sendo desenhada com uma espessura extra de 1.0 de diâmetro, quando não há área real a ser preenchida. Isso eu também considero um bug. VejaLimites de Preenchimento no Desenho.
---|---

Limites de Preenchimento no Desenho

Há alguns outros pontos que você deve observar sobre as várias primitivas de desenho. A largura de stroke funciona bem para valores de ponto flutuante acima de 1.0, mas parece falhar para valores menores que 1.0. Isso se deve ao algoritmo de implementação usado e não simplesmente porque está errado, já que funciona bem com linhas de maior espessura. Basicamente, se você usar uma largura de stroke de zero, poderia esperar que nenhuma cor de stroke fosse adicionada. Em vez disso, você obtém uma espécie de padrão de batimento em que a cor de stroke está em força total quando a linha passa pelo 'centro' real do pixel.. O que realmente deveria acontecer é que a quantidade de cor adicionada a um pixel deveria refletir a área da linha sendo desenhada, e não a distância do pixel até essa linha. Assim, linhas de largura zero não deveriam adicionar cor alguma à imagem, enquanto linhas de espessura menor que 1.0 deveriam adicionar apenas uma quantidade menor de cor. Veja os exemplos Desenhando Linhas, com StrokeWidth e Stroke acima. O outro problema é que a cor de fill não está sendo aplicada até a borda da forma (polígono) sendo desenhada, mas ½ pixel para fora. Isso inclui a situação em que nenhum 'stroke' está sendo aplicado, e a borda deveria ser exata. Inclui também o desenho de uma 'linha', que na verdade tem espessura de fill 'zero'. Basicamente, se você desenhar uma linha, sem habilitar o stroke, tecnicamente você não deveria ver nenhuma linha, pois ela não tem espessura de 'fill'. Em vez disso, as linhas são desenhadas com no mínimo 1 pixel de largura de cor de 'fill' incluída. Isso é por razões históricas e geralmente evita confusão para novos usuários do IM. Infelizmente, NÃO é correto para usuários avançados. Isso significa que, se você desenhar dois polígonos usando apenas a cor de fill, que compartilham uma borda, essa borda se sobreporá em 1 pixel, pois cada polígono é ½ pixel maior ao longo de todas as suas bordas. Em outras palavras, polígonos e outras formas não se encaixam, mas se sobrepõem! Por exemplo, aqui tento usar draw para dividir uma imagem em duas metades (desenhando preto sobre branco). Para isso desenho dois polígonos que compartilham uma borda, exatamente sem sobreposição. As 'minúsculas' imagens resultantes foram ampliadas para exibição.

  magick -size 10x10 xc: -draw 'polygon 2,-1 7,10 10,10 10,-1' bound_left.gif
  magick -size 10x10 xc: -draw 'polygon 2,-1 7,10 -1,10 -1,-1' bound_right.gif

  magick bound_left.gif bound_right.gif -compose Plus -composite bound_add.gif

[IM Output] [IM Output] [IM Output]

As duas partes pretas (que foi o que realmente foi desenhado) na verdade se sobrepõem! Em outras palavras, embora tenhamos tentado desenhar as duas áreas separadamente usando polígonos desenhados, a área preenchida é ligeiramente maior do que a solicitada. Também somei (Plus Composited) as duas imagens para que você possa realmente ver a sobreposição das áreas pretas desenhadas. Se os dois polígonos se encaixassem perfeitamente, o desenho 'somado' seria uma cor branca sólida. A quantidade real de sobreposição equivale à configuração padrão "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth) 1.0". Assim, normalmente espera-se que essa área extra seja coberta por uma largura de stroke normal. No entanto, isso pode causar problemas reais. À PARTE: Para um teste completo da junção você geraria áreas de 50% de cinza sobre um fundo preto e as somaria. Dessa forma você pode ver se as áreas não apenas se 'sobrepõem' (como mostrado acima), mas também testar se elas 'subrepõem' (deixando uma lacuna entre as áreas preenchidas) quando você soma as áreas. A imagem resultante deveria ser uma cor cinza 50% perfeitamente uniforme, sem variações de cor ao longo da junção. Uma verificação de transparência envolveria usar uma cor 50% transparente e 50% cinza sobre um fundo totalmente transparente. Para ver um exemplo de um corte e recomposição perfeitos, baseado em uma única imagem de máscara, veja os exemplos de método de composição, Compose DstOut. CORREÇÃO FUTURA DE BUG: A área preenchida deveria ser exata, mas para compensar isso ao desenhar formas, a 'cor de stroke' padrão deveria ser definida como a cor de fill (a menos que ela própria seja definida especificamente).


MVG - Magick Vector Graphics

Os primitivos mostrados acima formam a base de todas as operações "[-draw](https://imagemagick.org/command-line-options/#draw)" disponíveis. Juntos, eles são o ponto de partida para uma linguagem interna especial do ImageMagick, chamada linguagem Magick Vector Graphics. Para mais detalhes sobre essa linguagem, consulte Summary of MVG Primitives and Syntax no site do IM. Essa linguagem "MVG" foi projetada com o objetivo de permitir que o ImageMagick lide com a linguagem SVG (Scalable Vector Graphics), ainda mais complexa. Ela faz isso tentando converter imagens fornecidas no formato SVG para o formato interno MVG, mais simples. Para mais detalhes, consulte SVG handling abaixo. Consequentemente, o que você viu acima é apenas uma pequena parte das capacidades do operador "[-draw](https://imagemagick.org/command-line-options/#draw)". No entanto, se você quiser desenhar objetos complexos, recomendo criar uma imagem separada do objeto no formato SVG usando um editor SVG como o "[Sodipodi](http://the-labs.com/Sodipodi/)". (Consulte Non-IM Vector Graphic Programs abaixo). Diferentemente do SVG, o MVG não possui nenhuma forma de 'contêineres' ou conjuntos de comandos de imagem. Todos eles são removidos durante o processo de conversão para produzir uma sequência simplificada de comandos de desenho MVG. Em vez disso, ele usa o conceito de Graphic Contexts para salvar e restaurar diversas configurações de desenho, que é o que veremos a seguir.

Configurações da Linha de Comando vs Configurações MVG

Antes de tudo, quase todas as configurações que você define pelas opções de linha de comando usadas pelos primitivos de desenho têm equivalentes diretos nos comandos de desenho MVG. A principal diferença entre defini-las por uma opção de linha de comando (como "-strokewidth") ou usar uma configuração dentro de uma string de desenho MVG (por exemplo, 'stroke-width) é que a configuração MVG só dura enquanto durar a string de comando MVG.

**Summary of the General Drawing Settings**
  __cmd_option__   __draw_MVG__        __Argument__
    -fill            fill                color/tile for inside shapes
    -tile            fill                image tile, replaces fill color

    -stroke          stroke              line color/tile around the shapes
    -strokewidth     stroke-width        pixel width
    +antialias       stroke-antialias    0/1 aliasing line edges

    -font            font                font_name / font_file
    -family          font-family            ?
    -weight            ?                    ?
    -stretch           ?                    ?
    -pointsize       font-size           height in points
    -kerning           -                 extra inter-character spacing

    +antialias       text-antialias      0/1 aliasing drawing text
    -box             text-undercolor     fill color for font bounding box
      -              decorate        (None, Underline, LineThrough or Overline)

    -gravity         gravity             (None, North, South-East,...)
    -fuzz              -                 color delta / percentage
    -bordercolor       -                 color

Notes:
  - no such option      ? unknown
Essas configurações costumam ser bem compreendidas, pois são usadas e demonstradas regularmente acima. Uma font, stretch, style e weight são usadas para identificar uma fonte na lista de fontes do ImageMagick. A maioria das pessoas, porém, apenas seleciona uma fonte específica e um pointsize para usar. Por isso, elas raramente são usadas no IM.
Como você pode ver, as configurações especiais dos primitivos de 'preenchimento de cor' não têm equivalentes diretos no MVG. Ou seja, o "-bordercolor" e o fator "-fuzz". Estes devem ser especificados na linha de comando antes de usar o operador "[-draw](https://imagemagick.org/command-line-options/#draw)". Algumas configurações MVG provavelmente seriam mais úteis como configurações globais de linha de comando, como a configuração 'decorate' para o desenho de fontes. AVISO: "-gravity" não faz parte da especificação SVG. Dentro do MVG, ela é usada apenas para o posicionamento de texto e imagens e para a justificação. Atualmente não existe uma configuração de justificação separada dos efeitos 'gravitacionais' padrão. No entanto, como a justificação faz parte do tratamento de texto do SVG, isso provavelmente mudará em algum momento no futuro. Agora, as configurações globais de linha de comando (fora da string de desenho MVG) são usadas para inicializar as configurações de cada operação "-draw" que você aplica, e é por isso que você pode definir uma cor "-fill" que pode então usar para desenhar um círculo dessa cor.
---
  magick -size 100x60 xc:skyblue   -fill red \
          -draw "circle 50,30 40,10"          draw_circle_global.gif

[IM Output]
Você pode sobrescrever essa configuração global localmente dentro do argumento MVG do "-draw"...


|

  magick -size 100x60 xc:skyblue   -fill red \
          -draw "fill green   circle 50,30 40,10"  draw_circle_override.gif

[IM Output]
No entanto, as configurações definidas dentro de um único argumento MVG do "-draw" só existem durante a duração daquela operação "-draw". Ou seja, as configurações dentro de um "-draw" são locais apenas àquele desenho e não são transferidas para argumentos "-draw" separados posteriores.


|

  magick -size 100x60 xc:skyblue   -fill red   -draw 'fill green' \
          -draw "circle 50,30 40,10"          draw_circle_local.gif

[IM Output]
Se você planeja fazer muitas operações, pode ser melhor fazê-las todas em uma única string MVG, em vez de múltiplas operações "-draw".


|

  magick -size 100x60 xc:skyblue  \
          -draw "fill green  circle 41,39 44,57
                 fill blue   circle 59,39 56,57
                 fill red    circle 50,21 50,3  "  draw_circle_multi.gif

[IM Output]
Configurações Específicas do MVG Outras configurações MVG que controlam a forma como linhas e objetos são desenhados também são úteis de conhecer, mesmo ao usar as operações primitivas. Elas incluem..

   __draw_MVG__       __Description/Argument__
  fill-opacity        fill transparency, from 0.0 to 1.0
  clip-rule           fill style for crossed lines (evenodd, nonzero)

  stroke-opacity      line transparency, number from 0.0 to 1.0
  stroke-dasharray    list of 'on' and 'off' lengths for lines
  stroke-dash
  stroke-linecap      End of line look: butt round square
  stroke-linejoin     Lines joins:  butt  miter round square
  stroke-miterlimit   Angle when 'miter' joins become 'bevel' (or 'butt')

Lembre-se de que uma lista completa de todas as configurações MVG e operadores de desenho pode ser vista em Summary of MVG Primitives and Syntax no site do IM. Vamos ver os efeitos de algumas das configurações mais simples... |

  # Stroke Opacity
  magick -size 100x60 xc:skyblue -fill none -stroke black \
          -draw "                           path 'M 10,10 L 90,10'" \
          -draw "stroke-opacity 0.8         path 'M 10,20 L 90,20'" \
          -draw "stroke-opacity 0.6         path 'M 10,30 L 90,30'" \
          -draw "stroke-opacity 0.4         path 'M 10,40 L 90,40'" \
          -draw "stroke-opacity 0.2         path 'M 10,50 L 90,50'" \
          set_stroke_opacity.gif

  # Fill Opacity
  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "                    rectangle  5,10 15,50 " \
          -draw "fill-opacity 0.8    rectangle 20,10 30,50 " \
          -draw "fill-opacity 0.6    rectangle 35,10 45,50 " \
          -draw "fill-opacity 0.4    rectangle 50,10 60,50 " \
          -draw "fill-opacity 0.2    rectangle 65,10 75,50 " \
          -draw "fill-opacity  0     rectangle 80,10 90,50 " \
          set_fill_opacity.gif

[IM Output]
[IM Output]
|

  # Plain and Dashed Lines
  magick -size 100x60 xc:skyblue -fill none -stroke black \
          -draw "                           path 'M 10,10 L 90,10'" \
          -draw "stroke-dasharray 5 3       path 'M 10,20 L 90,20'" \
          -draw "stroke-dasharray 5 5       path 'M 10,30 L 90,30'" \
          -draw "stroke-dasharray 10 3 3 3  path 'M 10,40 L 90,40'" \
          -draw "stroke-dasharray 1 6       path 'M 10,50 L 90,50'" \
          set_lines.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "                           path 'M 10,10 L 90,10'" \
          -draw "stroke-dasharray 5 3       path 'M 10,20 L 90,20'" \
          -draw "stroke-dasharray 5 5       path 'M 10,30 L 90,30'" \
          -draw "stroke-dasharray 10 3 3 3  path 'M 10,40 L 90,40'" \
          -draw "stroke-dasharray 1 6       path 'M 10,50 L 90,50'" \
          set_lines_fill.gif

  # Note: Technically the second image should be the same as the first
  # as the 'filled' lines contain no area.  This I regard as a BUG.

[IM Output]
[IM Output]
|

  # Stroke Ends and Joins
  magick -size 100x60 xc:skyblue -fill white -stroke black -strokewidth 8 \
          -draw "                           path 'M 20,20 L 20,70'" \
          -draw "stroke-linecap butt        path 'M 40,20 L 40,70'" \
          -draw "stroke-linecap round       path 'M 60,20 L 60,70'" \
          -draw "stroke-linecap square      path 'M 80,20 L 80,70'" \
          set_endcaps.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black -strokewidth 5 \
          -draw "                        path 'M  5,70 L 20,20  35,70'" \
          -draw "stroke-linejoin miter   path 'M 35,70 L 50,20  65,70'" \
          -draw "stroke-linejoin bevel   path 'M 55,70 L 70,20  85,70'" \
          -draw "stroke-linejoin round   path 'M 75,70 L 90,20 105,70'" \
          set_linejoin.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black -strokewidth 5 \
          -draw "                        path 'M  5,70 L 20,20  35,70'" \
          -draw "stroke-miterlimit 7     path 'M 35,70 L 50,20  65,70'" \
          -draw "stroke-miterlimit 6     path 'M 65,70 L 80,20  95,70'" \
          set_miterlimit.gif

[IM Output]
[IM Output]
[IM Output]
O ajuste 'stroke-miterlimit' é bastante difícil de demonstrar. Essa propriedade define o ângulo no qual uma junção 'miter' é transformada em uma junção 'bevel'. Basicamente, para ângulos muito agudos, um miter pode se estender bastante a partir da junção real das duas linhas. Isso define um limite máximo para essa agudeza, aparando o ponto do canto quando ele fica longo demais. Observe, porém, que ele representa um valor trigonométrico de algum tipo de ângulo, e não um comprimento ou distância. O valor deve ser maior que 1.0. O exemplo acima mostra como, para o ângulo de junção que estou exibindo, o miter será subitamente transformado em bevel em algum ponto entre um valor de 6 e 7. Por exemplo, um 'stroke-miterlimit' de 1.414 converte um 'miter' em 'bevel' para qualquer ângulo menor que 90 graus. Um valor de 4.0 (o padrão) converte a junção para ângulos menores que aproximadamente 29 graus. Já um valor de 10.0 os converte para um ângulo menor que aproximadamente 11.5 graus. Desenho de Caminhos SVG O caminho SVG é o primitivo básico de desenho do SVG. Ele é usado para desenhar linhas, formas, círculos, curvas, arcos e assim por diante. A especificação completa dos caminhos SVG pode ser encontrada no documento SVG Path Specification. No entanto, esse documento não é fácil de ler, pois é voltado a programadores, não a usuários, então vou simplificar e resumir a especificação de caminhos...

  • As letras são comandos, enquanto todos os números (ponto flutuante) são argumentos.
  • Vírgulas ou espaços podem ser usados como separadores de argumentos; caso contrário, são completamente ignorados.
  • Os dois últimos argumentos (x,y) de cada componente de caminho se tornam o ponto final (ou 'nó') desse componente de caminho.
  • Letras maiúsculas especificam as coordenadas absolutas do ponto final.
    Letras minúsculas são relativas ao ponto final do componente anterior.
    Por exemplo: " M 1,2 l 3,4 l 2,-4 " é o mesmo que " M 1,2 L 4,6 L 6,2 ".
    Ou seja, 3,4 foi somado a 1,2 para desenhar uma linha até 4,6.
    Em seguida, 2,-4 foi somado para desenhar uma linha até a coordenada final de 6,2.
  • Os argumentos de cada elemento podem ser repetidos sem reemitir a mesma letra de caminho, bastando adicionar mais grupos de argumentos numéricos. No entanto, para curvas, recomendo adicionar as letras de função de qualquer forma, para facilitar a leitura.
  • Argumentos repetidos de "M" ou "m" são tratados como "L" ou "l", respectivamente.
    Por exemplo: " M 1,2 3,4 5,6 " é o mesmo que " M 1,2 L 3,4 L 5,6 "
    E: " m 1,2 3,4 2,-4 " é o mesmo que " m 1,2 l 3,4 l 2,-4 "
  • Para bezier cúbica, todos os pontos (pontos de controle e nó final) são dados em relação ao ponto final do componente de caminho anterior.

Observe como você pode especificar as coisas como coordenadas absolutas ou coordenadas relativas. Assim, você pode definir um objeto em termos de coordenadas relativas e apenas fornecer uma coordenada 'move' absoluta inicial para posicionar todo o caminho. Por outro lado, você também pode usar outros comandos de 'graphic-content' para mover todo um desenho dentro de uma 'viewbox' ou 'translation' (veja abaixo). Então, na verdade, não importa se você usa coordenadas absolutas ou relativas em caminhos SVG. Movimentos, Linhas e Fechamentos de Caminho são o ponto de partida inicial para aprender sobre os caminhos de objetos SVG. |

  # Open, Completed and Closed Paths (same points)

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 40,10 L 20,50 90,10 70,40'" path_open.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 40,10 L 20,50 90,10 70,40 40,10'" path_complete.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 40,10 20,50 90,10 70,40 Z'" path_closed.gif

[IM Output] [IM Output]
[IM Output]
Observe, porém, que 'Z' apenas fecha o laço. Ele NÃO cria um objeto separado. Assim, dois caminhos 'fechados' ainda são classificados como um único objeto desenhado, estejam eles sobrepostos ou completamente desconectados. Aqui mostramos dois laços fechados, mas sobrepostos, desenhados na mesma direção. Como apenas um único caminho é usado, o objeto é um único objeto, e a configuração 'fill-rule ' controla como a região sobreposta deve ser preenchida. |

  # Overlapping Paths and Fill Rule

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "fill-rule evenodd \
                 path 'M 40,10 20,20 70,50 Z
                       M 20,40 70,40 90,10 Z' " path_evenodd.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "fill-rule nonzero \
                 path 'M 40,10 20,20 70,50 Z
                       M 20,40 70,40 90,10 Z' " path_nonzero.gif

[IM Output]
[IM Output]
Como os objetos foram desenhados na mesma direção angular ao redor do centro, os dois laços fechados envolverão uma área que tem um valor de ciclo de 2. Por isso, a regra 'evenodd' deixou essa área sem preenchimento, enquanto a regra 'nonzero' (não-zero) a preencheu. Observe, porém, que todos os caminhos são visíveis, pois na verdade são o mesmo objeto. A direção em que os caminhos são desenhados é muito importante e, em geral, todos os caminhos devem ser desenhados exatamente na mesma direção em relação ao 'interior' do objeto. Por exemplo, aqui desenho o segundo objeto na direção inversa ao primeiro. Assim, quando os dois objetos se sobrepõem, essa área é circulada 'zero ' vezes. Ou seja, ela ficará sem preenchimento independentemente da 'fill-rule' usada, criando um 'buraco'. |

  # Overlapping Closed Objects, Second object drawn in reverse

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "fill-rule evenodd \
                 path 'M 40,10 20,20 70,50 Z
                       M 20,40 90,10 70,40 Z' " path_rvs_evenodd.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "fill-rule nonzero \
                 path 'M 40,10 20,20 70,50 Z
                       M 20,40 90,10 70,40 Z' " path_rvs_nonzero.gif

[IM Output]
[IM Output]
Isso significa que você pode gerar 'buracos' em um objeto, invertendo a direção, de modo a manter o 'interior' do objeto do mesmo lado da direção do percurso. |

  # An object with a reversed drawn hole!

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,10 20,55 70,50 80,5 Z
                       M 50,20 60,40 40,30 Z' " path_with_hole.gif

[IM Output]
O resultado é o mesmo independentemente da configuração 'fill-rule', pois o buraco é ao mesmo tempo 'par' e 'zero', ficando sem preenchimento. Claro que, se você usar um elemento 'path' completamente separado, gerará um objeto completamente separado. Nesse caso, a 'fill-rule' não se aplica e os objetos são simplesmente desenhados um sobre o outro, na ordem indicada. |

  # Separate paths are separate objects

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 40,10 20,20 70,50 Z'
                 path 'M 20,40 70,40 90,10 Z' " path_separate.gif

[IM Output]

FUTURE: coordinate aligned paths  "H" and "V"

Arcos Elípticos são a função de desenho de círculos dos Caminhos SVG...
Os parâmetros 'large' e 'sweep' são especialmente importantes, pois são usados para determinar qual das quatro maneiras você 'arqueará' do seu ponto inicial ao ponto final daquele componente de caminho. As duas flags 'large' e 'sweep' definem qual dos quatro arcos daquele raio conectará os dois pontos. |

  #  Elliptical Arcs :   A  radius_x,y  angle   large,sweep  x,y

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40  A 30,15 0 0,0 70,20'"    path_arc.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40  A 30,15 0 0,1 70,20'"    path_arc2.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40  A 30,15 0 1,0 70,20'"    path_arc3.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40  A 30,15 0 1,1 70,20'"    path_arc4.gif

[IM Output]
[IM Output]
[IM Output]
[IM Output]
a segunda flag 'sweep' simplesmente determina de qual lado da direção da linha reta o arco deve ser desenhado. A flag 'large' é usada para selecionar o caminho mais longo, contornando o centro da elipse. Ou seja, o ângulo definido do arco será maior que 180 graus. Se desativada, você obtém o 'arco' menor, que não contém o centro da elipse e se arqueia sobre um ângulo menor que 180 graus. Fechar um arco com um 'Z' apenas desenha um segmento de linha reta final. Para criar uma elipse ou círculo completo, você precisará de pelo menos dois segmentos de 'arco', indo do primeiro ao segundo ponto e depois de volta ao primeiro ponto. Ambos os arcos devem ter a mesma configuração 'sweep', de modo que o arco fique em lados diferentes, com a direção de percurso diferente. Um dos arcos deve ter a configuração 'large' ativada. |

  # Closed and angled elliptical arcs  (defined by two edge points)

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40  A 30,20  20  0,0 70,20 Z '" path_arc5.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40  A 30,20  20  1,1 70,20 Z '" path_arc6.gif

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40  A 30,20  20  0,0 70,20 \
                                A 30,20  20  1,0 30,40 Z '" path_arc7.gif

[IM Output]
[IM Output]
[IM Output]
Observe que, se a linha for longa demais para caber na elipse do tamanho fornecido no ângulo indicado, o tamanho da elipse será ampliado para caber na linha, com a elipse centrada sobre a linha. Isso significa que, usando números pequenos para os raios dos eixos, você pode apenas especificar uma proporção entre os comprimentos dos eixos e garantir que o caminho da linha direta passe pelo ponto central da elipse. Ou seja, o caminho forma um diâmetro elíptico de um lado da elipse ao outro. Este não é necessariamente o eixo maior ou menor da elipse, apenas um diâmetro elíptico. |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40   A 3,2  45  0,0 70,20'" path_arc_x.gif

[IM Output]
Claro que usar comprimentos de "1,1" resulta em um semicírculo perfeito, indo de um ponto ao ponto seguinte. O ângulo elíptico, nesse caso, não fará diferença. |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40   A 1,1  0  0,0 70,20'" path_hcircle.gif

[IM Output]
Para um círculo completo centrado entre os dois pontos, use... |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40   A 1,1  0  0,0 70,20
                                 A 1,1  0  1,0 30,40  Z'" path_circle.gif

[IM Output]
A definição SVG de 'arc' também declara que, se qualquer um dos dois raios for zero, uma linha reta deve ser desenhada. Assim, qualquer arco com raios "0,0" é apenas um simples arco de linha reta... |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40   A 0,0  0  0,0 70,20'" path_arc_line.gif

[IM Output]
Se você especificar raios muito grandes para o arco e não especificar um 'large sweep' para o caminho de retorno, poderá criar uma forma de lente daquele raio entre os dois pontos. |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 30,40   A 50,50  0  0,0 70,20
                                 A 50,50  0  0,0 30,40  Z'" path_lens.gif

[IM Output]
Esse tipo de arco é um recurso essencial. Ele permite dar a uma linha que de outra forma seria reta uma curva pequena, mas bem distinta, com muita facilidade. Por exemplo, em vez de um simples triângulo como este... |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 20,55  L 25,10  L 70,5 L 20,55 Z' "   triangle.gif

[IM Output]
Você pode substituir cada linha por um arco de raio grande para dar a elas apenas uma leve curvatura. |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 20,55  A 100,100 0 0,0 25,10
                                A 100,100 0 0,0 70,5
                                A 100,100 0 0,0 20,55 Z' " triangle_curved.gif

[IM Output]
Os pontos finais das linhas não mudam; tudo o que aconteceu foi que cada 'L' foi substituído por um segmento de arco. O tamanho do arco, porém, deve ser proporcional ao comprimento da linha. Como não fiz isso, a linha diagonal mais longa tem uma curva muito mais forte e profunda do que as outras duas. Lembre-se de que, ao redimensionar ou escalar o objeto desenhado, você também deve escalar o raio na mesma proporção do comprimento da linha, para que a curva seja redimensionada de acordo e o arco também escale corretamente. Observe que a flag 'sweep' controla se a curva se projeta para fora ou para dentro, conforme a direção em que cada segmento do path é desenhado (veja acima). |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 20,55  A 100,100 0 0,0 25,10
                                A 100,100 0 0,1 70,5
                                A 100,100 0 0,1 20,55 Z' " triangle_bulge.gif

[IM Output]
O triângulo de aparência 'estática', com arestas retas, agora se parece um pouco com uma vela se enchendo de vento. Se você realmente quiser deixar a linha perfeitamente reta sem convertê-la de volta em segmentos de reta verdadeiros, pode desativar a curva usando um raio de arco igual a zero. Assim, os arcos são úteis não apenas para gerar elipses e círculos, mas também para desenhar segmentos de linha retos e levemente curvados. É um path de desenho ponto a ponto de propósito geral muito versátil. Uma alternativa simples ao uso de Arcos Elípticos para gerar segmentos de linha curvos separados é usar Segmentos de Bézier Quadráticos. A principal diferença é que se usa um único ponto de controle, em vez de um raio circular para definir o arco. Isso também permite enviesar o arco em direção a uma das extremidades do segmento de linha, mas ao custo de tornar mais difícil gerar um arco simétrico. Você pode, é claro, 'combinar os dois' usando ambos. Exemplo de Gráfico de Pizza Para encerrar o uso de arcos, vamos dar um exemplo do seu uso para gerar fatias circulares. É claro que você pode precisar de alguma matemática trigonométrica externa (quão boa era sua matemática do ensino médio?) para determinar os pontos finais do path necessários. |

  magick -size 140x130 xc:white -stroke black \
    -fill red   -draw "path 'M 60,70 L   60,20   A 50,50 0 0,1 68.7,20.8 Z'" \
    -fill green -draw "path 'M 60,70 L 68.7,20.8 A 50,50 0 0,1 77.1,23.0 Z'" \
    -fill blue  -draw "path 'M 68,65 L 85.1,18.0 A 50,50 0 0,1  118,65   Z'" \
    -fill gold  -draw "path 'M 60,70 L  110,70   A 50,50 0 1,1   60,20   Z'" \
    -fill black -stroke none  -pointsize 10 \
    -draw "text 57,19 '10' text 70,20 '10' text 90,19 '70' text 113,78 '270'" \
    piechart.jpg

[IM Output]
Observe que todos os arcos são desenhados à esquerda do 'path de linha' e são sinalizados de acordo (usando a flag 'sweep'). Mas, se o arco cobrir um ângulo maior que 180 graus, é preciso definir a flag 'large'. Veja o último componente 'gold' no exemplo acima. Observe também que você deve desenhar cada seção completamente, mesmo que isso signifique ter de desenhar linhas de borda duas vezes. Se não fizer isso, provavelmente ou não preencherá totalmente aquela seção com cor, ou a cor de preenchimento se sobreporá ao contorno de uma seção desenhada anteriormente. A única maneira de evitar duplicar múltiplas linhas é desenhar todas as áreas preenchidas e depois repetir para desenhar os contornos. Ou seja, você precisará desenhar tudo duas vezes, garantindo que as coisas se encaixem adequadamente. Assim, duplicar os contornos é provavelmente a solução mais simples. As curvas Bézier Cúbicas podem ser definidas usando uma função 'C' que define dois pontos de controle e o ponto final. Para dar continuidade a curvas Bézier Cúbicas que usam uma imagem espelhada do último ponto de controle (para uma curva contínua), você pode usar uma função 'S'. Eis um exemplo. Por causa da complexidade dessa função, preparei antecipadamente um canvas mostrando a localização dos pontos de controle, bem como o 'espelho presumido' do último ponto de controle. |

  # Cubic Bezier:    C  control_1_x,y control_2_x,y  x,y
  # Smooth " :       S  control_2_x,y  x,y

  magick path_cubic_canvas.gif  -fill white -stroke black \
          -draw "path 'M 10,30  C 10,4 50,4 50,30  S 90,55 90,30' " \
          path_cubic.gif

[IM Output]
A linha que conecta o ponto de controle ao ponto final do path daquele segmento (linha de controle) define, basicamente, a direção da curva ao passar por aquele ponto do path. Uma linha de controle longa produz uma curva mais suave naquele ponto, enquanto uma linha curta gera uma curva mais acentuada. Se o ponto de controle coincidir com o ponto da curva (linha de controle de comprimento zero), a curva terá uma descontinuidade abrupta naquele ponto, como se apenas segmentos de reta tivessem sido usados. Como exemplo mais prático, o trecho de código a seguir foi extraído do Script Gerador do Logo dos IM Examples, que cria a área de respingo curvo do Logo dos IM Examples. A parte complicada do exemplo é que eu transformo a string do path Bézier Cúbico que uso em outro path que mostra as linhas de controle usadas para gerar a curva bézier. Isso me deixa ver os ângulos e comprimentos das linhas de controle da curva, tornando muito mais fácil ajustar os resultados. Apenas um conjunto de pontos precisa ser ajustado para mostrar tanto a curva quanto os controles, mantendo os erros ao mínimo. |

   curve="M 12,27  C 7,37  18,50 18,60  S  0,80 10,94
          S 40,74 50,78  S 60,99 76,95  S 72,70 75,65
          S 95,55 95,42  S 69,37 66,32  S 67,2  53,7
          S 43,17 35,22  S 17,17 12,27  Z"
   c_ctrls=`echo $curve | \
              sed '1s/\([0-9]\)  *\([0-9]\)/\1 M \2/;
                   s/S/M/g; s/C/ /;' -`
   magick -size 100x100 xc:white \
           -draw "stroke None  fill Green  path '$curve'" \
           -draw "stroke Red   fill None   path '$c_ctrls'" \
           curvy_splash.gif

[IM Output]
Se você olhar atentamente para a imagem, verá que o início e o fim da curva têm duas linhas de controle voltadas em direções opostas. Para um path fechado e contínuo, tanto a linha de controle inicial quanto a final devem estar no mesmo ângulo (apenas em direção espelhada) e, é claro, com o mesmo comprimento. Isso é importante lembrar, pois é fácil errar. Todos os outros pontos ao longo da curva têm apenas um único ponto/linha de controle, que aponta na direção oposta à direção em que a curva é desenhada. Quanto mais longo esse segmento de linha, menos 'acentuada' é a curva naquele ponto de controle, sendo que um comprimento zero produz um 'ponto'. A função 'S' gera internamente o ponto/linha de controle espelhado para o próximo segmento a partir dos dados do segmento anterior, de modo a produzir uma continuação suave da curva. Para mais exemplos dessa função de path, veja SVG: Cubic Bezier Curve Commands. Gerar Manualmente uma Curva Bézier é relativamente simples, sem precisar de ferramentas gráficas sofisticadas.

  • Primeiro, defina todos os pontos de coordenada por onde você quer que a curva passe, repetindo a coordenada inicial no fim da lista.
  • Agora expanda essa lista duplicando todos os pontos de coordenada x,y em pares e adicione uma função 'S' (Cúbica Suave) antes de cada par. O primeiro número de cada par é o ponto de controle conectado ao segundo número, que representa o ponto da curva. O primeiro par de pontos, porém, tem isso invertido: o primeiro ponto é o início da curva e o segundo representa o primeiro e único ponto de controle invertido.
  • Mude a letra da função do primeiro par de coordenadas de 'S' para 'M', depois adicione um 'C' entre esse par de coordenadas. Por fim, remova o 'S' do segundo par de coordenadas para completar a função Cúbica ('C') inicial.
  • Complete o path adicionando um 'Z' final para fechar a curva.
    Veja a sequência de exemplo acima para ver como deve ficar.
  • Neste ponto você já pode testar o desenho do seu path. O path consistirá apenas em segmentos de reta, pois todas as linhas de controle terão comprimento zero.
  • Tudo o que você precisa fazer agora é ajustar lenta e cuidadosamente a posição do segmento de linha de controle (a primeira coordenada de cada par 'S') para obter a curva final desejada. Não faça as linhas de controle longas demais, nem na direção errada, ou você obterá uma curva de aparência muito engraçada.
  • Para ajudar a ver suas mudanças e encontrar erros, use o comando "sed" de conversão apresentado acima para desenhar as linhas de controle entre os pontos de controle do path e o ponto de controle da curva. Observe, porém, que linhas de controle de comprimento zero não são visíveis, mas, como a linha produzirá um ponto acentuado, a posição deve ser óbvia.
  • Por fim, garanta que o primeiro ponto/linha de controle após um 'C' seja exatamente oposto ao do ponto/linha de controle final, naquela mesma posição.

A Geração Interativa de Curvas também é possível usando alguns editores de gráficos vetoriais. Por exemplo, Luis Guerra relata que curvas bézier geradas pelo "Inkscape" podem ser acessadas usando a função "Edit -> XML Editor" e selecionando o path ou a forma cujos pontos de controle você deseja.

Você conhece outras maneiras de extrair uma curva bézier (fornecendo dois ou um ponto de controle por ponto da curva) usando uma ferramenta GUI? Ou talvez alguma outra técnica para gerar tais curvas? Escreva para mim! Eu adoraria saber a respeito. Você será creditado pela técnica, como outros já foram.

A Bézier Quadrática é uma simplificação da função Bézier Cúbica, na qual os dois pontos de controle são fundidos em um único ponto de controle. Novamente, você pode iniciar a curva com uma função 'Q' e então usar uma função 'T' para continuá-la, espelhando o último ponto de controle. |

  #  Quadratic Bezier:  Q  control_x,y  x,y
  #  Smooth " :         T  x,y

  magick path_quad_canvas.gif  -fill white -stroke black \
          -draw "path 'M 10,30   Q 20,4 50,30   T 90,30' " \
          path_quad.gif

[IM Output]
Devo avisá-lo, porém, que a função de continuação 'T' realmente só funciona para paths que conectam pontos igualmente espaçados. Não recomendo seu uso. A vantagem das Curvas Quadráticas é servir como substituição aos Arcos Elípticos, pois usa uma posição real, em vez de um raio, para o arco. Ela também pode enviesar o arco em favor de uma extremidade sobre a outra, o que não é prático ao usar Arcos Elípticos. |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "path 'M 20,55  Q 30,32 25,10
                                Q 50,1 70,5
                                Q 50,45 20,55 Z' " triangle_bulge_2.gif

[IM Output]
Neste caso, os arcos não são tão uniformes, e você obtém algo como uma barbatana de tubarão de cabeça para baixo, em vez de uma vela. Lembre-se de que Arcos Quadráticos são parábolas, enquanto Arcos Elípticos geram basicamente segmentos circulares. Isso pode ser a chave para determinar qual tipo de segmento de linha em arco você deve usar. Para mais exemplos dessa função de path, veja SVG: Quadratic Bezier Curve Commands.

Deformação da Superfície de Desenho

Além dessas capacidades, a superfície de desenho sobre a qual os objetos são desenhados pode ser deformada de várias maneiras, permitindo que você faça coisas incríveis. Primeiro, você pode aplicar algumas modificações gerais à superfície de desenho, como... 'translate', 'rotate', 'scale', 'skewX', 'skewY' e 'affine'. Por exemplo, dado um 'path' de linhas, podemos "transladar" a origem, ou ponto 0,0, da superfície de desenho para outro local. |

  magick -size 100x60 xc:skyblue \
          -draw "translate 50,30
                 image over 3,3 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' "  transform_translate.gif

[IM Output]
Observe que o '0,0', ou origem, da área de desenho está agora centralizado na imagem, embora o eixo Y permaneça negativo no topo e positivo na parte inferior da imagem. A operação "rotate" rotaciona a superfície de desenho, de modo que qualquer coisa desenhada depois nessa superfície será desenhada rotacionada. É claro que ela rotaciona em torno da origem transladada, então é uma boa ideia usar os dois operadores de transformação juntos. |

  magick -size 100x60 xc:skyblue \
          -draw "translate 50,30    rotate -30
                 image over 4,4 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' "  transform_rotate.gif

[IM Output]
"scale" amplia e reduz a superfície de desenho em torno da origem. |

  magick -size 100x60 xc:skyblue \
          -draw "translate 50,30    scale 1.5,1.5
                 image over 4,4 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' "  transform_scale.gif

[IM Output]
Um uso comum de "scale" é inverter o eixo Y para que um valor Y positivo aponte para cima. É claro que a origem também deve ser movida para o centro ou para o canto inferior esquerdo, para manter as coisas em ordem. |

  magick -size 100x60 xc:skyblue \
          -draw "translate 50,30    scale 1,-1
                 image over 4,4 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' "    transform_flip.gif

[IM Output]
E, por fim, "skewX" e "skewY" cisalham a imagem nas direções X e Y. Por exemplo, aqui usamos "skewX" para dar uma inclinação ao eixo vertical Y da imagem. |

  magick -size 100x60 xc:skyblue \
          -draw "translate 50,30   skewX 20
                 image over 4,4 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' "    transform_skewY.gif

[IM Output]
Esses operadores têm equivalentes fora da string MVG "[-draw](https://imagemagick.org/command-line-options/#draw)", para uso geral. No entanto, essas versões de linha de comando são operadores e se aplicam imediatamente a imagens já existentes na memória, em vez de a uma superfície de desenho na qual objetos vetoriais ainda não foram desenhados. Para mais detalhes, veja Distorcendo Imagens.

Deformação Afim da Superfície de Desenho

Todas as cinco transformações de canvas acima podem ser combinadas em um Operador de Matriz Afim geral, seja usando a primitiva MVG 'affine', seja definindo a transformação afim com "[-affine](https://imagemagick.org/command-line-options/#affine)" antes de chamar "[-draw](https://imagemagick.org/command-line-options/#draw)". As transformações afins usam um conjunto de 'Coeficientes de Matriz' que define como as coordenadas que você fornece devem ser modificadas em coordenadas de desenho reais. Para mais detalhes sobre como esses 'coeficientes' realmente funcionam, veja Affine Matrix Transforms. Por exemplo... Para apenas definir uma origem central em relação à qual os objetos são desenhados... |

  magick -size 100x60 xc:skyblue \
          -draw "affine 1,0,0,1,50,30
                 image over 4,4 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' "  affine_null.gif

[IM Output]
Inverter a imagem... |

  magick -size 100x60 xc:skyblue \
          -draw "affine 1,0,0,-1,50,30
                 image over 4,4 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' " affine_flip.gif

[IM Output]
Rotacionar em 30 graus em torno da origem... |

  magick -size 100x60 xc:skyblue \
          -draw "affine .866,-.5,.5,.866,50,30
                 image over 4,4 0,0 'terminal.gif'
                 fill white  stroke black
                 path 'M 0,20 -45,20 20,-25 -25,-25'
                 fill none  stroke red
                 path 'M 0,10 0,-10  M 10,0 -10,0' "    affine_rot.gif

[IM Output]
Para transformações afins mais complexas, você pode usar os Scripts Auxiliares Afins que foram criados para esse fim. Esses scripts transformam coisas como um ângulo de rotação e um ponto central em coordenadas afins que você pode usar diretamente na sua configuração "[-draw](https://imagemagick.org/command-line-options/#draw) affine" ou "[-affine](https://imagemagick.org/command-line-options/#affine)".

Empilhar/Desempilhar Contexto

Algumas primitivas MVG na verdade dependem do uso dessas transformações para serem usadas corretamente. Por exemplo, a Primitiva Ellipse só pode ser especificada diretamente com o eixo alinhado ortogonalmente. |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "ellipse 50,30 30,15 0,360"   ellipse_orthogonal.gif

[IM Output]
No entanto, usando as Transformações de Desenho, podemos facilmente adicionar um 'ângulo de rotação' à elipse. |

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "push graphic-context
                 translate 50,30   rotate 30
                 fill white  stroke black
                 ellipse 0,0 30,15 0,360
                 pop graphic-context"       ellipse_rotated.gif

[IM Output]
Observe que o 'centro' da elipse (o ponto de rotação) foi primeiro transladado, antes de a rotação ser aplicada. A 'ellipse' foi então desenhada nessa posição transladada, em '0,0'. O exemplo acima também mostra duas novas primitivas de desenho MVG: 'push graphic-context' e 'pop graphic-context'. Elas não são estritamente necessárias no exemplo acima, mas são recomendadas ao fazer transformações de desenho importantes. O que as primitivas 'push' e 'pop' fazem é salvar o estado atual de desenho, ou 'graphic-context', e depois restaurá-lo. Quaisquer configurações de desenho alteradas entre as duas primitivas serão esquecidas. Isso inclui qualquer deformação de superfície, como 'translate' e 'rotate', bem como as configurações de cor 'fill' e 'stroke', ou qualquer outra coisa que modifique o 'estado' de desenho. Essas primitivas facilitam desenhar objetos muito complexos com muitas transformações e depois restaurar as coisas a uma situação mais 'normal' para operações de desenho posteriores. Você pode ver uma demonstração mais prática disso em Desenhando Setas abaixo.

Empilhar/Desempilhar Objetos Especiais

Em Construção

Mais configurações usadas especificamente para o tratamento MVG do formato SVG.

    font-family   font-stretch   font-style   font-weight
    encoding 'UTF-8'

    push defs

      push gradient 'def_name' linear X1,Y1 X2,Y2
        stop-color 'color' where
        stop-color 'color' where
          # where is a point between the two pixels given (0 = X1,Y1  1= X2,Y2)
        gradient-units 'objectBoundingBox|userSpaceOnUse'
        affine ....
      pop gradient

      push gradient 'def_name' radial CX,CY FX,FY R
        # Here CX,CY is the center of the radial gradient of radius R
        # the FX,FY is the focal, and is usually the same a CX,CY
        # unless you are trying to warp the gradient in a specific direction
        stop-color 'color' where
        ...
      pop gradient

    pop defs

    push graphic-context
      fill 'url(#def_name)'
      ... draw things here ...
    pop graphic-context

Para exemplos, veja o site de desenvolvimento de _Florent Monnier_...
  <http://www.linux-nantes.fr.eu.org/~fmonnier/OCaml/MVG/>

Lendo Arquivos MVG Como você pode ver nos exemplos acima, os argumentos do MVG "-draw" podem ficar muito longos. Na verdade, a conversão de SVG para MVG pode produzir argumentos de desenho MVG extremamente longos (veja abaixo). No entanto, a interface geral de linha de comando do IM permite que você leia qualquer argumento string a partir de um arquivo usando um argumento "@filename". Isso é prático, pois significa que você pode ler seus comandos de desenho MVG muito longos e complexos de um arquivo separado. Por exemplo, se eu colocar operações MVG em um arquivo chamado "draw_circles.mvg", posso então desenhá-lo assim... |

  magick -size 100x60 xc:skyblue  -draw @mvg_circles.mvg  mvg_draw.gif

[IM Output] | [IM Output]
Não só isso, mas o ImageMagick também entende a leitura direta do formato de arquivo de imagem "MVG:", permitindo desenhar tais comandos de forma mais direta. No entanto, a menos que o arquivo MVG defina um canvas, você pode precisar especificar o canvas inicial ("-size" e "-background") para que ele desenhe sobre ele. |

  magick -size 100x60  -background limegreen  mvg_circles.mvg  mvg_file.gif

[IM Output] | [IM Output]
Você pode mover as configurações do canvas inicial para dentro da imagem MVG adicionando uma 'viewbox' ao arquivo MVG, com os desenhos de preenchimento de cor de fundo apropriados. Isso completa o arquivo de imagem MVG como uma definição completa de imagem. |

  magick   mvg_circles2.mvg    mvg_image.gif

[IM Output] | [IM Output]
| _Atualmente só existe uma maneira de ler um arquivo MVG externo de dentro de uma string de argumento MVG, e é usando uma primitiva de desenho 'image'. Infelizmente, isso converte o include MVG em uma imagem rasterizada ANTES de sobrepor essa imagem à superfície de desenho.

Em outras palavras, atualmente não existe uma função de 'include' MVG._ :-(
---|---

Em Construção

Você pode gerar as operações de desenho de baixo nível do IM usando o "[+render](https://imagemagick.org/command-line-options/#render)" para registrá-las.

Quando você então fornecer uma configuração/operador "[-render](https://imagemagick.org/command-line-options/#render)", o IM desenhará imediatamente essas
operações salvas.

Estranhamente, apenas gerar a saída para um arquivo "MVG" também parece fazer isso...
     magick ...   -draw '....'  draw_commands.mvg

NOTA: se você desenhar uma curva ao gerar um arquivo no formato MVG, o arquivo lista
a curva como uma série de segmentos de reta curtos, em vez da curva original.

Você pode, é claro, ir até o fim e usar o formato SVG, mais universal.
Veja "[SVG format handling](#svg)" abaixo.

Composição Alfa MVG

Em Construção

Não vi nenhum uso de composição Alfa (além do algoritmo do 'pintor', que é
basicamente uma composição alfa 'over') para o desenho de objetos.

No entanto, isso não quer dizer que não possa ser feito.

Se você quiser compor seu rectangle, ellipse, circle, ou o que quer que seja, com uma
composição alfa diferente (como 'DstOver', que é uma composição do tipo
Under), então desenhe sua figura em um canvas transparente em branco do mesmo
tamanho que o original e componha-a sobre sua imagem.

No entanto, como o SVG permite usar composição alfa para desenhar texto e outros
itens sobre imagens, imagino que isso seja uma adição futura.

Fique ligado!

Desenhando Símbolos

Às vezes você tem um conjunto de pontos em uma imagem onde deseja desenhar símbolos de referência, como cruzes, círculos, etc... Infelizmente, no momento o IM não possui comandos para desenhar esses símbolos com facilidade, mas com um pouco de trabalho extra é possível fazê-lo.

Técnicas de Desenho de Símbolos

O truque para desenhar múltiplos símbolos em uma dada lista de posições é gerar os comandos de desenho MVG usando um script de shell, ou qualquer API que você esteja usando, de modo a transformar o conjunto de pontos fornecido no conjunto apropriado de comandos de desenho. Por exemplo, aqui eu transformo uma lista de pontos em um 'mais' em cada um desses pontos... |

  # Define a string of X and Y coordinates
  # comma between values, space between coordinates.
  points="6.6,7.7  25.0,75.0 42.2,85.4 75.8,94.7 51.5,39.3  92.5,66.6"

  # magick each point into a draw command for a cross (using 'awk')
  # the 'tr' converts spaces into 'newlines' (one point per line).
  crosses=`echo $points | tr -s ' ' '\012' |\
     awk -F, '{ print "line " $1-3 "," $2 " " $1+3 "," $2 ;
                print "line " $1 "," $2-3 " " $1 "," $2+3 ; }' -`

  # draw a red line between the points, and blue crosses on the points.
  magick -size 100x100 xc:white \
          -draw "fill none stroke red   polyline $points " \
          -draw "fill none stroke blue  $crosses " \
          points_plus.gif

[IM Output]
O exemplo acima usa "tr" para separar cada ponto (dois números) em um ponto por linha, e depois usa "awk" para fazer todos os cálculos matemáticos necessários para desenhar o 'mais' sobre o ponto fornecido. Você pode usar o que preferir para isso, pois estou simplesmente aplicando uma forma de expansão de macro de texto na lista de pontos de entrada. Praticamente qualquer linguagem de programação consegue fazer isso. No caso do script de shell acima, apenas achei que "awk" era o meio mais simples e rápido. Na verdade, você pode até usar o próprio Imagemagick para fazer essa expansão de 'macro' usando a opção de formato do "magick"... Por exemplo, aqui eu a uso para calcular um ponto na circunferência do círculo, para este 'símbolo de ponto'. |

  # Define a string of X and Y coordinates
  # comma between values, space between coordinates.
  points="6.6,7.7  25.0,75.0 42.2,85.4 75.8,94.7 51.5,39.3  92.5,66.6"

  # circle radius (or symbol size) to draw around each point.
  radius=3.5

  # magick each point into a draw command for a cross
  # In this case, points are space separated by the shell
  circles=$(for point in $points; do
             x=$(echo "$point" | cut -d, -f1)
             y=$(echo "$point" | cut -d, -f2)
             # use IM to do some floating point math, EG:  y2=$y+$radius
             y2=$(magick xc: -format '%[fx:'"$y"'+'"$radius"']' info:)
             echo "circle $x,$y $x,$y2"
           done)

  # Draw a red line between the points, and blue circles on the points.
  magick -size 100x100 xc:white \
          -draw "fill none stroke red   polyline $points " \
          -draw "fill none stroke blue  $circles " \
          points_circle.gif

[IM Output]
Agora, as strings de desenho que você gera podem ficar bastante longas e começar a causar problemas com o tamanho do seu comando final. Assim, em vez de converter os pontos em longas strings que então passamos ao IM na linha de comando, você pode canalizar (pipe) os comandos de desenho ao IM como um arquivo. Desta vez também uso o método de desenho por Caminho SVG em vez dos métodos de desenho por Primitiva de Desenho. Além disso, o símbolo que gero são triângulos ao redor de cada ponto. |

  # Define a string of X and Y coordinates
  # comma between values, space between coordinates.
  points="6.6,7.7  25.0,75.0 42.2,85.4 75.8,94.7 51.5,39.3  92.5,66.6"

  # magick each point into a draw commands to draw a triangle
  for point in $points; do
     echo "path 'M $point  m 0,-5 -4,+8 +8,0 -4,-8'"
  done |\
    magick -size 100x100 xc:white \
          -fill none -stroke red  -draw "path 'M $points' " \
          -fill none -stroke blue -draw '@-' \
          points_tri.gif

[IM Output]
O Caminho SVG na verdade facilita isso, ao permitir movimentos relativos em pixels, deixando você projetar o símbolo de modo que ele exija apenas um único movimento absoluto inicial 'M' antes de fornecer a sequência de 'movimentos' e 'linhas' para desenhar o símbolo. Por causa disso, você na verdade não precisa de nenhum cálculo de ponto flutuante, pois o desenho do IM fará a matemática de posicionamento necessária. | O item de movimento relativo do Caminho SVG 'm' está quebrado antes do IM v6.4.3-5. Se o seu IM for mais antigo que isso, os exemplos acima (e o próximo) podem não desenhar nada. Você pode corrigir isso em versões mais antigas substituindo os movimentos relativos 'm' acima por uma sequência apropriada de linhas relativas, 'l'.
---|---
Agora você pode levar isso ainda um passo adiante e alimentar um arquivo MVG totalmente formado, completo com a especificação da tela de desenho, diretamente no IM como um pipeline de comandos de desenho. Desta vez, vamos fazer uma 'cruz', semelhante ao primeiro exemplo de 'mais' acima, que exigia muitos cálculos. |

  # Define a string of X and Y coordinates
  # comma between values, space between coordinates.
  points="6.6,7.7  25.0,75.0 42.2,85.4 75.8,94.7 51.5,39.3  92.5,66.6"

  # Generate a MVG file for IM to draw all components
  ( echo "viewbox 0 0 100 100   fill white  rectangle 0,0 100 100"
    echo "fill none stroke red   path 'M $points'"
    echo "fill none stroke blue  path '"
    for point in $points; do
      echo "  M $point  m -2,-2 +4,+4  m -4,0 +4,-4"
    done
    echo "'"
  ) | magick mvg:- points_cross.gif

[IM Output]
Isso usa a técnica especial de programação de shell na qual tudo o que é 'ecoado' dentro dos parênteses do shell será alimentado no comando final "magick" como um arquivo MVG. O primeiro 'echo' define e preenche a tela de desenho da imagem, enquanto o laço 'while' converte cada 'point' fornecido em um círculo do raio dado. A vantagem desse método é que você não fica sujeito a nenhuma limitação de tamanho de string que poderia ocorrer usando os outros dois métodos. Outros símbolos que você poderia gerar incluem caixas, losangos, barras de erro, etc... Veja também 'Desenhando Círculos' abaixo, para outros métodos de círculo, incluindo o desenho de um círculo por 'path' relativo sem cálculos.

Alternativas ao Desenho de Símbolos

Há outras formas de adicionar símbolos a imagens, além de desenhá-los diretamente.

Fontes de Símbolos

Você pode extrair símbolos de uma Fonte de Símbolos e salvá-los como um pequeno bitmap. Você também pode usar imagens pequenas pré-definidas e coloridas para isso. No entanto, isso pode ter dificuldade em posicionar a fonte exatamente em relação a um pixel específico. Ou seja, não é uma técnica muito precisa. Mas você pode compor qualquer imagem em qualquer posição de pixel. Por exemplo, estes símbolos foram extraídos de várias fontes, para uso específico nestas páginas de exemplo.

Exemplos de composição de imagens sobre um fundo maior são dados na seção sobre Camadas de Imagens. No entanto, um método em laço pode ser mais útil, como o apresentado em Posicionamento Programado de Imagens em Camadas. FUTURO: exemplo de camadas de imagens usando coordenadas

Morfologia

Outra alternativa é usar Morfologia, para 'Dilatar' um único pixel, usando núcleos de 'forma' especiais como '[Disk](morphology.html#disk)', '[Ring](morphology.html#ring)' e '[Plus](morphology.html#plus)', ou mesmo o seu próprio Núcleo Definido pelo Usuário. Por exemplo...

  magick -size 80x80 xc:black -fill white \
          -draw 'point 20,15 point 55,30 point 40,60'  points_pixels.gif
  magick points_pixels.gif -morphology Dilate Ring    points_rings.gif
  magick points_pixels.gif -morphology Dilate Plus:4  points_pluses.gif
  magick points_pixels.gif -morphology Dilate Cross:3 points_crosses.gif

[IM Output] [IM Output] [IM Output] [IM Output]

O resultado pode então ser convertido diretamente em uma sobreposição colorida usando o Operador Alpha Shape. A grande vantagem disso é que você não precisa realmente saber as posições individuais de cada símbolo. Nem quantos símbolos existem. Mas isso também pode ser uma desvantagem. Uma desvantagem importante é que as posições são apenas em posições inteiras. Você não consegue 'desenhar' usando um posicionamento de 'sub-pixel' de ponto flutuante.

Convolução

Uma técnica quase idêntica é usar 'Convolve', com núcleos especialmente projetados, o que permite definir vários tons de cinza, em vez de apenas um resultado simples de ligado/desligado, como acima. Ao usar um Núcleo Definido pelo Usuário diferente para cada canal da imagem (vermelho, verde, azul e alfa), é até possível criar um símbolo multicolorido a partir de cada coordenada de pixel. [IM Output] Para isso, uso um script especial "[image2kernel](../static/img/scripts/image2kernel)" que escrevi para transformar uma imagem colorida (veja à direita) em núcleos de convolução de ponto flutuante separados para cada um dos canais.

  image2kernel -q marker.png marker.dat

Isso gera quatro arquivos, como "[marker_R.dat](../static/img/draw/marker_R.dat)", um para cada canal da imagem de entrada muito pequena, que são representações Definidas pelo Usuário da imagem (com a origem centralizada na imagem). Agora, usando esses arquivos de dados de núcleo, podemos Convolve esses pontos únicos em nossa imagem de marcador colorida sobre um fundo transparente.

  magick points_pixels.gif -alpha off \
          \( -clone 0 -morphology Convolve @marker_R.dat \) \
          \( -clone 0 -morphology Convolve @marker_G.dat \) \
          \( -clone 0 -morphology Convolve @marker_B.dat \) \
          \( -clone 0 -morphology Convolve @marker_A.dat \) \
          -delete 0 -channel RGBA -combine point_markers.png

[IM Output] [IM Output]

| Antes do IM v6.7.6-9, o Operador Combine exige que o canal de transparência da imagem seja fornecido como valores de 'opacidade' em vez de valores alfa; assim, o canal alfa resultante criado precisa ser negado. EG: |

  ... "`cat marker_A.dat`" -negate \) \

Apenas imagens pequenas devem ser usadas, com os pontos de pixel espalhados o suficiente para que os símbolos não se sobreponham. Isso porque Convolve somará as áreas sobrepostas, tornando-as mais brilhantes do que o esperado. O exemplo acima foi convertido em um script de shell UNIX "[convolve_image](../static/img/scripts/convolve_image)", para facilitar seu uso.

  convolve_image  points_pixels.gif marker.png   point_markers.png

Esta técnica surgiu de uma discussão nos Fóruns do IM A Fun Experience with IM. O usuário queria posicionar pessoinhas sobre uma imagem de fundo de um campo de futebol, de modo que suas posições soletrassem o nome de uma pessoa na imagem.

Em Camadas

Uma técnica diferente, como Camadas de Imagens, posicionadas usando uma lista dos pixels que você extraiu da imagem de origem, pode ser a melhor abordagem. Você pode sobrepor primeiro as imagens de símbolo mais distantes, antes das imagens em primeiro plano, e pode escolher programaticamente, ou aleatorizar, qual símbolo substitui qual ponto. Para um exemplo disso, veja Pins in a Map.

Desenhando Círculos

As opções de desenho oferecem várias maneiras de fazer algo bem básico... Desenhar Círculos. Você pode, por exemplo, desenhar um círculo passando por qualquer ponto de sua circunferência. Assim, você precisará calcular um ponto central e um segundo ponto que esteja o raio (digamos, 25 pixels) de distância do primeiro ponto. |

  magick -size 100x60 xc:  -stroke Firebrick  -fill tomato  -strokewidth 2 \
          -draw 'circle 50,30 50,55'    circle_circle.gif

[IM Output]
Fred Weinhaus observou que, usando uma translação, você pode eliminar a necessidade de calcular a coordenada da borda do círculo, e simplesmente fornecer o raio diretamente. |

  magick -size 100x60 xc:  -stroke SeaGreen  -fill PaleGreen  -strokewidth 2 \
          -draw 'translate 50,30 circle 0,0 25,0'    circle_circle_trans.gif

[IM Output]
No entanto, ao desenhar múltiplos círculos, o acima exigirá operações "[-draw](https://imagemagick.org/command-line-options/#draw)" separadas para cada círculo, ou o uso de Empilhamento de Contexto. Usando uma elipse, você pode especificar diretamente o raio como comprimentos de eixo |

  magick -size 100x60 xc:  -stroke Sienna  -fill Wheat  -strokewidth 2 \
          -draw 'ellipse 50,30 25,25 0,360'    circle_ellipse.gif

[IM Output]
Você também pode gerar um círculo desenhando uma linha muito muito curta com 'stroke-linecap round'. A largura do traço define então o diâmetro do círculo. NOTE que a linha precisa ter algum comprimento (por menor que seja) ou o desenho não produzirá nada. |

  magick -size 100x60 xc:  -stroke Blue  -strokewidth 50 \
          -draw 'stroke-linecap round line 50,30 50,30.0001' \
          circle_line.gif

[IM Output]
Esta técnica, infelizmente, não consegue contornar o círculo gerado, mas para cobrir áreas grandes, larguras de traço grandes podem ser úteis. Veja Alguns exemplos simples abaixo. Este método faz uso do método de desenho por Caminho SVG para que o círculo possa ser desenhado sem precisar calcular nenhuma coordenada extra. |

  magick -size 100x60 xc:  -stroke Blue  -fill DodgerBlue  -strokewidth 2 \
          -draw "path 'M 50,30  m 0,25  a 1,1 0 0,0 0,-50  a 1,1 0 1,0 0,50'" \
          circle_path.gif

[IM Output]
Apenas o movimento absoluto inicial 'M' é necessário para definir o centro; o '25' e o '50' nos demais componentes do caminho que se seguem definem o raio e o diâmetro do círculo em relação a esse centro. | O item de movimento relativo do Caminho SVG 'm' está quebrado antes do IM v6.4.3-5. Se o seu IM for mais antigo que isso, o círculo pode aparecer apenas como um único pixel. Você pode corrigir isso em versões mais antigas substituindo o 'm' acima por um 'l'.
---|---
Fred Weinhaus acrescentou o seguinte método de círculo por bezier. Ele fica muito próximo de um círculo real (embora não exato) e exige um cálculo de ponto flutuante. |

  r=25;  cx=50;  cy=30;
  x1=25;     x2=75;      # = cx ± radius
  y1=-3.25;  y2=63.25;   # = cy ± radius*1.275
  magick -size 100x60 xc:  -stroke Purple  -fill Violet  -strokewidth 2 \
          -draw "bezier $x1,$cy $x1,$y1  $x2,$y1 $x2,$cy" \
          -draw "bezier $x1,$cy $x1,$y2  $x2,$y2 $x2,$cy" \
          circle_bezier.gif

[IM Output]
Se desenhar um círculo exato não for importante, você pode usar este caminho SVG de 4 segmentos bezier, que usa apenas os limites X e Y do círculo em seu cálculo. |

  r=25;  cx=50;  cy=30;
  x1=25;    x2=75;      # X bounds = cx ± radius
  y1=5;     y2=55;      # Y bounds = cy ± radius
  magick -size 100x60 xc:  -stroke Tomato  -fill Gold  -strokewidth 2 \
     -draw "path 'M $cx,$y1 Q $x1,$y1 $x1,$cy T $cx,$y2 $x2,$cy $cx,$y1 z'" \
     circle_bezier_path.gif

[IM Output]
Se você preferir um que seja desenhado completamente em relação a um ponto central de partida, pode usar esta técnica. Apenas o valor do raio é usado, tornando-a simples de gerar, usando apenas funções de string em uma API. |

  magick -size 100x60 xc:  -stroke Orange  -fill LemonChiffon  -strokewidth 2 \
     -draw "path 'M 50,30  m 0,25  q 25,0 25,-25  t -25,-25  -25,25  25,25 z'"\
     circle_bezier_path_rel.gif

[IM Output]
Você consegue pensar em outras maneiras de desenhar círculos?

Desenhando Setas -- posicionar, rotacionar e escalar símbolos

Usando as técnicas acima, você pode criar símbolos especiais, como uma ponta de seta, que você pode posicionar de modo que sua ponta fique exatamente no final de uma linha, e desenhar sobre ela... Se você desenhar a seta depois da linha (situação típica), então a seta será desenhada por cima da linha. No entanto, há três tipos de setas que podem ser definidas, e cada tipo é definido de maneiras diferentes dependendo do uso a que se destina.

  • Medição onde você simplesmente quer marcar as extremidades de uma linha com uma ponta de seta para indicar os limites de uma medida em algum diagrama de engenharia. Muito simples.
  • Vetores , mostrando a direção e a intensidade de algum valor.
    Por exemplo, em uma carta meteorológica de vento. É necessária uma cauda, e o ponto 0,0 é a extremidade da cauda. Frequentemente, cria-se uma grande grade desses vetores.
  • Indicadores , que apontam para algum detalhe.
    Para isso, o ponto 0,0 provavelmente deveria ser a ponta, ou alguma distância à frente da própria seta.

Setas de Medição

Simplesmente adicionar uma ponta de seta ao final de uma linha é relativamente fácil de fazer. Basicamente você cria um símbolo de 'ponta de seta' e o desenha na posição correta. Por exemplo... |

  arrow_head="l -15,-5  +5,+5  -5,+5  +15,-5 z"

  magick -size 100x60 xc: -draw 'line 10,30 80,30' \
          -draw "stroke blue fill skyblue
                 path 'M 80,30  $arrow_head' " \
          arrow_horizontal.gif

[IM Output]
Note que desenhei o símbolo de modo que seu ponto de partida seja exatamente o final da linha. Dessa forma, ele pode ser desenhado para trás, por cima da linha desenhada anteriormente, criando um símbolo bem elegante e limpo. As setas, no entanto, têm uma direção associada. Você poderia criar um número enorme de definições de seta em muitos ângulos diferentes, e muitos programas fazem isso. Mas como a seta é um vetor, por que não rotacionar a seta como um vetor? O comando de desenho do IM tem rotações de desenho (Deformação da Tela) embutidas, então vamos usá-las. Isso também tem a vantagem de mover a posição para fora da definição do 'path' da ponta de seta, permitindo que você especifique o caminho inteiro como uma 'constante'... |

  arrow_head="path 'M 0,0  l -15,-5  +5,+5  -5,+5  +15,-5 z'"

  magick -size 100x60 xc: -draw 'line 25,55 70,10' \
          -draw "stroke blue fill skyblue
                 translate 70,10 rotate -45
                 $arrow_head
                " \
          arrow_rotate.gif

[IM Output]
Se você quiser alterar o tamanho da seta, adicione uma opção de desenho "scale" depois do rotate. |

  arrow_head="path 'M 0,0  l -15,-5  +5,+5  -5,+5  +15,-5 z'"

  magick -size 100x60 xc: -draw 'line 25,55 70,10' \
          -draw "stroke blue fill skyblue
                 translate 70,10 rotate -45 scale 2,2
                 $arrow_head
                " \
          arrow_scale.gif

[IM Output]
Note como ela aumentou de tamanho mantendo a 'ponta' da seta onde você a especificou. Este é um aspecto muito importante do manuseio de setas, pois é apenas o ponto final e o ângulo da linha à qual você está adicionando a seta que importam. A ordem das 'transformações' é importante e, na verdade, é o inverso da ordem em que elas são de fato executadas. Ou seja, a escala é aplicada primeiro às coordenadas, depois a rotação, e por fim a translação. Se as transformações de coordenadas não fossem feitas nessa ordem, acabaríamos também escalando a posição final da seta, e ela não ficaria onde esperamos. Além disso, como a escala tem dois números, e a ponta de seta original foi projetada horizontalmente (ângulo zero), você pode escalar separadamente a largura da seta em relação à sua altura. Note também como a largura do traço também foi escalada com o tamanho da ponta de seta, mantendo tudo consistente. |

  arrow_head="path 'M 0,0  l -15,-5  +5,+5  -5,+5  +15,-5 z'"

  magick -size 100x60 xc: -draw 'line 25,55 70,10' \
          -draw "stroke blue fill skyblue
                 translate 70,10 rotate -45 scale 2,1
                 $arrow_head
                " \
          arrow_scale_aspect.gif

[IM Output]
Agora, como você está deformando a tela para desenhar setas individuais, talvez junto com muitas outras operações de desenho, você pode querer fazê-las todas em uma única operação "[-draw](https://imagemagick.org/command-line-options/#draw)". Digamos, para desenhar a linha e depois adicionar setas em AMBAS as extremidades, exigindo diferentes conjuntos de cores, posições, rotações e talvez até escalas diferentes. Isso significa que precisamos limitar o escopo da deformação da tela ao desenho de cada ponta de seta individual. Se você não limitar o escopo, poderá começar a afetar outras operações de desenho posteriores e nunca terá certeza do que está gerando. Para limitar o escopo da deformação (e de todos os outros atributos de desenho), você envolve a seção envolvida em um "graphic-context" ... |

  arrow_head="path 'M 0,0  l -15,-5  +5,+5  -5,+5  +15,-5 z'"

  magick -size 100x60 xc: \
          -draw "stroke black fill none
                 path 'M 10,40 A 50,50 0 0,1 90,40'
                 push graphic-context
                   stroke blue fill skyblue
                   translate 10,40 rotate 135
                   $arrow_head
                 pop graphic-context
                 push graphic-context
                   stroke firebrick fill tomato
                   translate 90,40 rotate 45
                   $arrow_head
                 pop graphic-context
                " \
          arrow_context.gif

[IM Output]
O 'push' essencialmente salva todos os atributos de desenho atuais para uso futuro, enquanto o 'pop' restaura esses atributos, substituindo quaisquer configurações (cores, deformações, posições etc.) pelas configurações salvas anteriormente. Isso significa que, após o 'pop', a 'deformação da tela' é cancelada, e o desenho retorna ao estado em que estava antes das modificações. A técnica acima é apenas uma forma de gerar setas, e uma boa opção ao desenhar setas como parte da medição de distâncias, como em desenhos técnicos.

Setas Vetoriais

Vetores, como mencionado, mostram tanto a direção quanto a intensidade de algum valor. Isso significa que o comprimento da seta é variável, e a ponta de seta pode estar em praticamente qualquer posição a partir do ponto de início do vetor. Você poderia fazer alguns cálculos pesados para determinar a posição onde a ponta de seta deveria ser colocada, dados o comprimento e o ângulo do vetor, mas há uma maneira bem melhor, que deixa o ImageMagick fazer esses cálculos por você. A solução é desenhar o comprimento do vetor como uma linha horizontal do tamanho certo no Espaço da Tela Deformada. Quando essa linha tiver sido desenhada, simplesmente transladar novamente o espaço de desenho até o final da linha enquanto a tela permanece 'deformada'. Você está agora posicionado corretamente, com a rotação certa para desenhar a 'ponta de seta' do vetor normalmente. Por exemplo, aqui gero um vetor de 70 pixels de comprimento em um ângulo de -35 graus. |

  vector_head="path 'M 0,0  l -15,-5  +5,+5  -5,+5  +15,-5 z'"
  indicator="path 'M 10,0  l +15,+5  -5,-5  +5,-5  -15,+5  m +10,0 +20,0 '"

  magick -size 100x100 xc: \
          -draw "stroke black fill none  circle 20,50 23,50
                 push graphic-context
                   stroke blue fill skyblue
                   translate 20,50 rotate -35
                   line 0,0  70,0
                   translate 70,0
                   $vector_head
                 pop graphic-context
                 push graphic-context
                   stroke firebrick fill tomato
                   translate 20,50 rotate 40
                   $indicator
                   translate 40,0 rotate -40
                   stroke none fill firebrick
                   text 3,6 'Center'
                 pop graphic-context
                " \
          arrow_with_tails.gif

[IM Output]

Setas Indicadoras

No exemplo acima, também demonstrei uma seta indicadora apontando para o ponto de início da seta vetorial anterior. No entanto, em vez de desenhar a seta como fiz antes, eu a criei como um símbolo de seta invertida, que começa a 10 pixels de distância da origem (ou ponto de início). Ou seja, um símbolo é posicionado na posição que quero indicar, então não quero de fato a seta diretamente sobre essa posição, mas um pouco afastada dela. Agora, embora os indicadores sejam mais simples de manejar que os vetores, normalmente não precisando de comprimento variável, você geralmente quer adicionar um texto na extremidade distante do indicador para especificar o que está sendo indicado. Como antes, pode ser difícil calcular essa posição, então por que se dar ao trabalho? A solução para posicionar o texto também é a mesma dos vetores. Mantenha o espaço deformado original usado para desenhar a seta indicadora e transladar a origem até a cauda dessa seta (40 pixels horizontalmente no espaço deformado). Agora que reposicionamos as coisas, podemos des-rotacionar a deformação em torno dessa nova posição, para que você possa desenhar o texto normalmente (com um leve deslocamento). Infelizmente, embora a justificação de texto padrão 'left' funcione no exemplo acima, atualmente você não consegue especificar uma justificação de texto no MVG, como uma configuração separada da gravidade. Se isso for um problema, faça uma solicitação no fórum de bugs do IM, e com sorte a justificação de texto (separada do posicionamento por gravidade) se tornará realidade, especialmente por ser de fato parte da especificação SVG.


Desenhando Objetos

Traços Largos de Cor

Você não precisa cercar completamente uma área de preenchimento com um caminho ou contorno para criar formas variadas. Usando Traços muito grandes e largos, é possível gerar grandes áreas e manchas de cor sobre uma tela. Por exemplo, um arco elíptico com traço largo pode gerar uma boa área de cor que eu de fato já vi ser usada na criação de um pôster. |

  magick -size 100x100 xc: -fill none -stroke powderblue \
          -draw 'stroke-width 70 ellipse -30,0 90,90 10,50' \
          -rotate 180  arc_background.gif

[IM Output]
Ou você pode gerar o sorriso bastante complexo de um palhaço. |

  magick -size 100x100 xc: \
          -draw 'fill none stroke-linecap round
             stroke-width 40 stroke tomato ellipse 50,0 70,70 65,115
             stroke-width 2  stroke black  ellipse 50,0 70,70 60,120
             stroke-width 40 stroke palegreen line 50,40 50,40.01' clown.gif

[IM Output]
O que você consegue criar? Conte para nós.

Cilindros

Em uma Discussão no Fórum do IM houve um debate intenso sobre o desenho de cilindros, e especificamente cilindros sombreados, usando os comandos de desenho do ImageMagick. O truque para desenhar cilindros é desenhar primitivas 'roundrectangle' de tal forma que as extremidades formem ovais. Ou seja, se o cilindro tem, digamos, 50 pixels de largura, você arredonda os cantos do retângulo em 25 e 12 pixels, respectivamente. Isto é, metade da largura do retângulo e, depois, metade novamente. Um cilindro passa então a ser apenas dois retângulos arredondados desenhados um sobre o outro. A segunda 'oval de extremidade', preenchida com uma cor mais clara, tem tamanho exatamente igual ao dobro de ambas as dimensões dos cantos. Por exemplo... |

  magick -size 60x100 xc:white -stroke snow4 \
          -fill chartreuse3    -draw 'roundrectangle 5,5 55,95 25,12' \
          -fill chartreuse2    -draw 'roundrectangle 5,5 55,29 25,12' \
          cylinder.gif

[IM Output]
Ao substituir a primeira cor de preenchimento por um sombreado em gradiente (usando uma técnica de Ladrilho em Memória), você pode fazer o cilindro parecer um pouco mais tridimensional... |

  magick -size 60x100 xc:white -stroke snow4 \
          \( -size 1x60 gradient:chartreuse1-chartreuse4 -rotate -90 \
             -write mpr:shading +delete \) \
          -tile mpr:shading  -draw 'roundrectangle 5,5 55,95 25,12' +tile \
          -fill chartreuse2  -draw 'roundrectangle 5,5 55,29 25,12' \
          cylinder_shade.gif

[IM Output]
Refinando aos poucos o desenho do cilindro (como foi discutido no fórum do IM), é possível chegar muito longe na geração de cilindros bastante complexos e visualmente atraentes. Isso incluiu a adição de cilindros de vidro semitransparentes ao redor, efeitos de sombra e rotulagem. O resultado final daquela discussão é um script "[cylinder_bar](../static/img/scripts/cylinder_bar)", que gera uma barra de porcentagem em forma de cilindro...

  cylinder_bar 95 cylinder_95.png

[IM Output]

O script pode gerar uma imagem de qualquer tamanho, ajustando todos os parâmetros de forma apropriada com base nesse tamanho e em outras configurações definidas no início do script. Ele também inclui o conceito de uma 'espessura do vidro', para criar uma folga entre o cilindro de vidro semitransparente externo e o cilindro colorido interno. Observe os sombreados muito sutis do cilindro, especialmente quando a extremidade do cilindro verde se sobrepõe à extremidade do cilindro de vidro! É impressionante o que se pode fazer com um pouco de planejamento prévio.


Desenhando Caracteres Especiais na String de Texto

Usar Aspas ou Barra Invertida?

Um dos maiores problemas que as pessoas têm com -draw é o desenho de caracteres que também têm significado especial para os shells UNIX e a linha de comando do DOS, ou mesmo outras linguagens como C, Perl, PHP, R ou Visual Basic. Os principais culpados nesse aspecto são os dois tipos de caracteres de aspas, além dos caracteres de substituição de variáveis como o cifrão '$' e o caractere de escape do shell e do ImageMagick, a barra invertida '\'. Basicamente, como o argumento MVG de "[-draw](https://imagemagick.org/command-line-options/#draw)" precisa estar entre aspas, e o argumento da string 'text' interna também pode precisar de algumas aspas adicionais. Para resolver isso, os usuários normalmente usam dois caracteres de aspas diferentes, um para o shell e outro para a string de texto MVG.

`**-draw '... text 0,0 "string" ...'**`

Observe que essa é a única opção real para usuários do windows, que têm seus próprios problemas e métodos de aspas. Alternativamente, eles trocariam as aspas e usariam...

**-draw "... text 0,0 'string' ..."**

O que permite incluir substituições de variáveis do shell (usando '$') sem escape. A escolha da forma correta resolve a maioria dos problemas, mas alguns caracteres ainda apresentam dificuldades, e cada solução depende exatamente de qual conjunto de aspas você usa, já que elas também definem como os caracteres especiais devem ser escapados. Aqui estão os quatro casos de uso de aspas e tratamento de caracteres especiais...

  • Usando Aspas Simples para o argumento do shell,
    com Aspas Duplas em torno da string de texto MVG.A técnica mais simples para lidar com strings de texto de desenho é usar uma aspa simples para envolver o argumento do shell. Isso, porém, significa que, para incluir um apóstrofo na string desenhada, você precisa sair do 'modo de aspas simples' do shell e fornecer esse apóstrofo fora das aspas simples do shell. Por exemplo, veja como lidar com os quatro caracteres especiais de que falei. |
    magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw 'text 0,0 "  '\''  \"  $  \\  " ' \
              -trim +repage  text_special_sd.gif
    

[IM Output]
Observe que, como o cifrão não precisa de escape, você também não pode usá-lo para substituir o conteúdo de uma variável do shell. É importante lembrar que a barra invertida é o único caractere especial que a string de desenho do IM trata. Além disso, sua razão de existir é puramente permitir que você escape quaisquer 'aspas da string de desenho do IM', como usamos acima para as aspas duplas. Além disso, todas as outras esquisitices são causadas pelo shell da linha de comando UNIX, e não pelo IM. O PC-DOS tem suas próprias esquisitices, e eu agradeceria contribuições sobre o escape de caracteres especiais ao usar o IM nesse ambiente. * Usando Aspas Duplas para o argumento do shell,
com Aspas Simples em torno da string de texto MVG.Se você realmente quiser inserir uma 'variável do shell' na string desenhada, então terá que usar aspas duplas para o argumento externo do shell. Isso torna todo o assunto muito mais complexo, pois você perde a proteção do shell e agora precisa escapar não apenas os cifrões '$', mas também as barras invertidas '\'. Por outro lado, o shell não precisará então usar caracteres de aspas simples como delimitador de fim de argumento, então esse aspecto fica simplificado. Vamos resumir os resultados para nossa pequena lista de caracteres especiais. |

    magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw "text 0,0 '  \\'  \"  \$  \\\\  ' " \
              -trim +repage  text_special_ds.gif

[IM Output]
Observe que, se você quiser desenhar uma barra invertida em si, a string de texto MVG precisa que a barra invertida seja duplicada (como no exemplo anterior), mas o próprio shell também precisa que cada uma dessas barras invertidas seja duplicada, produzindo um total de quatro barras invertidas só para produzir um único caractere desse tipo. Essa duplicação pode rapidamente se tornar avassaladora e confusa, exigindo muitas barras invertidas para alcançar o que você quer. Basta ir com calma e devagar, e você resolverá para a sua situação. * Usando Aspas Simples para o argumento do shell,
com Aspas Simples em torno da string de texto MVG. Vamos concluir com um resumo das duas combinações finais de aspas. Deixo para você descobrir como elas são decodificadas pelo shell e pelo MVG. |

    magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw 'text 0,0 '\''  \'\''  "  $  \\  '\'' ' \
              -trim +repage  text_special_ss.gif

[IM Output]
* Usando Aspas Duplas para o argumento do shell,
com Aspas Duplas em torno da string de texto MVG. |

    magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw "text 0,0 \"  '  \\\"  \$  \\\\  \"" \
              -trim +repage  text_special_dd.gif

[IM Output]

Como você pode ver, os argumentos de "[-draw](https://imagemagick.org/command-line-options/#draw)" na linha de comando têm que lidar tanto com o shell da linha de comando quanto com o escape de barras invertidas e aspas dentro da string de texto MVG. Os resultados podem ser confusos e complicados. Basta lembrar que o shell trata os dois tipos de aspas de forma diferente, enquanto a string de texto MVG não. É claro que, em scripts complexos, o melhor caminho pode ser evitar completamente o shell e quaisquer problemas de scripting. Você pode fazer isso lendo os argumentos de "[-draw](https://imagemagick.org/command-line-options/#draw)" a partir de um arquivo de desenho MVG.

`**-draw @drawfile.mvg**`

É claro que você ainda precisará escapar com barra invertida qualquer caractere de aspas que estiver usando, bem como quaisquer barras invertidas dentro do texto. No entanto, isso é bem mais simples do que tentar lidar com o próprio sistema de aspas e escape do shell ao mesmo tempo que o do IM. |

  magick -size 500x50 xc:lightblue  -font Candice -pointsize 36 \
          -gravity center     -draw @text_quotes.mvg      text_quotes.gif

[IM Output]
[IM Output]
A primeira imagem é de um dos arquivos de texto "MVG" que usei. Ele não contém escapes ou aspas do shell. Assim, apenas as aspas e escapes do MVG estão presentes. Observe que, no exemplo acima, se eu tivesse usado aspas simples para a string de texto MVG, a única mudança seria que eu precisaria escapar com barra invertida os caracteres de aspas simples, em vez dos caracteres de aspas duplas na string. Sobre os Caracteres de Porcentagem Apenas um último ponto sobre caracteres 'de escape' especiais no operador "-draw text". Os caracteres de porcentagem '%' devem ser desenhados 'como estão'. Você não deve precisar fazer nada de especial para desenhá-los. Se eles não forem desenhados 'como estão', então você tem uma versão antiga do IM e deve atualizar o quanto antes. | Até a versão 6.2.4 do IM, o caractere '%' era usado como caractere de escape para incluir informações extras da imagem na string de texto desenhada. Isso não é mais o caso, pois esses escapes eram confusos e incorretos quando as imagens SVG também tentavam desenhar caracteres de porcentagem.
---|---
Esse uso de 'escapes' de porcentagem (assim como os escapes de nova linha '\n') foi considerado incompatível com o operador "[-draw](https://imagemagick.org/command-line-options/#draw)" e com o uso pretendido do formato MVG para lidar com formatos de imagem SVG. Assim, a partir da versão 6.2.4 do IM, os escapes de % não funcionam, e as barras invertidas escapam apenas a si mesmas e as aspas ao redor. |

    magick -size 250x50 xc:none -box white  -pointsize 20 -gravity center \
            -draw 'text 0,0 "%w\n%h"'    -trim +repage text_escapes.gif

[IM Output]
Para mais detalhes sobre o 'bug de porcentagem' e maneiras de evitá-lo ao usar "[-draw](https://imagemagick.org/command-line-options/#draw)" em versões mais antigas do ImageMagick, consulte a página Desenhando um Bug de Porcentagem. Annotate em vez de Draw A melhor maneira de evitar esses tipos de problemas é usar "-annotate" em vez de draw para desenhar texto. Esse operador é um invólucro em torno do operador draw e permite o uso de todos os recursos de draw, mas de forma mais simples. Basicamente, esse operador só precisa de um conjunto de aspas (para o shell). Isso torna o tratamento de caracteres especiais muito mais simples. Infelizmente, embora você não precise mais escapar aspas para o IM, agora você tem Escapes de Porcentagem, como leituras de arquivo com '@', novas linhas '\n' e outras expansões de escape de porcentagem. Por exemplo, usando aspas simples... |

    magick -size 200x50 xc:none  -box white  -pointsize 20 -gravity center \
            -annotate 0 '\@  '\''  "  $  \\  %% ' \
            -trim +repage  annotate_s.gif

[IM Output]
e para aspas duplas... |

    magick -size 200x50 xc:none -box white -pointsize 20 -gravity center \
            -annotate 0 "\@  '  \"  \$  \\\\  %% " \
            -trim +repage  annotate_d.gif

[IM Output]
No entanto, todas as aspas e escapes de anotação são completamente ignorados se você usar o escape '@' para ler a string de um arquivo. Por exemplo, aqui incluímos informações sobre a largura e a altura de uma imagem! |

    magick -size 200x50 xc:none -box white -pointsize 20 -gravity center \
            -annotate 0 '%w\n%h' -trim +repage    annotate_percents.gif

[IM Output]
No entanto, todos os escapes são completamente ignorados ao ler uma string de anotação de um arquivo. |

    echo -n '@ %w\n%h' |\
      magick -size 200x50 xc:none -box white -pointsize 20 -gravity center \
              -annotate 0 '@-'  -trim +repage  annotate_file.gif

[IM Output]
Para mais informações, consulte Operador de Desenho de Texto Annotate, e especialmente Caracteres de Escape do Annotate.


O IM e o tratamento de SVG

Drivers de Entrada SVG: RSVG vs MSVG

Lidar com o formato de imagem SVG em si é algo muito complexo. O motor precisa lidar com todos os seus aspectos, conforme definido pelo documento SVG -- Scalable Vector Graphics. Algo que exige muito esforço de programação e tempo. Portanto, o ImageMagick fornece dois métodos para lidar com imagens no formato SVG. O primeiro é usar a biblioteca de código aberto RSVG, para converter o formato SVG em uma imagem rasterizada que o IM não tem problemas em manipular. Esse motor é completo em praticamente todos os aspectos do tratamento de SVG. O segundo método é o IM tentar converter SVG em MVG, usando um método interno chamado MSVG. O MSVG tenta converter uma imagem SVG na linguagem de desenho "MVG" dos operadores "-draw" do IM. Boa parte da funcionalidade do MVG de draw foi criada especificamente para esse propósito. Infelizmente, embora o desenho básico de linhas e a coloração estejam presentes, ele está longe de ser um conversor de SVG completo. Você pode forçar o uso do conversor MSVG interno lendo a imagem SVG usando o formato de entrada especial "MSVG:" (adicionado no IM v6.3.4). Mas se a biblioteca RSVG estiver presente, a maioria dos ImageMagick a usará em vez disso para renderizar imagens SVG. Para descobrir o que o seu IM fará, use...

  magick -list format | grep SVG

[IM Text]

Como você pode ver pelo "RSVG" entre parênteses, meu próprio IM usará a biblioteca RSVG, na versão indicada, que está presente no meu computador. Aqui eu 'desenho' uma pequena imagem SVG feita à mão, "diagonal.svg" (contribuída pelo usuário do fórum penciledin), que cria um retângulo com um gradiente diagonal simples, sobre um fundo branco. |

  magick diagonal.svg  diagonal_rsvg.gif

[IM Output]
Perfeito. Um gradiente diagonal adequado é produzido. No entanto, se você renderizar isso usando o MSVG interno (o padrão caso a biblioteca RSVG não esteja presente)... |

  magick msvg:diagonal.svg  diagonal_msvg.gif

[IM Output]
Como você pode ver, a conversão MSVG interna falha, retornando um gradiente vertical em vez de um diagonal. Você também pode ver os comandos MVG reais que o IM gera convertendo um SVG diretamente em um arquivo MVG.

[IM Text]

  magick msvg:diagonal.svg mvg:diagonal.mvg

[IM Text]

Você provavelmente consegue ver como o conversor MSVG tentou converter SVG em comandos de desenho MVG. Coisas com as quais o MSVG interno atual é conhecido por falhar incluem...

  • Gradientes não verticais (sem conversão para o novo tratamento de gradiente do MVG)
  • Texto ao longo de um caminho curvo
  • Justificação de texto (como algo separado da gravity)

No entanto, a maioria das ações básicas de desenho é tratada. Lembre-se também de que a linguagem MVG pode, na verdade, lidar com coisas que o SVG não pode, incluindo o uso de gravity para posicionar imagem e texto. A gravity não faz parte da especificação SVG, embora seja parte integrante do tratamento de texto e fontes do IM. Lembre-se também de que o MVG não tem o mesmo mecanismo de contêiner que o SVG tem. O conversor MSVG interno substitui os contêineres XML pelo empilhamento e desempilhamento de contextos gráficos (veja a saída MVG acima), o que tem o mesmo efeito.

Configurações de SVG

O formato de imagem SVG é um formato vetorial (veja Uma palavra sobre formatos de Imagem Vetorial) e, como tal, a imagem normalmente não tem um 'tamanho' padrão. Em vez disso, ela é 'desenhada' ou 'renderizada' em uma "[-density](https://imagemagick.org/command-line-options/#density)" específica, assim como o postscript (a densidade padrão é 72 dpi). Além disso, se o SVG não 'pintar' o fundo, você pode especificar a cor de fundo a ser usada por meio da configuração "[-background](https://imagemagick.org/command-line-options/#background)". Por exemplo, aqui está outra pequena imagem SVG "[home.svg](../static/img/images/home.svg)", que foi 'renderizada' usando 3 densidades diferentes, com 3 fundos diferentes, incluindo um fundo transparente.

  magick -density 36                      home.svg  home_1.gif
  magick             -background skyblue home.svg  home_2.gif
  magick -density 144 -background none    home.svg  home_3.png

[IM Output] [IM Output] [IM Output]

Observe que usei uma imagem no formato PNG para a versão maior com fundo transparente do exemplo acima. Isso produz uma imagem mais limpa do que o formato de imagem GIF produziria, por causa dos pixels semitransparentes das bordas. O PNG é sempre recomendado quando há transparência na imagem final. | _Descobri que algumas imagens SVG não escalam. Ou seja, elas foram definidas em termos de 'pixels', em vez de comprimentos do mundo real como 'pontos', 'polegadas' ou 'milímetros'. Como consequência, embora a configuração "[-density](https://imagemagick.org/command-line-options/#density)" possa alterar o tamanho geral da imagem (em unidades do mundo real), o tamanho dos 'pixels' não muda, e assim a própria imagem não muda de tamanho. Tais imagens SVG são, no entanto, bastante raras.

Pior ainda, algumas imagens SVG usam uma mistura de medidas em 'pixel' e 'ponto' e, a menos que o autor tenha feito isso de propósito, você pode obter uma verdadeira bagunça ao tentar usá-la em uma densidade diferente da que o autor pretendia. Estas são, felizmente, ainda mais raras.

Uma correção simples costuma ser apenas alterar todas as unidades em 'pixels' no SVG para 'pontos', mas isso não deve ser feito às cegas, caso o uso de 'pixels' tenha sido proposital._
---|---

Tratamento da Saída SVG

A partir do IM v6.4.2, o IM pode converter QUALQUER imagem bitmap em um gráfico vetorial SVG! A conversão nem sempre é bem-sucedida, mas imagens maiores e/ou mais simples (como uma máscara bitmap) serão convertidas muito bem. Por exemplo, aqui eu converto uma forma bitmap horrível em uma imagem SVG e depois a converto de volta, de modo a suavizar o bitmap em uma forma adequadamente anti-serrilhada.

  magick -pointsize 72 -font Candice label:A -threshold 50% \
          -trim +repage -bordercolor white -border 5x5 A.gif
  magick A.gif  A.svg
  magick A.svg  A.png

[IM Output] | | | [IM Text]

| [IM Output]

Para que isso funcione, porém, a biblioteca 'de desenvolvimento' "[AutoTrace](http://autotrace.sourceforge.net/)" precisa estar instalada, e o IM configurado com a opção "--with-autotrace". Se a biblioteca "[AutoTrace](http://autotrace.sourceforge.net/)" não estiver instalada e compilada no IM, então a saída SVG gerada será um número enorme de círculos de um único pixel, gerando um resultado binário, em vez de uma imagem SVG suave em contorno. Tais imagens são enormes em comparação e, muitas vezes, levam muito tempo para serem renderizadas pelo renderizador de SVG. É realmente necessária uma técnica padrão melhor de rasterizado para vetor, provavelmente usando técnicas de esqueleto por Morfologia e MAT. Havia um "autotrace:' delegate de entrada, para 'suavizar imagens bitmap de entrada', que fazia todos os passos acima de uma só vez usando o comando "autotrace" diretamente. No entanto, da última vez que verifiquei, esse delegate havia desaparecido. Era assim que você o usaria... |

  magick autotrace:A.gif  A_traced.png

[IM Output]
É claro que isso NÃO fornecerá a saída SVG do comando "autotrace", apenas filtrará a imagem de entrada através de SVG para suavizá-la. Como alternativa, você pode, na verdade, usar o comando "autotrace" diretamente, como mostrado nos exemplos Contorno de Rasterizado para Vetor e Esqueleto usando Autotrace. Você também pode gostar de ver os resultados de cancerberosgx, em Gerando Imagens SVG, que analisou soluções para converter fotos.


Editores de Gráficos Vetoriais Fora do IM

O ImageMagick é um processador de arrays de pixels. Ele geralmente não salva imagens vetoriais ('MVG' é a única exceção a isso), apenas as lê e as converte em arrays de pixels. O mesmo vale para outros editores de imagem em pixels, como Gimp, Photoshop e assim por diante. Para editar e manipular imagens baseadas em vetor, use programas como Sodipodi Editor de Gráficos Vetoriais baseado em SVG
Xfig Editor de Objetos Vetoriais simples, mas muito bom
(Ótimo para placas, mapas e organização de fotos em uma página)
Dia
AutoTrace Converte uma forma em um array bitmap em contornos vetoriais
Sketch Editor vetorial baseado em Python com texto curvo.
Esta, é claro, não é uma lista completa. Até muitos processadores de texto, como OpenOffice, Word e TeX, geralmente têm vários editores de objetos simples, embora muitas vezes difíceis de usar. No entanto, para converter genericamente um formato de gráfico vetorial em um formato vetorial diferente, não use o ImageMagick. O ImageMagick é, e sempre será, essencialmente um conversor e manipulador de imagens rasterizadas ou gráficos bitmap. Para mais informações, consulte Uma palavra sobre formatos de Imagem Vetorial.