ImageMagick 範例 --
繪圖

索引
ImageMagick 範例 前言與索引
ImageMagick Draw 指令
Draw 指令的細節
MVG - Magick 向量圖形
繪製符號
 
繪製物件
 
繪製文字字串
 
IM 和 SVG 處理
 
非 IM 向量圖形程式
在 IM 中繪圖是在現有影像中新增新元素的方法。雖然許多文字繪製的內容在複合字型效果範例頁面和影像註釋中都有介紹,但本頁面將探討「-draw」運算子的其他更通用的面向。draw 指令一開始是用來建立簡單的影像,但隨著時間推移,它已擴展成為向量圖形到點陣圖像轉換的介面。

ImageMagick Draw 指令

電腦中的影像通常以兩種不同的方式儲存。第一種也是最常見的方式,您在本範例頁面中已經看過,稱為點陣圖形。在這種方法中,影像以像素矩陣的方式儲存。另一種方式比較不常見,而且修改性較低,但在另一方面卻更靈活,那就是物件向量圖形。以這種形式,影像是以線條、弧線、色彩填充以及有時以深度來描述。這很有用,因為您可以將這些影像縮放到幾乎任何您想要的大小,而且它們仍然可以完美顯示。與點陣格式的影像相比,您也可以用非常小的空間來描述非常大且複雜的影像。向量圖形影像的範例包括 PostScript 和新的 SVG - 可縮放向量圖形。TrueType 字型也是向量圖形的範例,因為這允許以任何比例使用個別的字元描述。「-draw」影像運算子是 ImageMagick 向量繪圖函數的窗口,並形成一組與 IM 的一般命令列影像運算子完全不同的指令集。
一般常用的向量圖形檔案格式只有幾種,因為每種格式通常都與其他格式有很大的不同。因此,程式碼共用的可能性很小。

因此,ImageMagick 更關注於使用向量圖形來繪製 SVG 格式的圖像。Postscript 和 TrueType 字體圖形會被傳遞給其他更適合繪製這類向量圖形格式的外部「委託」函式庫和應用程式。

也就是說,並非 SVG 沒有可用的委託。一個例子是編譯時可用的 RSVG 函式庫或 GTK SVG 函式庫。IM 會連結到這些函式庫來處理 SVG,而不是嘗試自己處理。

基本繪圖指令

讓我們從 MVG 指令的「-draw」影像運算子的最古老、最簡單和最常見的繪圖基元開始。請注意,所有參數都被視為浮點數,不一定是整數,例如我在這些範例中通常使用的。

  # 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]
根據給出的註釋,當涉及半透明顏色時,這兩種點方法會產生不同的結果。有關詳細資訊,請參閱下面的 顏色填充基元

  # 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]
arc」繪圖基元與矩形一起列出,因為它實際上只是一個「橢圓」,它適合由兩個坐標定義的「rectangle」內。部分弧很少使用,因為除非角度限制為 90 度的倍數,否則很難確定端點。
circle」和「ellipse」基元涉及帶有「邊緣」坐標的「中心」坐標,或者分別為「大小」和「角度」值。

  # 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]
您也可以查看 推送/彈出上下文,以獲取有關如何創建旋轉橢圓的範例。

  # 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]
繪製線條和曲線的更好方法是使用 SVG 路徑繪製,它可以更加通用,甚至允許「相對線條繪製」。

  # 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]
最後兩個填充類型操作是目前唯一受「-gravity」影響的繪圖操作。這些操作的其他修飾符包括:「-fill」、「-tile」、「-origin」、「-stroke」、「-strokewidth」、「-font」、「-pointsize」、「-box」,還有其他修飾符,但這些都與更高級的 Magick 向量圖形語言 相關。

貝塞爾曲線基元

bezier」基元用於繪製曲線。每個指令只會繪製一條曲線段。通常給出 4 個點(8 個數字):一個起點「節點」、兩個控制點和一個終點「節點」。兩個控制點定義了方向以及曲線偏離連接的終點「節點」的速度。要平滑地連接兩條曲線,應通過「節點」鏡像終點的控制點,以形成下一條貝塞爾曲線中的控制點。例如,我在這裡繪製了兩條平滑連接在一起的貝塞爾曲線。請注意控制線和點(也已繪製)如何在角度和長度上都通過連接坐標鏡像。這一點很重要,否則曲線將不平滑。

  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]
如果我移動其中一個控制點,使其沒有通過另一個控制點的連接「節點」進行「反射」,則曲線將是不連續的。

  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]
如果再次移動控制點使其與相關的「節點」點匹配,則線條將直接從該點開始,而根本沒有任何「曲線」。

  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]
如果兩個控制點都設置為其各自的「節點」,則會生成一條直線。

  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]
如果沒有指定所有 4 個點,「bezier」圖元就沒有什麼用處。只有第一個和最後一個點被歸類為曲線將穿過(或結束)的「節點」。所有其他中間點都被視為純粹的控制點,按給定的順序影響曲線,控制點離得越遠,它對曲線那一段的影響就越大。

  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]
建議您每個「bezier」曲線段不要使用超過或少於 4 個點,以保持簡單。實際上,我建議您根本不要使用「bezier」圖元,而是使用 SVG 路徑三次貝塞爾曲線 來生成曲線。它具有一個特殊的「S」曲線延續函數,可以自動執行適當的控制點「反射」,以生成平滑連接的曲線段,並減少您需要使用的控制點數量。您還可以定義相對於路徑中最後一個端點的點。

色彩填充基本圖形

除了上述「簡單」圖元之外,「-draw」還提供了一組顏色填充或修改圖元。它們根據所選方法修改從指定點開始的圖像中的顏色。這些填充方法實際上並不是真正的「繪製」命令,而是顏色替換函數。它們被添加到繪製中,因為在程序的早期版本中,這是將其操作插入 ImageMagick 的最簡單位置。就像上面一樣,使用的顏色是用「-fill」顏色設置設置的,但如果設置了,則將使用「-tile」圖像。上面的其他設置選項不會被使用,並且對這些操作沒有影響。您還將對這些圖元應用兩個額外的設置,「-bordercolor」和「-fuzz」係數設置。但是,這些設置不能在「MVG」語言中定義,因此只能在使用「-draw」運算符之前設置。您已經在上面的示例中看到了這些「顏色點」中的第一個,作為「」繪製圖元的替代方案。如果您仔細觀察,您將會看到我們在測試圖像中設置的單個白色像素。

  magick color_test.png   -fill white \
          -draw 'color 30,20 point'      color_point.png
[IM Output]
但是,在繪製透明和半透明顏色時,這些函數並不相同。這裡我們有一個三個像素的紅色圖像(放大),我們使用「」函數用半透明的藍色繪製了第二個或中間像素,得到紫色結果。但是,如果使用「顏色點」函數(最後一個或右邊的像素),則紅色將被半透明的藍色像素完全替換。它沒有被覆蓋。

  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]
所有「顏色」函數都執行完全顏色替換,而所有其他顏色圖元都將顏色「繪製」在圖像的頂部。因此,您可以使用「顏色」來繪製透明顏色。「顏色替換」繪製函數將替換指定位置處給定顏色的所有實例。正如您所見,這些區域不必是連接的。

  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]
然而,正如您在第一個結果中所見,邊緣上的一些像素沒有被替換。這些像素與所選像素的顏色並不「完全」相同,因此被忽略了。新增少量的 模糊係數 也會包含與原始顏色相似的顏色。如上面的第二個範例所示。當然,「模糊係數」並不是一個好的解決方案,因為它不會捕捉到所有此類邊緣像素。這是所有這些「顏色填充」方法都會遇到的問題,而且沒有通用的解決方案。如果您想替換特定的已知顏色,而不是從圖像本身選擇顏色,則可以使用「-opaque」圖像運算符。此函數還使用「-fuzz」係數設置來增加與給定顏色匹配的顏色範圍。「floodfill」方法也很簡單,因為它只會填充所選點周圍的整個區域,而不會選擇任何其他以某種方式未連接的相似顏色區域。您也可以使用「-fuzz」來擴展要填充的區域,以包含相似的顏色。在這種情況下,我們選擇的值足以包含交叉邊界,從而允許泛洪填充「洩漏」到圖像的另一側。

  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]
使用顏色泛洪填充區域並非沒有問題。顏色可能會穿過細小的邊界洩漏到不需要的區域(請參閱 背景圖案上的 GIF 以了解此情況)。或者,它可能無法填充所選區域到邊緣的右側(請參閱 消除鋸齒和泛洪填充問題)。但它的確有效。「filltoborder」類似於「floodfill」,只是您指定了與要填充的區域接壤的顏色,而不是填充過程中要替換的顏色。
當然,還建議使用 模糊係數 來包含該邊界顏色選擇中的「相似顏色」,以進一步限制泛洪填充。

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


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


  magick color_test.png   -fill white  -bordercolor blue  -fuzz 30% \
          -draw 'color 30,20 filltoborder'   color_filltoborder_fuzz.png
[IM Output]
[IM Output]
[IM Output]
最後一種繪製顏色方法是「reset」,它只是將整個圖像替換或重置為填充顏色。在這種情況下,實際選擇的像素與結果完全沒有關係。

  magick color_test.png   -fill white \
          -draw 'color 30,20 reset'      color_reset.png
[IM Output]
這實際上非常有用,因為它提供了一種從現有圖像生成純色(或平鋪圖像)畫布的簡單方法。(請參閱 大小調整為現有圖像的畫布)以了解此方法和其他實現相同目標的方法。未來:使用「-tile」圖案填充區域。

Alpha 填充基本圖形

alpha」繪製基元的工作方式與上述「color」基元完全相同,只是它不會替換所選區域的顏色,而只會替換所選區域的「alpha」通道。(也就是說,只有「alpha」通道會被這些填充函數調整)。就像「color」填充函數一樣,「alpha」值使用填充顏色(除非使用「-tile」作為要使用的「alpha」值的來源)。在這裡,我們使用與上面相同的「color floodfill」範例,但這裡只調整 alpha 通道以使填充的部分完全透明。也就是說,原始顏色仍然存在,只是透明的!

  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]
