⚠️ Este es un sitio de traducción no oficial, sin relación con ImageMagick Studio LLC. Para información autorizada, consulte la página original (https://usage.imagemagick.org/draw/index.html).

Ejemplos de ImageMagick -- Dibujo

Dibujar en IM es la forma de añadir nuevos elementos a una imagen existente. Aunque buena parte del dibujo de texto se trata en la página de ejemplos sobre Efectos compuestos de fuentes, y en Anotación de imágenes, esta página trata los demás aspectos más generales del operador "[-draw](https://imagemagick.org/command-line-options/#draw)". El comando draw nació como un medio para crear imágenes simples. Pero con el tiempo se ha ampliado hasta convertirse en la interfaz para la conversión de gráficos vectoriales a imágenes ráster.


Comandos de dibujo de ImageMagick Las imágenes en los ordenadores se suelen guardar de dos maneras distintas. La primera y más común, que has visto a lo largo de estas páginas de ejemplos, se conoce como gráficos ráster. En este enfoque, las imágenes se almacenan como una matriz rectangular de píxeles. La otra forma es menos común, y menos modificable, pero en otro sentido más versátil: los gráficos vectoriales de objetos. En esta forma la imagen se describe en términos de líneas, arcos, rellenos de color y, a veces, profundidad. Esto resulta útil porque puedes escalar estas imágenes a casi cualquier tamaño que desees y siguen mostrándose perfectamente. También puedes describir imágenes muy grandes y complejas en muy poco espacio en comparación con el equivalente en formato ráster. Ejemplos de imágenes de gráficos vectoriales son postscript y el nuevo SVG -- Scalable Vector Graphics. Las fuentes True-Type también son ejemplos de gráficos vectoriales, ya que esto permite usar las descripciones de cada carácter a cualquier escala. El operador de imagen "[-draw](https://imagemagick.org/command-line-options/#draw)" es una ventana a las funciones de dibujo vectorial de ImageMagick, y forma un conjunto de comandos bastante separado de los operadores de imagen normales de la línea de comandos de IM. | _Solo hay unos pocos formatos de archivo de gráficos vectoriales de uso general, ya que cada formato suele ser muy distinto de los demás. El resultado es que existe muy poco margen para compartir código.

Por esta razón, ImageMagick se centra más en el uso de gráficos vectoriales para dibujar imágenes en formato SVG. Los gráficos de postscript y de fuentes true-type se pasan a otras bibliotecas y aplicaciones 'delegate' externas que están mucho mejor preparadas para dibujar ese tipo de formatos de gráficos vectoriales.

Es decir, no quiere decir que no haya delegates disponibles para SVG. Un ejemplo es la biblioteca RSVG o la biblioteca GTK SVG, disponible en tiempo de compilación. IM se enlazará con esas bibliotecas para procesar SVG en lugar de intentar hacerlo por sí mismo._
---|---

Comandos primitivos de dibujo

Empecemos con las primitivas de dibujo más antiguas, más simples y más comunes del operador de imagen "[-draw](https://imagemagick.org/command-line-options/#draw)" de los comandos MVG. Ten en cuenta que todos los argumentos se tratan como números de punto flotante, y no tienen por qué ser enteros, como suelo usar en estos ejemplos. |

  # 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]
Estos dos métodos de punto producen resultados distintos cuando intervienen colores semitransparentes, según el comentario indicado. Consulta Primitivas de relleno de color más abajo para más detalles. |

  # 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]
La primitiva de dibujo 'arc' se incluye junto con los rectángulos porque en realidad es simplemente una 'ellipse' ajustada dentro del 'rectangle' definido por las dos coordenadas. Los arcos parciales se usan rara vez, ya que puede ser difícil determinar los puntos finales a menos que los ángulos se limiten a múltiplos de noventa grados.
Las primitivas 'circle' y 'ellipse' usan una coordenada de 'centro' junto con, respectivamente, una coordenada de 'borde', o valores de 'tamaño' y 'á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]
También puedes consultar Apilar/Desapilar contexto para ver un ejemplo de cómo crear una elipse rotada. |

  # 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]
Un método mejor para dibujar líneas y curvas es usar el Dibujo de trazados SVG, que puede ser mucho más versátil e incluso permite el 'dibujo de líneas 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 dos últimas operaciones de tipo relleno son actualmente las únicas operaciones de dibujo afectadas por "[-gravity](https://imagemagick.org/command-line-options/#gravity)". Otros modificadores de estas operaciones son: "[-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)". Hay otros modificadores, pero están relacionados con el más avanzado lenguaje Magick Vector Graphics.

Primitiva Bezier

La primitiva 'bezier' se usa para dibujar curvas. Cada comando dibuja solo un segmento de curva. Normalmente se dan 4 puntos (8 números): un punto inicial 'nudo', dos puntos de control y un punto final 'nudo'. Los dos puntos de control definen la dirección y la rapidez con que la curva se aleja de los puntos 'nudo' finales asociados. Para unir dos curvas suavemente, el punto de control del extremo debe reflejarse a través del 'nudo' para formar el punto de control de la siguiente curva Bezier. Por ejemplo, aquí dibujo dos curvas bezier que se unen suavemente. Observa cómo las líneas y puntos de control (también dibujados) se reflejan en línea recta a través de la coordenada de unión, tanto en ángulo como en longitud. Esto es importante, o la curva no 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]
Si muevo uno de los puntos de control, de modo que NO quede 'reflejado' a través del 'nudo' asociado respecto al otro punto de control del mismo 'nudo', entonces la curva será discontinua. |

  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]
Si el punto de control se mueve de nuevo de modo que coincida con el punto 'nudo' asociado, la línea saldrá directamente desde ese punto sin ninguna 'curva' en absoluto. |

  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]
Si ambos puntos de control se fijan en sus respectivos 'nudos', se generará una línea recta. |

  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]
La primitiva 'bezier' no resulta realmente útil sin especificar los 4 puntos. Solo el primero y el último punto se clasifican como 'nudos' por los que pasará (o terminará) la curva. Todos los demás puntos intermedios se consideran puramente puntos de control, que afectan a la curva en la secuencia dada; cuanto más lejos esté el punto de control, mayor será su efecto sobre ese segmento de la 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]
No se recomienda usar más o menos de 4 puntos por segmento de curva 'bezier', para mantener las cosas simples. En realidad recomiendo que no uses la primitiva 'bezier' en absoluto, sino que uses el Bezier cúbico de trazados SVG para generar curvas. Este dispone de una función especial de continuación de curva 'S' que realiza automáticamente la 'reflexión' apropiada de los puntos de control para generar segmentos de curva que se unen suavemente, y reduce el número de puntos de control que necesitas usar. También puedes definir puntos relativos al último punto final del trazado.

Primitivas de relleno de color

Además de las primitivas 'simples' anteriores, "[-draw](https://imagemagick.org/command-line-options/#draw)" también ofrece un conjunto de primitivas de relleno o modificación de color. Estas modifican el color (o los colores) de la imagen empezando en el punto especificado, según el método elegido. Estos métodos de relleno en realidad no son verdaderos comandos de 'draw', sino funciones de reemplazo de color. Se añadieron a draw porque era el lugar más fácil para insertar sus operaciones en ImageMagick en una versión muy temprana del programa. Igual que antes, el color usado se establece con el ajuste de color "[-fill](https://imagemagick.org/command-line-options/#fill)", pero si está definida, se usará en su lugar la imagen "[-tile](https://imagemagick.org/command-line-options/#tile)". Las demás opciones de ajuste anteriores no se usan y no tienen efecto sobre estas operaciones. Otros dos ajustes que también se aplican a estas primitivas son los ajustes de "[-bordercolor](https://imagemagick.org/command-line-options/#bordercolor)" y de factor "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)". Sin embargo, estos ajustes NO se pueden definir dentro del lenguaje 'MVG', por lo que solo se pueden establecer antes de usar el operador "[-draw](https://imagemagick.org/command-line-options/#draw)". La primera de ellas, 'color point', ya la has visto como alternativa a la primitiva de dibujo 'point' en los ejemplos anteriores. Si miras con atención verás el único píxel blanco que fijamos en nuestra imagen de prueba.

|

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

[IM Output]
Sin embargo, al dibujar colores transparentes y semitransparentes, estas funciones no son iguales. Aquí tenemos una imagen roja de tres píxeles (ampliada); en el segundo píxel, o central, usamos la función 'point' para pintar sobre el píxel rojo un color azul semitransparente, dando un resultado púrpura. Si en cambio usamos la función 'color point' (último píxel, el de la derecha), el color rojo es reemplazado completamente por el píxel azul semitransparente. No se superpone. |

  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 las funciones 'color' realizan un reemplazo total del color, mientras que las demás primitivas de color 'pintan' el color encima de la imagen. Por eso puedes usar 'color' para dibujar el color transparente. La función de dibujo 'color replace' reemplazará todas las apariciones del color exacto dado en la ubicación especificada. Y como puedes ver, las áreas no tienen por qué 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]
Sin embargo, como puedes ver en el primer resultado, algunos píxeles a lo largo de los bordes no se reemplazaron. Estos píxeles no son exactamente del mismo color que el píxel seleccionado, por lo que se ignoraron. Añadir un pequeño factor de fuzz también incluirá colores que sean similares al color original. Como se muestra en el segundo ejemplo anterior. Por supuesto, un 'factor de fuzz' no es una gran solución, ya que no capturará todos esos píxeles de borde. Este es un problema recurrente de todos estos métodos de 'relleno de color', y que no tiene una solución general. Si quieres reemplazar un color concreto conocido, en lugar de seleccionar un color de la propia imagen, puedes usar en su lugar el operador de imagen "[-opaque](https://imagemagick.org/command-line-options/#opaque)". Esta función también usa un ajuste de factor "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" para ampliar el rango de colores que coinciden con el color dado. El método 'floodfill' también es bastante simple, ya que simplemente rellenará toda el área alrededor del punto seleccionado y no seleccionará ninguna otra área de colores similares que no esté conectada de algún modo. También puedes ampliar el área que se rellena usando "[-fuzz](https://imagemagick.org/command-line-options/#fuzz)" para incluir colores similares. En este caso elegimos un valor lo bastante alto como para incluir también el borde de la cruz, permitiendo que el relleno por inundación 'se filtre' al otro lado de la imagen. |

  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]
Rellenar áreas por inundación con un color no está exento de problemas. El color puede filtrarse a través de un límite delgado, hacia áreas donde no se deseaba (consulta GIFs sobre un patrón de fondo como demostración de ello). O puede que no rellene el área seleccionada hasta el borde mismo (consulta Problemas de antialiasing y relleno por inundación). Pero funciona. El método 'filltoborder' es como 'floodfill', salvo que especificas un color que bordea el área que se va a rellenar, en lugar del color que se reemplazará por el proceso de relleno. Por supuesto, también se recomienda un factor de fuzz para incluir 'colores similares' en esa selección de color de borde, para limitar aún más el relleno por inundación. |

  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]
El último método de color de dibujo es 'reset', que simplemente reemplaza, o restablece, toda la imagen al color de relleno. En este caso, el píxel realmente seleccionado no influye en absoluto en el resultado. |

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

[IM Output]
Esto es en realidad muy útil, ya que ofrece una forma simple de generar un lienzo de color sólido (o de imagen en mosaico) a partir de una imagen existente. (Consulta Lienzos dimensionados según una imagen existente) para esta y otras formas de hacer lo mismo. FUTURO: Usar un patrón "[-tile](https://imagemagick.org/command-line-options/#tile)" para rellenar el área.

Primitivas de relleno de alfa

La primitiva de dibujo 'alpha' funciona exactamente igual que la primitiva 'color' descrita arriba, salvo que no reemplazará el color de las áreas seleccionadas, sino solo el canal 'alpha' de las áreas seleccionadas. (Es decir, estas funciones de relleno solo ajustan el canal 'alpha'). Igual que la función de relleno 'color', el valor 'alpha' usa el color de relleno (a menos que "[-tile](https://imagemagick.org/command-line-options/#tile)" sea la fuente del 'valor alpha' a usar). Aquí usamos el mismo ejemplo de 'color floodfill' de arriba, pero aquí solo ajustamos el canal alfa para hacer las partes rellenadas totalmente transparentes. ¡Es decir, el color original sigue presente, solo que 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]
La función 'alpha reset' también se puede usar para hacer toda una imagen semitransparente. Por supuesto, en este caso debemos generar la salida en PNG, que puede aceptar colores semitransparentes en las imágenes. |

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

[IM Output]
Observa que el componente de color 'black' no se usó en las operaciones, solo el componente alfa del color. El color original de la imagen se deja tal cual. FUTURO: Usar el patrón "[-tile](https://imagemagick.org/command-line-options/#tile)" para un efecto alfa interesante. Tanto 'color' como 'alpha' son funciones de reemplazo total del color, que siempre producirán un tipo de reemplazo de color booleano (todo o nada). Por ello, los bordes de tales áreas siempre mostrarán efectos de aliasing. Debido a esto, estos no suelen ser buenos operadores de imagen para el desarrollo general de imágenes, salvo para establecer las áreas transparentes de imágenes GIF (que también son booleanas). Sin embargo, no todo está perdido, como puede verse en los ejemplos de Eliminación de fondo.


Detalles sobre los comandos de dibujo

Coordenadas de píxel

El comando "[-draw](https://imagemagick.org/command-line-options/#draw)" (y muchos otros en IM) usa lo que se denomina "coordenadas de píxel". Es decir, una coordenada de '10,10' es el centro del píxel 10 píxeles hacia abajo y a la izquierda desde la esquina superior izquierda. En este sistema de coordenadas, 0,0 es el centro del píxel superior izquierdo, y w-1,h-1 es el centro de la esquina inferior derecha. Los bordes reales se encuentran en -0.5,-0.5 y w-0.5,h-0.5, y el píxel central (si la imagen tiene un tamaño impar) se encuentra en '(w-1)/2,(h-1)/2'. Sin embargo, cuando procesas una imagen matemáticamente (como al usar distort), los píxeles reales no tienen un significado real, por lo que se usan "coordenadas de imagen". En este sistema el borde real de la imagen está en '0,0' y 'w,h'. Y el centro de la imagen (que puede coincidir o no con el centro de un píxel) está en 'w/2,h/2'. Para convertir 'coordenadas de píxel' a coordenadas de imagen, suma ½. Así, el centro del píxel superior izquierdo es '0.5,0.5' y el del píxel inferior derecho es 'w-0.5,h-0.5'. Ejemplo: centro de un círculo en una imagen pequeña

Dibujar con corrección de gamma y espacio de color

Como casi todas las operaciones de ImageMagick, "[-draw](https://imagemagick.org/command-line-options/#draw)" es un operador lineal, y como tal trabaja en un espacio de color RGB lineal. Esto significa que, para obtener bordes bien suaves, puede que necesites hacer alguna corrección de gamma de las imágenes antes de guardarlas, de modo que se almacenen usando el espacio de color sRGB no lineal (corregido por gamma). Por ejemplo, si dibujas un círculo grande y simplemente lo guardas... |

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

[IM Output]
Fíjate en los bordes del círculo: en realidad no se ven muy suaves. Puedes ver efectos de escalera significativos. Eso se debe a que dibujaste el círculo en el espacio de color RGB lineal. ¡Pero luego guardaste la imagen como si fuera realmente del espacio de color sRGB! Para corregir esto necesitamos añadir una corrección de gamma a la imagen antes de guardarla. |

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

[IM Output]
Ahora los bordes del círculo se ven realmente suaves y redondeados, tal como deberían. Si quieres hacerlo correctamente, deberíamos hacer realmente la corrección usando el espacio de color. Sin embargo, como IM asume que RGB es el espacio de color predeterminado para guardar, necesitas un manejo algo delicado para que haga las cosas correctamente. |

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

[IM Output]
| Ten en cuenta que el espacio de color sRGB (que es la forma correcta de guardar imágenes) no es exactamente lo mismo que aplicar simplemente una corrección de gamma de 2.2. Sin embargo, las diferencias en los resultados entre ambos son mínimas, y solo se aprecian en imágenes muy muy oscuras.
---|---
| Antes de IM v6.7.5-1, los nombres de espacio de color 'sRGB' y 'RGB' (RGB lineal) estaban en realidad invertidos. Por eso, en versiones más antiguas de IM, las dos etiquetas anteriores deberían intercambiarse.
---|---
Para dibujar correctamente (o hacer cualquier procesamiento de imagen 'lineal') usando una imagen real (en IMv7), primero necesitas eliminar cualquier gamma existente, procesar la imagen y luego restaurar esa corrección de gamma. Consulta Redimensionar usando corrección de espacio de color para más detalles. Aquí tienes un ejemplo de dibujo sobre una imagen real... Primero sin corrección de color alguna (en bruto), y luego con correcciones de gamma y de espacio de color. |

  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 puedes ver, usando corrección de gamma o de espacio de color, la línea queda muy suave, sin el efecto de aliasing en 'escalera' dentado que se aprecia al dibujar directamente. (Necesitas un monitor muy bueno para verlo) | La línea anterior se dibujó usando un color "[-stroke](https://imagemagick.org/command-line-options/#stroke)". Puedes dibujar la línea usando "[-fill](https://imagemagick.org/command-line-options/#fill)" y obtener los mismos resultados, pero entonces no tendrás control del grosor de línea mediante "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)". Consulta Ajuste del color de stroke más abajo para más información.
---|---
| _Los nombres de color se definen en realidad usando valores del espacio de color 'sRGB' PERO draw los aplica como si la imagen estuviera en el espacio de color RGB lineal. Por eso, usar la corrección de gamma anterior con colores nombrados (distintos de 'white' o 'black') hará que esos colores queden distorsionados. En tales casos puede ser mejor no usar corrección de gamma ni de espacio de color, para que los colores nombrados se mapeen correctamente.

El mapeo correcto de los colores 'sRGB' nombrados al espacio de color de la imagen sobre la que se dibuja se corregirá como parte del desarrollo de IMv7.

_
---|---

Interacción entre Stroke, StrokeWidth y Fill

Las opciones "[-stroke](https://imagemagick.org/command-line-options/#stroke)" y "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" se usan al dibujar un contorno alrededor del borde de una fuente. Estas opciones se usan habitualmente con "[-fill](https://imagemagick.org/command-line-options/#fill)" para hacer el texto más interesante, con muy poco esfuerzo.

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

[IM Output]

Los ajustes predeterminados son "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth) 1" y "[-stroke](https://imagemagick.org/command-line-options/#stroke) None". Pero esto hace invisible el trazo del contorno, dejando solo el color de "[-fill](https://imagemagick.org/command-line-options/#fill)"; no lo verás. El único efecto que tiene "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" cuando el "[-stroke](https://imagemagick.org/command-line-options/#stroke)" es 'invisible' es sobre los atributos de tamaño de la fuente, lo que significa que aún puede afectar al posicionamiento de la fuente y al tamaño de la generación de imágenes de Etiqueta y Leyenda. Por lo demás, el grosor no tiene efecto visible hasta que haces visible el trazo. Para ver cómo "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" afecta realmente al aspecto de una fuente (cuando se hace visible), aquí he dibujado un texto con varios grosores, desde 'desactivado' y aumentando.

    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]

Observa en los ejemplos anteriores que establecer un "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" de '0' NO es lo mismo que establecer el color de "[-stroke](https://imagemagick.org/command-line-options/#stroke)" en 'none' (el predeterminado). El primero hace un contorno de trazo muy muy fino, mientras que el segundo lo desactiva efectivamente. En ambos casos el trazo todavía se dibuja. Sin embargo, también debes tener en cuenta que incluso con un "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" de '0' el contorno de la imagen se expandirá muy muy ligeramente respecto al de una imagen simplemente 'rellenada' (usando un color de "[-stroke](https://imagemagick.org/command-line-options/#stroke)" de 'none'). Esencialmente, usar cualquier grosor menor de '1.0' no funciona correctamente. Y deberías tener cuidado en los casos en que esto pueda importar. Recuerda, sin embargo, que "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" también es un ajuste de punto flotante. Es decir, un grosor de trazo de '0.5' también es válido. Sin embargo, normalmente esto solo es importante cuando intentas Dibujar círculos finos en mapa de bits con el Antialiasing desactivado.
Aquí tienes un ejemplo de uso de un grosor de trazo extremadamente 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]

Observa que "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" expande las líneas tanto hacia dentro como hacia fuera. Aquí está el mismo ejemplo, pero con la fuente vuelta a dibujar, sin el contorno de trazo, para eliminar la parte interior del trazo muy grueso.

   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 más ejemplos del uso de stroke, consulta Efectos compuestos de fuentes. Fíjate especialmente en el "Efecto globo".

Dibujo de líneas (Stroke)

El dibujo de líneas predeterminado en IM tiene algunos comportamientos raros que conviene conocer. Aquí está el dibujo de línea predeterminado... |

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

[IM Output]
Puedes establecer el color de la línea con una opción "[-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]
También puedes hacer una línea ligeramente más gruesa estableciendo el color de "[-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]
¿Pero qué pasó con el color blanco que especificamos con la opción "[-fill](https://imagemagick.org/command-line-options/#fill)"? Este es el aspecto delicado del dibujo de líneas en ImageMagick. Lo que hace el programa es considerar realmente la línea como un objeto relleno de aproximadamente 1 píxel de ancho. Esto es natural, ya que normalmente se usan varias líneas para barrer un área que se va a rellenar. Así, igual que cuando usamos stroke con fuentes en la sección anterior, IM dibuja la línea (u objeto) usando el color de relleno y luego la rodea con el color de stroke. El resultado es que la línea con color de stroke anterior es ahora ligeramente más gruesa, con el color de relleno completamente oculto debajo. Si haces el color de stroke semitransparente puedes hacer visible de nuevo ese color de relleno. En resumen, las líneas parecerán dibujarse con el color de "[-fill](https://imagemagick.org/command-line-options/#fill)", pero esa opción carece de importancia una vez que el color de "[-stroke](https://imagemagick.org/command-line-options/#stroke)" se ha definido como algo distinto de los colores predeterminados "none" o "transparent". | La opción "-linewidth" es realmente solo un alias de "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)", y no debería usarse.
---|---
Por ejemplo, probablemente pensarías que este comando produciría una línea muy gruesa. Lo hace, pero como el color de "[-stroke](https://imagemagick.org/command-line-options/#stroke)" es invisible no puedes verlo. Solo ves el 'relleno' interior del área de un píxel de ancho de la línea. |

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

[IM Output]
| El resultado anterior lo considero en realidad un error. No se debería haber dibujado nada, ya que no hay 'área' que rellenar, y no se ha establecido ningún 'color de stroke' para la línea. La razón por la que IM hace esto actualmente es para evitar confusiones a los usuarios nuevos, pero en realidad solo causa problemas a los usuarios avanzados. Consulta Límites de relleno de dibujo para más detalles.
---|---
Pero si también se define el color de stroke, obtendrás la línea gruesa solicitada... |

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

[IM Output]
Si el ajuste "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" se establece en uno, la línea anterior quedará completamente cubierta. |

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

[IM Output]
Por supuesto, una vez que dispones de este conocimiento, puedes usarlo para ser creativo, igual que con el dibujo de fuentes. |

  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]
Aquí usé el ajuste "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth)" más fino de '0', igual que hice con las fuentes anteriores. |

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

[IM Output]
Esto produce el resultado muy extraño de una línea de puntos, formada por puntos negros y segmentos grises. Es el resultado de una rara "frecuencia de batido de color" entre los colores de stroke, fill y de fondo. Aquí tienes una vista ampliada de la línea... |

  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]