alpha reset」函數還可以用於使整個圖像半透明。當然,在這種情況下,我們必須輸出到 PNG,因為 PNG 可以接受圖像中的半透明顏色。

  magick color_test.png   -fill '#00000080' \
          -draw 'alpha 30,20 reset'      matte_reset.png
[IM Output]
請注意,在操作中僅使用了顏色的 alpha 分量,而未使用「black」顏色分量。圖像的原始顏色保持不變。未來:使用「-tile」模式來獲得有趣的 alpha 效果。「color」和「alpha」都是顏色函數的完整替換,它們將始終產生布林值(全部或不產生)類型的顏色替換。因此,這些區域的邊緣將始終顯示鋸齒效應。因此,除了設定 GIF 圖像(也是布林值)的透明區域外,這些通常不是一般圖像開發的良好圖像運算子。然而,並非所有東西都已失去,如背景移除範例所示。

繪製命令的細節

像素座標

-draw」命令(以及 IM 中的許多其他命令)使用稱為「像素座標」的內容。也就是說,「10,10」的座標是從左上角向下和向左移動 10 個像素的像素中心。在此座標系中,0,0 是左上角像素的中心,而 w-1,h-1 是右下角的中心。實際邊緣位於 -0.5,-0.5 和 w-0.5,h-0.5 處,而中心像素(如果圖像大小為奇數)位於「(w-1)/2,(h-1)/2」處。但是,當您以數學方式處理圖像時(例如使用扭曲時),實際像素沒有實際意義,因此它使用「圖像座標」。在此系統中,圖像的實際邊緣位於「0,0」和「w,h」處。圖像的中心(可能是也可能不是像素的中心)位於「w/2,h/2」處。要將「像素座標」轉換為圖像座標,請加上 ½。因此,左上角像素的中心為「0.5,0.5」,而右下角像素為「w-0.5,h-0.5」。範例:小圖像中圓形的中心

使用 Gamma 和色彩空間校正進行繪圖

與幾乎所有 ImageMagick 操作一樣,「-draw」是一個線性運算子,因此在線性 RGB 色彩空間中工作。這表示要獲得漂亮的平滑邊緣,您可能需要在儲存圖像之前對其進行一些伽瑪校正,以便使用非線性(伽瑪校正)sRGB 色彩空間儲存它們。
例如,如果您繪製一個大圓圈,然後直接儲存它...

  magick -size 81x81 xc:black -fill white -draw 'circle 40,40 40,3' \
          circle_raw.png
[IM Output]
請看圓圈的邊緣,它們看起來並不是很平滑。您可以看到明顯的階梯效應。這是因為您是在線性 RGB 色彩空間中繪製圓圈的。但是您卻將圖像儲存為 sRGB 色彩空間!
要解決此問題,我們需要在儲存圖像之前對其添加伽瑪校正。

  magick -size 81x81 xc:black -fill white -draw 'circle 40,40 40,3' \
          -gamma 2.2 circle_gamma.png
[IM Output]
現在,圓圈邊緣看起來確實很平滑和圓潤,就像它們應該的那樣。如果您想正確執行此操作,我們真的應該使用色彩空間進行校正。但是,由於 IM 假設 RGB 是儲存的預設色彩空間,因此您需要進行一些棘手的處理才能使其正確執行操作。

  magick -size 81x81 xc:black -set colorspace RGB \
          -fill white -draw 'circle 40,40 40,3' \
          -colorspace sRGB circle_sRGB.png
[IM Output]
請注意,sRGB 色彩空間(這是儲存圖像的正確方法)與僅應用 2.2 伽瑪校正並不完全相同。但是,兩者之間的結果差異很小,並且僅在非常暗的圖像中可見。
在 IM v6.7.5-1 之前,色彩空間名稱「sRGB」和「RGB」(線性 RGB)實際上是相反的。因此,在舊版本的 IM 上,上述兩個標籤應互換。
要使用真實圖像(在 IMv7 中)正確繪製(或進行任何「線性」圖像處理),您需要先移除任何現有的伽瑪,處理圖像,然後恢復該伽瑪校正。有關更多詳細信息,請參閱使用色彩空間校正調整大小。以下是繪製在真實圖像上的範例...首先是不進行任何色彩校正(原始),然後是進行伽瑪和色彩空間校正。

  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]
如您所見,使用伽瑪或色彩空間校正後,線條看起來非常平滑,沒有直接繪製時可見的鋸齒狀“階梯”鋸齒效應。(您需要一台非常好的顯示器才能看到它)
上面這條線是使用“-stroke”顏色繪製的。您可以使用“-fill”繪製線條並獲得相同的結果,但您將無法使用“-strokewidth”來控制線條粗細。有關更多資訊,請參閱下方的筆畫顏色設定
顏色名稱實際上是使用“sRGB”色彩空間的值定義的,但繪製時會應用,就好像圖像處於線性 RGB 色彩空間中一樣。因此,對命名顏色(“白色”或“黑色”除外)使用上述伽瑪校正將導致這些顏色失真。在這種情況下,最好不要使用伽瑪或色彩空間校正,以便正確映射命名顏色。

將命名的“sRGB”顏色正確映射到正在繪製的圖像的色彩空間,將作為 IMv7 開發的一部分進行修復。

筆畫、筆畫寬度和填充交互

-stroke”和“-strokewidth”選項在字體邊緣周圍繪製輪廓時使用。這些選項通常與“-fill”一起使用,只需很少的努力即可使文本更有趣。

    magick -size 380x70 xc:lightblue -pointsize 50 -font Chisel \
            -fill green  -stroke black  -draw 'text 10,55 "Black Border"' \
            stroke_font.jpg
[IM Output]
默認設置是“-strokewidth 1”和“-stroke None”。但这会使轮廓笔画不可见,只留下“-fill”颜色,您将看不到它。当“-stroke”为“不可见”时,“-strokewidth”的唯一效果是在字体大小属性上,这意味着它仍然可以影响字体定位和标签和标题图像生成的大小。否则,在您使笔画可见之前,宽度没有任何可见效果。为了了解“-strokewidth”如何实际影响字体的 tampilan(当可见时),我在这里绘制了一些文本,其宽度从“关闭”开始并逐渐变大。

    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]
请注意,从上面的示例中可以看出,将“-strokewidth”设置为“0”与将“-stroke”颜色设置为“none”(默认值)不同。前者会产生非常非常细的笔画轮廓,而后者则有效地将其关闭。在这两种情况下,仍然会绘制笔画。但是,您还应该注意,即使“-strokewidth”为“0”,图像轮廓也会比仅使用纯“填充”图像(使用“-stroke”颜色“none”)略微扩展。从本质上讲,使用任何小于“1.0”的宽度都无法正常工作。在这种情况下,您应该谨慎行事。但是请记住,“-strokewidth”也是一个浮点设置。也就是说,“0.5”的笔画宽度也是有效的。但是,通常只有在您尝试在抗锯齿关闭的情况下绘制细位图圆时,这才重要。
以下是一个使用极大笔画宽度的示例。

   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]
请注意,“-strokewidth”会向内和向外扩展线条。以下是相同的示例,但重新绘制了字体,没有笔画轮廓,以移除非常粗的笔画的内部部分。

   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]
如需更多使用筆畫的範例,請參閱 複合字體效果。請特別注意「氣球效果」。

繪製(筆畫)線條

IM 中的預設線條繪製有一些奇怪的行為,值得注意。以下是預設線條繪製...

  magick -size 100x40 xc:lightblue \
          -draw "line 5,35 95,5" \
          line_default.jpg
[IM Output]
您可以使用「-fill」選項設定線條的顏色。

  magick -size 100x40 xc:lightblue \
          -fill white -draw "line 5,35 95,5" \
          line.jpg
[IM Output]
您也可以透過設定「-stroke」顏色來使線條稍微變粗。

  magick -size 100x40 xc:lightblue \
          -fill white -stroke black -draw "line 5,35 95,5" \
          line_stroke.jpg
[IM Output]
但是我們使用「-fill」選項指定的白色發生了什麼事?這是 ImageMagick 中繪製線條的棘手之處。程式實際上將線條視為寬度約為 1 個像素的填充物件。這是很自然的,因為通常會使用多條線條來掃描要填充的區域。因此,就像我們在上一節中對字體使用筆畫時一樣,IM 使用填充顏色繪製線條(或物件),然後使用筆畫顏色在其周圍繪製。結果是,上面的筆畫顏色線條現在稍微變粗,填充顏色完全隱藏在下方。如果您將筆畫顏色設定為半透明,則可以再次顯示該填充顏色。總之,線條將顯示為使用「-fill」顏色繪製,但是一旦將「-stroke」顏色定義為預設「none」或「transparent」顏色以外的其他顏色,該選項就無關緊要了。
選項「-linewidth」實際上只是「-strokewidth」的別名,不應使用。
例如,您可能會認為此命令會產生一條非常粗的線條。確實如此,但是由於「-stroke」顏色是不可見的,因此您看不到它。您只能看到線條 1 個像素寬區域的內部「填充」。

  magick -size 100x40 xc:lightblue \
          -fill white -strokewidth 3 -draw "line 5,35 95,5" \
          line_fill_3.jpg
[IM Output]
我實際上將上述結果視為一個錯誤。不應該繪製任何內容,因為沒有要填充的「區域」,也沒有設定線條「筆畫顏色」。IM 目前這樣做的原因是為了避免與新使用者混淆,但實際上它只會給進階使用者帶來問題。如需詳細資訊,請參閱 繪製填充邊界
但是,如果也定義了筆畫顏色,您將獲得所要求的粗線條...

  magick -size 100x40 xc:lightblue \
          -stroke black -strokewidth 3 -draw "line 5,35 95,5" \
          line_stroke_3.jpg
[IM Output]
如果將「-strokewidth」設定設定為 1,則上述線條將被完全覆蓋。

  magick -size 100x40 xc:lightblue \
          -stroke black -strokewidth 1 -draw "line 5,35 95,5" \
          line_stroke_1.jpg
[IM Output]
當然,當您掌握了這些知識後,就可以像繪製字體一樣,利用它來發揮創意。

  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]