| El efecto de "frecuencia de batido de color" no es muy distinto del de un "batido de sonido" que se obtiene cuando tienes dos guitarras muy ligeramente desafinadas. En este caso obtienes un punto negro donde el color de stroke anula por completo el color de fill subyacente, y obtienes un punto gris donde el color de stroke se mezcla con AMBOS, el fill y el color de fondo. La mezcla de colores es una consecuencia natural de los procesos de antialiasing que IM usa para tratar de mejorar el aspecto de las líneas y otros objetos de dibujo. Para más información, consulta mi página de discusión y ejemplos Antialiasing en IM.
---|---
Observa que este efecto solo aparece en líneas inclinadas, no en líneas puramente horizontales o verticales, donde el aliasing no tiene efecto y, por tanto, no hay efectos de "frecuencia de batido de color". |

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

[IM Output]
Aquí usé distintos colores de fill subyacentes en la vista ampliada, para que puedas ver cómo el color cambia el batido 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]
Comparemos eso con un 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 puedes ver, al dibujar líneas muy finas, puedes reducir ese 'batido' usando los mismos colores de fill y stroke, O estableciendo uno de los colores en none para desactivarlo. Aunque lo segundo es la mejor idea, lo primero puede ser más práctico para tus necesidades concretas de programación. Observa que el grosor de la línea de fill es '0'. Pero la línea de stroke puede tener un grosor mayor. ¡También es un valor de punto flotante! Una línea de 2.5 píxeles de ancho es perfectamente válida. | Estos resultados se deben no solo a un grosor de trazo 0 defectuoso, que causa un batido de color, sino también a que el 'color de relleno' se dibuja con un grosor adicional de 1.0 de diámetro, cuando no hay ningún área real que rellenar. Esto también lo considero un error. Consulta Límites de relleno de dibujo.
---|---

Límites de relleno de dibujo

Hay algunos otros puntos que deberías tener en cuenta sobre las distintas primitivas de dibujo. El grosor de trazo funciona bien para valores de punto flotante por encima de 1.0, pero parece fallar para valores menores de 1.0. Esto se debe al algoritmo de implementación utilizado y no simplemente a que sea incorrecto, ya que funciona bien con líneas de mayor grosor. Básicamente, si usas un grosor de trazo de cero, podrías esperar que no se añadiera ningún color de stroke. En su lugar obtienes una especie de patrón de batido en el que el color de stroke está a plena intensidad cuando la línea pasa por el 'centro' real del píxel. Lo que realmente debería pasar es que la cantidad de color añadida a un píxel reflejara el área de la línea que se está dibujando, y no la distancia del píxel a esa línea. Por eso, las líneas de grosor cero no deberían añadir color alguno a la imagen, mientras que las líneas de menos de 1.0 de grosor solo deberían añadir una cantidad menor de color. Consulta los ejemplos de Dibujo de líneas, con StrokeWidth y Stroke más arriba. El otro problema es que el color de relleno no se está aplicando hasta el borde de la forma (polígono) que se dibuja, sino ½ píxel más afuera. Esto incluye la situación en la que no se aplica ningún 'stroke' y el borde debería ser exacto. También incluye el dibujo de una 'línea', que en realidad tiene un grosor de relleno 'cero'. Básicamente, si dibujas una línea sin habilitar stroke, técnicamente no deberías ver línea alguna, ya que no tiene grosor de 'relleno'. En su lugar, las líneas se dibujan con un color de 'relleno' de como mínimo 1 píxel de ancho incluido. Esto es por razones históricas, y generalmente evita la confusión de los usuarios nuevos de IM. Por desgracia, NO es correcto para los usuarios avanzados. Lo que esto significa es que si dibujas dos polígonos usando solo color de relleno, que comparten un borde, ese borde se solapará en 1 píxel, ya que cada polígono es ½ píxel más grande a lo largo de todos sus bordes. En otras palabras, ¡los polígonos y otras formas no encajan, sino que se solapan! Por ejemplo, aquí intento usar draw para dividir una imagen en dos mitades (dibujando negro sobre blanco). Para hacerlo, dibujo dos polígonos que comparten un borde, exactamente sin solaparse. Las imágenes 'diminutas' resultantes se han ampliado para su visualización.

  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]

¡Las dos partes negras (que es lo que realmente se dibujó) se solapan entre sí! En otras palabras, aunque intentamos dibujar las dos áreas por separado usando polígonos dibujados, el área rellenada es ligeramente mayor que lo solicitado. También sumé (compuestas con Plus) las dos imágenes para que puedas ver realmente el solapamiento de las áreas negras dibujadas. Si los dos polígonos encajaran perfectamente, el dibujo 'sumado' sería de un color blanco sólido. La cantidad real de solapamiento equivale al ajuste predeterminado "[-strokewidth](https://imagemagick.org/command-line-options/#strokewidth) 1.0". Por eso normalmente se espera que esta área extra quede cubierta por un grosor de trazo normal. Sin embargo, puede causar algunos problemas reales. APARTE: Para una prueba completa de la unión, generarías áreas grises al 50% sobre un fondo negro y las sumarías. De esa forma puedes ver si las áreas no solo 'se solapan' (como se muestra arriba), sino también comprobar si 'quedan cortas' (dejando un hueco entre las áreas rellenadas) al sumar las áreas. La imagen resultante debería ser un color gris al 50% perfectamente uniforme, sin variaciones de color a lo largo de la unión. Una comprobación de transparencia implicaría usar un color gris al 50% transparente al 50% sobre un fondo totalmente transparente. Para ver un ejemplo de un corte y reensamblado perfectos, basados en una sola imagen de máscara, consulta los ejemplos de método de composición, Compose DstOut. CORRECCIÓN DE ERROR FUTURA: El área rellenada debería ser exacta, pero para compensar esto al dibujar formas, el 'color de stroke' predeterminado debería establecerse en el color de relleno (a menos que se haya establecido específicamente él mismo).


MVG - Magick Vector Graphics

Las primitivas mostradas arriba forman la base de todas las operaciones de "[-draw](https://imagemagick.org/command-line-options/#draw)" disponibles. En conjunto son el punto de partida de un lenguaje interno especial de ImageMagick, llamado lenguaje Magick Vector Graphics. Para más detalle de este lenguaje consulta Summary of MVG Primitives and Syntax en el sitio web de IM. Este lenguaje "MVG" se diseñó con el objetivo de permitir que ImageMagick maneje el lenguaje SVG (Scalable Vector Graphics), aún más complejo. Lo logra intentando convertir las imágenes dadas en formato SVG al formato interno MVG, más sencillo. Para más detalles consulta SVG handling más abajo. En consecuencia, lo que viste arriba es solo una pequeña parte de las capacidades del operador "[-draw](https://imagemagick.org/command-line-options/#draw)". No obstante, si quieres dibujar objetos complejos, te recomiendo que crees una imagen separada en formato SVG del objeto usando un editor SVG como "[Sodipodi](http://the-labs.com/Sodipodi/)". (Consulta Non-IM Vector Graphic Programs más abajo). A diferencia de SVG, MVG no tiene ninguna forma de 'contenedores' ni conjuntos de comandos de imagen. Todos ellos se eliminan durante el proceso de conversión para producir una secuencia simplificada de comandos de dibujo MVG. En su lugar usa un concepto de Graphic Contexts para guardar y restaurar los distintos ajustes de dibujo, que es lo que veremos ahora.

Ajustes de la línea de comandos frente a ajustes MVG

En primer lugar, casi todos los ajustes que defines mediante las opciones de la línea de comandos que usan las primitivas de dibujo tienen equivalentes directos en los comandos de dibujo MVG. La principal diferencia entre definirlos mediante una opción de la línea de comandos (como "-strokewidth") o usar un ajuste dentro de una cadena de dibujo MVG (por ejemplo 'stroke-width'), es que el ajuste MVG solo dura mientras dura la cadena del comando MVG.

**Resumen de los ajustes generales de dibujo**
  __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
Estos ajustes suelen entenderse bien, ya que se usan y demuestran con regularidad más arriba. Una fuente, su extensión, estilo y peso se usan para identificar una fuente de la lista de fuentes de ImageMagick. La mayoría de la gente, sin embargo, simplemente selecciona una fuente y un tamaño de punto concretos. Por ello rara vez se usan en IM.
Como puedes ver, los ajustes especiales para las primitivas de 'relleno de color' no tienen equivalentes directos en MVG. Es decir, el ajuste "-bordercolor" y el factor "-fuzz". Estos deben especificarse desde la línea de comandos antes de usar el operador "[-draw](https://imagemagick.org/command-line-options/#draw)". Algunos ajustes MVG probablemente serían más útiles como ajustes globales de la línea de comandos, como el ajuste 'decorate' para el dibujo de fuentes. ADVERTENCIA: "-gravity" no forma parte de la especificación SVG. Dentro de MVG solo se usa para la colocación de texto e imágenes, y la justificación. Actualmente no hay un ajuste de justificación separado de los efectos 'gravitacionales' por defecto. Sin embargo, como la justificación forma parte del manejo de texto de SVG, eso probablemente cambiará en algún momento en el futuro. Ahora bien, los ajustes globales de la línea de comandos (fuera de la cadena de dibujo MVG) se usan para inicializar los ajustes de cada operación "-draw" que aplicas, por lo que puedes definir un color "-fill" que luego puedes usar para dibujar un círculo de ese color.
---
  magick -size 100x60 xc:skyblue   -fill red \
          -draw "circle 50,30 40,10"          draw_circle_global.gif

[IM Output]
Puedes sustituir ese ajuste global localmente dentro del argumento MVG de "-draw"...


|

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

[IM Output]
Sin embargo, los ajustes definidos dentro de un único argumento MVG de "-draw" solo existen mientras dura esa operación "-draw". Es decir, los ajustes dentro de un "-draw" son locales solo a ese dibujo y no se trasladan a argumentos "-draw" posteriores y separados.


|

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

[IM Output]
Si planeas realizar muchas operaciones, puede ser mejor hacerlas todas en una única cadena MVG, en lugar de múltiples operaciones "-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]
Ajustes específicos de MVG Otros ajustes MVG que controlan la forma en que se dibujan las líneas y los objetos también es útil conocerlos incluso cuando se usan las operaciones primitivas. Estos incluyen...

   __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')

Recuerda que en el sitio web de IM se puede ver una lista completa de todos los ajustes y operadores de dibujo MVG en Summary of MVG Primitives and Syntax. Veamos los efectos de algunos de los ajustes más sencillos... |

  # 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]
El ajuste 'stroke-miterlimit' es bastante difícil de demostrar. Esta propiedad define el ángulo en el que una unión 'miter' se transforma en una unión 'bevel'. Básicamente, para ángulos muy agudos un mitre puede extenderse a gran distancia de la unión real de las dos líneas. Esto establece un límite máximo a esa agudeza, romando la esquina puntiaguda cuando se vuelve demasiado larga. Ten en cuenta, no obstante, que representa un valor trigonométrico de un ángulo de algún tipo, y no una longitud o distancia. El valor debe ser mayor que 1.0. Lo anterior muestra cómo, para el ángulo de unión que estoy mostrando, el mitre se transformará de pronto en un bisel en algún punto entre un valor de 6 a 7. Por ejemplo, un 'stroke-miterlimit' de 1.414 convierte un 'miter' en 'bevel' para cualquier ángulo menor de 90 grados. Un valor de 4.0 (el predeterminado) convierte la unión para ángulos menores de aproximadamente 29 grados. Mientras que un valor de 10.0 los convierte para un ángulo menor de aproximadamente 11.5 grados. Dibujo de rutas SVG La ruta SVG es la primitiva de dibujo básica de SVG. Se usa para dibujar líneas, formas, círculos, curvas, arcos y demás. La especificación completa de las rutas SVG se puede encontrar en el documento SVG Path Specification. Sin embargo, no es un documento fácil de leer, ya que está pensado realmente para programadores, no para usuarios, así que simplificaré y resumiré la especificación de rutas...

  • Las letras son comandos, mientras que todos los números (de punto flotante) son argumentos.
  • Las comas o los espacios pueden usarse como separadores de argumentos; de lo contrario, se ignoran por completo.
  • Los dos últimos argumentos (x,y) de cada componente de la ruta se convertirán en el punto final (o 'nudo') de ese componente de la ruta.
  • Las letras mayúsculas especifican las coordenadas absolutas del punto final.
    Las letras minúsculas son relativas al punto final del componente anterior.
    Por ejemplo: " M 1,2 l 3,4 l 2,-4 " es lo mismo que " M 1,2 L 4,6 L 6,2 ".
    Es decir, 3,4 se sumó a 1,2, para dibujar una línea hasta 4,6.
    Luego se sumó 2,-4 para dibujar una línea hasta la coordenada final de 6,2.
  • Los argumentos de cada elemento pueden repetirse sin volver a indicar la misma letra de ruta, añadiendo más grupos de argumentos numéricos. No obstante, para las curvas, recomiendo añadir de todos modos las letras de función para facilitar la lectura.
  • Los argumentos repetidos de "M" o "m" se tratan como "L" o "l" respectivamente.
    Por ejemplo: " M 1,2 3,4 5,6 " es lo mismo que " M 1,2 L 3,4 L 5,6 "
    Y : " m 1,2 3,4 2,-4 " es lo mismo que " m 1,2 l 3,4 l 2,-4 "
  • Para la bezier cúbica, todos los puntos (los de control y el nudo del punto final) se dan en relación con el punto final del componente de ruta anterior.