在這裡,我使用了最細的「-strokewidth」設定「0」,就像我上面對字體所做的一樣。

  magick -size 100x40 xc:lightblue \
          -fill white -stroke black -strokewidth 0 -draw "line 5,35 95,5" \
          line_stroke_0.jpg
[IM Output]
這會產生由黑點和灰色線段組成的虛線,這是非常奇怪的結果。這是筆畫、填充和背景顏色之間奇怪的「顏色拍頻」的結果。以下是線條的放大視圖...

  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]
「顏色拍頻」效應與兩把吉他略微走音時產生的「聲音拍頻」沒有什麼不同。在這種情況下,當筆畫顏色完全覆蓋底層填充顏色時,您會得到一個黑點;當筆畫顏色與填充顏色和背景顏色混合時,您會得到一個灰點。

顏色混合是 IM 用於嘗試改善線條和其他繪製物件外觀的反鋸齒處理過程的自然結果。如需詳細資訊,請參閱我的 IM 中的反鋸齒討論和範例頁面。

請注意,此效應僅出現在傾斜線條上,而不出現於純水平或垂直線條上,因為鋸齒效應對其沒有影響,因此也沒有「顏色拍頻」效應。

  magick -size 100x40 xc:lightblue \
          -fill white -stroke black -strokewidth 0 -draw "line 5,20 95,20" \
          line_stroke_horz.jpg
[IM Output]
在這裡,我在放大視圖上使用了不同的底層填充顏色,以便您可以看到顏色如何改變產生的拍頻。

  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]
讓我們將其與沒有描邊的情況進行比較…

  magick -size 25x10 xc:lightblue \
          -fill black -stroke none -draw "line 2,8 22,1" \
          -scale 400%    line_stroke_-_black.jpg
[IM Output]
如您所見,在繪製非常細的線條時,您可以通過使用相同的填充和描邊顏色或將其中一種顏色設置為「無」來將其關閉,從而減少「跳動」。雖然後者是最好的方法,但前者可能更適合您的特定編程需求。請注意,填充線條粗細為「0」。但描邊線條可以有更大的粗細。它也是一個浮點值!2.5 像素寬的線條是完全有效的。
這些結果不僅是由於描邊寬度為 0 的錯誤導致顏色跳動,而且當沒有實際區域需要填充時,「填充顏色」會以額外 1.0 直徑的粗細繪製。我也認為這是一個錯誤。請參閱繪製填充邊界

繪製填充邊界

關於各種繪製原語,您還需要注意其他幾點。描邊寬度適用於大於 1.0 的浮點值,但對於小於 1.0 的值似乎會失效。這是由於所使用的實現算法造成的,並非僅僅因為它是錯誤的,因為它適用於較大的粗細線條。基本上,如果您使用零的描邊寬度,您可以預期不會添加描邊顏色。相反,當線條穿過像素的實際「中心」時,您會得到一種跳動模式,其中描邊顏色處於最強強度。真正應該發生的是添加到像素的顏色量應該反映正在繪製的線條的面積,而不是像素到該線條的距離。因此,零寬度的線條不應為圖像添加任何顏色,而小於 1.0 粗細的線條應只添加較少的顏色。請參閱上面的示例使用 StrokeWidth 和 Stroke 繪製線條。另一個問題是填充顏色沒有應用到正在繪製的形狀(多邊形)的邊緣,而是向外延伸了 ½ 個像素。這包括沒有應用「描邊」的情況,並且邊緣應該是精確的。它還包括繪製「線條」,它實際上具有「零」填充粗細。基本上,如果您繪製一條線條,而不啟用描邊,從技術上講,您應該看不到任何線條,因為它沒有「填充」粗細。相反,線條的繪製至少包含 1 個像素寬的「填充」顏色。這是出於歷史原因,並且通常可以避免 IM 的新用戶產生混淆。不幸的是,對於高級用戶來說,這是不正確的。這意味著,如果您使用僅填充顏色繪製兩個共享邊緣的多邊形,則該邊緣將重疊 1 個像素,因為每個多邊形沿其所有邊緣都大 ½ 個像素。換句話說,多邊形和其他形狀不能完全吻合,而是會重疊!例如,在這裡我嘗試使用繪製將圖像分成兩半(在白色上繪製黑色)。為此,我繪製了兩個共享邊緣的多邊形,完全沒有重疊。生成的「微小」圖像已被放大以供顯示。

  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]
兩個黑色的部分(實際繪製的部分)實際上互相重疊!換句話說,即使我們嘗試使用繪製的多邊形分別繪製兩個區域,填充區域也比要求的略大。我還將兩張圖片(加法合成)在一起,以便您可以實際看到繪製的黑色區域的重疊。如果兩個多邊形完全吻合,「加法」繪圖將是純白色。實際的重疊量等於默認的「-strokewidth 1.0」設置。因此,通常預計這個額外區域將被正常的筆劃寬度覆蓋。然而,它可能會導致一些真正的問題。題外話:要對連接進行完整測試,您需要在黑色背景上生成 50% 的灰色區域並將它們加在一起。這樣,當您將這些區域加在一起時,您不僅可以看到這些區域是否「重疊」(如上所示),還可以測試它們是否「重疊不足」(在填充區域之間留有間隙)。生成的圖像應該是完全平滑的 50% 灰色,連接處沒有顏色變化。透明度檢查將涉及在完全透明的背景上使用 50% 透明度的 50% 灰色。要查看基於單個蒙版圖像的完美切割和重新添加的示例,請參閱合成方法示例,合成 DstOut。未來錯誤修復:填充區域應該是準確的,但是為了在繪製形狀時彌補這一點,默認的「筆劃顏色」應該設置為填充顏色(除非它本身被特別設置)。

MVG - 魔法向量圖形

上面顯示的基元構成了所有提供的「-draw」操作的基礎。它們共同構成了 ImageMagick 中一種特殊內部語言的起點,稱為魔法向量圖形語言。有關此語言的更多詳細信息,請參閱 IM 網站上的MVG 基元和語法摘要。這種「MVG」語言的設計目標是允許 ImageMagick 處理更複雜的 SVG(可縮放向量圖形)語言。它通過嘗試將給定 SVG 格式的圖像變為更簡單的內部 MVG 格式來實現這一點。有關更多詳細信息,請參閱下面的SVG 處理。因此,您在上面看到的只是「-draw」運算符功能的一小部分。但是,如果您想繪製複雜的對象,我建議您使用 SVG 編輯器(例如「Sodipodi」)創建對象的單獨 SVG 格式圖像。(請參閱下面的非 IM 向量圖形程序)。與 SVG 不同,MVG 没有任何形式的「容器」或圖像命令集。這些都在轉換過程中被刪除,以生成簡化的 MVG 繪圖命令序列。相反,它使用圖形上下文的概念來保存和恢復各種繪圖設置,這就是我們現在要看到的。

命令列設定與 MVG 設定

首先,幾乎所有通過繪圖基元使用的命令行選項設置的設置在 MVG 繪圖命令中都有直接的等效項。通過命令行選項(例如「-strokewidth」)設置與在 MVG 繪圖字符串中使用設置(例如「stroke-width」)之間的主要區別在於,MVG 設置僅在 MVG 命令字符串的持續時間內有效。
Summary of the General Drawing Settings
  __cmd_option__   __draw_MVG__        __Argument__
    -fill            fill                color/tile for inside shapes
    -tile            fill                image tile, replaces fill color

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

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

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

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

Notes:
  - no such option      ? unknown
這些設置通常很容易理解,因為它們經常被使用並且在上面已經演示過。
字體、伸展、樣式和粗細用於從 ImageMagick 字體列表中識別字體。 然而,大多數人只選擇要使用的特定字體和點大小。 因此,它們在 IM 中很少使用。
如您所見,「顏色填充」基本圖形的特殊設定在 MVG 中沒有直接的對應設定。 也就是說,「-bordercolor」和「-fuzz」因素設定。 這些必須在使用「-draw」運算符之前從命令列指定。 一些 MVG 設定作為全域命令列設定可能會更有用,例如用於字體繪製的「decorate」設定。 警告:「-gravity」不是 SVG 規範的一部分。 在 MVG 中,它僅用於文字和圖像放置以及對齊。 目前沒有與預設「重力」效果分開的對齊設定。 然而,由於對齊是 SVG 文字處理的一部分,因此將來可能會有所改變。 現在,全域命令列設定(在 MVG 繪製字串之外)用於初始化您應用的每個「-draw」操作的設定,這就是為什麼您可以設定「-fill」顏色,然後您可以使用該顏色繪製圓圈。

  magick -size 100x60 xc:skyblue   -fill red \
          -draw "circle 50,30 40,10"          draw_circle_global.gif
[IM Output]
您可以在「-draw」MVG 參數中局部覆蓋該全域設定...

  magick -size 100x60 xc:skyblue   -fill red \
          -draw "fill green   circle 50,30 40,10"  draw_circle_override.gif
[IM Output]
但是,在單個「-draw」MVG 參數中設定的設定僅在該「-draw」操作期間存在。 也就是說,「-draw」中的設定僅對該繪製是局部的,並且不會延續到後面的單獨「-draw」參數中。

  magick -size 100x60 xc:skyblue   -fill red   -draw 'fill green' \
          -draw "circle 50,30 40,10"          draw_circle_local.gif
[IM Output]
如果您打算執行許多操作,最好在單個 MVG 字串中完成所有操作,而不是執行多個「-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]

MVG 特定設定

其他控制線條和物件繪製方式的 MVG 設定,即使在使用基本圖形操作時也很有用。 這些包括..
   __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')
請記住,所有 MVG 設定和繪圖運算符的完整列表可以在 IM 網站上的MVG 基本圖形和語法摘要中找到。 讓我們看一下一些更簡單設定的效果...

  # 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]
stroke-miterlimit」設定很難示範。此屬性定義將「miter」連接更改為「bevel」連接的角度。基本上,對於非常銳利的角度,斜角可以從兩條線的實際連接處延伸很長一段距離。這為該銳度設定了最大限制,並在拐角點過長時將其鈍化。但請注意,它表示某種角度的三角函數值,而不是長度或距離。該值必須大於 1.0。上面顯示了我正在顯示的連接角度,斜角會在 6 到 7 之間的某個值突然變成斜角。例如,「stroke-miterlimit」為 1.414 會將小於 90 度的任何角度的「miter」轉換為「bevel」。值 4.0(預設值)會將小於約 29 度的角度的連接轉換。而值 10.0 會將它們轉換為小於約 11.5 度的角度。