Observa cómo puedes especificar las cosas ya sea como coordenadas absolutas o coordenadas relativas. Así puedes definir un objeto en términos de coordenadas relativas y simplemente proporcionar una coordenada 'move' absoluta inicial para posicionar toda la ruta. Por otro lado, también puedes usar otros comandos de 'graphic-content' para mover todo un dibujo dentro de un 'viewbox' o 'translation' (ver más abajo). Así que en realidad no importa si usas coordenadas absolutas o relativas en las rutas SVG. Los movimientos, las líneas y los cierres de ruta son el punto de partida inicial para aprender sobre las rutas 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]
Ten en cuenta, no obstante, que 'Z' solo cierra el bucle. NO crea un objeto separado. Por tanto, dos rutas 'cerradas' siguen clasificándose como un único objeto dibujado, ya sea que se superpongan o estén completamente desconectadas. Aquí mostramos dos bucles cerrados pero superpuestos, dibujados en la misma dirección. Como solo se usa una única ruta, el objeto es un único objeto, y el ajuste 'fill-rule' controla cómo se ha de rellenar la región superpuesta. |

  # 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 los objetos se dibujaron en la misma dirección angular alrededor del centro, los dos bucles cerrados encerrarán un área que tiene un valor de ciclo de 2. Por ello, la regla 'evenodd' dejó esa área sin rellenar, mientras que la regla no-cero 'nonzero' la rellenó. Ten en cuenta, no obstante, que todas las rutas son visibles, ya que en realidad son el mismo objeto. La dirección en la que se dibujan las rutas es muy importante y, en general, todas las rutas deberían dibujarse exactamente en la misma dirección relativa al 'interior' del objeto. Por ejemplo, aquí dibujo el segundo objeto en dirección inversa al primero. Por ello, cuando los dos objetos se superponen, esa área queda rodeada 'cero' veces. Es decir, quedará sin rellenar sin importar qué 'fill-rule' se use, creando un 'agujero'. |

  # 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]
Esto significa que puedes generar 'agujeros' en un objeto invirtiendo la dirección, de modo que el 'interior' del objeto se mantenga del mismo lado de la dirección de recorrido. |

  # 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]
El resultado es el mismo independientemente del ajuste 'fill-rule', ya que el agujero es a la vez 'par' y 'cero', por lo que queda sin rellenar. Por supuesto, si usas un elemento 'path' completamente separado, generarás un objeto completamente separado. En cuyo caso, el 'fill-rule' no se aplica y los objetos simplemente se dibujan uno encima del otro, en el orden dado. |

  # 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"

Los arcos elípticos son la función de dibujo de círculos de las rutas SVG...
Los parámetros 'large' y 'sweep' son especialmente importantes, ya que se usan para determinar de cuál de las cuatro maneras vas a 'arquear' desde tu punto inicial hasta el punto final de ese componente de ruta. Los dos indicadores 'large' y 'sweep' definen cuál de los cuatro arcos de ese radio conectará los dos puntos. |

  #  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]
el segundo indicador 'sweep' simplemente determina de qué lado de la dirección de la línea recta de la ruta debe dibujarse el arco. El indicador 'large' se usa para seleccionar el camino más largo, rodeando el centro de la elipse. Es decir, el ángulo definido del arco será mayor de 180 grados. Si se desactiva, obtienes el 'arco' más pequeño, que no contiene el centro de la elipse, arqueándose sobre un ángulo menor de 180 grados. Cerrar un arco con una 'Z' simplemente dibuja un segmento de línea recta final. Para crear una elipse o círculo completos necesitarás al menos dos segmentos de 'arco', yendo del primer al segundo punto, y luego de vuelta al primer punto. Ambos arcos deberían tener el mismo ajuste de 'sweep', de modo que el arco quede en lados diferentes, con la diferente dirección de recorrido. Uno de los arcos debería tener activado el ajuste 'large'. |

  # 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]
Ten en cuenta que si la línea es demasiado larga para caber en el tamaño de elipse dado con el ángulo indicado, el tamaño de la elipse se agrandará para ajustarse a la línea, con la elipse centrada en la línea. Esto significa que, usando números pequeños para los radios de los ejes, puedes simplemente especificar una proporción de longitudes de eje, y garantizar que el camino de línea directa pase por el punto central de la elipse. Es decir, la ruta forma un diámetro elíptico de un lado de la elipse al otro. Este no es necesariamente el eje mayor o menor de la elipse, solo un 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]
Por supuesto, usar longitudes de "1,1" da como resultado un semicírculo perfecto, yendo de un punto al siguiente. El ángulo elíptico en este caso no supondrá ninguna diferencia. |

  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 un círculo completo centrado entre los dos puntos usa... |

  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]
La definición SVG de 'arc' también declara que si cualquiera de los dos radios es cero, entonces debe dibujarse una línea recta. Así, cualquier arco con radios "0,0" es simplemente un arco de línea recta sencillo... |

  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]
Si especificas radios muy grandes para el arco, y no especificas un 'large sweep' para el camino de retorno, puedes crear una forma de lente de ese radio entre los dos puntos. |

  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]
Este tipo de arco es una característica clave. Permite dar a lo que de otro modo sería una línea recta una curva pequeña pero distinta con mucha facilidad. Por ejemplo, en lugar de un triángulo simple 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]
Puedes sustituir cada línea por un arco usando un radio grande para darles solo una ligera curva. |

  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]
Los puntos finales de las líneas no tienen cambios; todo lo que ha sucedido es que cada 'L' se sustituyó por un segmento de arco. El tamaño del arco, sin embargo, debería ser proporcional a la longitud de la línea. Como no lo hice así, la línea diagonal más larga tiene una curva mucho más fuerte y profunda que las otras dos. Recuerda que al redimensionar o escalar el objeto que se dibuja, también deberías escalar el radio en la misma proporción que la longitud de esa línea para que la curva se redimensione en consecuencia, de modo que el arco también escale correctamente. Ten en cuenta que el indicador 'sweep' controla si la curva se abulta hacia fuera o hacia dentro, según la dirección en que se dibuja cada segmento de ruta (ver más arriba). |

  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]
El triángulo de aspecto 'estático' de bordes rectos ahora se parece un poco a una vela hinchándose con el viento. Si realmente quieres que la línea sea perfectamente recta sin convertirla de nuevo en verdaderos segmentos de línea, puedes desactivar la curva usando un radio de arco de cero. Los arcos, por tanto, no solo son buenos para generar elipses y círculos, sino que son útiles para dibujar segmentos de línea rectos y ligeramente curvos. Es un camino de dibujo punto a punto general muy versátil. Una alternativa sencilla a usar arcos elípticos para generar segmentos de línea curvos separados es usar Quadratic Bezier Segments en su lugar. La principal diferencia es que se usa un único punto de control, en lugar de un radio circular para definir el arco. Esto también te permite sesgar el arco hacia uno de los extremos del segmento de línea, pero a costa de hacer más difícil generar un arco simétrico. Por supuesto, puedes 'mezclar y combinar' usando ambos. Ejemplo de gráfico circular Para terminar con el uso de arcos, demos un ejemplo de cómo usarlos para generar cuñas circulares. Por supuesto, puede que necesites usar algo de matemática trigonométrica externa (¿qué tal andabas de matemáticas en el instituto?) para determinar los puntos finales de la ruta que se requieren. |

  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]
Ten en cuenta que todos los arcos se dibujan a la izquierda del 'camino de línea', y se marcan en consecuencia (usando el indicador 'sweep'). Pero si el arco abarca un ángulo mayor de 180 grados, hay que activar el indicador 'large'. Mira el último componente 'gold' en el ejemplo anterior. Ten en cuenta también que deberías dibujar cada sección por completo, aunque esto signifique que tengas que dibujar las líneas limítrofes dos veces. Si no lo haces, probablemente o bien no rellenes por completo esa sección con color, o bien el color de relleno se superpondrá al contorno de una sección dibujada previamente. La única manera de evitar la duplicación de múltiples líneas es dibujar todas las áreas rellenas y luego repetir para dibujar los contornos. Es decir, tendrás que dibujarlo todo dos veces, asegurándote de que las cosas encajen correctamente. Por tanto, la duplicación de los contornos es probablemente la solución más sencilla. Las curvas de Bezier cúbicas pueden definirse usando una función 'C' que define dos puntos de control y el punto final. Para continuar curvas de Bezier cúbicas que usan una imagen reflejada del último punto de control (para una curva continua), puedes usar una función 'S'. Aquí tienes un ejemplo. Debido a la complejidad de esta función, preparé de antemano un lienzo que muestra la ubicación de los puntos de control, así como el 'reflejo supuesto' del último punto de control. |

  # 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]
La línea que conecta el punto de control con el punto final de la ruta de ese segmento (línea de control) básicamente define la dirección de la curva al pasar por ese punto de la ruta. Una línea de control larga producirá una curva más suave en ese punto, mientras que una línea corta genera una curva más pronunciada en ese punto. Si el punto de control coincide con el punto de la curva (la línea de control tiene longitud cero), la curva tendrá una discontinuidad abrupta en ese punto, como si solo se hubieran usado segmentos de línea recta. Como ejemplo más práctico, el siguiente fragmento de código está extraído del IM Examples Logo Generator Script que crea el área curva de salpicadura del IM Examples Logo. La parte complicada del ejemplo es que convierto la cadena de ruta de Bezier cúbica que uso en otra ruta que muestra las líneas de control empleadas para generar la curva de Bezier. Esto me permite ver los ángulos y las longitudes de las líneas de control de la curva, lo que hace mucho más fácil ajustar los resultados. Solo es necesario ajustar un conjunto de puntos para mostrar tanto la curva como los controles, reduciendo los errores al 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]
Si miras de cerca la imagen, verás que el inicio y el final de la curva tienen dos líneas de control orientadas en direcciones opuestas. Para una ruta continua cerrada, tanto la línea de control de inicio como la de final deberían estar en el mismo ángulo (solo que en dirección reflejada) y, por supuesto, con la misma longitud. Esto es importante recordarlo, ya que es fácil equivocarse. Todos los demás puntos a lo largo de la curva solo tienen un único punto/línea de control que apunta en la dirección opuesta a la dirección en que se dibuja la curva. Cuanto más largo sea ese segmento de línea, menos 'pronunciada' es la curva en ese punto de control, produciendo una longitud cero un 'pico'. La función 'S' genera internamente el punto/línea de control reflejado para el siguiente segmento a partir de los datos del segmento anterior, de modo que produzca una continuación suave de la curva. Para más ejemplos de esta función de ruta consulta SVG: Cubic Bezier Curve Commands. Generar manualmente una curva de Bezier es relativamente sencillo sin necesidad de herramientas GUI sofisticadas.

  • Primero define todos los puntos de coordenadas por los que quieres que pase la curva, repitiendo la coordenada inicial al final de la lista.
  • Ahora expande esta lista duplicando todos los puntos de coordenadas x,y en pares y añade una función 'S' (Smooth Cubic) antes de cada par. El primer número de cada par es el punto de control conectado al segundo número, que representa el punto sobre la curva. El primer par de puntos, sin embargo, tiene esto invertido: el primer punto es el inicio de la curva y el segundo representa el primer y único punto de control invertido.
  • Cambia la letra de función del primer par de coordenadas de una 'S' a una 'M', luego añade una 'C' entre ese par de coordenadas. Finalmente, elimina la 'S' del segundo par de coordenadas, para completar la función Cúbica ('C') inicial.
  • Completa la ruta añadiendo una 'Z' final para cerrar la curva.
    Mira la secuencia de ejemplo anterior para ver cómo debería quedar.
  • En este punto puedes probar a dibujar tu ruta. La ruta solo constará de segmentos de línea recta, ya que todas las líneas de control tendrán longitud cero.
  • Lo único que tienes que hacer ahora es ajustar lenta y cuidadosamente la posición del segmento de línea de control (la primera coordenada de cada par 'S') para conseguir la curva final que deseas. No hagas las líneas de control demasiado largas, ni en la dirección equivocada, o conseguirás una curva de aspecto muy raro.
  • Para ayudar a ver tus cambios y encontrar errores, usa el comando "sed" de conversión anterior para dibujar las líneas de control entre los puntos de control de la ruta y el punto de control de la curva. Ten en cuenta, no obstante, que las líneas de control de longitud cero no son visibles, pero como la línea producirá un pico agudo, la posición debería ser obvia.
  • Por último, asegúrate de que el primer punto/línea de control tras una 'C' sea exactamente opuesto al del control/línea de cierre, en esa misma posición.