SVG 路徑繪製

SVG 路徑是 SVG 的基本繪圖原語。它用於繪製線條形狀、圓形、曲線、弧線等。SVG 路徑的完整規範可以在SVG 路徑規範文件中找到。然而,這不是一個容易閱讀的文件,因為它實際上是針對程式設計師的,而不是針對使用者的,因此我將簡化和總結路徑規範...
  • 字母是指令,而所有數字(浮點數)都是參數。
  • 逗號或空格可用作參數分隔符,否則它們將被完全忽略。
  • 每個路徑組件的最後兩個參數 (x,y) 將成為該路徑組件的終點(或「節點」)。
  • 大寫字母指定最終點的絕對坐標。
    小寫字母是相對於前一個組件的終點的。
    例如:「 M 1,2   l 3,4   l 2,-4 」等同於「 M 1,2   L 4,6   L 6,2 」。
    也就是說,將 3,4 加到 1,2 上,畫一條線到 4,6。
    然後添加 2,-4 以繪製一條線到最終坐標 6,2。
  • 每個元素的參數可以重複,而無需重新發出相同路徑字母,方法是添加更多數字參數組。但是對於曲線,我建議您添加函數字母以便於閱讀。
  • M」或「m」的重複參數分別被視為「L」或「l」。
    例如:「 M 1,2   3,4   5,6 」等同於「 M 1,2   L 3,4   L 5,6
    並且:「 m 1,2   3,4   2,-4 」等同於「 m 1,2   l 3,4   l 2,-4
  • 對於三次貝茲曲線,所有點(控制點和終點節點)都相對於前一個路徑組件的終點給出。
請注意如何將事物指定為絕對坐標或相對坐標。因此,您可以根據相對坐標定義一個物件,只需提供一個初始的絕對「移動」坐標即可定位整個路徑。另一方面,您也可以使用其他「圖形內容」指令在「視窗」或「轉換」中移動整個繪圖(見下文)。所以實際上在 SVG 路徑中使用絕對坐標還是相對坐標並不重要。 移動、線條和路徑閉合是學習 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]
但請注意,「Z」只會關閉路徑。它並不會建立單獨的物件。因此,兩條「封閉」路徑仍然被視為單一繪製物件,無論它們是重疊還是完全斷開。 這裡我們展示兩個封閉但重疊的迴圈,以相同方向繪製。由於僅使用單一路徑,因此該物件是單一物件,而「fill-rule」設定控制重疊區域的填充方式。

  # 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]
由於物件是圍繞中心以相同的角度方向繪製的,因此兩個封閉迴圈將圍繞一個循環值為 2 的區域。因此,「evenodd」規則使該區域未填充,而非零的「nonzero」規則則填充了該區域。但請注意,所有路徑都是可見的,因為它們實際上是同一個物件。繪製路徑的方向非常重要,一般而言,所有路徑都應相對於物件的「內部」以完全相同的方向繪製。例如,我在這裡以與第一個物件相反的方向繪製第二個物件。因此,當兩個物件重疊時,該區域將被「」次環繞。也就是說,無論使用何種「fill-rule」,它都不會被填充,從而形成一個「孔洞」。

  # 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]
這意味著您可以通過反轉方向在物件中產生「孔洞」,以便將物件的「內部」保持在行進方向的同一側。

  # 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]
結果與「fill-rule」設定無關,因為孔洞既是「偶數」又是「零」,因此未填充。當然,如果您使用完全獨立的「path」元素,則會產生完全獨立的物件。在這種情況下,「fill-rule」不適用,物件只會按照給定的順序彼此疊加繪製。

  # 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" 
橢圓弧是 SVG 路徑的圓形繪製函數……
「large」和「sweep」參數尤其重要,因為它們用於確定您將從起點到該路徑組件的終點「弧形」的四種方式中的哪一種。
兩個標誌「large」和「sweep」定義了將連接兩點的四個弧中的哪一個。

  #  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]
第二個標誌「sweep」僅確定應在直線路徑方向的哪一側繪製弧線。「large」標誌用於選擇較長的路径,圍繞橢圓的中心。也就是說,設置的弧角度將大於 180 度。如果關閉此選項,您將獲得不包含橢圓中心且弧度小於 180 度的較小「弧」。使用「Z」關閉弧線只會繪製一條最終的直線段。要創建完整的橢圓或圓形,您至少需要兩個「弧」段,從第一個點到第二個點,然後返回到第一個點。兩個弧線應具有相同的「sweep」設置,因此弧線將位於不同的側面,行進方向也不同。其中一個弧線應設置「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]
請注意,如果線條過長而無法以給定角度適應給定的橢圓大小,則橢圓的大小將會擴大以適應以線條為中心的橢圓。這意味著,通過對軸半徑使用較小的數值,您可以僅指定軸長的比率,並確保直線路徑穿過橢圓的中心點。也就是說,路徑形成從橢圓一側到另一側的橢圓直徑。這未必是橢圓的長軸或短軸,而只是一個橢圓直徑。

  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]
當然,使用長度為「1,1」會形成一個完美的半圓,從一個點到下一個點。 在這種情況下,橢圓角度沒有區別。

  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]
對於以兩點為中心的完整圓,請使用...

  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]
「圓弧」的 SVG 定義還聲明,如果兩個半徑中的任何一個為零,則應繪製一條直線。 因此,任何具有「0,0」半徑的圓弧都只是一條簡單的直線圓弧...

  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]
如果您為圓弧指定非常大的半徑,並且沒有為返回路徑指定「大掃掠」,則可以在兩點之間創建該半徑的透鏡形狀。

  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]
這種圓弧是一個關鍵特性。 它使您可以非常輕鬆地為原本的直線賦予一條小而清晰的曲線。 例如,不要像這樣簡單的三角形...

  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]
您可以使用大圓弧替換每條線,使其略微彎曲。

  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]
線條的端點沒有變化,所發生的只是每個「L」都被圓弧段替換。 然而,圓弧的大小應該與線條的長度成正比。 由於我沒有這樣做,所以較長的對角線比其他兩條線具有更強更深的曲線。 請記住,在調整繪製對象的大小或縮放時,您還應該按與線條長度相同的量縮放半徑,以便相應地調整曲線的大小,以便圓弧也能正確縮放。 請注意,「掃掠」標誌控制曲線是向外還是向內凸出,具體取決於繪製每個路徑段的方向(見上文)。

  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]
具有筆直邊緣的「靜態」三角形,現在看起來有點像充滿風的帆。 如果你真的想讓線條完美筆直而不將它們轉換回真正的線段,你可以使用零的圓弧半徑來關閉曲線。 因此,圓弧不僅適用於生成橢圓和圓形,而且還可以用於繪製直線和略微彎曲的線段。 它是一種非常通用的點對點繪製路徑。 一種使用橢圓弧生成分離曲線段的簡單替代方法是改用二次貝塞爾曲線段。 主要區別在於使用單個控制點而不是圓形半徑來定義圓弧。 這也允許您將圓弧偏向線段的一端,但代價是難以生成對稱圓弧。 您當然可以通過同時使用兩者來「混合搭配」。 圓餅圖範例最後使用圓弧,讓我們舉一個使用它們生成圓形楔形的例子。 當然,您可能需要使用一些外部三角數學(您高中的數學成績如何?)來確定所需的結束路徑點。

  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]
請注意,所有弧線都繪製在「線路徑」的左側,並相應地標記(使用「sweep」標誌)。但如果弧線覆蓋的角度大於 180 度,則需要設定「large」標誌。請參閱上面範例中的最後一個「金色」組件。另請注意,您應該完整繪製每個區段,即使這表示您可能必須繪製兩次邊界線。如果沒有,您可能無法用顏色完全填充該區段,或者填充顏色會覆蓋先前繪製的區段輪廓。避免重複多條線的唯一方法是繪製所有填充區域,然後重複繪製輪廓。也就是說,您需要繪製兩次所有內容,確保內容正確匹配。因此,重複輪廓可能是最簡單的解決方案。 三次貝茲曲線可以使用定義兩個控制點和最終端點的「C」函數來定義。對於使用最後一個控制點的鏡像(用於連續曲線)的連續三次貝茲曲線,您可以使用「S」函數。以下是一個例子。由於此函數的複雜性,我預先準備了一個畫布,顯示了控制點的位置,以及最後一個控制點的「假設鏡像」。

  # 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]
連接控制點和該路徑段路徑上的終點的線(控制線)基本上定義了曲線穿過該路徑點的方向。長控制線將在該點產生更平滑的曲線,而短線在該點產生更尖銳的曲線。如果控制點與曲線的點匹配(控制線的長度為零),則曲線在該點將具有尖銳的不連續性,就像僅使用直線段一樣。作為一個更實際的例子,以下代碼段摘自IM 範例標誌生成器腳本,該腳本創建了IM 範例標誌的彎曲啟動畫面區域。該範例的棘手部分是我將我使用三次貝茲曲線路徑字符串變成另一條顯示用於生成貝茲曲線的控制線的路徑。這讓我可以看到曲線的控制線角度和長度,從而更容易調整結果。只需要調整一組點即可顯示曲線和控件,從而最大限度地減少錯誤。

   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]