La generación interactiva de curvas también es posible usando algunos editores de gráficos vectoriales. Por ejemplo, Luis Guerra informa de que las curvas de Bezier generadas con "Inkscape" pueden hacerse accesibles usando la función "Edit -> XML Editor" y seleccionando luego la ruta o forma de la que quieres los puntos de control.

¿Conoces otras maneras de extraer una curva de Bezier (dando uno o dos puntos de control por cada punto de la curva) usando una herramienta GUI? ¿O quizá alguna otra técnica para generar tales curvas? ¡Escríbeme! Me encantaría saberlo. Se te dará crédito por la técnica, como a otros.

La Bezier cuadrática es una simplificación de la función de Bezier cúbica, en la que los dos puntos de control se fusionan en un único punto de control. De nuevo, puedes iniciar la curva con una función 'Q', y luego usar una función 'T' para continuar la curva, reflejando el último punto de control. |

  #  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]
Debo advertirte, no obstante, que la función de continuación 'T' realmente solo funciona para rutas que conectan puntos igualmente espaciados. No recomiendo su uso. La ventaja de las curvas cuadráticas es como sustituto de los Elliptical Arcs, ya que usan una posición real, en lugar de un radio para el arco. También puede sesgar el arco a favor de un extremo sobre otro, algo que no es práctico al usar Elliptical Arcs. |

  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]
En este caso, los arcos no son tan uniformes, y obtienes algo parecido a una aleta de tiburón invertida, en lugar de una vela. Recuerda que los arcos cuadráticos son parábolas, mientras que los arcos elípticos generan básicamente segmentos circulares. Esta puede ser la clave para determinar qué tipo de segmento de línea arqueada deberías usar. Para más ejemplos de esta función de ruta consulta SVG: Quadratic Bezier Curve Commands.

Deformación de la superficie de dibujo

Además de estas capacidades, la superficie de dibujo sobre la que se dibujan los objetos puede deformarse de varias maneras para permitirte hacer cosas asombrosas. Primero puedes aplicar algunas modificaciones generales de la superficie de dibujo como... 'translate', 'rotate', 'scale', 'skewX', 'skewY' y 'affine'. Por ejemplo, dado un 'path' de líneas podemos "translate" (trasladar) el origen, o punto 0,0, de la superficie de dibujo a otra ubicación. |

  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]
Observa que el '0,0', u origen del área de dibujo, ahora está centrado en la imagen, aunque el eje Y sigue siendo negativo en la parte superior y positivo en la parte inferior de la imagen. La operación "rotate" rotará la superficie de dibujo de modo que cualquier cosa dibujada después sobre esa superficie se dibujará rotada. Por supuesto, rotará alrededor del origen trasladado, así que es buena idea usar ambos operadores de transformación 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" ampliará y reducirá la superficie de dibujo alrededor del origen. |

  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]
Un uso común de "scale" es invertir el eje Y de modo que un valor Y positivo apunte hacia arriba. Por supuesto, el origen también debería desplazarse, ya sea al centro o a la esquina inferior izquierda, para mantener las cosas en orden. |

  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]
Y por último, "skewX" y "skewY" cizallan la imagen en las direcciones X e Y. Por ejemplo, aquí usamos "skewX" para dar al eje Y vertical de la imagen una inclinación. |

  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]
Estos operadores tienen equivalentes fuera de la cadena MVG "[-draw](https://imagemagick.org/command-line-options/#draw)", para uso general. Sin embargo, estas versiones de la línea de comandos son operadores y se aplican de inmediato a imágenes ya existentes en memoria, en lugar de a una superficie de dibujo sobre la que aún no se han dibujado objetos vectoriales. Para más detalles consulta Distorting Images.

Deformación afín de la superficie de dibujo

Las cinco transformaciones de lienzo anteriores pueden combinarse en un operador general de matriz afín, ya sea usando la primitiva MVG 'affine' o definiendo la transformación afín con "[-affine](https://imagemagick.org/command-line-options/#affine)" antes de llamar a "[-draw](https://imagemagick.org/command-line-options/#draw)". Las transformaciones afines usan un conjunto de 'coeficientes de matriz' que definen cómo las coordenadas que indicas deben modificarse para convertirse en las coordenadas reales de dibujo. Para más detalles sobre cómo funcionan realmente estos 'coeficientes', consulta Affine Matrix Transforms. Por ejemplo... Para simplemente establecer un origen central respecto al cual se dibujan los objetos... |

  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]
Voltear la imagen... |

  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]
Rotar 30 grados alrededor del origen... |

  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 transformaciones afines más complejas puedes hacer uso de los Affine Helper Scripts que se crearon con ese propósito. Estos scripts convierten cosas como un ángulo de rotación y un punto central en coordenadas afines que puedes usar directamente en tu ajuste "[-draw](https://imagemagick.org/command-line-options/#draw) affine" o "[-affine](https://imagemagick.org/command-line-options/#affine)".

Push/Pop de contexto

Algunas primitivas MVG dependen en realidad del uso de estas transformaciones para emplearse correctamente. Por ejemplo, la Ellipse Primitive solo puede especificarse directamente con ejes alineados ortogonalmente. |

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

[IM Output]
Sin embargo, usando Drawing Transforms podemos añadir fácilmente un 'ángulo de rotación' a la 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]
Observa que el 'centro' de la elipse (el punto de rotación) se trasladó primero, antes de aplicar una rotación. La 'ellipse' se dibujó luego en esa posición trasladada en '0,0'. Lo anterior también muestra dos nuevas primitivas de dibujo MVG: 'push graphic-context' y 'pop graphic-context'. Estas no son estrictamente necesarias en el ejemplo anterior, pero se recomiendan al realizar transformaciones de dibujo importantes. Lo que hacen las primitivas 'push' y 'pop' es guardar el estado actual de dibujo o 'graphic-context', y luego restaurarlo de nuevo después. Cualquier ajuste de dibujo que se cambie entre las dos primitivas se olvidará. Esto incluye cualquier deformación de la superficie, como 'translate' y 'rotate', así como los ajustes de color 'fill' y 'stroke', o cualquier otra cosa que modificara el 'estado' de dibujo. Estas primitivas facilitan dibujar objetos muy complejos con muchas transformaciones, y luego restaurar las cosas a una situación más 'normal' para operaciones de dibujo posteriores. Puedes ver una demostración más práctica de esto en Drawing Arrows más abajo.

Push/Pop de objetos especiales

En construcción

More settings used specifically for MVG handling of SVG format.

    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

For examples see _Florent Monnier's_ development site...
  <http://www.linux-nantes.fr.eu.org/~fmonnier/OCaml/MVG/>

Lectura de archivos MVG Como puedes ver en los ejemplos anteriores, los argumentos MVG de "-draw" pueden volverse muy largos. De hecho, la conversión de SVG a MVG puede producir argumentos de dibujo MVG extremadamente largos (ver más abajo). Sin embargo, la interfaz general de la línea de comandos de IM te permite leer cualquier argumento de cadena desde un archivo usando un argumento "@filename" en su lugar. Esto es práctico, ya que significa que puedes leer tus comandos de dibujo MVG, muy largos y complejos, desde un archivo separado. Por ejemplo, si pongo operaciones MVG en un archivo llamado "draw_circles.mvg", puedo dibujarlo así... |

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

[IM Output] | [IM Output]
No solo eso, sino que ImageMagick también entiende la lectura directa del formato de archivo de imagen "MVG:", lo que te permite dibujar tales comandos de forma más directa. Sin embargo, a menos que el archivo MVG defina un lienzo, puede que necesites especificar el lienzo inicial ("-size" y "-background") para que se dibuje sobre él. |

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

[IM Output] | [IM Output]
Puedes trasladar los ajustes del lienzo inicial al propio archivo de imagen MVG añadiendo un 'viewbox' al archivo MVG, con los dibujos de relleno de color de fondo apropiados. Eso completa el archivo de imagen MVG como una definición de imagen completa. |

  magick   mvg_circles2.mvg    mvg_image.gif

[IM Output] | [IM Output]
| _Actualmente solo hay una manera de leer un archivo MVG externo desde dentro de una cadena de argumentos MVG, y es usando una primitiva de dibujo 'image'. Lamentablemente, esto convierte el MVG incluido en una imagen ráster ANTES de superponer esa imagen sobre la superficie de dibujo.