如果仔細觀察圖像,您會發現曲線的起點和終點有兩條方向相反的控制線。對於封閉的連續路徑,起點和終點控制線應處於相同的角度(僅在鏡像方向上),當然長度也應相同。這一點很重要,因為很容易弄錯。沿曲線的所有其他點只有一條控制點/線,指向曲線繪製方向的相反方向。線段越長,該控制點處的曲線越「不尖銳」,零長度會產生「點」。「S」函數從前一段的數據內部生成下一段的鏡像控制點/線,以便產生平滑的曲線延續。有關此路徑函數的更多示例,請參閱SVG:三次貝茲曲線命令手動生成貝茲曲線相對簡單,不需要任何花哨的 GUI 工具。
  • 首先定義您希望曲線穿過的所有坐標點,在列表末尾重複起始坐標。
  • 現在,藉由將所有 x,y 座標點成對加倍並在每對之前添加「S」(平滑三次方)函數,來展開此列表。每對中的第一個數字是連接到代表曲線上點的第二個數字的控制點。但是,第一個點對的順序相反,第一個點是曲線的起點,第二個點代表第一個也是唯一的反轉控制點。
  • 將第一對座標的函數字母從「S」更改為「M」,然後在這對座標之間添加「C」。最後,從第二對座標中刪除「S」,以完成初始三次方(「C」)函數。
  • 透過添加最後的「Z」來閉合曲線,從而完成路徑。
    請參閱上面的範例序列,了解其外觀。
  • 此時,您可以測試繪製您的路徑。由於所有控制線的長度都為零,因此該路徑將僅包含直線段。
  • 您現在需要做的就是緩慢而小心地調整控制線段的位置(每對「S」的第一個座標),以獲得所需的最終曲線。不要使控制線過長或方向錯誤,否則您將獲得一條看起來很奇怪的曲線。
  • 為了幫助查看您的更改並發現錯誤,請使用上面的轉換「sed」命令在路徑控制點和曲線控制點之間繪製控制線。但是請注意,零長度的控制線不可見,但由於該線將產生一個尖點,因此其位置應該很明顯。
  • 最後,確保「C」之後的第一個控制點/線與結束控制點/線的方向完全相反,且位於同一位置。
互動式曲線生成也可以使用一些向量圖形編輯器來完成。例如,Luis Guerra 報告說,可以使用「編輯 -> XML 編輯器」功能,然後選擇要獲取其控制點的路徑或形狀,來訪問「Inkscape」生成的貝茲曲線。
您是否知道使用 GUI 工具提取貝茲曲線(為曲線上的每個點提供兩個或一個控制點)的其他方法?或者生成此類曲線的其他技術?請發送電子郵件給我!我很想听聽。您將像其他人一樣獲得該技術的讚譽。
二次貝茲曲線是三次貝茲曲線函數的簡化形式,當兩個控制點合併為一個控制點時。同樣,您可以使用「Q」函數開始曲線,然後使用「T」函數繼續曲線,鏡像最後一個控制點。

  #  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]
但是,我應該警告您,「T」延續函數實際上只適用於連接等距點的路徑。我不建議使用它。二次曲線的優點是可以替代橢圓弧,因為它使用實際位置而不是弧的半徑。它還可以使弧線偏向一端而不是另一端,而這在使用橢圓弧時是不切實際的。

  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]
在這種情況下,弧線不太均勻,您會得到類似於倒置鯊魚鰭的東西,而不是帆。請記住,二次弧線是拋物線,而橢圓弧線基本上生成圓形線段。這可能是確定應使用哪種類型的弧線段的關鍵。有關此路徑函數的更多示例,請參見SVG:二次貝茲曲線命令

繪圖表面的扭曲

除了這些功能之外,繪製物件的繪圖表面還可以透過各種方式扭曲,讓您做出驚人的效果。首先,您可以套用一些通用的繪圖表面修改,例如... 'translate'、'rotate'、'scale'、'skewX'、'skewY' 和 'affine'。例如,給定一個線條的 'path',我們可以將繪圖表面的原點或 0,0 點「平移」到另一個位置。

  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]
請注意,繪圖區域的 '0,0' 或原點現在位於影像的中心,但 Y 軸在影像頂部為負值,底部為正值。「rotate」操作會旋轉繪圖表面,因此之後在該表面上繪製的任何內容都會旋轉繪製。當然,它會圍繞平移後的原點旋轉,因此最好同時使用兩個變換運算子。

  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」會圍繞原點放大和縮小繪圖表面。

  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]
scale」的一個常見用途是翻轉 Y 軸,使正 Y 值向上。當然,也應該將原點移動到中心或左下角,以保持順序。

  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]
最後,「skewX」和「skewY」會沿 X 和 Y 方向剪切影像。例如,在這裡我們使用「skewX」來賦予影像的垂直 Y 軸一個傾斜度。

  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]
這些運算子在 MVG "-draw" 字串之外也有等效的運算子,供一般用途使用。但是,這些命令列版本是運算子,會立即套用於記憶體中已存在的影像,而不是僅套用於尚未繪製向量物件的繪圖表面。有關更多詳細資訊,請參閱扭曲影像

繪圖表面的仿射扭曲

以上五種畫布變換都可以組合成一個通用的仿射矩陣運算子。可以使用 MVG 基元 'affine' 或在呼叫 "-draw" 之前使用 "-affine" 設定仿射變換。仿射變換使用一組「矩陣係數」來定義如何將您提供的座標修改為實際的繪圖座標。有關這些「係數」實際工作原理的更多詳細資訊,請參閱仿射矩陣變換。例如... 若只要設定繪製物件時的相對中心原點...

  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]
翻轉影像...

  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]
圍繞原點旋轉 30 度...

  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]
對於更複雜的仿射變換,您可以使用為此目的建立的仿射輔助指令碼。這些指令碼會將旋轉角度和中心點等內容轉換為仿射座標,您可以在 "-draw affine" 或 "-affine" 設定中直接使用這些座標。

推送/彈出上下文

某些 MVG 基元實際上依賴於這些變換的使用才能正常使用。例如,橢圓基元只能使用正交對齊的軸直接指定。

  magick -size 100x60 xc:skyblue -fill white -stroke black \
          -draw "ellipse 50,30 30,15 0,360"   ellipse_orthogonal.gif
[IM Output]
但是,透過使用繪圖變換,我們可以輕鬆地為橢圓新增「旋轉角度」。

  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]
請注意,在套用旋轉之前,橢圓的「中心」(旋轉點)會先被平移。「ellipse」接著會繪製在「0,0」的平移位置。以上也顯示了兩個新的 MVG 繪圖基本元素。「push graphic-context」和「pop graphic-context」。雖然在上面的範例中並不需要使用它們,但在進行主要的繪圖轉換時,建議使用它們。「push」和「pop」基本元素的作用是儲存目前的繪圖狀態或「繪圖上下文」,然後在其後恢復它。在這兩個基本元素之間變更的任何繪圖設定都會被遺忘。這包括表面扭曲,例如「translate」和「rotate」,以及顏色設定「fill」和「stroke」,或任何其他修改繪圖「狀態」的設定。這些基本元素可以輕鬆地繪製具有許多轉換的非常複雜的物件,然後將事物恢復到更「正常」的情況,以便稍後進行繪圖操作。您可以在下面的繪製箭頭中看到更實際的演示。

推入/彈出特殊物件

建構中
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/

讀取 MVG 檔案

如您在上述範例中所見,MVG "-draw" 參數可能會變得非常長。事實上,SVG 轉換為 MVG 時,可能會產生一些極長的 MVG 繪圖參數(見下文)。但是,IM 的通用命令列介面允許您使用「@filename」參數從檔案中讀取任何字串參數。這很方便,因為這表示您可以從另一個檔案中讀取非常長且複雜的 MVG 繪圖命令。例如,如果我將 MVG 操作放入名為「draw_circles.mvg」的檔案中,則可以像這樣繪製它...

  magick -size 100x60 xc:skyblue  -draw @mvg_circles.mvg  mvg_draw.gif
[IM Output] ==> [IM Output]
不僅如此,ImageMagick 還可以直接讀取「MVG:」影像檔案格式,讓您可以更直接地繪製這些命令。但是,除非 MVG 檔案定義了畫布,否則您可能需要為它指定初始畫布(「-size」和「-background」)以供繪製。

  magick -size 100x60  -background limegreen  mvg_circles.mvg  mvg_file.gif
[IM Output] ==> [IM Output]
您可以透過將「viewbox」新增到 MVG 檔案中,並使用適當的背景顏色填充繪製,將初始畫布設定移動到 MVG 影像中。這樣就完成了作為完整影像定義的 MVG 影像檔案。

  magick   mvg_circles2.mvg    mvg_image.gif
[IM Output] ==> [IM Output]
目前只有一種方法可以從 MVG 參數字串內讀取外部 MVG 檔案,那就是使用「image」繪圖基本元素。不幸的是,這會在將影像疊加到繪圖表面之前,將 MVG include 轉換為點陣圖。