En otras palabras, actualmente no hay ninguna función de 'include' en MVG._ :-(
---|---

En construcción

You can generate the low level draw operations of IM, using the "[+render](https://imagemagick.org/command-line-options/#render)" to record them.

When you then give a "[-render](https://imagemagick.org/command-line-options/#render)" setting/operator, IM will immediately draw those saved
operations.

Strangely just outputting to a "MVG" file also seems to do this...
     magick ...   -draw '....'  draw_commands.mvg

NOTE: if you draw a curve while outputting a MVG format file, the file lists
the curve as a series of short line segments, rather than the original curve.

You can of course go the whole way and use the more universal SVG format.
See "[SVG format handling](#svg)" below.

Composición alfa MVG

En construcción

I have not seen any use of Alpha composition (other than 'painters' algorithm
which is basically a 'over' alpha composition) for the drawing of objects.

However that is not to say it can not be done.

If you like to compose your rectangle, ellipse, circle, or whatever with a
different alpha composition (such as 'DstOver' which is an Under-like
composition),  then draw your figure on a blank transparent canvas the same
size as the original and compose it onto your image.

However as SVG allows you to use alpha composition to draw text and other
items onto images, I would imagine that it will be a future addition.

Stay Tuned!

Dibujar símbolos

A veces se tiene un conjunto de puntos en una imagen donde se quieren dibujar símbolos de referencia, como cruces, círculos, etc... Por desgracia, en este momento IM no tiene comandos para dibujar esos símbolos con facilidad, pero con un poco de trabajo extra se pueden dibujar.

Técnicas para dibujar símbolos

El truco para dibujar varios símbolos en una lista determinada de ubicaciones consiste en generar los comandos de dibujo MVG mediante un script de shell, o cualquier API que se esté usando, de modo que transforme un conjunto de puntos dado en el conjunto de comandos de dibujo adecuado. Por ejemplo, aquí transformo una línea de puntos en un 'plus' en cada uno de esos puntos... |

  # 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]
El ejemplo anterior usa "tr" para separar cada punto (dos números) en uno por línea, y luego usa "awk" para hacer todos los cálculos matemáticos necesarios para dibujar el 'plus' sobre el punto dado. Se puede usar cualquier herramienta que se prefiera para esto, ya que simplemente estoy aplicando una forma de expansión de macros de texto sobre la lista de puntos de entrada. Casi cualquier lenguaje de programación puede hacerlo. Para el caso del script de shell anterior, simplemente encontré que "awk" era el medio más simple y rápido. De hecho, incluso se puede usar el propio ImageMagick para hacer esa expansión de 'macros' mediante la opción de formato "magick"... Por ejemplo, aquí lo uso para calcular un punto en la circunferencia del círculo, para este 'símbolo de punto'. |

  # 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]
Ahora bien, las cadenas de dibujo que se generan pueden volverse bastante largas y empezar a causar problemas con la longitud del comando final. Por eso, en lugar de convertir los puntos en cadenas largas que luego pasamos a IM en la línea de comandos, se pueden canalizar (pipe) los comandos de dibujo a IM como un archivo. Esta vez también uso un método de dibujo de Path SVG en lugar de los métodos de dibujo de Primitivas de dibujo. Además, los símbolos que genero son triángulos alrededor de cada punto. |

  # 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]
El Path SVG en realidad facilita esto, al permitir movimientos relativos de píxeles, lo que permite diseñar el símbolo de modo que solo requiera un único movimiento absoluto inicial 'M' antes de dar la secuencia de 'movimientos' y 'líneas' para dibujar el símbolo. Gracias a esto, no se necesita ningún cálculo en coma flotante, ya que el dibujo de IM hará la aritmética de posicionamiento necesaria. | El elemento de movimiento relativoPath SVG 'm' está roto antes de IM v6.4.3-5. Si tu IM es más antiguo que esto, los ejemplos anteriores (y el siguiente) podrían no dibujar nada. Puedes corregir esto en versiones antiguas reemplazando los movimientos relativos 'm' anteriores por una secuencia apropiada de líneas relativas, 'l'.
---|---
Ahora puedes llevar esto un paso más allá, alimentando un archivo MVG completamente formado, junto con la especificación del lienzo de dibujo, directamente a IM como una canalización de comandos de dibujo. Esta vez hagamos una 'cruz' similar al primer ejemplo de 'plus' anterior, que necesitaba muchos 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]
Esto usa la técnica especial de programación de shell donde todo lo que se hace 'echo' dentro de los paréntesis del shell se alimentará al comando final "magick" como un archivo MVG. El primer 'echo' define y rellena el lienzo de dibujo de la imagen, mientras que el bucle 'while' convierte cada 'punto' dado en un círculo del radio indicado. La ventaja de este método es que no se obtiene ninguna limitación de longitud de cadena que sí se podría obtener con los otros dos métodos. Otros símbolos que se podrían generar incluyen cajas, rombos, barras de error, etc... Consulta también 'Dibujar círculos' más abajo, para otros métodos de círculo, incluido un dibujo de círculo con 'path' relativo sin cálculos.

Alternativas para dibujar símbolos

Hay otras formas de añadir símbolos a las imágenes, además de dibujarlos directamente.

Fuentes de símbolos

Puedes extraer símbolos de una Fuente de símbolos y guardarlos como un pequeño mapa de bits. También puedes usar imágenes pequeñas predefinidas pero coloridas para esto. Sin embargo, esto puede tener problemas para posicionar exactamente la fuente respecto a un píxel específico. Es decir, no es una técnica muy precisa. Pero puedes componer cualquier imagen en cualquier ubicación de píxel. Por ejemplo, estos símbolos fueron extraídos de varias fuentes, para un uso específico en estas páginas de ejemplo.

En la sección sobre Superposición de imágenes se dan ejemplos de composición de imágenes sobre un fondo más grande. Sin embargo, un método con bucles puede ser más útil, como el que se da en Posicionamiento programado de imágenes en capas. FUTURO: ejemplo de superposición de imágenes usando coordenadas

Morfología

Otra alternativa es usar Morfología, para 'Dilatar' un solo píxel, usando núcleos de 'forma' especiales como '[Disk](morphology.html#disk)', '[Ring](morphology.html#ring)' y '[Plus](morphology.html#plus)', o incluso tu propio Núcleo definido por el usuario. Por ejemplo...

  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]

El resultado puede luego convertirse directamente en una superposición coloreada usando el Operador de forma alfa. La gran ventaja de esto es que en realidad no necesitas conocer las ubicaciones individuales de cada símbolo. Ni cuántos símbolos hay. Pero eso también puede ser una desventaja. Una desventaja importante es que las posiciones solo se dan en ubicaciones enteras. No puedes 'dibujar' usando un posicionamiento 'subpíxel' en coma flotante.

Convolución

Una técnica casi idéntica es usar 'Convolve', con núcleos especialmente diseñados, lo que permite establecer varios tonos de gris, en lugar de un simple resultado de encendido/apagado, como antes. Al usar un Núcleo definido por el usuario distinto para cada canal de la imagen (rojo, verde, azul y alfa), incluso es posible crear un símbolo multicolor a partir de cada coordenada de píxel. [IM Output] Para esto uso un script especial "[image2kernel](../static/img/scripts/image2kernel)" que escribí para transformar una imagen coloreada (ver a la derecha) en núcleos de convolución en coma flotante separados para cada uno de los canales.

  image2kernel -q marker.png marker.dat

Esto genera cuatro archivos, como "[marker_R.dat](../static/img/draw/marker_R.dat)", uno para cada canal de la diminuta imagen de entrada, que son representaciones definidas por el usuario de la imagen (con el origen centrado en la imagen). Ahora, usando esos archivos de datos de núcleo, podemos Convolucionar esos puntos individuales en nuestra colorida imagen de marcador sobre un fondo 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 de IM v6.7.6-9 elOperador Combine requiere que el canal de transparencia de la imagen se dé como valores de 'opacidad' en lugar de valores alfa; por ello, el canal alfa resultante que se crea debe negarse. EG: |

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

Solo deben usarse imágenes pequeñas, con los puntos de píxel suficientemente separados para que los símbolos no se solapen. Esto se debe a que Convolve suma las áreas que se solapan, haciéndolas más brillantes de lo esperado. Lo anterior se ha convertido en un script de shell de UNIX "[convolve_image](../static/img/scripts/convolve_image)", para facilitar su uso.

  convolve_image  points_pixels.gif marker.png   point_markers.png

Esta técnica surgió de una discusión en los foros de IM A Fun Experience with IM. El usuario quería colocar diminutas personas sobre una imagen de fondo de un campo de fútbol de modo que sus posiciones deletrearan el nombre de una persona en la imagen.

En capas

Una técnica distinta, como las Capas de imágenes, posicionadas usando una lista de los píxeles que extrajiste de la imagen de origen, puede ser el mejor enfoque. Puedes superponer primero las imágenes de símbolos más lejanas, antes de las imágenes en primer plano, y puedes elegir de forma programada, o aleatorizar, qué símbolos reemplazan a qué punto. Para ver un ejemplo de esto, consulta Chinchetas en un mapa.

Dibujar círculos

Las opciones de dibujo te proporcionan varias formas de hacer algo muy básico... Dibujar círculos. Puedes, por ejemplo, dibujar un círculo que pase por cualquier punto de su circunferencia. Por lo tanto, necesitarás calcular un punto central y un segundo punto que esté a una distancia del radio (por ejemplo, 25 píxeles) del primer punto. |

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

[IM Output]
Fred Weinhaus señaló que, usando una traslación, puedes eliminar la necesidad de calcular la coordenada del borde del círculo, y simplemente dar el radio directamente. |

  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]
Sin embargo, al dibujar varios círculos lo anterior necesitará operaciones "[-draw](https://imagemagick.org/command-line-options/#draw)" separadas para cada círculo, o bien usar Apilamiento de contexto. Usando una elipse puedes especificar el radio directamente como longitudes de los ejes. |

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

[IM Output]
También puedes generar un círculo dibujando una línea muy muy corta con 'stroke-linecap round'. El grosor del trazo establece entonces el diámetro del círculo. NOTA: la línea debe tener algo de longitud (por pequeña que sea) o el dibujo no dibujará 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, por desgracia, no puede delinear el círculo generado, pero para cubrir áreas grandes, los trazos anchos pueden ser útiles. Consulta Algunos ejemplos simples más abajo. Este método hace uso del método de dibujo de Path SVG para que el círculo pueda dibujarse sin necesidad de calcular coordenadas adicionales. |

  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]
Solo se necesita el movimiento absoluto inicial 'M' para definir el centro; el '25' y el '50' en el resto de los componentes del path que siguen definen el radio y el diámetro del círculo respecto a este centro. | El elemento de movimiento relativoPath SVG 'm' está roto antes de IM v6.4.3-5. Si tu IM es más antiguo que esto, el círculo podría aparecer solo como un único píxel. Puedes corregir esto en versiones antiguas reemplazando el 'm' anterior por una 'l'.
---|---
Fred Weinhaus añadió el siguiente método de círculo con curvas bézier. Es muy parecido a un círculo real (aunque no exacto), y requiere un cálculo en coma flotante. |

  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]
Si dibujar un círculo exacto no es importante, puedes usar este path SVG de 4 segmentos bézier, que solo usa los límites X e Y del círculo para su 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]
Si prefieres uno que se dibuje completamente de forma relativa a un punto central de inicio, puedes usar esta técnica. Solo se usa el valor del radio, lo que hace que sea sencillo de generar, usando únicamente funciones de cadena en una 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]
¿Se te ocurren otras formas de dibujar círculos?

Dibujar flechas -- posicionar, rotar y escalar símbolos

Usando las técnicas anteriores puedes crear símbolos especiales, como una punta de flecha, que puedes posicionar de modo que su punta quede justo en el extremo de una línea, y dibujarla encima. Si dibujas la flecha después de la línea (la situación típica), entonces la flecha se dibujará sobre la línea. Sin embargo, existen tres tipos de flechas que se pueden definir, y cada tipo se define de forma diferente según el uso que se le dé.

  • Medición, donde simplemente quieres marcar los extremos de una línea con una punta de flecha para indicar los límites de una medida en algún diagrama de ingeniería. Muy sencillo.
  • Vectores, que muestran la dirección e intensidad de algún valor.
    Por ejemplo, en un gráfico meteorológico de viento. Se requiere una cola y el punto 0,0 es el extremo de la cola. A menudo se crea una gran cuadrícula de tales vectores.
  • Indicadores, que señalan algún detalle.
    Para esto, el punto 0,0 probablemente debería ser o bien la punta, o cierta distancia delante de la propia flecha.

Flechas de medición

Simplemente añadir una punta de flecha al extremo de una línea es relativamente fácil de hacer. Básicamente creas un símbolo de 'punta de flecha' y lo dibujas en la posición correcta. Por ejemplo... |

  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]
Observa que dibujé el símbolo de modo que su punto de inicio sea el extremo mismo de la línea. De esta forma puede dibujarse hacia atrás sobre la línea previamente dibujada, formando un símbolo muy bonito y limpio. Sin embargo, las flechas tienen una dirección asociada. Podrías crear un enorme número de definiciones de flecha en muchos ángulos distintos, y muchos programas hacen esto. Pero como la flecha es un vector, ¿por qué no rotar la flecha como un vector? El comando de dibujo de IM tiene rotaciones de dibujo (Deformación del lienzo) integradas, así que usémoslas. Esto también tiene la ventaja de sacar la posición de la definición 'path' de la punta de flecha, lo que te permite especificar todo el path como una '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]
Si quieres cambiar el tamaño de la flecha, añade una opción de dibujo "scale" después del 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]
Observa cómo se amplió dejando la 'punta' de la flecha donde la especificas. Este es un aspecto muy importante del manejo de flechas, ya que solo importa el punto final y el ángulo de la línea a la que estás añadiendo la flecha. El orden de las 'transformaciones' es importante, y en realidad es inverso al orden en que se ejecutan realmente. Es decir, la escala se aplica primero a las coordenadas, luego la rotación, y después la traslación. Si las transformaciones de coordenadas no se hicieran en ese orden, terminaríamos escalando también la ubicación final de la flecha, y no quedaría donde esperamos. Además, como la escala tiene dos números, y el símbolo original de la punta de flecha se diseñó horizontalmente (ángulo cero), puedes escalar por separado el ancho de la flecha respecto a su altura. Observa también cómo el grosor del trazo también se escaló con el tamaño de la punta de flecha, manteniendo las cosas coherentes. |

  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]
Ahora bien, como estás deformando el lienzo para dibujar flechas individuales, quizá junto con muchas otras operaciones de dibujo, podrías querer hacerlas todas en una única operación "[-draw](https://imagemagick.org/command-line-options/#draw)". Digamos, dibujar la línea y luego añadir flechas en AMBOS extremos, requiriendo diferentes conjuntos de colores, posiciones, rotaciones, e incluso quizá distintas escalas. Eso significa que necesitamos limitar el alcance de la deformación del lienzo al dibujo de cada punta de flecha individual. Si no limitas el alcance, podrías empezar a afectar a otras operaciones de dibujo posteriores y nunca estar del todo seguro de lo que estás generando. Para limitar el alcance de la deformación (y de todos los demás atributos de dibujo) envuelves la sección implicada en un "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]
El 'push' esencialmente guarda todos los atributos de dibujo actuales para uso futuro, mientras que el 'pop' restaura esos atributos reemplazando cualquier configuración (colores, deformaciones, posiciones, etc.) con la configuración guardada previamente. Esto significa que, después de hacer 'pop', la 'deformación del lienzo' se cancela, y el dibujo vuelve al estado en que estaba antes de que se modificaran las cosas. La técnica anterior es solo una forma de generar flechas, una buena cuando se dibujan flechas como parte de la medición de distancias, como en los dibujos técnicos.

Flechas de vector

Los vectores, como se mencionó, muestran tanto la dirección como la intensidad de algún valor. Eso significa que la longitud de la flecha es variable, y la punta de flecha podría estar en casi cualquier posición alejada del punto de inicio del vector. Ahora bien, podrías hacer cálculos matemáticos pesados para calcular la posición en que debería colocarse la punta de flecha dada la longitud y el ángulo del vector, pero hay una forma mucho mejor, que deja que ImageMagick haga esos cálculos por ti. La solución consiste en dibujar la longitud del vector como una línea horizontal de la longitud correcta en el Espacio de lienzo deformado. Una vez dibujada esa línea, simplemente trasladas de nuevo el espacio de dibujo hasta el extremo de la línea mientras el lienzo permanece 'deformado'. Ahora estás posicionado correctamente, con la rotación adecuada para dibujar la 'punta de flecha' del vector de forma normal. Por ejemplo, aquí genero un vector de 70 píxeles de largo a un ángulo de -35 grados. |

  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]

Flechas indicadoras

En el ejemplo anterior también mostré una flecha indicadora que apunta al punto de inicio de la flecha de vector previa. Sin embargo, en lugar de dibujar la flecha como hice antes, la creé como un símbolo de flecha invertida, que comienza a 10 píxeles de distancia del origen (o punto de inicio). Es decir, un símbolo se sitúa en la posición que quiero indicar, así que en realidad no quiero la flecha justo encima de esa posición, sino un poco alejada de ella. Ahora bien, aunque los indicadores son más simples de manejar que los vectores, ya que normalmente no necesitan una longitud variable, lo habitual es querer añadir texto en el extremo lejano del indicador para especificar qué se está indicando. Como antes, puede ser difícil calcular esa posición, así que ¿para qué molestarse? La solución para posicionar el texto es también la misma que para los vectores. Mantén el espacio deformado original usado para dibujar la flecha indicadora, y traslada el origen al extremo de la cola de esa flecha (40 píxeles horizontalmente en el espacio deformado). Ahora que hemos reposicionado las cosas, podemos deshacer la rotación de la deformación alrededor de esa nueva posición, de modo que puedas dibujar el texto de forma normal (con un ligero desplazamiento). Por desgracia, aunque la justificación de texto predeterminada de 'izquierda' funciona en el ejemplo anterior, actualmente no puedes especificar una justificación de texto en MVG como un ajuste separado de la gravedad. Si esto es un problema, pon una solicitud en el foro de bugs de IM, y con suerte la justificación de texto (como algo separado del posicionamiento por gravedad) se hará realidad, especialmente porque en realidad forma parte de la especificación SVG.


Dibujar objetos

Trazos anchos de color

No tienes que encerrar por completo un área de relleno con un path o contorno para crear varias formas. Usando Trazos muy grandes y anchos puedes generar grandes áreas y muestras de color en un lienzo. Por ejemplo, un arco elíptico de trazo ancho puede generar una bonita área de color que de hecho he visto usar en la creación de un 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]
O puedes generar la sonrisa bastante compleja de un payaso. |

  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]
¿Qué se te ocurre a ti? Háznoslo saber.

Cilindros

En una Discusión del foro de IM hubo una intensa discusión sobre el dibujo de cilindros, y específicamente cilindros sombreados, usando comandos de dibujo de ImageMagick. El truco para dibujar cilindros es dibujar primitivas 'roundrectangle' de tal modo que los extremos formen óvalos. Es decir, si el cilindro mide, por ejemplo, 50 píxeles de ancho, redondeas las esquinas del rectángulo en 25 y 12 píxeles respectivamente. Es decir, la mitad del ancho del rectángulo, y luego la mitad otra vez. Un cilindro se convierte así simplemente en dos rectángulos redondeados dibujados uno encima del otro. El segundo 'óvalo del extremo' relleno de un color más claro se dimensiona exactamente al doble de ambas dimensiones de las esquinas. Por ejemplo... |

  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]
Reemplazando el primer color de relleno por un sombreado de degradado (usando una técnica de mosaico en memoria) puedes hacer que el cilindro parezca un poco más 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 lentamente el dibujo del cilindro (como se discutió en el foro de IM), puedes llegar muy lejos en la generación de cilindros muy complejos y visualmente atractivos. Esto incluía la adición de cilindros de vidrio semitransparentes que lo envuelven, efectos de sombra y etiquetado. El resultado final de esa discusión es un script "[cylinder_bar](../static/img/scripts/cylinder_bar)", que genera una barra porcentual de cilindro...

  cylinder_bar 95 cylinder_95.png

[IM Output]

El script puede generar una imagen de cualquier tamaño, ajustando todos los parámetros de forma apropiada según ese tamaño y otros ajustes definidos al inicio del script. También incluye el concepto de un 'grosor de vidrio', para crear un hueco entre un cilindro de vidrio semitransparente envolvente y el cilindro coloreado interior. ¡Observa los sombreados muy sutiles del cilindro, especialmente cuando el extremo del cilindro verde se solapa con el extremo del cilindro de vidrio! Es asombroso lo que se puede hacer con un poco de previsión.


Dibujar caracteres especiales en la cadena de texto

¿Comillas o barra invertida?

Uno de los mayores problemas que tiene la gente con -draw es el dibujo de caracteres que también tienen un significado especial para los shells de UNIX y la línea de comandos de DOS, o incluso otros lenguajes como C, Perl, PHP, R o Visual Basic. El mayor culpable en este sentido son los dos tipos de comillas, así como caracteres de sustitución de variables como el dólar '$' y el carácter de escape del shell y de ImageMagick, la barra invertida '\'. Básicamente, como el argumento MVG de "[-draw](https://imagemagick.org/command-line-options/#draw)" necesita estar entre comillas, y el argumento de cadena 'text' que va dentro también puede necesitar algunas comillas adicionales, para resolver esto los usuarios suelen usar dos tipos de comillas distintos, uno para el shell y otro diferente para la cadena de texto MVG.

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

Ten en cuenta que esta es la única opción real para los usuarios de Windows, que tiene sus propios problemas y métodos de comillas. Alternativamente, intercambiarían las comillas y usarían...

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

Lo que te permite incluir sustituciones de variables del shell (usando '$') sin escaparlas. La selección de la forma correcta resolverá la mayoría de los problemas, pero algunos caracteres siguen presentando dificultades, y cada solución depende de exactamente qué juego de comillas uses, ya que también definen cómo deben escaparse los caracteres especiales. Aquí están los cuatro casos de comillas y el manejo de caracteres especiales...

  • Usar comillas simples para el argumento del shell,
    con comillas dobles alrededor de la cadena de texto MVG. La técnica más simple para manejar las cadenas de texto de dibujo es usar comillas simples para el argumento del shell que envuelve. Sin embargo, esto significa que para incluir un apóstrofo en la cadena dibujada necesitas salir del 'modo comillas simples' del shell y suministrar ese apóstrofo fuera de las comillas simples del shell. Por ejemplo, así es como se manejan los cuatro caracteres especiales de los que hablé. |
    magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw 'text 0,0 "  '\''  \"  $  \\  " ' \
              -trim +repage  text_special_sd.gif
    

[IM Output]
Observa que, como el signo de dólar no necesita escaparse, tampoco puedes usarlo para sustituir el contenido de una variable del shell. Es importante recordar que la barra invertida es el único carácter especial que maneja la cadena de dibujo de IM. Además, su razón de existir es puramente permitirte escapar cualquier 'comilla de cadena de dibujo de IM', como usamos arriba para las comillas dobles. Más allá de esto, todo el resto de la rareza la causa el shell de la línea de comandos de UNIX, no IM. PC-DOS tiene su propia rareza, y agradecería aportaciones sobre el escape de caracteres especiales al usar IM desde ese entorno. * Usar comillas dobles para el argumento del shell,
con comillas simples alrededor de la cadena de texto MVG. Si quieres insertar una 'variable del shell' en la cadena dibujada, entonces tendrás que usar comillas dobles para el argumento externo del shell. Esto hace que todo el asunto sea mucho más complejo, ya que pierdes la protección del shell y ahora tienes que escapar no solo los signos de dólar '$', sino también las barras invertidas '\'. Por otro lado, el shell no necesitará entonces usar las comillas simples como su carácter de delimitación de fin de argumento, así que ese aspecto se simplifica. Resumamos los resultados para nuestra breve lista de caracteres especiales. |

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

[IM Output]
Observa que si quieres dibujar una barra invertida en sí, la cadena de texto MVG necesita que la barra invertida se duplique (como en el ejemplo anterior), pero el propio shell también necesita que cada una de esas barras invertidas se duplique, produciendo un total de cuatro barras invertidas solo para producir uno de esos caracteres. Esta duplicación puede volverse muy rápidamente abrumadora y confusa, requiriendo muchas barras invertidas para lograr lo que quieres. Tómatelo con calma, y conseguirás resolverlo para tu situación. * Usar comillas simples para el argumento del shell,
con comillas simples alrededor de la cadena de texto MVG. Terminemos esto con un resumen de las dos últimas combinaciones de comillas. Te dejaré a ti que averigües cómo las decodifican el shell y MVG. |

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

[IM Output]
* Usar comillas dobles para el argumento del shell,
con comillas dobles alrededor de la cadena 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 puedes ver, los argumentos de "[-draw](https://imagemagick.org/command-line-options/#draw)" desde la línea de comandos tienen que lidiar tanto con el shell de la línea de comandos como con el escape de barras invertidas y comillas dentro de la cadena de texto MVG. Los resultados pueden ser confusos y complicados. Solo recuerda que el shell trata los dos tipos de comillas de forma diferente, mientras que la cadena de texto MVG no. Por supuesto, en scripts complejos, la mejor manera puede ser evitar por completo el shell y cualquier problema de scripting. Puedes hacerlo leyendo los argumentos de "[-draw](https://imagemagick.org/command-line-options/#draw)" desde un archivo de dibujo MVG.

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