換句話說,目前沒有 MVG 的「include」函數。
:-(
建構中
You can generate the low level draw operations of IM, using the "+render" to record them. 

When you then give a "-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" below.

MVG Alpha 合成

建構中
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!

繪製符號

有時,您在影像上有一組點,您想在這些點上繪製參考符號,例如十字、圓圈等... 不幸的是,目前 IM 沒有可以輕鬆繪製這些符號的命令,但是只要稍微多花點心思,您就可以繪製這些符號。

符號繪製技巧

繪製給定位置列表中多個符號的訣竅是使用 shell 指令碼或您正在使用的任何 API 產生 MVG 繪圖命令,以便將給定的點集轉換為適當的繪圖命令集。例如,在這裡,我將一條線的點變成每個點上的「加號」...

  # 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]
以上程式碼使用 "tr" 將每個點(兩個數字)分隔成每行一個點,然後使用 "awk" 進行繪製「加號」所需的所有數學計算。您可以使用任何您喜歡的方式,因為我只是在輸入點列表上應用一種文字巨集展開的形式。幾乎任何程式語言都可以做到這一點。對於上述的 shell 腳本案例,我只是發現 "awk" 是最簡單、最快的方法。實際上,您甚至可以使用 Imagemagick 本身使用 "magick" 格式選項來完成「巨集」展開... 例如,在這裡我使用它來計算圓周上的一個點,用於此「點符號」。

  # 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]
現在,您生成的繪製字串可能會變得相當長,並且可能會開始導致最終命令的長度出現問題。因此,您可以將繪製命令作為檔案傳送到 IM,而不是將點轉換成長字串,然後在命令列上传遞給 IM。這次我也使用 SVG 路徑 繪製方法,而不是 繪製圖元 繪製方法。此外,我生成的符號是每個點周圍的三角形。

  # 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]
SVG 路徑 實際上使這更容易,它允許相對像素移動,允許您設計符號,使其只需要一個初始絕對移動 'M',然後給出繪製符號的「移動」和「線條」序列。正因為如此,您實際上根本不需要任何浮點計算,因為 IM 繪製將會進行所需的定位數學計算。
相對移動 SVG 路徑 項目 'm' 在 IM v6.4.3-5 之前被破壞。如果您的 IM 版本早於此版本,則以上(和下一個)範例可能無法繪製任何內容。您可以透過將上述內容中的相對移動 'm' 替換為適當的相對線條序列 'l' 來修復舊版本的此問題。
現在,您可以更進一步,將完整形成的 MVG 檔案(包含繪圖畫布規格)直接作為繪製命令的管道饋送到 IM 中。這次我們來製作一個「十字」,它類似於上面第一個需要大量計算的「加號」範例。

  # 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]
這使用了特殊的 shell 程式設計技巧,其中 shell 括號內「回應」的所有內容都將作為 MVG 檔案饋送到最終的 "magick" 命令中。第一個 'echo' 定義並填充圖像的繪圖畫布,而 'while' 循環則將給定的每個「點」轉換為給定半徑的圓形。這種方法的優點是,您不會遇到使用其他兩種方法時可能遇到的任何字串限制。您可以生成的其它符號包括方框、菱形、誤差線等...另請參閱下面的「繪製圓形」,了解其他圓形方法,包括無需計算的相對「路徑」圓形繪製。

繪製符號的替代方案

除了直接繪製符號之外,還有其他方法可以將符號添加到圖像中。

符號字體

您可以從 符號字體 中提取符號,並將其保存為小型點陣圖。您也可以使用預先定義的小型彩色圖像。然而,這在精確定位字體相對於特定像素的位置時可能會遇到問題。也就是說,它不是一種非常精確的技術。但您可以在任何像素位置組合任何圖像。例如,這些符號是從許多字體中提取的,用於這些範例頁面中的特定用途。
<=  =>  x  +  +  +  o  o  o  o
關於將圖像合成到較大背景的範例,請參閱有關 圖層圖像 的章節。但是,循環方法可能更有用,例如 圖層圖像的程式設計定位 中給出的方法。*未來:使用坐標對圖像進行分層的範例*

形態學

另一種方法是使用 形態學,使用特殊的「形狀」核心,例如「圓盤」和「」和「加號」,甚至您自己的 使用者定義核心 來「擴張」單個像素。例如...

  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]
然後可以使用Alpha 形狀運算器將結果直接轉換為彩色覆蓋。這樣做最大的好處是您實際上不需要知道每個符號的個別位置。或者有多少個符號。但這也可能是一個缺點。一個主要的缺點是位置只能在整數位置。您不能使用浮點「次像素」定位進行「繪製」。

捲積

一個幾乎相同的技術是使用經過特殊設計的內核的「捲積」,它允許您設置各種灰度,而不僅僅像上面那樣簡單的開/關結果。通過對圖像的每個通道(紅色、綠色、藍色和 Alpha)使用不同的用戶定義內核,甚至可以從每個像素坐標創建多色符號。[IM 輸出] 為此,我使用了一個特殊的腳本「image2kernel」,我編寫了將彩色圖像(見右圖)轉換成每個通道的單獨浮點捲積內核。

  image2kernel -q marker.png marker.dat
這會生成四個文件,例如「marker_R.dat」,每個文件對應非常小的輸入圖像的一個通道。這些文件是圖像的用戶定義表示(原點位於圖像中心)。現在,使用這些內核數據文件,我們可以將這些單個點捲積成我們在透明背景上的彩色標記圖像。

  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]
在 IM v6.7.6-9 之前,組合運算器要求圖像的透明度通道以「不透明度」值而不是 Alpha 值給出,因此需要對創建的 Alpha 通道進行反轉。例如

  ... "`cat marker_A.dat`" -negate \) \
應該只使用小圖像,像素點之間的間距要足夠大,以使符號不重疊。這是因為捲積會將重疊區域加在一起,使其比預期的更亮。以上內容已轉換為 UNIX shell 腳本「convolve_image」,以便於使用。

  convolve_image  points_pixels.gif marker.png   point_markers.png
這種技術源於 IM 論壇上的一次討論IM 的有趣體驗。用戶希望將小人放置在足球場的背景圖像上,以便他們的位置在圖片中拼出一個人的名字。

分層

一種不同的技術,例如圖像層,使用從源圖像中提取的像素列表進行定位,可能是更好的方法。您可以先覆蓋較遠的符號圖像,然後再覆蓋前景圖像,並且可以通過編程方式選擇或隨機選擇哪些符號替換哪些點。有關示例,請參見地圖上的圖釘

繪製圓形

繪製選項為您提供了一些執行非常基本操作的方法……繪製圓圈。例如,您可以通過圓周上的任何一點繪製一個圓圈。因此,您需要計算一個中心點和另一個點,該點距離第一個點的半徑(例如 25 個像素)。

  magick -size 100x60 xc:  -stroke Firebrick  -fill tomato  -strokewidth 2 \
          -draw 'circle 50,30 50,55'    circle_circle.gif
[IM Output]
Fred Weinhaus指出,通過使用平移,您可以無需計算圓邊坐標,而可以直接給出半徑。

  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]
但是,在繪製多個圓時,以上操作需要為每個圓執行單獨的「-draw」操作,或者使用上下文推送。使用橢圓,您可以直接將半徑指定為軸長

  magick -size 100x60 xc:  -stroke Sienna  -fill Wheat  -strokewidth 2 \
          -draw 'ellipse 50,30 25,25 0,360'    circle_ellipse.gif
[IM Output]
您也可以通過繪製一條非常短的「stroke-linecap round」線來生成圓形。然後,筆劃寬度設置圓的直徑。請注意,線條必須有一定的長度(無論多短),否則繪製將不會繪製任何內容。

  magick -size 100x60 xc:  -stroke Blue  -strokewidth 50 \
          -draw 'stroke-linecap round line 50,30 50,30.0001' \
          circle_line.gif
[IM Output]
遺憾的是,這種技術無法勾勒出生成的圓形,但對於覆蓋大面積,較大的筆劃寬度可能很有用。請參閱下面的一些簡單示例。此方法利用了SVG 路徑繪製方法,因此可以在無需計算任何額外坐標的情況下繪製圓形。

  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]
只需要使用初始的絕對移動指令 'M' 來定義圓心,後續路徑組件中的 '25' 和 '50' 分別定義相對於此圓心的圓半徑和直徑。
在 IM v6.4.3-5 之前的版本中,相對移動 SVG 路徑 項目 'm' 會被斷開。如果您的 IM 版本早於此版本,則圓形可能只會顯示為單個像素。您可以通過將上述內容中的 'm' 替換為 'l' 來修復舊版本的這個問題。
Fred Weinhaus 添加了以下貝茲曲線圓的方法。它非常接近真正的圓形(儘管不完全相同),並且需要進行浮點計算。

  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]
如果繪製精確的圓形並不重要,您可以使用這個 4 個貝茲曲線段的 SVG 路徑,它僅使用圓形的 X 和 Y 邊界進行計算。

  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]
如果您喜歡完全相對於中心起點繪製的圓形,則可以使用這種技術。它只使用半徑值,這使得生成變得簡單,只需在 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]
您還能想到其他繪製圓形的方法嗎?

繪製箭頭-- 定位、旋轉和縮放符號

使用上述技術,您可以創建特殊的符號,例如箭頭,您可以將其定位在其點位於線條的最末端,並在其上繪製。如果您在線條之後繪製箭頭(典型情況),則箭頭將繪製在線條的頂部。但是,可以定義三種類型的箭頭,並且每種類型根據其用途以不同的方式定義。
  • 測量,您只需在線條的兩端標記一個箭頭,以指示某些工程圖中測量的界限。非常簡單。
  • 向量,顯示某些值的方向和強度。
    例如,在天氣風力圖中。需要一個箭尾,並且 0,0 點是箭尾的末端。通常會創建這樣一個大型的向量網格。
  • 指示器,用於指出某些細節。
    為此,0,0 點可能應該是箭頭的尖端,或者距離箭頭本身一定距離的位置。

測量箭頭

在線條的末端添加一個箭頭相對容易做到。您基本上創建一個「箭頭」符號,並將其繪製在正確的位置。例如...

  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]
請注意,我繪製符號時,其起點是線條的最末端。這樣,它可以在先前繪製的線條之上向後繪製,從而形成一個非常漂亮且整潔的符號。但是,箭頭具有方向性。您可以創建大量不同角度的箭頭定義,許多程序都這樣做。但是由於箭頭是一個向量,所以為什麼不將箭頭作為向量旋轉呢?IM 繪圖命令具有內置的繪圖旋轉功能(畫布扭曲),所以讓我們使用它們。這還有一個優點,即將位置從箭頭的 'path' 定義中移出,允許您將整個路徑指定為「常量」...

  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]
如果您想更改箭頭的大小,請在旋轉後添加「縮放」繪圖選項。

  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]
請注意它是如何放大箭頭的,同時保持箭頭的「尖端」在您指定的位置。這是處理箭頭時一個非常重要的方面,因為只有線條的終點和角度才是重要的,而您要在該線條上添加箭頭。 「變換」的順序很重要,實際上與它們實際執行的順序相反。也就是說,首先將縮放應用於坐標,然後旋轉,然後平移。如果坐標變換不是按該順序完成的,我們最終也會縮放箭頭的最終位置,並且它不會在我們期望的位置。此外,由於縮放有兩個數字,並且原始箭頭符號是水平設計的(角度為零),因此您可以單獨縮放箭頭的寬度和高度。另請注意筆劃寬度是如何隨著箭頭大小縮放的,從而保持事物的一致性。

  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]
現在,當您扭曲畫布以繪製單個箭頭時(可能還有許多其他繪圖操作),您可能希望在一項「-draw」操作中完成所有操作。例如,繪製線條,然後在兩端添加箭頭,這需要不同的顏色、位置、旋轉,甚至可能需要不同的比例。這意味著我們需要將畫布扭曲的範圍限制在每個箭頭的繪製範圍內。如果您不限制範圍,您可能會開始影響後面的其他繪圖操作,並且永遠無法確定您正在生成什麼。要限制扭曲的範圍(以及所有其他繪圖屬性),您可以將涉及的部分包裝在「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]
push」本質上是將當前所有繪圖屬性保存起來以供將來使用,而「pop」則恢復這些屬性,並用先前保存的設置(顏色、扭曲、位置等)替換任何設置。這意味著在「彈出」後,「畫布扭曲」被取消,並且繪製返回到修改前的狀態。上述技術只是生成箭頭的一種方法,當繪製箭頭作為測量距離的一部分時,例如在技術圖紙中,這是一種很好的方法。

向量箭頭

如前所述,向量顯示了某個值的 direção 和強度。這意味著箭頭的長度是可變的,並且箭頭可以位於距離向量起點的任何位置。現在,您可以進行一些繁重的數學運算來計算給定向量長度和角度的情況下箭頭應放置的位置,但還有一種更好的方法,即讓 ImageMagick 為您完成這些計算。解決方案是在扭曲畫布空間中繪製一條具有正確長度的水平線作為向量的長度。繪製該線後,只需將繪圖空間再次平移到線的末端,同時畫布保持「扭曲」狀態。現在您已正確定位,並進行了正確的旋轉,可以像往常一樣繪製向量的「箭頭」。例如,這裡我生成了一個 70 像素長、角度為 -35 度的向量。

  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]

指示器箭頭

在上面,我還演示了一個指示箭頭,指向先前向量箭頭的起點。但是,我沒有像以前那樣繪製箭頭,而是創建了一個反轉的箭頭符號,它從距離原點(或起點)10 個像素處開始。也就是說,符號位於我要指示的位置,因此我實際上不希望箭頭直接位於該位置的頂部,而是希望它稍微偏離一點。現在,雖然指示器比向量更容易處理,通常不需要可變長度,但您通常希望在指示器的最末端添加文本以指定指示的內容。和以前一樣,計算該位置可能很困難,所以何必呢。定位文本的解決方案也與向量相同。保留用於繪製指示箭頭的原始扭曲空間,並將原點平移到該箭頭的尾端(在扭曲空間中水平方向為 40 個像素)。現在我們已經重新定位了事物,我們可以取消圍繞該新位置的扭曲旋轉,因此您可以正常繪製文本(稍微偏移)。不幸的是,雖然「左對齊」的默認文本對齊方式在上面有效,但您目前無法在 MVG 中將文本對齊方式指定為與重力分開的設置。如果這是一個問題,請在 IM 错误论坛上提出請求,希望文本對齊方式(與重力定位分開)將成為現實,特別是因為它實際上是 SVG 规范的一部分。

繪製物件

寬度色彩筆畫

您不必用路徑或輪廓完全包圍填充區域來創建各種形狀。使用非常大且寬的筆劃,您可以在畫布上生成大面積的色塊。
例如,一條寬筆劃的橢圓弧可以生成一個漂亮的顏色區域,我實際上已經看到它用於創建海報。

  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]
或者你可以生成一個相當複雜的小丑笑容。

  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]
你能想出什麼?讓我們知道。

圓柱體

IM 論壇討論中,有一個關於使用 ImageMagick draw 命令繪製圓柱體,特別是著色圓柱體的熱烈討論。繪製圓柱體的技巧是以這樣一種方式繪製「roundrectangle」基元,使其末端形成橢圓形。也就是說,如果圓柱體的寬度為 50 個像素,則分別以 25 個像素和 12 個像素對矩形的角進行圓角處理。也就是說,矩形寬度的一半,然後再減半。因此,圓柱體變成了僅在彼此之上繪製的兩個圓角矩形。第二個較淺的顏色填充「端橢圓」的大小正好是兩個角尺寸的兩倍。例如...

  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]
通過用漸變陰影替換第一種填充顏色(使用內存平鋪技術),您可以使圓柱體看起來更像 3D...

  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]
通過慢慢完善圓柱體繪製(如 IM 論壇中所討論的),您可以通過很長的路徑來生成非常複雜且視覺上吸引人的圓柱體。這包括添加封閉的半透明玻璃圓柱體、陰影效果和標籤。該討論的最終結果是一個腳本「cylinder_bar」,生成一個圓柱百分比條...

  cylinder_bar 95 cylinder_95.png
[IM Output]
該腳本可以生成任何大小的圖像,根據該大小和在腳本頂部定義的其他設置適當地調整所有參數。它還包括「玻璃厚度」的概念,以在封閉的半透明玻璃圓柱體和其中的彩色圓柱體之間創建間隙。請注意圓柱體非常細微的陰影,尤其是當綠色圓柱體的末端與玻璃圓柱體的末端重疊時!只需稍微考慮一下,您就能做到這一點,真是太神奇了。

在文本字符串中繪製特殊字符

使用引號還是反斜線?

使用者在使用 -draw 時遇到的最大問題之一,是如何繪製同時對 UNIX shell 和 DOS 命令列,甚至是 C、Perl、PHP、R 或 Visual Basic 等其他語言具有特殊意義的字元。在這方面,最大的罪魁禍首是兩種引號字元,以及像美元符號「$」這樣的變數替換字元,還有 shell 和 ImageMagick 的跳脫字元,反斜線「\」。基本上,由於「-draw」的 MVG 參數需要用引號括起來,*而且* 其中的「text」字串參數也可能需要一些額外的引號。為了要解決這個問題,使用者通常會使用兩種不同的引號字元,一種用於 shell,另一種用於 MVG 文字字串。
-draw '... text 0,0 "string" ...'
請注意,這是 Windows 使用者唯一真正的選擇,它有自己的引號問題和方法。或者,他們會交換引號,並使用...

  -draw "... text 0,0 'string' ..."
這讓您可以在不使用跳脫字元的情況下包含 shell 變數替換(使用「$」)。選擇正確的形式將可以解決大多數問題,但有些字元仍然會造成困難,而且每個解決方案都取決於您使用的引號集,因為它們也定義了應如何跳脫特殊字元。以下是引號的四種情況,以及特殊字元的處理方式...
  • 對 shell 參數使用單引號,
    對 MVG 文字字串使用雙引號。處理繪製文字字串最簡單的技巧是,對包裝 shell 參數使用單引號。然而,這表示若要包含撇號在繪製的字串中,您需要離開 shell 的「單引號模式」,並在 shell 單引號之外提供該撇號。例如,以下是處理我提到的四個特殊字元的方法。
    
      magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw 'text 0,0 "  '\''  \"  $  \\  " ' \
              -trim +repage  text_special_sd.gif
    
    [IM Output]
    請注意,由於不需要跳脫美元符號,因此您也不能使用它來替換 shell 變數的內容。請務必記住,反斜線是 IM 繪製字串唯一會處理的特殊字元。此外,它之所以存在,純粹是為了讓您能夠跳脫任何「IM 繪製字串引號」,例如我們上面用於雙引號的引號。除此之外,所有其他奇怪的現象都是由 UNIX 命令列 shell 造成的,而不是 IM。PC-DOS 有其自身的奇怪之處,如果您能提供從環境中使用 IM 時跳脫特殊字元的相關資訊,我將不勝感激。
  • 對 shell 參數使用雙引號,
    對 MVG 文字字串使用單引號。如果您確實想要將「shell 變數」插入繪製的字串中,則必須對外部 shell 參數使用雙引號。這使得整個事情變得更加複雜,因為您失去了 shell 的保護,而且您現在不僅必須跳脫美元符號「$」,還必須跳脫反斜線「\」。另一方面,shell 就不需要使用單引號字元作為其參數結尾分隔字元,因此這方面就簡化了。讓我們總結一下我們簡短的特殊字元清單的結果。
    
      magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw "text 0,0 '  \\'  \"  \$  \\\\  ' " \
              -trim +repage  text_special_ds.gif
    
    [IM Output]
    請注意,如果您想要繪製反斜線本身,MVG 文字字串需要將反斜線加倍(如上一個範例所示),但 shell 本身也需要將每個反斜線加倍,總共需要四個反斜線才能產生一個這樣的字元。這種加倍很快就會變得難以應付且令人困惑,需要大量的反斜線才能達到您想要的效果。只要慢慢來,您就會找到適合您情況的方法。
  • 對 shell 參數使用單引號,
    對 MVG 文字字串使用單引號。讓我們總結一下最後兩種引號組合來結束這個主題。我將讓您自己去弄清楚 shell 和 MVG 如何解碼它們。
    
      magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw 'text 0,0 '\''  \'\''  "  $  \\  '\'' ' \
              -trim +repage  text_special_ss.gif
    
    [IM Output]
  • 對 shell 參數使用雙引號,
    對 MVG 文字字串使用雙引號。
    
      magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw "text 0,0 \"  '  \\\"  \$  \\\\  \"" \
              -trim +repage  text_special_dd.gif
    
    [IM Output]
如您所見,從命令列中使用「-draw」參數時,必須同時處理命令列 shell 的跳脫字元,以及 MVG 文字字串中的反斜線和引號跳脫。結果可能會造成混淆和棘手。只要記住,shell 會區分兩種引號的處理方式,而 MVG 文字字串則不會。當然,在複雜的腳本中,更好的方法可能是完全避免使用 shell 和任何腳本問題。您可以透過從 MVG 繪圖檔案中讀取「-draw」參數來達成此目的。
-draw @drawfile.mvg
當然,您仍然需要對使用的任何引號字元以及文字中的任何反斜線進行反斜線跳脫。然而,這比同時處理 shell 自己的引號和跳脫系統以及 IM 的系統要簡單得多。

  magick -size 500x50 xc:lightblue  -font Candice -pointsize 36 \
          -gravity center     -draw @text_quotes.mvg      text_quotes.gif