Por supuesto, todavía necesitarás poner una barra invertida antes de cualquier carácter de comilla que estés usando, así como antes de cualquier barra invertida dentro del texto. Sin embargo, esto es mucho más simple que intentar lidiar con el propio sistema de comillas y escape del shell al mismo tiempo que con el de IM. |

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

[IM Output]
[IM Output]
La primera imagen proviene de uno de los archivos de texto "MVG" que usé. No contiene escapes ni comillas del shell. Por ello, solo están presentes las comillas y escapes de MVG. Observa que, en el ejemplo anterior, si hubiera usado comillas simples para la cadena de texto MVG, el único cambio sería que necesitaría poner una barra invertida antes de los caracteres de comilla simple en lugar de antes de los caracteres de comilla doble en la cadena. Sobre los caracteres de porcentaje Solo un último punto sobre los caracteres especiales de 'escape' en el operador "-draw text". Los caracteres de porcentaje '%' deberían dibujarse 'tal cual'. No deberías necesitar hacer nada especial para dibujarlos. Si no se dibujan 'tal cual', entonces tienes una versión antigua de IM y deberías actualizar lo antes posible. | Hasta la versión 6.2.4 de IM, el carácter '%' se usaba como carácter de escape para incluir información adicional de la imagen en la cadena de texto dibujada. Este ya no es el caso, ya que tales escapes eran confusos e incorrectos cuando las imágenes SVG también intentaban dibujar caracteres de porcentaje.
---|---
Este uso de 'escapes' de porcentaje (así como los escapes de nueva línea '\n') se consideró incompatible con el operador "[-draw](https://imagemagick.org/command-line-options/#draw)" y con el uso previsto del formato MVG para manejar formatos de imagen SVG. Por ello, a partir de la versión 6.2.4 de IM, los escapes con % no funcionan, y las barras invertidas solo escapan a sí mismas y a las comillas que las rodean. |

    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 más detalles sobre el 'bug del porcentaje', y formas de evitarlo al usar "[-draw](https://imagemagick.org/command-line-options/#draw)" en versiones antiguas de ImageMagick, consulta la página Bug del porcentaje en el dibujo. Annotate en lugar de Draw La mejor manera de evitar este tipo de problemas es usar "-annotate" en lugar de draw para dibujar texto. Este operador es un envoltorio alrededor del operador draw y permite usar todas las capacidades de draw, pero de una forma más simple. Básicamente, este operador solo necesita un juego de comillas (para el shell). Esto hace que lidiar con caracteres especiales sea mucho mucho más simple. Por desgracia, aunque ya no necesitas escapar las comillas para IM, ahora tienes Escapes de porcentaje, como las lecturas de archivo '@', las nuevas líneas '\n' y otras expansiones de escape de porcentaje. Por ejemplo, usando comillas simples... |

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

[IM Output]
y para comillas dobles... |

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

[IM Output]
Sin embargo, todas las comillas y escapes de la anotación se ignoran por completo si usas el escape '@' para leer la cadena desde un archivo. Por ejemplo, aquí incluimos información sobre el ancho y la altura de una imagen. |

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

[IM Output]
Sin embargo, todos los escapes se ignoran por completo cuando se lee una cadena de anotación desde un archivo. |

    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 más información, consulta Operador de dibujo de texto Annotate, y especialmente Caracteres de escape de Annotate.


IM y el manejo de SVG

Controladores de entrada SVG: RSVG vs MSVG

Manejar el formato de imagen SVG en sí es un asunto muy complejo. El motor necesita manejar todos sus aspectos, tal como se definen en el documento SVG -- Scalable Vector Graphics. Algo que requiere mucho esfuerzo de programación y tiempo. Por ello, ImageMagick proporciona dos métodos para el manejo de imágenes en formato SVG. El primero es usar una biblioteca de código abierto, RSVG, para transformar el formato SVG en una imagen ráster que IM no tiene problemas en manejar. Este motor es completo en casi todos los aspectos del manejo de SVG. El segundo método consiste en que IM intente transformar SVG en MVG, usando un método integrado llamado MSVG. MSVG intenta transformar una imagen SVG en el lenguaje de dibujo "MVG" de los operadores "-draw" de IM. Gran parte de la funcionalidad de MVG de draw se creó específicamente para este propósito. Por desgracia, aunque el dibujo básico de líneas y el coloreado están presentes, está lejos de ser un conversor completo de SVG. Puedes forzar el uso del conversor interno MSVG leyendo la imagen SVG mediante el formato de entrada especial "MSVG:" (añadido en IM v6.3.4). Pero si la biblioteca RSVG está presente, la mayoría de los ImageMagick la usarán en su lugar para renderizar imágenes SVG. Para averiguar qué hará tu IM, usa...

  magick -list format | grep SVG

[IM Text]

Como puedes ver por el "RSVG" entre paréntesis, mi propio IM usará la biblioteca RSVG, con la versión indicada, que está presente en mi ordenador. Aquí 'dibujo' una pequeña imagen SVG hecha a mano, "diagonal.svg" (contribuida por el usuario del foro penciledin), que crea un rectángulo con un simple degradado diagonal, sobre un fondo blanco. |

  magick diagonal.svg  diagonal_rsvg.gif

[IM Output]
Perfecto. Se produce un degradado diagonal adecuado. Sin embargo, si renderizas esto usando el MSVG interno (lo predeterminado si la biblioteca RSVG no está presente)... |

  magick msvg:diagonal.svg  diagonal_msvg.gif

[IM Output]
Como puedes ver, la conversión interna MSVG falla, devolviendo un degradado vertical en lugar de uno diagonal. También puedes ver los comandos MVG reales que IM genera convirtiendo un SVG directamente en un archivo MVG.

[IM Text]

  magick msvg:diagonal.svg mvg:diagonal.mvg

[IM Text]

Probablemente puedas ver cómo el conversor MSVG intentó transformar SVG en comandos de dibujo MVG. Las cosas con las que se sabe que el MSVG interno actual falla incluyen...

  • Degradados no verticales (sin conversión al nuevo manejo de degradados de MVG)
  • Texto a lo largo de un path curvado
  • Justificación de texto (como algo separado de la gravedad)

Sin embargo, la mayoría de las acciones básicas de dibujo se manejan. Recuerda también que el lenguaje MVG en realidad puede manejar cosas que SVG no puede, incluido el uso de la gravedad para posicionar imágenes y texto. La gravedad no forma parte de la especificación SVG, aunque es una parte integral del manejo de texto y fuentes de IM. Recuerda también que MVG no tiene el mismo mecanismo de contenedores que tiene SVG. El conversor interno MSVG reemplaza los contenedores XML por el apilamiento (push) y desapilamiento (pop) de contextos gráficos (ver la salida MVG de arriba), lo que tiene el mismo efecto.

Ajustes de SVG

El formato de imagen SVG es un formato vectorial (consulta Unas palabras sobre los formatos de imagen vectorial), y como tal la imagen normalmente no tiene un 'tamaño' predeterminado. En su lugar, se 'dibuja' o 'renderiza' a una "[-density](https://imagemagick.org/command-line-options/#density)" particular, igual que postscript (la densidad predeterminada es 72 dpi). Además, si el SVG no 'pinta' el fondo, puedes especificar el color de fondo a usar mediante el ajuste "[-background](https://imagemagick.org/command-line-options/#background)". Por ejemplo, aquí hay otra pequeña imagen SVG "[home.svg](../static/img/images/home.svg)", que ha sido 'renderizada' usando 3 densidades distintas, con 3 fondos diferentes, incluido un fondo 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]

Observa que usé una imagen en formato PNG para la versión más grande con fondo transparente del ejemplo anterior. Esto produce una imagen más limpia de la que produciría el formato de imagen GIF, debido a los píxeles de borde semitransparentes. Siempre se recomienda PNG cuando la transparencia está involucrada en la imagen final. | _He observado que algunas imágenes SVG no se escalan. Es decir, se han definido en términos de 'píxeles', en lugar de longitudes del mundo real como 'puntos', 'pulgadas' o 'milímetros'. Como consecuencia, aunque el ajuste "[-density](https://imagemagick.org/command-line-options/#density)" puede cambiar el tamaño general de la imagen (en unidades del mundo real), el tamaño de los 'píxeles' no cambia, y por tanto la imagen en sí no cambia de tamaño. Sin embargo, tales imágenes SVG son bastante raras.

Peor aún, unas pocas imágenes SVG usan una mezcla de medidas en 'píxeles' y en 'puntos', y a menos que el autor lo hiciera a propósito, podrías obtener un verdadero desastre si intentas usarla a una densidad distinta de la que el autor pretendía. Estas son, afortunadamente, aún más raras.

Una solución sencilla suele ser simplemente cambiar todas las unidades de 'píxeles' del SVG a 'puntos', pero no debe hacerse a ciegas, por si el uso de 'píxeles' fue intencionado._
---|---

Manejo de la salida SVG

A partir de IM v6.4.2, IM puede transformar CUALQUIER imagen de mapa de bits en un gráfico vectorial SVG. La conversión no siempre tiene éxito, pero las imágenes más grandes y/o más simples (como una máscara de mapa de bits) se transformarán muy bien. Por ejemplo, aquí transformo una horrible forma de mapa de bits en una imagen SVG, y luego la vuelvo a transformar, para suavizar el mapa de bits y obtener una forma adecuada con suavizado de bordes (anti-aliasing).

  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]

Sin embargo, para que esto funcione debe estar instalada la biblioteca 'de desarrollo' "[AutoTrace](http://autotrace.sourceforge.net/)", e IM configurado con un interruptor "--with-autotrace". Si la biblioteca "[AutoTrace](http://autotrace.sourceforge.net/)" no está instalada y compilada en IM, entonces la salida SVG generada será un enorme número de círculos de un solo píxel, generando un resultado binario, en lugar de una imagen SVG suavizada y con contorno. Tales imágenes son enormes en comparación, y a menudo tardan muchísimo en renderizarse en un renderizador SVG. En realidad, se necesita una mejor técnica predeterminada de ráster a vector, probablemente usando técnicas de esqueleto y MAT de morfología. Había un delegado de entrada "autotrace:' delegado de entrada, para 'suavizar imágenes de mapa de bits de entrada', que hacía todos los pasos anteriores de una vez usando el comando "autotrace" directamente. Sin embargo, la última vez que miré este delegado había desaparecido. Así es como lo usarías... |

  magick autotrace:A.gif  A_traced.png

[IM Output]
Por supuesto, esto NO te dará la salida SVG del comando "autotrace", solo filtra la imagen de entrada a través de SVG para suavizarla. Como alternativa, en realidad puedes usar el comando "autotrace" directamente, como se muestra en los ejemplos Bordes de ráster a vector y Esqueleto usando Autotrace. También quizá te interese ver los resultados de cancerberosgx, en Generating SVG Images, que estudió soluciones para convertir fotos.


Editores de gráficos vectoriales ajenos a IM

ImageMagick es un procesador de matrices de píxeles. Por lo general no guardará imágenes vectoriales ('MVG' es la única excepción a esto), solo las lee y las transforma en matrices de píxeles. Lo mismo ocurre con otros editores de imágenes de píxeles, como Gimp, Photoshop, etc. Para editar y manejar imágenes basadas en vectores, usa programas como Sodipodi Editor de gráficos vectoriales basado en SVG
Xfig Editor de objetos vectoriales simple, pero muy bueno
(Estupendo para señales, mapas y disponer fotos en una página)
Dia
AutoTrace Convierte una forma en una matriz de mapa de bits en contornos vectoriales
Sketch Editor vectorial basado en Python con texto curvado.
Esta, por supuesto, no es una lista completa. Incluso muchos procesadores de texto, como OpenOffice, Word y TeX, suelen tener varios editores de objetos simples, aunque a menudo difíciles de usar. Sin embargo, para convertir en general un formato de gráfico vectorial a un formato vectorial distinto, no uses ImageMagick. ImageMagick es, y siempre será, esencialmente un conversor y manipulador de imágenes ráster o gráficos de mapa de bits. Para más información, consulta Unas palabras sobre los formatos de imagen vectorial.