[IM Output]
==> [IM Output]
第一個影像是來自我使用的其中一個「MVG」文字檔案。它不包含 shell 跳脫字元或引號。因此,只存在 MVG 引號和跳脫字元。請注意,在上述範例中,如果我對 MVG 文字字串使用單引號,則唯一的變化是我需要對字串中的單引號字元進行反斜線跳脫,而不是雙引號字元。關於百分比符號 最後一點關於「-draw 文字」運算子中的特殊「跳脫」字元。百分比符號「%」應該「照原樣」繪製。您不需要執行任何特殊操作即可繪製它們。如果它們沒有「照原樣」繪製,則表示您使用的是舊版的 IM,應該盡快升級。
在 IM 6.2.4 版之前,百分比符號「%」被用作跳脫字元,以便在繪製的文字字串中包含額外的影像資訊。由於當 SVG 影像也嘗試繪製百分比符號時,這種跳脫方式會造成混淆且不正確,因此現在已不再使用。
這種使用百分比「跳脫字元」(以及「\n」換行跳脫字元)的方式被認為與「-draw」運算子和 MVG 格式處理 SVG 影像格式的預期用途不相容。因此,從 IM 6.2.4 版開始,百分比跳脫字元不再有效,而反斜線只會跳脫自身和周圍的引號。

    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]
如需「百分比錯誤」的更多詳細資訊,以及在舊版 ImageMagick 中使用「-draw」時避免此錯誤的方法,請參閱繪製百分比錯誤頁面。使用註釋取代繪製 避免這些問題的更好方法是使用「-annotate」來繪製文字,而不是使用「draw」。這個運算子是「draw」運算子的包裝器,允許使用「draw」的所有功能,但形式更簡單。基本上,這個運算子只需要一組引號(用於 shell)。這使得處理特殊字元變得更加簡單。遺憾的是,雖然您不再需要為 IM 跳脫引號,但您現在必須處理百分比跳脫字元,例如「@」檔案讀取、「\n」換行和其他百分比跳脫字元展開。例如,使用單引號...

    magick -size 200x50 xc:none  -box white  -pointsize 20 -gravity center \
            -annotate 0 '\@  '\''  "  $  \\  %% ' \
            -trim +repage  annotate_s.gif
[IM Output]
以及使用雙引號...

    magick -size 200x50 xc:none -box white -pointsize 20 -gravity center \
            -annotate 0 "\@  '  \"  \$  \\\\  %% " \
            -trim +repage  annotate_d.gif
[IM Output]
但是,如果您使用「@」跳脫字元從檔案中讀取字串,則所有註釋引號和跳脫字元都將被完全忽略。例如,這裡我們包含了有關影像寬度和高度的資訊!

    magick -size 200x50 xc:none -box white -pointsize 20 -gravity center \
            -annotate 0 '%w\n%h' -trim +repage    annotate_percents.gif
[IM Output]
但是,當從檔案中讀取註釋字串時,所有跳脫字元都將被完全忽略。

    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]
如需更多資訊,請參閱註釋文字繪製運算子,特別是註釋跳脫字元

IM 和 SVG 處理

SVG 輸入驅動程式:RSVG 與 MSVG

處理實際的 SVG 影像格式是一件非常複雜的事情。引擎需要處理其所有方面,如 SVG - 可縮放向量圖形 文件中所定義。這需要大量的程式設計工作和時間。因此,ImageMagick 在處理 SVG 格式影像時提供了兩種方法。第一種是使用開源的 RSVG 函式庫,將 SVG 格式轉換為 IM 可以輕鬆處理的點陣圖。這個引擎幾乎可以處理 SVG 的所有方面。第二種方法是讓 IM 嘗試使用內建的 MSVG 方法將 SVG 轉換為 MVG。MSVG 嘗試將 SVG 影像轉換為 IM "-draw" 運算元的 "MVG" 繪圖語言。繪製 MVG 的許多功能都是專門為此目的而創建的。不幸的是,雖然基本的線條繪製和著色都存在,但它遠非一個完整的 SVG 轉換器。您可以使用特殊的輸入格式「MSVG:」(IM v6.3.4 中添加)讀取 SVG 影像,強制使用內部的 MSVG 轉換器。但是,如果存在 RSVG 函式庫,大多數 ImageMagick 將會使用它來渲染 SVG 影像。要了解您的 IM 將會執行什麼操作,請使用...

  magick -list format | grep SVG
[IM Text]
如您在括號中的「RSVG」所見,我自己的 IM 將使用電腦上安裝的指定版本的 RSVG 函式庫。
在這裡,我「繪製」了一個小型的、手工製作的 SVG 影像「diagonal.svg」(由論壇使用者 penciledin 提供),它在白色背景上創建了一個帶有簡單對角線漸層的矩形。

  magick diagonal.svg  diagonal_rsvg.gif
[IM Output]
完美。產生了正確的對角線漸層。
但是,如果您使用內部的 MSVG(如果沒有 RSVG 函式庫,則為預設值)渲染它...

  magick msvg:diagonal.svg  diagonal_msvg.gif
[IM Output]
如您所見,內部的 MSVG 轉換失敗,返回的是垂直漸層而不是對角線漸層。您還可以通過將 SVG 直接轉換為 MVG 文件來查看 IM 生成的實際 MVG 命令。
[IM Text]

  magick msvg:diagonal.svg mvg:diagonal.mvg
[IM Text]
您可能可以看到 MSVG 轉換器如何嘗試將 SVG 轉換為 MVG 繪圖命令。目前已知內部 MSVG 無法處理的事情包括...
  • 非垂直漸層(未轉換為新的 MVG 漸層處理)
  • 沿曲線路徑的文字
  • 文字對齊(與重力分開)
但是,大多數基本的繪圖動作都可以處理。還要記住,MVG 語言實際上可以處理 SVG 無法處理的事情,包括使用重力來定位影像和文字。重力不是 SVG 規範的一部分,但它是 IM 文字和字體處理中不可或缺的一部分。還要記住,MVG 沒有與 SVG 相同的容器機制。內部的 MSVG 轉換器使用圖形上下文的推送和彈出來替換 XML 容器(請參見上面的 MVG 輸出),其效果相同。

SVG 設定

SVG 影像格式是一種向量格式(請參見 關於向量影像格式的說明),因此影像通常沒有預設的「大小」。相反,它是在特定的「-density」(預設解析度為 72 dpi)下「繪製」或「渲染」的,就像 PostScript 一樣。此外,如果 SVG 沒有「繪製」背景,您可以使用「-background」設定來指定要使用的背景顏色。例如,以下是另一個小型 SVG 影像「home.svg」,它使用 3 種不同的解析度和 3 種不同的背景(包括透明背景)進行了「渲染」。

  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]
請注意,我在上面範例中較大的透明背景版本中使用了 PNG 格式的影像。與 GIF 影像格式相比,這會產生更清晰的影像,因為 GIF 影像格式會產生半透明的邊緣像素。當最終影像中涉及透明度時,始終建議使用 PNG。
我發現有些 SVG 圖像無法縮放。也就是說,它們是用「像素」定義的,而不是現實世界的長度,例如「點」、「英吋」或「毫米」。因此,雖然「-density」設定可能會改變整體圖像尺寸(以現實世界的單位表示),但「像素」的大小不會改變,因此圖像本身的大小也不會改變。然而,這樣的 SVG 圖像相當少見。

更糟糕的是,一些 SVG 圖像混合使用了「像素」和「點」作為度量單位,除非作者是故意這樣做的,否則當您嘗試以與作者預期不同的密度使用它時,可能會遇到很大的麻煩。幸運的是,這些情況更加罕見。

一個簡單的解決方法通常是將 SVG 中的所有「像素」單位更改為「點」,但不應該盲目地這樣做,以防萬一使用「像素」是有意為之。

SVG 輸出處理

從 IM v6.4.2 版本開始,IM 可以將任何點陣圖圖像轉換為 SVG 向量圖形!轉換並不總是成功的,但較大或較簡單的圖像(例如點陣圖遮罩)的轉換效果非常好。例如,在這裡我將一個糟糕的點陣圖形狀轉換為 SVG 圖像,然後再將其轉換回來,以便將點陣圖平滑為適當的反鋸齒形狀。

  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]
然而,要使其正常工作,必須安裝「開發中」的「AutoTrace」程式庫,並使用「--with-autotrace」開關配置 IM。如果沒有安裝「AutoTrace」程式庫並將其編譯到 IM 中,則生成的 SVG 輸出將是大量的單像素圓圈,生成二進制結果,而不是平滑的 SVG 輪廓圖像。這樣的圖像相比較而言非常巨大,而且 SVG 渲染通常需要很長時間才能完成。實際上需要一種更好的預設點陣圖轉向量技術,可能使用形態骨架化和 MAT 技術。曾經有一個「autotrace:' 輸入委託,用於「平滑輸入點陣圖圖像」,它使用「autotrace」命令一次性完成上述所有步驟。然而,我上次查看時,這個委託已經消失了。以下是它的使用方法...

  magick autotrace:A.gif  A_traced.png
[IM Output]
當然,這不會讓您獲得「autotrace」命令的 SVG 輸出,而只是通過 SVG 過濾輸入圖像以使其平滑。或者,您可以直接使用「autotrace」命令,如示例 點陣圖轉向量邊緣化使用 Autotrace 進行骨架化 中所示。您可能還想看看 cancerberosgx生成 SVG 圖像 中的結果,他研究了轉換照片的解決方案。

非 IM 向量圖形編輯器

ImageMagick 是一個像素陣列處理器,它通常不會保存向量圖像(「MVG」是唯一的例外),而只會讀取它們並將它們轉換為像素陣列。其他像素圖像編輯器也是如此,例如 Gimp、Photoshop 等等。要編輯和處理基於向量的圖像,請使用以下程式:
Sodipodi  基於 SVG 的向量圖形編輯器
Xfig 簡單但非常好的向量對象編輯器
(非常適合標誌、地圖和在頁面上排列照片)
Dia
AutoTrace 將點陣圖陣列中的形狀轉換為向量輪廓
Sketch 基於 Python 的向量編輯器,具有彎曲文字功能。
當然,這不是一個完整的列表。即使是許多文字處理器,例如 OpenOffice、Word 和 TeX,通常也都有各種簡單但通常難以使用的對象編輯器。但是,對於將向量圖形格式轉換為不同的向量圖形格式,請勿使用 ImageMagick。ImageMagick 過去、現在和將來都只是一個點陣圖像或點陣圖圖形轉換器和處理器。有關更多信息,請參見 關於向量圖像格式的說明