⚠️ Ini adalah situs terjemahan tidak resmi dan tidak berafiliasi dengan ImageMagick Studio LLC. Untuk informasi resmi, lihat halaman asli (https://usage.imagemagick.org/draw/index.html).

Contoh penggunaan ImageMagick -- menggambar

Menggambar di IM adalah cara untuk menambahkan elemen baru ke gambar yang sudah ada. Banyak hal tentang penggambaran teks sudah dibahas di halaman contoh Efek font gabungan dan Anotasi gambar, jadi halaman ini menangani sisi lain yang lebih umum dari operator "-draw". Perintah draw bermula sebagai sarana untuk membuat gambar sederhana. Namun seiring waktu ia berkembang menjadi antarmuka untuk mengonversi grafik vektor menjadi gambar raster.


Perintah draw ImageMagick Gambar di komputer umumnya disimpan dengan dua cara yang berbeda. Cara pertama dan yang paling umum, yang sudah Anda lihat di sepanjang halaman contoh ini, dikenal sebagai grafik raster. Pada pendekatan ini gambar disimpan sebagai larik piksel berbentuk persegi panjang. Cara yang lain kurang umum dan kurang mudah diubah, tetapi dalam arti lain lebih serbaguna, yaitu grafik vektor berbasis objek. Dalam bentuk ini gambar diuraikan sebagai garis, busur, isian warna, dan kadang kedalaman. Ini berguna karena gambar semacam itu dapat diskalakan ke hampir semua ukuran dan tetap tampil sempurna. Gambar yang sangat besar dan rumit pun dapat diuraikan dalam ruang yang sangat kecil dibandingkan padanannya dalam format raster. Contoh gambar grafik vektor antara lain postscript dan SVG -- Scalable Vector Graphics yang lebih baru. Font True-Type juga termasuk grafik vektor, karena bentuk ini membuat uraian tiap karakter dapat dipakai pada skala berapa pun. Operator gambar "-draw" adalah jendela ke fungsi penggambaran vektor ImageMagick, dan membentuk sekumpulan perintah yang cukup terpisah dari operator gambar baris perintah IM yang biasa. | _Hanya ada sedikit format file grafik vektor yang umum dipakai karena tiap format semacam itu biasanya sangat berbeda dari format lainnya. Akibatnya, hampir tidak ada kemungkinan berbagi kode.

Karena itu, ImageMagick lebih berfokus pada penggunaan grafik vektor untuk menggambar gambar berformat SVG. Grafik postscript dan font true-type diserahkan ke pustaka dan aplikasi 'delegate' eksternal lain yang jauh lebih cocok untuk menggambar format grafik vektor semacam itu.

Bukan berarti delegate untuk SVG tidak tersedia. Salah satu contohnya adalah pustaka RSVG atau pustaka GTK SVG yang tersedia saat kompilasi. IM akan menautkan diri ke pustaka tersebut untuk mengonversi SVG, alih-alih mencoba melakukannya sendiri._

Perintah draw primitif

Mari kita mulai dengan primitif penggambaran yang paling tua, paling sederhana, dan paling umum dari operator gambar "-draw" di antara perintah MVG. Perhatikan bahwa semua argumen diperlakukan sebagai bilangan floating point dan tidak harus bilangan bulat, seperti yang biasa saya pakai pada contoh-contoh ini. |

  # 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]
Kedua metode point ini memberi hasil yang berbeda bila warna semitransparan terlibat, sesuai komentar yang diberikan. Lihat Primitif isian warna di bawah untuk rinciannya. |

  # 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]
Primitif draw 'arc' didaftarkan bersama persegi panjang karena sebenarnya ia hanyalah 'ellipse' yang dipaskan ke dalam 'rectangle' yang ditentukan oleh dua koordinat itu. Busur parsial jarang dipakai karena titik ujungnya sulit ditentukan kecuali sudutnya dibatasi pada kelipatan sembilan puluh derajat.
Primitif 'circle' dan 'ellipse' melibatkan koordinat 'center' beserta koordinat 'edge', atau nilai 'size' dan 'angle', masing-masing. |

  # 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]
Anda mungkin juga ingin melihat Push/Pop konteks untuk contoh cara membuat elips yang diputar. |

  # 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]
Metode yang lebih baik untuk menggambar garis dan kurva adalah menggambar path SVG, yang jauh lebih serbaguna dan bahkan mendukung 'penggambaran garis relatif'. |

  # 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]
Dua operasi bertipe isian terakhir ini untuk saat ini adalah satu-satunya operasi draw yang dipengaruhi oleh "-gravity". Pengubah lain untuk operasi ini antara lain: "-fill", "-tile", "-origin", "-stroke", "-strokewidth", "-font", "-pointsize", "-box", Ada pengubah lain lagi, tetapi semuanya berkaitan dengan bahasa Magick Vector Graphics yang lebih lanjut.

Primitif bezier

Primitif 'bezier' dipakai untuk menggambar kurva. Tiap perintah hanya menggambar satu segmen kurva. Biasanya diberikan 4 titik (8 angka): satu titik awal 'knot', dua titik kendali, dan satu titik akhir 'knot'. Kedua titik kendali menentukan arah dan seberapa cepat kurva menyimpang dari titik 'knot' ujung yang menempel padanya. Agar dua kurva menyambung mulus, titik kendali dari ujung harus dicerminkan melalui 'knot' untuk membentuk titik kendali pada kurva Bezier berikutnya. Sebagai contoh, di sini saya menggambar dua kurva bezier yang menyambung mulus. Perhatikan bagaimana garis dan titik kendali (yang juga digambar) tercermin lurus melalui koordinat sambungan, baik dari sudut maupun panjangnya. Ini penting; kalau tidak, kurvanya tidak akan mulus. |

  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]
Jika saya memindahkan salah satu titik kendali sehingga ia TIDAK 'dicerminkan' melalui 'knot' yang menempel dari titik kendali lain pada 'knot' yang sama, kurvanya menjadi tidak kontinu. |

  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]
Jika titik kendali digeser lagi sampai berimpit dengan titik 'knot' terkait, garisnya akan langsung berangkat dari titik itu tanpa 'kurva' sama sekali. |

  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]
Jika kedua titik kendali disetel ke 'knot' masing-masing, yang dihasilkan adalah garis lurus. |

  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]
Primitif 'bezier' tidak begitu berguna tanpa menentukan keempat titiknya. Hanya titik pertama dan terakhir yang tergolong 'knot', yaitu titik yang dilalui (atau tempat berakhirnya) kurva. Semua titik lain di antaranya dianggap murni sebagai titik kendali, yang memengaruhi kurva sesuai urutan pemberiannya; makin jauh titik kendali itu, makin besar pengaruhnya pada segmen kurva tersebut. |

  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]
Sebaiknya jangan memakai lebih atau kurang dari 4 titik per segmen kurva 'bezier', supaya semuanya tetap sederhana. Sebenarnya saya menyarankan agar primitif 'bezier' tidak dipakai sama sekali; untuk menghasilkan kurva, pakailah Cubic Bezier path SVG. Cara itu punya fungsi penerus kurva 'S' khusus yang secara otomatis melakukan 'pencerminan' titik kendali yang tepat sehingga segmen kurva menyambung mulus, sekaligus mengurangi jumlah titik kendali yang perlu dipakai. Titik juga dapat didefinisikan relatif terhadap titik akhir sebelumnya di dalam path.

Primitif isian warna

Selain primitif 'sederhana' di atas, "-draw" juga menyediakan sekumpulan primitif untuk mengisi atau mengubah warna. Primitif ini mengubah warna di dalam gambar mulai dari titik yang ditentukan, sesuai metode yang dipilih. Metode isian ini sebenarnya bukan perintah 'draw' yang sesungguhnya, melainkan fungsi penggantian warna. Semuanya ditambahkan ke draw karena di situlah tempat termudah untuk menyisipkan operasinya ke ImageMagick pada versi program yang sangat awal. Sama seperti di atas, warna yang dipakai ditentukan lewat pengaturan warna "-fill", tetapi bila disetel, gambar "-tile" yang akan dipakai sebagai gantinya. Opsi pengaturan lain di atas tidak dipakai dan tidak berpengaruh pada operasi ini. Ada dua pengaturan tambahan yang juga berlaku untuk primitif ini, yaitu "-bordercolor" dan faktor "-fuzz". Namun pengaturan tersebut TIDAK dapat didefinisikan di dalam bahasa 'MVG', sehingga hanya bisa disetel sebelum operator "-draw" dipakai. Yang pertama, 'color point', sudah Anda lihat sebagai alternatif primitif draw 'point' pada contoh di atas. Kalau diperhatikan baik-baik, akan tampak satu piksel putih yang kita setel pada gambar uji kita.
|

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

[IM Output]
Namun ketika menggambar warna transparan dan semitransparan, kedua fungsi ini tidak sama. Di sini kita punya gambar merah tiga piksel (diperbesar); pada piksel kedua atau tengah kita memakai fungsi 'point' untuk melukis di atas piksel merah dengan warna biru semitransparan, sehingga hasilnya ungu. Namun jika kita memakai fungsi 'color point' (piksel terakhir atau kanan), warna merahnya diganti sepenuhnya oleh piksel biru semitransparan. Warna itu tidak ditimpakan. |

  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]
Semua fungsi 'color' melakukan penggantian warna secara penuh, sedangkan semua primitif warna lain 'melukis' warna di atas gambar. Karena itu 'color' dapat dipakai untuk menggambar warna transparan. Fungsi draw 'color replace' akan mengganti semua kemunculan warna yang persis sama dengan warna di lokasi yang ditentukan. Dan seperti terlihat, areanya tidak harus tersambung. |

  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]
Namun seperti terlihat pada hasil pertama, sebagian piksel di sepanjang tepi tidak ikut diganti. Piksel-piksel itu warnanya tidak persis sama dengan piksel yang dipilih, jadi diabaikan. Menambahkan faktor fuzz kecil akan menyertakan pula warna-warna yang mirip dengan warna aslinya, seperti pada contoh kedua di atas. Tentu saja 'faktor fuzz' bukan solusi yang bagus, karena tidak semua piksel tepi semacam itu tertangkap. Ini masalah yang berulang pada semua metode 'isian warna' ini, dan belum ada solusi umumnya. Bila yang ingin diganti adalah warna tertentu yang sudah diketahui, bukan warna yang diambil dari gambar itu sendiri, operator gambar "-opaque" bisa dipakai sebagai gantinya. Fungsi ini juga memakai pengaturan faktor "-fuzz" untuk memperlebar rentang warna yang cocok dengan warna yang diberikan. Metode 'floodfill' juga cukup sederhana karena ia hanya mengisi seluruh area di sekitar titik yang dipilih dan tidak memilih area lain berwarna mirip yang tidak tersambung. Area yang diisi juga dapat diperluas dengan "-fuzz" agar warna-warna mirip ikut tercakup. Dalam hal ini kita memilih nilai yang cukup tinggi sehingga batas garis silangnya pun ikut tercakup, sehingga flood fill 'bocor' ke sisi lain gambar. |

  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]
Mengisi area dengan warna secara flood fill bukannya tanpa masalah. Warnanya bisa bocor melewati batas yang tipis, masuk ke area yang tidak diinginkan (lihat GIF di atas pola latar belakang sebagai peragaannya). Atau area yang dipilih bisa saja tidak terisi sampai ke tepinya (lihat Masalah anti-aliasing dan flood fill). Meski begitu, cara ini bekerja. 'filltoborder' mirip 'floodfill', bedanya yang ditentukan adalah warna yang membatasi area yang akan diisi, bukan warna yang akan diganti oleh proses pengisian. Tentu saja faktor fuzz juga disarankan agar 'warna-warna mirip' ikut terpilih sebagai warna batas, sehingga floodfill lebih terbatas. |

  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]
Metode warna draw yang terakhir adalah 'reset', yang cuma mengganti atau mereset seluruh gambar menjadi warna fill. Dalam hal ini piksel yang dipilih sama sekali tidak memengaruhi hasilnya. |

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

[IM Output]
Ini sebenarnya sangat berguna karena memberi satu cara sederhana untuk menghasilkan kanvas berwarna polos (atau gambar yang di-tile) dari gambar yang sudah ada. (Lihat Membuat gambar berukuran sama) untuk cara ini dan cara lain melakukan hal yang sama. FUTURE: Using a "-tile" pattern to fill the area.

Primitif isian alpha

Primitif draw 'alpha' bekerja persis seperti primitif 'color' yang dijelaskan di atas, bedanya ia tidak mengganti warna area yang dipilih, melainkan hanya kanal 'alpha' dari area tersebut. (Artinya, fungsi isian ini hanya menyetel kanal 'alpha'.) Sama seperti fungsi isian 'color', nilai 'alpha' memakai warna fill (kecuali bila "-tile" dipakai sebagai sumber 'nilai alpha'). Di sini kita memakai contoh 'color floodfill' yang sama seperti di atas, tetapi kali ini hanya menyetel kanal alpha agar bagian yang terisi menjadi transparan sepenuhnya. Artinya, warna aslinya masih ada, hanya saja transparan! |

  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]
Fungsi 'alpha reset' juga dapat dipakai untuk membuat seluruh gambar menjadi semitransparan. Tentu saja dalam hal ini kita harus menghasilkan PNG, yang dapat menerima warna semitransparan di dalam gambar. |

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

[IM Output]
Perhatikan bahwa komponen warna 'black' tidak dipakai dalam operasi itu, hanya komponen alpha dari warnanya. Warna asli gambar dibiarkan apa adanya. FUTURE: Using "-tile" pattern for in interesting alpha effect. Baik 'color' maupun 'alpha' adalah fungsi penggantian warna secara penuh, yang selalu menghasilkan penggantian warna bertipe Boolean (ada atau tidak sama sekali). Karena itu tepi area semacam itu akan selalu memperlihatkan efek aliasing. Karena itu pula, keduanya umumnya bukan operator gambar yang baik untuk pengembangan gambar secara umum, kecuali untuk menyetel area transparan gambar GIF (yang juga Boolean). Meski begitu, tidak semuanya sia-sia, seperti terlihat pada contoh Penghapusan latar belakang.


Rincian tentang perintah draw

Koordinat piksel

Perintah "-draw" (dan banyak perintah lain di IM) memakai apa yang disebut "koordinat piksel". Artinya, koordinat '10,10 adalah pusat piksel yang berjarak 10 piksel ke bawah dan ke kanan dari sudut kiri atas. Dalam sistem koordinat ini 0,0 adalah pusat piksel kiri atas, dan w-1,h-1 adalah pusat sudut kanan bawah. Tepi yang sebenarnya terletak di -0.5,-0.5 dan w-0.5,h-0.5, sedangkan piksel tengah (bila ukuran gambarnya ganjil) terletak di '(w-1)/2,(h-1)/2'. Namun ketika gambar diproses secara matematis (misalnya saat memakai distort), piksel yang sebenarnya tidak punya arti, sehingga yang dipakai adalah "koordinat gambar". Dalam sistem ini tepi gambar yang sebenarnya ada di '0,0' dan 'w,h'. Dan pusat gambar (yang belum tentu merupakan pusat sebuah piksel) ada di 'w/2,h/2'. Untuk mengonversi 'koordinat piksel' menjadi koordinat gambar, tambahkan ½. Jadi pusat piksel kiri atas adalah '0.5,0.5' dan piksel kanan bawah adalah 'w-0.5,h-0.5'. Contoh: pusat lingkaran pada gambar kecil

Menggambar dengan koreksi gamma dan ruang warna

Seperti hampir semua operasi ImageMagick, "-draw" adalah operator linear, dan karenanya bekerja di ruang warna RGB linear. Artinya, untuk mendapatkan tepi yang mulus, gambar mungkin perlu dikoreksi gamma-nya sebelum disimpan, supaya tersimpan memakai ruang warna sRGB yang nonlinear (terkoreksi gamma). Misalnya, kalau kita menggambar lingkaran besar lalu langsung menyimpannya... |

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

[IM Output]
Lihat tepi lingkarannya: sebenarnya tidak terlihat mulus. Efek tangganya cukup kentara. Itu karena lingkarannya digambar di ruang warna RGB linear, tetapi gambarnya lalu disimpan seolah-olah benar-benar berada di ruang warna sRGB! Untuk memperbaikinya, kita perlu menambahkan koreksi gamma pada gambar sebelum menyimpannya. |

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

[IM Output]
Sekarang tepi lingkarannya benar-benar tampak mulus dan membulat sebagaimana mestinya. Kalau ingin melakukannya dengan benar, koreksinya sebenarnya harus dibuat lewat ruang warna. Namun karena IM menganggap RGB sebagai ruang warna bawaan saat menyimpan, diperlukan penanganan yang agak berliku supaya hasilnya benar. |

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

[IM Output]
| Perhatikan bahwa ruang warna sRGB (cara yang benar untuk menyimpan gambar) tidak persis sama dengan sekadar menerapkan koreksi gamma 2.2. Namun perbedaan hasil keduanya kecil, dan hanya terlihat pada gambar yang sangat sangat gelap.
| Sebelum IM v6.7.5-1 nama ruang warna 'sRGB' dan 'RGB' (RGB linear) sebenarnya terbalik. Karena itu, pada IM versi lama kedua label di atas harus ditukar.
Untuk menggambar dengan benar (atau melakukan pemrosesan gambar 'linear' apa pun) pada gambar sungguhan (di IMv7), gamma yang ada harus dihilangkan lebih dulu, gambarnya diproses, lalu koreksi gamma itu dikembalikan. Lihat Resize dengan koreksi ruang warna untuk rinciannya. Berikut contoh menggambar pada gambar sungguhan... Pertama tanpa koreksi warna sama sekali (mentah), lalu dengan koreksi gamma dan koreksi ruang warna. |

  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]
Seperti terlihat, dengan koreksi gamma atau ruang warna garisnya tampak sangat mulus, tanpa efek aliasing 'tangga' yang bergerigi seperti yang muncul kalau digambar langsung. (Perlu monitor yang sangat bagus untuk melihatnya) | Garis di atas digambar memakai warna "-stroke". Garis itu bisa juga digambar memakai "-fill" dengan hasil yang sama, tetapi ketebalan garisnya tidak dapat dikendalikan lewat "-strokewidth". Lihat Interaksi stroke, strokewidth, dan fill di bawah untuk keterangan lebih lanjut.
| _Nama warna sebenarnya didefinisikan memakai nilai untuk ruang warna 'sRGB', TETAPI diterapkan oleh draw seolah-olah gambarnya berada di ruang warna RGB linear. Karena itu, memakai koreksi gamma di atas bersama warna bernama (selain 'white' atau 'black') akan membuat warna tersebut terdistorsi. Dalam kasus semacam itu mungkin lebih baik tidak memakai koreksi gamma atau ruang warna, supaya warna bernama terpetakan dengan benar.

Pemetaan yang benar dari warna 'sRGB' bernama ke ruang warna gambar yang digambari akan diperbaiki sebagai bagian dari pengembangan IMv7.

_

Interaksi stroke, strokewidth, dan fill

Opsi "-stroke" dan "-strokewidth" dipakai saat menggambar garis luar di sekeliling tepi font. Opsi ini biasa dipakai bersama "-fill" untuk membuat teks lebih menarik dengan usaha yang sangat kecil.

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

[IM Output]

Pengaturan bawaannya adalah "-strokewidth 1" dan "-stroke None". Namun ini membuat garis luar stroke tidak terlihat, hanya menyisakan warna "-fill", jadi strokenya tidak akan tampak. Satu-satunya pengaruh "-strokewidth" ketika "-stroke" 'tak terlihat' adalah pada atribut ukuran font, yang berarti ia tetap dapat memengaruhi penempatan font dan ukuran gambar Label dan caption yang dihasilkan. Selebihnya, lebar itu tidak berpengaruh secara kasatmata sampai strokenya dibuat terlihat. Untuk melihat bagaimana "-strokewidth" sebenarnya memengaruhi tampilan font (ketika dibuat terlihat), di sini saya menggambar beberapa teks dengan berbagai lebar, dari 'dimatikan' lalu makin besar.

    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]

Perhatikan dari contoh di atas bahwa menyetel "-strokewidth" ke '0' TIDAK sama dengan menyetel warna "-stroke" ke 'none' (bawaannya). Yang pertama menghasilkan garis luar stroke yang sangat sangat tipis, sedangkan yang kedua praktis mematikannya. Pada kedua kasus, strokenya tetap digambar. Namun perlu juga dicatat bahwa bahkan dengan "-strokewidth" '0', garis luar gambar akan melebar sangat sangat sedikit dibanding gambar yang sekadar 'diisi' (memakai warna "-stroke" 'none'. Pada dasarnya lebar berapa pun yang lebih kecil dari '1.0' tidak bekerja sebagaimana mestinya. Berhati-hatilah dalam kasus yang bisa terpengaruh oleh hal ini. Ingat pula bahwa "-strokewidth" adalah pengaturan floating point. Artinya, lebar stroke '0.5' juga sah. Namun biasanya hal ini baru penting ketika kita mencoba menggambar lingkaran bitmap tipis dengan anti-aliasing dimatikan.
Berikut contoh memakai lebar stroke yang teramat besar.

   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]

Perhatikan bahwa "-strokewidth" melebarkan garis ke dalam sekaligus ke luar. Berikut contoh yang sama, tetapi fontnya digambar ulang tanpa garis luar stroke, untuk menghilangkan bagian dalam dari stroke yang sangat tebal itu.

   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]

Untuk contoh lain penggunaan stroke, lihat Efek font gabungan. Perhatikan khususnya "Efek balon".

Menggambar garis (stroke)

Penggambaran garis bawaan di IM punya beberapa perilaku aneh yang layak diketahui. Berikut penggambaran garis bawaannya... |

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

[IM Output]
Warna garis dapat disetel dengan opsi "-fill". |

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

[IM Output]
Garis juga bisa dibuat sedikit lebih tebal dengan menyetel warna "-stroke". |

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

[IM Output]
Tetapi ke mana perginya warna putih yang kita tentukan lewat opsi "-fill" tadi? Inilah sisi yang membingungkan dari penggambaran garis di ImageMagick. Yang dilakukan program sebenarnya adalah memperlakukan garis sebagai objek terisi selebar sekitar 1 piksel. Ini wajar, karena biasanya banyak garis dipakai untuk menyapu suatu area yang akan diisi. Jadi sama seperti waktu kita memakai stroke pada font di bagian sebelumnya, IM menggambar garis (atau objek) itu memakai warna fill, lalu menggambar di sekelilingnya dengan warna stroke. Hasilnya, garis berwarna stroke di atas kini sedikit lebih tebal, dengan warna fill tersembunyi sepenuhnya di bawahnya. Kalau warna strokenya dibuat semitransparan, warna fill itu bisa terlihat lagi. Ringkasnya, garis akan tampak digambar dengan warna "-fill", tetapi opsi itu tidak lagi berarti begitu warna "-stroke" ditetapkan selain warna bawaan "none" atau "transparent". | Opsi "-linewidth" sebenarnya hanya alias untuk "-strokewidth", dan sebaiknya tidak dipakai.
Misalnya, Anda mungkin mengira perintah ini akan menghasilkan garis yang sangat tebal. Memang begitu, tetapi karena warna "-stroke"-nya tidak terlihat, hasilnya tak tampak. Yang terlihat hanya 'fill' di bagian dalam area garis selebar satu piksel itu. |

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

[IM Output]
| Hasil di atas sebenarnya saya anggap bug. Seharusnya tidak ada yang tergambar, karena tidak ada 'area' yang perlu diisi dan tidak ada 'warna stroke' garis yang disetel. Alasan IM saat ini berlaku begitu adalah untuk menghindari kebingungan pengguna baru, tetapi sebenarnya hal ini justru menyusahkan pengguna tingkat lanjut. LihatBatas isian draw untuk rinciannya.
Tetapi kalau warna strokenya juga ditetapkan, garis tebal yang diminta akan muncul... |

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

[IM Output]
Kalau pengaturan "-strokewidth" disetel ke satu, garis di atas akan tertutup sepenuhnya. |

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

[IM Output]
Tentu saja dengan berbekal pengetahuan ini, kita bisa memakainya secara kreatif, sama seperti pada penggambaran font. |

  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]
Di sini saya memakai pengaturan "-strokewidth" paling tipis, yaitu '0', sama seperti yang saya lakukan pada font di atas. |

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

[IM Output]
Hasilnya sangat aneh: garis putus-putus yang terdiri atas titik hitam dan segmen abu-abu. Ini akibat "frekuensi pelayangan warna" yang ganjil antara warna stroke, fill, dan latar belakang. Berikut tampilan garis itu diperbesar... |

  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]
| Efek "frekuensi pelayangan warna" tidak jauh berbeda dari "pelayangan bunyi" yang terdengar bila ada dua gitar yang sedikit sekali sumbang. Dalam hal ini titik hitam muncul di tempat warna stroke sepenuhnya menimpa warna fill di bawahnya, dan titik abu-abu muncul di tempat warna stroke bercampur dengan KEDUA warna fill dan latar belakang. Percampuran warna ini konsekuensi wajar dari proses anti-aliasing yang dipakai IM untuk memperbaiki tampilan garis dan objek draw lain. Untuk keterangan lebih lanjut, lihat halaman pembahasan dan contoh saya,Anti-aliasing di IM.
Perhatikan bahwa efek ini hanya muncul pada garis miring, bukan pada garis yang murni horizontal atau vertikal, karena di situ aliasing tidak berpengaruh sehingga tidak ada efek "frekuensi pelayangan warna". |

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

[IM Output]
Di sini saya memakai warna fill dasar yang berbeda-beda pada tampilan yang diperbesar, supaya terlihat bagaimana warna itu mengubah pelayangan yang dihasilkan. |

  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]
Mari kita bandingkan dengan stroke bernilai none... |

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

[IM Output]
Seperti terlihat, saat menggambar garis yang sangat tipis, 'pelayangan' itu dapat dikurangi dengan memakai warna fill dan stroke yang sama, ATAU dengan menyetel salah satu warnanya ke none untuk mematikannya. Cara kedua yang paling baik, tetapi cara pertama mungkin lebih praktis untuk kebutuhan pemrograman Anda. Perhatikan bahwa ketebalan garis fill adalah '0'. Namun garis stroke bisa punya ketebalan lebih besar, dan nilainya pun floating point! Garis selebar 2.5 piksel sepenuhnya sah. | Hasil ini disebabkan bukan hanya oleh lebar stroke 0 yang bermasalah sehingga menimbulkan pelayangan warna, tetapi juga oleh 'warna fill' yang digambar dengan tambahan ketebalan berdiameter 1.0 padahal tidak ada area yang perlu diisi. Ini pun saya anggap bug. LihatBatas isian draw.

Batas isian draw

Ada beberapa hal lain yang perlu dicatat tentang berbagai primitif draw. Stroke-width bekerja baik untuk nilai floating point di atas 1.0, tetapi tampaknya kacau untuk nilai di bawah 1.0. Ini karena algoritme implementasi yang dipakai, bukan semata karena salah, sebab untuk garis yang lebih tebal ia bekerja baik-baik saja. Pada dasarnya, kalau stroke-width nol dipakai, kita berharap tidak ada warna stroke yang ditambahkan. Yang terjadi malah semacam pola pelayangan: warna stroke muncul dengan kekuatan penuh ketika garisnya melewati 'pusat' piksel yang sesungguhnya.. Yang seharusnya terjadi adalah banyaknya warna yang ditambahkan ke sebuah piksel mencerminkan luas garis yang digambar, bukan jarak piksel itu dari garis tersebut. Dengan begitu, garis berlebar nol semestinya tidak menambahkan warna apa pun ke gambar, sedangkan garis dengan ketebalan di bawah 1.0 semestinya hanya menambahkan sedikit warna. Lihat contoh Menggambar garis (stroke) di atas. Masalah yang lain, warna fill tidak diterapkan tepat sampai ke tepi bentuk (poligon) yang digambar, melainkan ½ piksel lebih ke luar. Ini termasuk situasi ketika tidak ada 'stroke' yang diterapkan dan tepinya semestinya persis. Termasuk juga penggambaran 'line', yang sebenarnya punya ketebalan fill 'nol'. Pada dasarnya, kalau kita menggambar garis tanpa mengaktifkan stroke, secara teknis semestinya tidak ada garis yang terlihat karena ia tidak punya ketebalan 'fill'. Yang terjadi, garis tetap digambar dengan warna 'fill' selebar minimal 1 piksel. Ini karena alasan historis, dan umumnya menghindarkan kebingungan pengguna baru IM. Sayangnya hal itu TIDAK benar bagi pengguna tingkat lanjut. Artinya, kalau kita menggambar dua poligon hanya dengan warna fill dan keduanya berbagi satu tepi, tepi itu akan bertumpang tindih sejauh 1 piksel karena tiap poligon ½ piksel lebih besar di sepanjang semua tepinya. Dengan kata lain, poligon dan bentuk lain tidak saling pas, melainkan bertumpang tindih! Sebagai contoh, di sini saya mencoba memakai draw untuk membagi sebuah gambar menjadi dua bagian (menggambar hitam di atas putih). Untuk itu saya menggambar dua poligon yang berbagi satu tepi, persis tanpa tumpang tindih. Gambar 'mungil' yang dihasilkan sudah diperbesar untuk ditampilkan.

  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]

Kedua bagian hitam (yang memang benar-benar digambar) ternyata saling bertumpang tindih! Dengan kata lain, meskipun kita mencoba menggambar kedua area itu secara terpisah dengan poligon, area yang terisi sedikit lebih besar daripada yang diminta. Saya juga menjumlahkan (komposisi Plus) kedua gambar itu supaya tumpang tindih area hitam yang digambar benar-benar terlihat. Kalau kedua poligon itu pas sempurna, gambar hasil 'penjumlahan' akan berwarna putih polos. Besarnya tumpang tindih setara dengan pengaturan bawaan "-strokewidth 1.0". Jadi biasanya area tambahan ini diharapkan tertutup oleh lebar stroke yang normal. Meski begitu, hal ini bisa menimbulkan masalah nyata. ASIDE: Untuk menguji sambungan itu secara lengkap, buatlah area abu-abu 50% di atas latar belakang hitam lalu jumlahkan keduanya. Dengan begitu terlihat apakah areanya tidak hanya 'bertumpang tindih' (seperti di atas), tetapi juga apakah keduanya 'kurang bertemu' (menyisakan celah antararea terisi) ketika dijumlahkan. Gambar hasilnya semestinya berupa warna abu-abu 50% yang mulus sempurna tanpa variasi warna di sepanjang sambungan. Pemeriksaan transparansi dilakukan dengan memakai warna abu-abu 50% yang transparan 50% di atas latar belakang yang sepenuhnya transparan. Untuk melihat contoh pemotongan dan penggabungan ulang yang sempurna berdasarkan satu gambar mask, lihat contoh metode komposisi, Dst_Out. FUTURE BUG FIX: The area filled should be exact, but to compensate for this when drawing shapes, the default 'stroke color' should be set to the fill color (unless it is itself specifically set).


MVG - Magick Vector Graphics

Primitif yang ditunjukkan di atas menjadi dasar semua operasi "-draw" yang tersedia. Bersama-sama, semuanya merupakan titik awal sebuah bahasa internal khusus di ImageMagick yang disebut bahasa Magick Vector Graphics. Untuk rincian bahasa ini, lihat Ringkasan primitif dan sintaksis MVG di situs web IM. Bahasa "MVG" ini dirancang dengan tujuan agar ImageMagick dapat menangani bahasa SVG (Scalable Vector Graphics) yang jauh lebih rumit. Caranya adalah dengan mencoba mengonversi gambar yang diberikan dalam format SVG ke format MVG internal yang lebih sederhana. Untuk rinciannya lihat penanganan SVG di bawah. Akibatnya, apa yang kita lihat di atas hanyalah sebagian kecil dari kemampuan operator "-draw". Meski begitu, kalau yang ingin digambar adalah objek yang rumit, saya menyarankan agar gambar objek itu dibuat terpisah dalam format SVG memakai editor SVG seperti "Sodipodi". (Lihat editor grafik vektor non-IM di bawah). Tidak seperti SVG, MVG tidak punya bentuk 'kontainer' atau himpunan perintah gambar apa pun. Semuanya dibuang selama proses konversi sehingga yang dihasilkan adalah urutan perintah penggambaran MVG yang disederhanakan. Sebagai gantinya, MVG memakai konsep konteks grafik untuk menyimpan dan memulihkan berbagai pengaturan penggambaran, dan itulah yang akan kita lihat sekarang.

Pengaturan baris perintah vs pengaturan MVG

Pertama-tama, hampir semua pengaturan yang disetel lewat opsi baris perintah dan dipakai oleh primitif draw punya padanan langsung di dalam perintah penggambaran MVG. Perbedaan utama antara menyetelnya lewat opsi baris perintah (misalnya "-strokewidth") dan memakai pengaturan di dalam string penggambaran MVG (misalnya 'stroke-width) adalah bahwa pengaturan MVG hanya bertahan selama string perintah MVG itu berlangsung.

**Ringkasan pengaturan penggambaran umum**
  __cmd_option__   __draw_MVG__        __Argumen__
    -fill            fill                warna/tile untuk bagian dalam bentuk
    -tile            fill                tile gambar, menggantikan warna fill

    -stroke          stroke              warna/tile garis di sekeliling bentuk
    -strokewidth     stroke-width        lebar dalam piksel
    +antialias       stroke-antialias    0/1 aliasing tepi garis

    -font            font                font_name / font_file
    -family          font-family            ?
    -weight            ?                    ?
    -stretch           ?                    ?
    -pointsize       font-size           tinggi dalam poin
    -kerning           -                 spasi antarkarakter tambahan

    +antialias       text-antialias      0/1 aliasing penggambaran teks
    -box             text-undercolor     warna fill untuk kotak batas font
      -              decorate        (None, Underline, LineThrough atau Overline)

    -gravity         gravity             (None, North, South-East,...)
    -fuzz              -                 selisih warna / persentase
    -bordercolor       -                 warna

Catatan:
  - tidak ada opsi tersebut      ? tidak diketahui
Pengaturan ini biasanya sudah cukup dipahami karena kerap dipakai dan diperagakan di atas. font, stretch, style, dan weight dipakai untuk mengenali sebuah font dari daftar font ImageMagick. Namun kebanyakan orang cukup memilih font dan pointsize tertentu untuk dipakai. Karena itu keempatnya jarang dipakai di IM.
Seperti terlihat, pengaturan khusus untuk primitif 'isian warna' tidak punya padanan langsung di MVG, yaitu "-bordercolor" dan pengaturan faktor "-fuzz". Keduanya harus ditentukan dari baris perintah sebelum operator "-draw" dipakai. Beberapa pengaturan MVG mungkin akan lebih berguna sebagai pengaturan baris perintah global, misalnya pengaturan 'decorate' untuk penggambaran font. PERINGATAN: "-gravity" bukan bagian dari spesifikasi SVG. Di dalam MVG, ia hanya dipakai untuk penempatan teks dan gambar serta perataan. Saat ini belum ada pengaturan perataan yang terpisah dari efek 'gravitasi' bawaan. Namun karena perataan adalah bagian dari penanganan teks SVG, hal itu kemungkinan akan berubah suatu saat nanti. Nah, pengaturan baris perintah global (di luar string draw MVG) dipakai untuk menginisialisasi pengaturan tiap operasi "-draw" yang diterapkan, dan karena itulah kita bisa menyetel warna "-fill" lalu memakainya untuk menggambar lingkaran berwarna itu.
---
  magick -size 100x60 xc:skyblue   -fill red \
          -draw "circle 50,30 40,10"          draw_circle_global.gif

[IM Output]
Pengaturan global itu dapat ditimpa secara lokal di dalam argumen MVG "-draw"...
|

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

[IM Output]
Namun pengaturan yang disetel di dalam satu argumen MVG "-draw" hanya berlaku selama operasi "-draw" itu. Artinya, pengaturan di dalam sebuah "-draw" bersifat lokal untuk draw tersebut saja dan tidak terbawa ke argumen "-draw" terpisah berikutnya.
|

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

[IM Output]
Kalau berencana melakukan banyak operasi, mungkin lebih baik semuanya dikerjakan dalam satu string MVG saja, ketimbang lewat banyak operasi "-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]
Pengaturan khusus MVG Pengaturan MVG lain yang mengendalikan cara garis dan objek digambar juga berguna untuk diketahui, bahkan ketika memakai operasi primitif. Di antaranya..

   __draw_MVG__       __Deskripsi/Argumen__
  fill-opacity        transparansi fill, dari 0.0 sampai 1.0
  clip-rule           gaya isian untuk garis bersilangan (evenodd, nonzero)

  stroke-opacity      transparansi garis, angka dari 0.0 sampai 1.0
  stroke-dasharray    daftar panjang 'on' dan 'off' untuk garis
  stroke-dash
  stroke-linecap      Tampilan ujung garis: butt round square
  stroke-linejoin     Sambungan garis:  butt  miter round square
  stroke-miterlimit   Sudut saat sambungan 'miter' menjadi 'bevel' (atau 'butt')

Ingat, daftar lengkap semua pengaturan MVG dan operator penggambaran dapat dilihat di Ringkasan primitif dan sintaksis MVG pada situs web IM. Mari kita lihat efek beberapa pengaturan yang lebih sederhana... |

  # 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]
Pengaturan 'stroke-miterlimit' agak sulit diperagakan. Properti ini menentukan sudut saat sambungan 'miter' berubah menjadi sambungan 'bevel'. Pada dasarnya, untuk sudut yang sangat lancip, miter bisa menjulur jauh dari sambungan kedua garis yang sebenarnya. Pengaturan ini menetapkan batas maksimum ketajaman itu, dan menumpulkan titik sudutnya ketika terlalu panjang. Perhatikan bahwa nilainya mewakili nilai trigonometri dari suatu sudut, bukan panjang atau jarak. Nilainya harus lebih besar dari 1.0. Contoh di atas memperlihatkan bahwa, untuk sudut sambungan yang saya tampilkan, miter tiba-tiba berubah menjadi bevel di antara nilai 6 dan 7. Misalnya, 'stroke-miterlimit' 1.414 mengubah 'miter' menjadi 'bevel' untuk setiap sudut kurang dari 90 derajat. Nilai 4.0 (bawaannya) mengubah sambungan untuk sudut kurang dari kira-kira 29 derajat. Sedangkan nilai 10.0 mengubahnya untuk sudut kurang dari kira-kira 11.5 derajat. Menggambar path SVG Path SVG adalah primitif penggambaran dasar pada SVG. Path dipakai untuk menggambar garis, bentuk, lingkaran, kurva, busur, dan seterusnya. Spesifikasi lengkap SVG Path dapat ditemukan di dokumen Spesifikasi SVG Path. Namun dokumen itu tidak mudah dibaca karena memang ditujukan untuk pemrogram, bukan pengguna, jadi saya akan menyederhanakan dan meringkas spesifikasi path itu...

  • Huruf adalah perintah, sedangkan semua angka (floating point) adalah argumen.
  • Koma atau spasi boleh dipakai sebagai pemisah argumen; selain itu keduanya diabaikan sepenuhnya.
  • Dua argumen terakhir (x,y) pada tiap komponen path akan menjadi titik akhir (atau 'knot') komponen path tersebut.
  • Huruf kapital menyatakan koordinat absolut titik akhir.
    Huruf kecil bersifat relatif terhadap titik akhir komponen sebelumnya.
    Sebagai contoh: " M 1,2 l 3,4 l 2,-4 " sama dengan " M 1,2 L 4,6 L 6,2 ".
    Artinya, 3,4 ditambahkan ke 1,2 untuk menggambar garis ke 4,6.
    Lalu 2,-4 ditambahkan untuk menggambar garis ke koordinat akhir 6,2.
  • Argumen tiap elemen boleh diulang tanpa mengeluarkan lagi huruf path yang sama, yaitu dengan menambahkan kelompok argumen angka berikutnya. Namun untuk kurva, saya menyarankan huruf fungsinya tetap ditulis supaya mudah dibaca.
  • Argumen "M" atau "m" yang berulang diperlakukan berturut-turut sebagai "L" atau "l".
    Sebagai contoh: " M 1,2 3,4 5,6 " sama dengan " M 1,2 L 3,4 L 5,6 "
    Dan : " m 1,2 3,4 2,-4 " sama dengan " m 1,2 l 3,4 l 2,-4 "
  • Untuk cubic bezier, semua titik (titik kendali maupun titik knot akhir) diberikan relatif terhadap titik akhir komponen path sebelumnya.

Perhatikan bahwa segalanya dapat dinyatakan dalam koordinat absolut maupun relatif. Jadi sebuah objek dapat didefinisikan dalam koordinat relatif, lalu cukup diberi satu koordinat 'move' absolut di awal untuk menempatkan seluruh path. Di sisi lain, perintah 'graphic-content' lain juga bisa dipakai untuk memindahkan seluruh gambar di dalam 'viewbox' atau 'translation' (lihat di bawah). Jadi sebenarnya tidak jadi soal apakah koordinat absolut atau relatif yang dipakai di dalam path SVG. Move, garis, dan penutupan path adalah titik awal untuk mempelajari path objek 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]
Namun perhatikan bahwa 'Z' hanya menutup loop. Ia TIDAK membuat objek terpisah. Karena itu dua path 'tertutup' tetap tergolong satu objek gambar, baik keduanya bertumpang tindih maupun sama sekali terpisah. Di sini kita menampilkan dua loop tertutup yang bertumpang tindih, digambar dengan arah yang sama. Karena hanya satu path yang dipakai, objeknya tunggal, dan pengaturan 'fill-rule ' mengendalikan bagaimana daerah tumpang tindih itu diisi. |

  # 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]
Karena kedua objek digambar dengan arah sudut yang sama mengelilingi pusatnya, kedua loop tertutup itu melingkupi area dengan nilai siklus 2. Karena itu aturan 'evenodd' membiarkan area tersebut tidak terisi, sedangkan aturan 'nonzero' mengisinya. Namun perhatikan bahwa semua path tetap terlihat, karena sebenarnya semuanya objek yang sama. Arah penggambaran path sangat penting, dan secara umum semua path harus digambar dengan arah yang persis sama relatif terhadap 'bagian dalam' objek. Sebagai contoh, di sini saya menggambar objek kedua dengan arah yang berlawanan dari objek pertama. Akibatnya, ketika kedua objek bertumpang tindih, area itu terlingkari 'nol ' kali. Artinya, area tersebut tidak akan terisi apa pun 'fill-rule' yang dipakai, sehingga terbentuk 'lubang'. |

  # 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]
Artinya, 'lubang' pada sebuah objek dapat dihasilkan dengan membalik arahnya, sehingga 'bagian dalam' objek tetap berada di sisi yang sama terhadap arah gerak. |

  # 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]
Hasilnya sama apa pun pengaturan 'fill-rule'-nya, karena lubang itu sekaligus 'genap' dan 'nol' sehingga tidak terisi. Tentu saja, kalau elemen 'path' yang benar-benar terpisah dipakai, yang dihasilkan adalah objek yang benar-benar terpisah pula. Dalam hal itu 'fill-rule' tidak berlaku dan objek-objeknya sekadar digambar bertindihan sesuai urutan yang diberikan. |

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

Busur elips adalah fungsi penggambaran lingkaran pada path SVG...
Parameter 'large' dan 'sweep' sangat penting karena keduanya menentukan mana di antara empat cara 'membusur' dari titik awal ke titik akhir komponen path tersebut yang dipakai. Kedua flag 'large' dan 'sweep' menentukan mana di antara empat busur berjari-jari itu yang akan menghubungkan kedua titik. |

  #  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]
flag kedua, 'sweep', sekadar menentukan di sisi mana dari arah garis lurus path itu busurnya digambar. Flag 'large' dipakai untuk memilih lintasan yang lebih panjang, yang melingkari pusat elips. Artinya, sudut busurnya akan lebih besar dari 180 derajat. Bila dimatikan, yang didapat adalah 'busur' yang lebih kecil, tidak mencakup pusat elips, dan membusur pada sudut kurang dari 180 derajat. Menutup busur dengan 'Z' hanya menggambar satu segmen garis lurus terakhir. Untuk membuat elips atau lingkaran penuh diperlukan sedikitnya dua segmen 'arc', dari titik pertama ke titik kedua, lalu kembali ke titik pertama. Kedua busur harus punya pengaturan 'sweep' yang sama, sehingga busurnya berada di sisi yang berbeda karena arah geraknya berbeda. Salah satu busur harus memakai pengaturan '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]
Perhatikan bahwa kalau garisnya terlalu panjang untuk muat pada ukuran elips yang diberikan pada sudut tersebut, ukuran elipsnya akan diperbesar agar muat, dengan elips berpusat pada garis itu. Artinya, dengan memakai angka kecil untuk jari-jari sumbunya, kita cukup menentukan rasio panjang sumbu dan terjamin bahwa lintasan garis langsungnya melewati titik pusat elips. Dengan kata lain, path itu membentuk diameter elips dari satu sisi ke sisi lainnya. Ini belum tentu sumbu mayor atau minor elips, sekadar sebuah diameter elips. |

  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]
Tentu saja memakai panjang "1,1" menghasilkan setengah lingkaran yang sempurna, dari satu titik ke titik berikutnya. Sudut elipsnya dalam hal ini tidak berpengaruh. |

  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]
Untuk lingkaran penuh yang berpusat di antara kedua titik, pakailah... |

  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]
Definisi 'arc' pada SVG juga menyatakan bahwa bila salah satu dari kedua jari-jarinya nol, yang digambar adalah garis lurus. Jadi busur mana pun dengan jari-jari "0,0" hanyalah busur berupa garis lurus sederhana... |

  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]
Kalau jari-jari busurnya ditentukan sangat besar dan lintasan baliknya tidak diberi 'large sweep', bentuk lensa berjari-jari itu dapat dibuat di antara kedua titik. |

  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]
Busur jenis ini adalah fitur penting. Dengan mudah ia dapat memberi lengkung kecil tetapi jelas pada garis yang sebenarnya lurus. Misalnya, alih-alih segitiga sederhana seperti ini... |

  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]
Tiap garis dapat diganti dengan busur berjari-jari besar untuk memberinya lengkung yang tipis saja. |

  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]
Titik ujung garis-garisnya tidak berubah; yang terjadi hanyalah tiap 'L' diganti oleh segmen busur. Namun ukuran busurnya semestinya sebanding dengan panjang garisnya. Karena saya tidak melakukan itu, garis diagonal yang lebih panjang punya lengkung yang jauh lebih kuat dan dalam daripada dua garis lainnya. Ingat, saat mengubah ukuran atau menskalakan objek yang digambar, jari-jarinya harus diskalakan sebesar perubahan panjang garis itu juga supaya lengkungnya ikut berubah ukuran dan busurnya ikut terskalakan dengan benar. Perhatikan bahwa flag 'sweep' mengendalikan apakah lengkungnya menggembung ke luar atau ke dalam, sesuai arah penggambaran tiap segmen path (lihat di atas). |

  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]
Segitiga bertepi lurus yang tadinya tampak 'kaku' kini agak mirip layar yang terisi angin. Kalau garisnya benar-benar ingin dibuat lurus sempurna tanpa mengubahnya kembali menjadi segmen garis sungguhan, lengkungnya dapat dimatikan dengan memakai jari-jari busur nol. Jadi busur tidak hanya bagus untuk menghasilkan elips dan lingkaran, tetapi juga berguna untuk menggambar segmen garis yang lurus maupun yang sedikit melengkung. Ia adalah path draw titik-ke-titik yang sangat serbaguna. Satu alternatif sederhana selain busur elips untuk menghasilkan segmen garis melengkung yang terpisah adalah segmen Quadratic Bezier. Bedanya yang utama, yang dipakai adalah satu titik kendali, bukan jari-jari lingkaran, untuk mendefinisikan busurnya. Cara itu juga membuat busurnya bisa dicondongkan ke salah satu ujung segmen garis, dengan konsekuensi busur simetris jadi lebih sulit dibuat. Tentu saja keduanya bisa dicampur sesuai kebutuhan. Contoh diagram lingkaran Sebagai penutup pembahasan busur, mari kita beri contoh pemakaiannya untuk menghasilkan juring lingkaran. Tentu saja mungkin diperlukan sedikit matematika trigonometri dari luar (seberapa bagus nilai matematika SMA Anda?) untuk menentukan titik akhir path yang dibutuhkan. |

  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]
Perhatikan bahwa semua busur digambar di sebelah kiri 'lintasan garis' dan diberi flag yang sesuai (memakai flag 'sweep'). Tetapi kalau busurnya mencakup sudut lebih dari 180 derajat, flag 'large' perlu disetel. Lihat komponen 'gold' terakhir pada contoh di atas. Perhatikan juga bahwa tiap juring harus digambar utuh, meskipun itu berarti garis pembatasnya mungkin harus digambar dua kali. Kalau tidak, kemungkinan besar juring itu tidak terisi warna sepenuhnya, atau warna fill-nya menimpa garis luar juring yang digambar sebelumnya. Satu-satunya cara menghindari penggandaan garis adalah menggambar semua area terisi lebih dulu, lalu mengulanginya untuk menggambar garis luarnya. Artinya, semuanya harus digambar dua kali dan harus dipastikan cocok satu sama lain. Jadi, menggandakan garis luar mungkin memang solusi yang paling sederhana. Kurva Cubic Bezier dapat didefinisikan memakai fungsi 'C' yang menentukan dua titik kendali dan titik akhir. Untuk melanjutkan kurva Cubic Bezier yang memakai cerminan titik kendali terakhir (agar kurvanya kontinu), pakailah fungsi 'S'. Berikut contohnya. Karena fungsi ini rumit, saya sudah menyiapkan kanvas yang menunjukkan letak titik-titik kendali sekaligus 'cerminan yang diandaikan' dari titik kendali terakhir. |

  # 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]
Garis yang menghubungkan titik kendali ke titik akhir path pada segmen tersebut (garis kendali) pada dasarnya menentukan arah kurva saat melewati titik itu. Garis kendali yang panjang menghasilkan kurva yang lebih mulus di titik tersebut, sedangkan garis yang pendek menghasilkan kurva yang lebih tajam. Kalau titik kendalinya berimpit dengan titik kurva (panjang garis kendalinya nol), kurvanya akan patah tajam di titik itu, seolah-olah hanya segmen garis lurus yang dipakai. Sebagai contoh yang lebih praktis, potongan kode berikut diambil dari Skrip pembuat logo IM Examples yang membuat area cipratan melengkung pada logo IM Examples Bagian yang berliku dari contoh ini adalah bahwa saya mengubah string path Cubic Bezier yang saya pakai menjadi path lain yang menunjukkan garis kendali yang dipakai untuk menghasilkan kurva bezier itu. Dengan begitu saya bisa melihat sudut dan panjang garis kendali kurvanya, sehingga hasilnya jauh lebih mudah disesuaikan. Hanya satu himpunan titik yang perlu disesuaikan untuk menampilkan kurva sekaligus kendalinya, sehingga kesalahan dapat ditekan seminimal mungkin. |

   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]
Kalau gambarnya diperhatikan baik-baik, akan terlihat bahwa awal dan akhir kurva punya dua garis kendali yang menghadap ke arah berlawanan. Untuk path tertutup yang kontinu, garis kendali awal dan akhir harus punya sudut yang sama (hanya berlawanan arah cermin) dan tentu saja panjang yang sama pula. Ini penting diingat, karena mudah sekali keliru. Semua titik lain di sepanjang kurva hanya punya satu titik/garis kendali yang mengarah ke arah berlawanan dengan arah penggambaran kurva. Makin panjang segmen garis itu, makin tidak 'tajam' kurvanya di titik kendali tersebut, dan panjang nol menghasilkan 'sudut runcing'. Fungsi 'S' secara internal menghasilkan titik/garis kendali cerminan untuk segmen berikutnya dari data segmen sebelumnya, sehingga kurvanya berlanjut dengan mulus. Untuk contoh lain fungsi path ini, lihat SVG: perintah kurva Cubic Bezier. Membuat kurva Bezier secara manual relatif mudah tanpa perlu perkakas GUI yang canggih.

  • Pertama, tentukan semua titik koordinat yang ingin dilalui kurva, lalu ulangi koordinat awalnya di akhir daftar.
  • Sekarang perluas daftar itu dengan menggandakan semua titik koordinat x,y menjadi pasangan, lalu tambahkan fungsi 'S' (Smooth Cubic) di depan tiap pasangan. Angka pertama pada tiap pasangan adalah titik kendali yang terhubung ke angka kedua yang mewakili titik pada kurva. Namun pada pasangan titik pertama urutannya terbalik: titik pertama adalah awal kurva dan titik kedua mewakili titik kendali terbalik yang pertama dan satu-satunya.
  • Ubah huruf fungsi pada pasangan koordinat pertama dari 'S' menjadi 'M', lalu tambahkan 'C' di antara pasangan koordinat itu. Terakhir, hapus 'S' dari pasangan koordinat kedua untuk melengkapi fungsi Cubic ('C') yang pertama.
  • Lengkapi path dengan menambahkan 'Z' di akhir untuk menutup kurvanya.
    Lihat contoh urutan di atas untuk melihat bentuk seharusnya.
  • Pada tahap ini path Anda sudah bisa dicoba digambar. Path itu hanya akan terdiri dari segmen garis lurus, karena semua garis kendalinya berpanjang nol.
  • Yang perlu dilakukan sekarang hanyalah menyetel posisi segmen garis kendali (koordinat pertama dari tiap pasangan 'S') pelan-pelan dan hati-hati sampai kurvanya sesuai keinginan. Jangan membuat garis kendali terlalu panjang, atau mengarah ke arah yang keliru, karena kurvanya akan tampak sangat aneh.
  • Untuk membantu melihat perubahan dan menemukan kesalahan, gunakan perintah konversi "sed" di atas guna menggambar garis kontrol antara titik kontrol path dan titik kontrol kurva. Perhatikan bahwa garis kontrol berpanjang nol tidak terlihat, tetapi karena garisnya menghasilkan sudut yang tajam, posisinya tetap jelas.
  • Terakhir, pastikan titik/garis kontrol pertama sesudah 'C' benar-benar berlawanan arah dengan garis kontrol penutupnya, pada posisi yang sama.

Pembuatan kurva secara interaktif juga dimungkinkan dengan sejumlah editor grafik vektor. Sebagai contoh, Luis Guerra melaporkan bahwa kurva bezier yang dihasilkan "Inkscape" bisa diakses lewat fungsi "Edit -> XML Editor", lalu memilih path atau bentuk yang titik kontrolnya ingin dilihat.

Tahukah Anda cara lain untuk mengekstrak kurva bezier (yang memberi dua atau satu titik kontrol per titik pada kurva) dengan perkakas GUI? Atau mungkin teknik lain untuk menghasilkan kurva semacam itu? Kirimi saya email! Saya senang sekali mendengarnya. Nama Anda akan dicantumkan, seperti yang sudah-sudah.

Quadratic Bezier adalah penyederhanaan dari fungsi Cubic Bezier, yaitu ketika dua titik kendalinya dilebur menjadi satu titik kendali saja. Sekali lagi, kurvanya bisa dimulai dengan fungsi 'Q', lalu dilanjutkan dengan fungsi 'T' yang mencerminkan titik kontrol terakhir. |

  #  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]
Perlu saya ingatkan, fungsi penerus 'T' sebenarnya hanya bekerja untuk path yang menghubungkan titik-titik berjarak sama. Saya tidak menyarankan pemakaiannya. Keunggulan Quadratic Curve adalah sebagai pengganti Busur elips, karena yang dipakai posisi sebenarnya, bukan radius busur. Busurnya juga bisa dicondongkan ke salah satu ujung, hal yang tidak praktis bila memakai Busur elips. |

  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]
Dalam kasus ini busurnya tidak begitu seragam, dan hasilnya lebih mirip sirip hiu terbalik ketimbang layar perahu. Ingat bahwa Quadratic Arc berupa parabola, sedangkan busur elips pada dasarnya menghasilkan segmen lingkaran. Inilah yang mungkin menjadi kunci untuk menentukan jenis segmen garis melengkung mana yang sebaiknya dipakai. Untuk contoh lain fungsi path ini lihat SVG: perintah kurva Quadratic Bezier.

Pelengkungan permukaan gambar

Selain kemampuan-kemampuan itu, permukaan gambar tempat objek digambar juga bisa dilengkungkan dengan berbagai cara sehingga hal-hal menakjubkan bisa dikerjakan. Pertama, beberapa modifikasi umum atas permukaan gambar dapat diterapkan, seperti... 'translate', 'rotate', 'scale', 'skewX', 'skewY', dan 'affine'. Sebagai contoh, dari sebuah 'path' berisi garis kita bisa me-"translate" titik asal atau titik 0,0 permukaan gambar ke lokasi lain. |

  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]
Perhatikan bahwa '0,0' atau titik asal area gambar kini berada di tengah gambar, meski sumbu Y tetap bernilai negatif di bagian atas dan positif di bagian bawah gambar. Operasi "rotate" memutar permukaan gambar sehingga apa pun yang digambar sesudahnya pada permukaan itu ikut terputar. Tentu saja perputarannya mengelilingi titik asal hasil translate, jadi sebaiknya kedua operator transformasi ini dipakai bersamaan. |

  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" memperbesar dan memperkecil permukaan gambar di sekitar titik asal. |

  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]
Salah satu pemakaian umum "scale" adalah membalik sumbu Y supaya nilai Y positif mengarah ke atas. Tentu titik asalnya juga perlu dipindahkan ke tengah atau ke sudut kiri bawah agar semuanya tetap rapi. |

  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]
Dan terakhir, "skewX" dan "skewY" memiringkan gambar pada arah X dan Y. Sebagai contoh, di sini kita memakai "skewX" untuk memiringkan sumbu Y vertikal gambar. |

  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]
Operator-operator ini punya padanan di luar string MVG "-draw" untuk pemakaian umum. Namun versi baris perintahnya adalah operator dan langsung diterapkan pada gambar yang sudah ada di memori, bukan pada permukaan gambar yang objek vektornya belum digambar. Selengkapnya lihat Mendistorsi gambar.

Pelengkungan affine pada permukaan gambar

Kelima transformasi kanvas di atas dapat digabungkan menjadi satu Affine Matrix Operator umum, baik lewat primitif MVG 'affine' maupun dengan menetapkan transformasi affine memakai "-affine" sebelum memanggil "-draw". Transformasi affine memakai sekumpulan 'Matrix Coefficients ' yang menentukan bagaimana koordinat yang Anda berikan diubah menjadi koordinat gambar yang sebenarnya. Untuk keterangan lebih rinci tentang cara kerja 'coefficients' ini, lihat Affine Matrix Transforms. Sebagai contoh... untuk sekadar menetapkan titik asal di tengah sebagai acuan objek yang digambar... |

  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]
Membalik gambar... |

  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]
Memutar 30 derajat mengelilingi titik asal... |

  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]
Untuk transformasi affine yang lebih rumit, tersedia Affine Helper Scripts yang memang dibuat untuk keperluan itu. Skrip-skrip ini mengubah hal seperti sudut putar dan titik pusat menjadi koordinat affine yang langsung bisa dipakai pada "-draw affine" atau pengaturan "-affine".

Push/Pop konteks

Sebagian primitif MVG sebenarnya bergantung pada transformasi ini agar bisa dipakai dengan benar. Sebagai contoh, primitif ellipse hanya bisa ditentukan langsung dengan sumbu yang sejajar ortogonal. |

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

[IM Output]
Namun dengan transformasi permukaan gambar kita bisa dengan mudah menambahkan 'sudut putar' pada elips itu. |

  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]
Perhatikan bahwa 'pusat' ellipse (titik putarnya) di-translate lebih dulu, baru kemudian rotasi diterapkan. 'ellipse' lalu digambar pada posisi hasil translate itu, yaitu '0,0'. Contoh di atas juga memperlihatkan dua primitif gambar MVG yang baru: 'push graphic-context' dan 'pop graphic-context'. Keduanya sebenarnya tidak wajib pada contoh di atas, tetapi disarankan bila transformasi gambarnya besar-besaran. Yang dikerjakan primitif 'push' dan 'pop' adalah menyimpan keadaan gambar saat itu atau 'graphic-context', lalu memulihkannya kembali sesudahnya. Semua pengaturan gambar yang diubah di antara kedua primitif itu akan dilupakan. Termasuk di dalamnya pelengkungan permukaan seperti 'translate' dan 'rotate', pengaturan warna 'fill' dan 'stroke', serta apa pun yang mengubah 'state' penggambaran. Primitif ini memudahkan penggambaran objek yang sangat rumit dengan banyak transformasi, lalu mengembalikan semuanya ke keadaan yang lebih 'normal' untuk operasi gambar berikutnya. Peragaan yang lebih praktis bisa dilihat di Menggambar panah di bawah.

Push/Pop objek khusus

Sedang dikerjakan

Pengaturan tambahan yang khusus dipakai MVG untuk menangani format SVG.

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

    push defs

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

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

    pop defs

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

Untuk contohnya lihat situs pengembangan _Florent Monnier_...
  <http://www.linux-nantes.fr.eu.org/~fmonnier/OCaml/MVG/>

Membaca file MVG Seperti terlihat pada contoh-contoh di atas, argumen MVG untuk "-draw" bisa menjadi sangat panjang. Konversi SVG ke MVG bahkan dapat menghasilkan argumen gambar MVG yang teramat panjang (lihat di bawah). Untungnya antarmuka baris perintah IM secara umum memperbolehkan pembacaan argumen string mana pun dari sebuah file lewat argumen "@filename". Ini praktis, sebab artinya perintah gambar MVG yang panjang dan rumit bisa dibaca dari file terpisah. Sebagai contoh, kalau saya menaruh operasi MVG ke dalam file bernama "draw_circles.mvg", saya bisa menggambarnya seperti ini... |

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

[IM Output] | [IM Output]
Bukan itu saja, ImageMagick juga mengerti pembacaan format file gambar "MVG:" secara langsung, sehingga perintah semacam itu bisa digambar dengan lebih langsung pula. Namun, kecuali file MVG-nya mendefinisikan kanvas sendiri, kanvas awalnya mungkin perlu ditentukan ("-size" dan "-background") sebagai tempat menggambar. |

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

[IM Output] | [IM Output]
Pengaturan kanvas awal bisa dipindahkan ke dalam gambar MVG dengan menambahkan 'viewbox' pada file MVG, disertai penggambaran isian warna latar belakang yang sesuai. Dengan begitu file gambar MVG menjadi definisi gambar yang lengkap. |

  magick   mvg_circles2.mvg    mvg_image.gif

[IM Output] | [IM Output]
| _Saat ini hanya ada satu cara membaca file MVG eksternal dari dalam string argumen MVG, yaitu memakai primitif gambar 'image'. Sayangnya cara ini mengonversi MVG yang disertakan menjadi gambar raster SEBELUM gambar itu ditimpakan ke permukaan gambar.

Dengan kata lain, saat ini belum ada fungsi 'include' MVG._ :-(

Sedang dikerjakan

Operasi gambar tingkat rendah IM bisa dihasilkan dengan "[+render](https://imagemagick.org/command-line-options/#render)" untuk merekamnya.

Ketika kemudian pengaturan/operator "[-render](https://imagemagick.org/command-line-options/#render)" diberikan, IM langsung menggambar
operasi yang tersimpan itu.

Anehnya, sekadar mengeluarkan hasil ke file "MVG" pun tampaknya melakukan hal yang sama...
     magick ...   -draw '....'  draw_commands.mvg

CATATAN: bila kurva digambar sambil mengeluarkan file berformat MVG, file itu
mencatat kurvanya sebagai deretan segmen garis pendek, bukan kurva aslinya.

Tentu saja langkahnya bisa diteruskan sepenuhnya dengan memakai format SVG yang lebih universal.
Lihat "[Penanganan format SVG](#svg)" di bawah.

Komposisi alpha MVG

Sedang dikerjakan

Saya belum pernah melihat komposisi alpha dipakai (selain algoritma 'painters'
yang pada dasarnya komposisi alpha 'over') untuk penggambaran objek.

Meski begitu, bukan berarti hal itu tidak bisa dilakukan.

Kalau rectangle, ellipse, circle, atau apa pun ingin dikomposisikan dengan
komposisi alpha yang lain (misalnya 'DstOver' yang mirip komposisi Under),
gambarlah bangun itu pada kanvas transparan kosong berukuran sama dengan
aslinya, lalu komposisikan ke gambar Anda.

Namun karena SVG memungkinkan komposisi alpha dipakai untuk menggambar teks dan
benda lain ke atas gambar, saya membayangkan hal itu akan ditambahkan kelak.

Nantikan saja!

Menggambar simbol

Kadang ada sekumpulan titik pada sebuah gambar yang ingin ditandai dengan simbol acuan, seperti tanda silang, lingkaran, dan sebagainya... Sayangnya sampai saat ini IM belum punya perintah untuk menggambar simbol semacam itu dengan mudah, tetapi dengan sedikit kerja tambahan simbol seperti itu tetap bisa digambar.

Teknik menggambar simbol

Kiat menggambar banyak simbol pada sederet lokasi tertentu adalah membangkitkan perintah gambar MVG lewat skrip shell, atau lewat API apa pun yang Anda pakai, sehingga sekumpulan titik yang diberikan berubah menjadi kumpulan perintah gambar yang sesuai. Sebagai contoh, di sini saya mengubah sederet titik menjadi tanda 'plus' pada masing-masing titik itu... |

  # 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]
Contoh di atas memakai "tr" untuk memisahkan tiap titik (dua angka) menjadi satu titik per baris, lalu memakai "awk" untuk semua perhitungan matematis yang diperlukan guna menggambar 'plus' di atas titik tersebut. Silakan pakai apa saja yang Anda suka di sini, karena yang saya lakukan hanyalah semacam ekspansi makro teks atas daftar titik masukan. Hampir semua bahasa pemrograman bisa melakukannya. Untuk kasus skrip shell di atas, "awk" saya rasa cara paling sederhana dan paling cepat. Sebenarnya ImageMagick sendiri pun bisa dipakai untuk ekspansi 'makro' itu lewat opsi format "magick"... Sebagai contoh, di sini saya memakainya untuk menghitung sebuah titik pada keliling lingkaran, untuk 'simbol titik' ini. |

  # 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]
String draw yang dihasilkan bisa menjadi cukup panjang, dan bisa mulai menimbulkan masalah pada panjang perintah akhir Anda. Jadi, alih-alih mengubah titik-titik itu menjadi string panjang yang lalu diteruskan ke IM lewat baris perintah, perintah gambar bisa disalurkan (pipe) ke IM sebagai sebuah file. Kali ini saya juga memakai metode gambar Path SVG, bukan metode primitif draw. Simbol yang saya hasilkan pun berupa segitiga di sekeliling tiap titik. |

  # 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]
Path SVG sebenarnya membuat hal ini lebih mudah, karena mengizinkan gerak piksel relatif, sehingga simbolnya bisa dirancang agar hanya perlu satu gerak absolut awal 'M' sebelum deretan 'move' dan 'line' untuk menggambar simbol itu. Karena itu perhitungan floating point sama sekali tidak diperlukan, sebab draw IM yang akan mengerjakan matematika penempatannya. | Item gerak relatif 'm' pada Path SVG rusak sebelum IM v6.4.3-5. Bila IM yang Anda pasang lebih lama dari itu, contoh di atas (dan berikutnya) mungkin tidak menggambar apa pun. Untuk versi lama, ini bisa diperbaiki dengan mengganti gerak relatif 'm' di atas dengan deretan garis relatif 'l' yang sepadan.
Langkah ini bahkan bisa dibawa satu tahap lebih jauh: umpankan sebuah file MVG yang utuh, lengkap dengan spesifikasi kanvas gambar, langsung ke IM sebagai pipeline perintah gambar. Kali ini mari kita buat 'silang' yang mirip contoh 'plus' pertama di atas, yang tadi butuh banyak perhitungan. |

  # 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]
Ini memakai teknik pemrograman shell khusus, yaitu segala sesuatu yang di-'echo' di dalam tanda kurung shell akan diumpankan ke perintah "magick" terakhir sebagai file MVG. 'echo' pertama mendefinisikan sekaligus mengisi kanvas gambar, sedangkan perulangan 'while' mengubah tiap 'point' yang diberikan menjadi lingkaran dengan radius yang ditentukan. Keunggulan metode ini adalah tidak adanya batasan panjang string seperti pada dua metode lainnya. Simbol lain yang bisa dihasilkan antara lain kotak, belah ketupat, error-bar, dan sebagainya... Lihat juga 'Menggambar lingkaran di bawah untuk metode lingkaran yang lain, termasuk penggambaran lingkaran 'path' relatif tanpa perhitungan.

Alternatif selain menggambar simbol

Ada cara lain menambahkan simbol ke gambar selain menggambarnya secara langsung.

Font simbol

Simbol dapat diekstrak dari font simbol lalu disimpan sebagai bitmap kecil. Gambar berwarna kecil yang sudah disiapkan pun bisa dipakai untuk keperluan ini. Namun cara ini mungkin sulit menempatkan fontnya tepat relatif terhadap piksel tertentu. Artinya, tekniknya tidak terlalu presisi. Tetapi gambar apa pun bisa dikomposisikan di lokasi piksel mana pun. Sebagai contoh, simbol-simbol ini diekstrak dari sejumlah font, khusus untuk dipakai di halaman-halaman contoh ini.

Contoh mengomposisikan gambar ke latar belakang yang lebih besar diberikan pada bagian Melapiskan gambar. Namun metode berulang mungkin lebih berguna, seperti yang diberikan di Penempatan terprogram gambar berlapis. FUTURE: example of layering images using coordinates

Morfologi

Alternatif lain adalah memakai Morfologi untuk men-'Dilate' satu piksel, dengan kernel 'shape' khusus seperti 'Disk', 'Ring', dan 'Plus', atau bahkan kernel buatan pengguna Anda sendiri. Sebagai contoh...

  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]

Hasilnya lalu bisa langsung diubah menjadi overlay berwarna dengan operator Alpha Shape. Keunggulan besarnya, lokasi tiap simbol satu per satu tidak perlu diketahui. Begitu pula jumlah simbolnya. Tapi itu sekaligus bisa menjadi kelemahan. Kelemahan utamanya, posisinya hanya berada di lokasi bilangan bulat. Penggambaran dengan penempatan 'sub-piksel' floating point tidak bisa dilakukan.

Konvolusi

Teknik yang hampir sama adalah memakai 'Convolve' dengan kernel yang dirancang khusus, sehingga berbagai gradasi abu-abu bisa ditetapkan, bukan sekadar hasil hidup/mati seperti di atas. Dengan memakai kernel buatan pengguna yang berbeda untuk tiap kanal gambar (merah, hijau, biru, dan alpha), simbol beraneka warna bahkan bisa dibuat dari tiap koordinat piksel. [IM Output] Untuk ini saya memakai skrip khusus "image2kernel" yang saya tulis untuk mengubah gambar berwarna (lihat kanan) menjadi kernel konvolusi floating point terpisah bagi masing-masing kanal.

  image2kernel -q marker.png marker.dat

Ini menghasilkan empat file, misalnya "marker_R.dat", satu untuk tiap kanal gambar masukan yang sangat kecil itu, yang merupakan representasi buatan pengguna dari gambar tersebut (dengan titik asal di tengah gambar). Dengan file data kernel itu, kini kita bisa mem-Convolve titik-titik tunggal tadi menjadi gambar penanda berwarna di atas latar belakang transparan.

  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]

| Sebelum IM v6.7.6-9, operator Combine menuntut kanal transparansi gambar diberikan sebagai nilai 'opacity', bukan nilai alpha, sehingga kanal alpha yang dihasilkan perlu dinegasikan. Contoh: |

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

Sebaiknya hanya gambar kecil yang dipakai, dengan titik piksel yang cukup berjauhan supaya simbolnya tidak saling tumpang tindih. Sebab Convolve akan menjumlahkan area yang tumpang tindih, sehingga area itu menjadi lebih terang daripada yang diharapkan. Contoh di atas sudah dijadikan skrip shell UNIX "convolve_image" agar lebih mudah dipakai.

  convolve_image  points_pixels.gif marker.png   point_markers.png

Teknik ini lahir dari diskusi di Forum IM A Fun Experience with IM. Penanyanya ingin menempatkan orang-orang mungil di atas gambar latar lapangan sepak bola sehingga posisi mereka mengeja nama seseorang di dalam gambar itu.

Berlapis

Teknik lain seperti Lapisan gambar, yang ditempatkan memakai daftar piksel hasil ekstraksi dari gambar sumber, mungkin pendekatan yang lebih baik. Gambar simbol yang lebih jauh bisa ditimpakan lebih dulu sebelum gambar latar depan, dan pemilihan simbol untuk tiap titik bisa dilakukan secara terprogram atau diacak. Untuk contohnya lihat Pin pada peta.

Menggambar lingkaran

Opsi draw menyediakan beberapa cara untuk mengerjakan hal yang sangat mendasar... menggambar lingkaran. Sebagai contoh, lingkaran bisa digambar melalui titik mana pun pada kelilingnya. Jadi Anda perlu menghitung titik pusat dan titik kedua yang berjarak sebesar jari-jari (katakanlah 25 piksel) dari titik pertama. |

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

[IM Output]
Fred Weinhaus mencatat bahwa dengan memakai translate, kebutuhan menghitung koordinat tepi lingkaran bisa dihilangkan, dan radiusnya cukup diberikan langsung. |

  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]
Namun untuk menggambar banyak lingkaran, cara di atas memerlukan operasi "-draw" terpisah bagi tiap lingkaran, atau memakai push konteks. Dengan ellipse, jari-jarinya bisa ditentukan langsung sebagai panjang sumbu |

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

[IM Output]
Lingkaran juga bisa dihasilkan dengan menggambar garis yang sangat sangat pendek memakai 'stroke-linecap round'. Lebar stroke lalu menentukan diameter lingkarannya. CATATAN: garis itu harus punya panjang (sekecil apa pun), kalau tidak draw tidak akan menggambar apa-apa. |

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

[IM Output]
Sayangnya teknik ini tidak bisa memberi garis tepi pada lingkaran yang dihasilkan, tetapi untuk menutup area luas, lebar stroke yang besar bisa berguna. Lihat Beberapa contoh sederhana di bawah. Metode ini memanfaatkan cara gambar Path SVG sehingga lingkarannya bisa digambar tanpa perlu menghitung koordinat tambahan. |

  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]
Hanya gerak absolut awal 'M' yang diperlukan untuk menentukan pusatnya; '25' dan '50' pada komponen path selanjutnya menentukan radius dan diameter lingkaran relatif terhadap pusat itu. | Item gerak relatif 'm' pada Path SVG rusak sebelum IM v6.4.3-5. Bila IM yang Anda pasang lebih lama dari itu, lingkarannya mungkin hanya muncul sebagai satu piksel. Untuk versi lama, ini bisa diperbaiki dengan mengganti 'm' di atas dengan 'l'.
Fred Weinhaus menambahkan metode lingkaran bezier berikut. Hasilnya sangat mendekati lingkaran sungguhan (walau tidak persis), dan memerlukan perhitungan floating point. |

  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]
Kalau menggambar lingkaran yang persis tidak penting, path SVG dengan 4 segmen Bezier ini bisa dipakai; perhitungannya hanya memakai batas X dan Y lingkaran. |

  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]
Kalau Anda menginginkan lingkaran yang digambar sepenuhnya relatif terhadap titik awal di pusat, teknik ini bisa dipakai. Hanya nilai radius yang dipakai, sehingga mudah dibangkitkan hanya dengan fungsi string di sebuah 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]
Terpikir cara lain untuk menggambar lingkaran?

Menggambar panah -- menempatkan, memutar, dan menskalakan simbol

Dengan teknik di atas, simbol khusus seperti kepala panah bisa dibuat, lalu ditempatkan sehingga ujungnya persis di penghujung sebuah garis, dan digambar menimpanya.. Kalau panahnya digambar sesudah garis (situasi yang lazim), panah itu akan tergambar di atas garis. Namun ada tiga jenis panah yang bisa didefinisikan, dan tiap jenis didefinisikan dengan cara berbeda bergantung pada kegunaannya.

  • Pengukuran, yaitu saat Anda sekadar ingin menandai ujung-ujung sebuah garis dengan kepala panah untuk menunjukkan batas suatu pengukuran pada diagram teknik. Sangat sederhana.
  • Vektor , yang menunjukkan arah sekaligus intensitas suatu nilai.
    Misalnya pada peta angin cuaca. Ekornya diperlukan dan titik 0,0 berada di ujung ekor itu. Sering kali dibuat kisi besar berisi vektor semacam ini.
  • Penunjuk , yang menunjukkan suatu detail.
    Untuk yang ini titik 0,0 sebaiknya berada di ujung panah, atau agak di depan panahnya.

Panah pengukuran

Sekadar menambahkan kepala panah di ujung garis relatif mudah dilakukan. Pada dasarnya Anda membuat simbol 'kepala panah', lalu menggambarnya di posisi yang tepat. Sebagai contoh... |

  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]
Perhatikan bahwa saya menggambar simbolnya sedemikian rupa sehingga titik awalnya persis di penghujung garis. Dengan begitu simbol itu bisa digambar mundur menimpa garis yang tadi digambar, menghasilkan simbol yang rapi dan enak dilihat. Namun panah punya arah. Anda bisa saja membuat sangat banyak definisi panah pada bermacam sudut, dan banyak program memang begitu. Tapi karena panah itu sebuah vektor, kenapa tidak memutarnya sebagai vektor saja. Perintah draw IM sudah punya rotasi gambar bawaan (pelengkungan kanvas), jadi mari kita pakai. Cara ini juga menguntungkan karena posisinya keluar dari definisi 'path' kepala panah, sehingga seluruh path bisa ditetapkan sebagai 'konstanta'... |

  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]
Kalau ukuran panahnya ingin diubah, tambahkan opsi draw "scale" sesudah 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]
Perhatikan bagaimana panah itu membesar sambil membiarkan 'ujung'-nya tetap di tempat yang Anda tentukan. Ini aspek yang sangat penting dalam menangani panah, sebab yang berpengaruh hanyalah titik akhir dan sudut garis yang diberi panah. Urutan 'transform'-nya penting, dan sebenarnya kebalikan dari urutan pelaksanaannya. Artinya, scale diterapkan lebih dulu pada koordinat, lalu rotate, baru translate. Kalau transformasi koordinatnya tidak dikerjakan dalam urutan itu, penempatan akhir panahnya ikut terskalakan dan tidak akan berada di tempat yang kita harapkan. Selain itu, karena scale punya dua angka dan simbol kepala panah aslinya dirancang mendatar (sudut nol), lebar panah bisa diskalakan terpisah dari tingginya. Perhatikan juga bagaimana lebar stroke ikut terskalakan bersama ukuran kepala panah, sehingga semuanya tetap serasi. |

  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]
Nah, karena kanvasnya dilengkungkan untuk menggambar tiap panah, mungkin bersama banyak operasi gambar lain, Anda mungkin ingin mengerjakan semuanya dalam satu operasi "-draw". Katakanlah menggambar garisnya lalu menambahkan panah di KEDUA ujungnya, yang menuntut set warna, posisi, rotasi, dan bahkan mungkin skala yang berbeda. Artinya cakupan pelengkungan kanvas perlu dibatasi hanya pada penggambaran tiap kepala panah. Bila cakupannya tidak dibatasi, operasi gambar berikutnya bisa ikut terpengaruh dan Anda tidak akan pernah benar-benar yakin apa yang sedang dihasilkan. Untuk membatasi cakupan pelengkungan (dan semua atribut gambar lain), bagian yang bersangkutan dibungkus dalam sebuah "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]
Pada dasarnya 'push' menyimpan semua atribut gambar saat itu untuk dipakai nanti, sedangkan 'pop' memulihkan atribut tersebut, mengganti pengaturan apa pun (warna, pelengkungan, posisi, dan sebagainya) dengan pengaturan yang tadi disimpan. Artinya, sesudah 'pop', 'pelengkungan kanvas' dibatalkan dan draw kembali ke keadaan sebelum apa pun diubah. Teknik di atas hanyalah satu cara menghasilkan panah, dan cara yang bagus ketika panah digambar sebagai bagian dari pengukuran jarak, seperti pada gambar teknik.

Panah vektor

Seperti disebutkan, vektor menunjukkan arah sekaligus intensitas suatu nilai. Artinya panjang panahnya berubah-ubah, dan kepala panahnya bisa berada di posisi mana pun sejauh apa pun dari titik awal vektor. Anda bisa saja melakukan perhitungan berat untuk menentukan di mana kepala panah harus ditempatkan berdasarkan panjang dan sudut vektornya, tetapi ada cara yang jauh lebih baik, yaitu membiarkan ImageMagick yang menghitungnya. Solusinya adalah menggambar panjang vektor itu sebagai garis mendatar dengan panjang yang tepat di ruang kanvas yang dilengkungkan. Setelah garis itu tergambar, translate saja ruang gambarnya lagi ke ujung garis selagi kanvasnya masih 'melengkung'. Posisinya kini sudah benar, dengan rotasi yang tepat untuk menggambar 'kepala panah' vektornya seperti biasa. Sebagai contoh, di sini saya menghasilkan vektor sepanjang 70 piksel pada sudut -35 derajat. |

  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]

Panah penunjuk

Pada contoh di atas saya juga memperagakan panah penunjuk yang mengarah ke titik awal panah vektor sebelumnya. Namun alih-alih menggambar panahnya seperti tadi, saya membuatnya sebagai simbol panah terbalik yang dimulai 10 piksel dari titik asal (atau titik awal). Maksudnya, ada simbol di posisi yang ingin saya tunjuk, jadi saya justru tidak ingin panahnya persis menimpa posisi itu, melainkan sedikit menjauh darinya. Nah, meski penunjuk lebih sederhana ditangani daripada vektor dan umumnya tidak perlu panjang yang berubah-ubah, biasanya Anda ingin menambahkan teks di ujung jauh penunjuk itu untuk menjelaskan apa yang ditunjuk. Seperti sebelumnya, menghitung posisi itu bisa merepotkan, jadi untuk apa repot. Solusi penempatan teksnya pun sama seperti pada vektor. Pertahankan ruang lengkung yang tadi dipakai menggambar panah penunjuk, lalu translate titik asalnya ke pangkal ekor panah itu (40 piksel mendatar dalam ruang lengkung). Setelah posisinya berpindah, pelengkungannya bisa diputar balik di sekitar posisi baru itu, sehingga teksnya bisa digambar seperti biasa (dengan sedikit offset). Sayangnya, walaupun perataan teks bawaan 'left' berhasil pada contoh di atas, saat ini perataan teks belum bisa ditetapkan di MVG sebagai pengaturan yang terpisah dari gravity. Kalau ini menjadi masalah, ajukan permintaan di forum bug IM, dan mudah-mudahan perataan teks (yang terpisah dari penempatan gravity) menjadi kenyataan, apalagi hal itu sebenarnya bagian dari spesifikasi SVG.


Menggambar objek

Stroke warna yang lebar

Anda tidak harus menutup rapat sebuah area isian dengan path atau garis tepi untuk membuat berbagai bentuk. Dengan stroke yang sangat besar dan lebar, area serta bidang warna yang luas bisa dihasilkan pada sebuah kanvas. Sebagai contoh, busur eliptis berstroke lebar bisa menghasilkan bidang warna yang bagus, yang pernah benar-benar saya lihat dipakai untuk membuat poster. |

  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]
Atau Anda bisa menghasilkan senyum badut yang cukup rumit. |

  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]
Apa yang bisa Anda buat? Beri tahu kami.

Silinder

Dalam sebuah diskusi di Forum IM ada pembahasan panjang tentang menggambar silinder, khususnya silinder bergradasi, dengan perintah draw ImageMagick. Kiat menggambar silinder adalah menggambar primitif 'roundrectangle' sedemikian rupa sehingga ujung-ujungnya membentuk oval. Artinya, kalau silindernya selebar 50 piksel, sudut-sudut persegi panjangnya dibulatkan sebesar 25 dan 12 piksel. Yaitu setengah lebar persegi panjang, lalu setengahnya lagi. Dengan begitu silinder hanyalah dua persegi panjang bersudut bulat yang digambar bertumpuk. 'Oval ujung' kedua yang isian warnanya lebih terang dibuat berukuran tepat dua kali lipat kedua dimensi sudut tadi. Sebagai contoh... |

  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]
Dengan mengganti warna fill pertama dengan warna gradien (memakai teknik tiling di memori), silindernya bisa dibuat tampak sedikit lebih 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]
Dengan memperhalus gambar silindernya sedikit demi sedikit (seperti yang dibahas di forum IM), silinder yang sangat rumit dan enak dipandang bisa dihasilkan. Ini termasuk penambahan silinder kaca semitransparan di sekelilingnya, efek bayangan, dan pelabelan. Hasil akhir diskusi itu adalah skrip "cylinder_bar" yang menghasilkan bilah persentase berbentuk silinder...

  cylinder_bar 95 cylinder_95.png

[IM Output]

Skrip ini bisa menghasilkan gambar berukuran berapa pun, menyesuaikan semua parameter dengan tepat berdasarkan ukuran itu dan pengaturan lain yang didefinisikan di bagian atas skrip. Di dalamnya juga ada konsep 'ketebalan kaca', untuk membuat celah antara silinder kaca semitransparan di luar dan silinder berwarna di dalamnya. Perhatikan gradasi silinder yang begitu halus, terutama saat ujung silinder hijau bertumpang tindih dengan ujung silinder kacanya! Menakjubkan apa yang bisa dicapai dengan sedikit perencanaan di awal.


Menggambar karakter khusus di dalam string teks

Pakai tanda kutip atau backslash?

Salah satu masalah terbesar yang dihadapi orang dengan -draw adalah menggambar karakter yang juga punya arti khusus bagi shell UNIX dan baris perintah DOS, atau bahkan bagi bahasa lain seperti C, Perl, PHP, R, atau Visual Basic. Biang keroknya adalah dua jenis karakter kutip, ditambah karakter substitusi variabel seperti dolar '$' serta karakter escape shell dan ImageMagick, yaitu backslash '\'. Pada dasarnya argumen MVG untuk "-draw" perlu diapit tanda kutip, dan argumen string 'text' di dalamnya pun mungkin perlu tanda kutip tambahan. Untuk mengatasinya, pengguna biasanya memakai dua karakter kutip yang berbeda: satu untuk shell dan satu lagi untuk string teks MVG.

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

Perhatikan bahwa inilah satu-satunya pilihan nyata bagi pengguna Windows, yang punya masalah dan metode pengutipannya sendiri. Sebagai alternatif, tanda kutipnya bisa ditukar, dan dipakai...

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

Bentuk ini memungkinkan penyertaan substitusi variabel shell (memakai '$' tanpa escape. Memilih bentuk yang tepat akan menyelesaikan sebagian besar masalah, tetapi beberapa karakter tetap menyulitkan, dan tiap solusinya bergantung pada persis set tanda kutip mana yang dipakai, karena itu pula yang menentukan bagaimana karakter khusus harus di-escape. Berikut keempat kasus pengutipan dan penanganan karakter khususnya...

  • Memakai tanda kutip tunggal untuk argumen shell,
    dengan tanda kutip ganda mengapit string teks MVG.Teknik paling sederhana untuk menangani string teks draw adalah memakai kutip tunggal sebagai pembungkus argumen shell. Namun ini berarti, untuk menyertakan apostrof di dalam string yang digambar, Anda perlu keluar dari 'mode kutip tunggal' shell dan memberikan apostrof itu di luar kutip tunggalnya. Sebagai contoh, beginilah cara menangani keempat karakter khusus yang saya sebut tadi. |
    magick -size 250x50 xc:none  -box white  -pointsize 20 -gravity center \
              -draw 'text 0,0 "  '\''  \"  $  \\  " ' \
              -trim +repage  text_special_sd.gif
    

[IM Output]
Perhatikan bahwa karena tanda dolar tidak perlu di-escape, tanda itu juga tidak bisa dipakai untuk menyisipkan isi sebuah variabel shell. Penting diingat bahwa backslash adalah satu-satunya karakter khusus yang ditangani string draw IM. Alasan keberadaannya pun semata-mata agar 'tanda kutip string draw IM' bisa di-escape, seperti yang kita lakukan di atas untuk kutip ganda. Selebihnya, semua keanehan lain disebabkan oleh shell baris perintah UNIX, bukan oleh IM. PC-DOS punya keanehannya sendiri, dan saya akan berterima kasih atas masukan tentang cara meng-escape karakter khusus ketika memakai IM dari lingkungan tersebut. * Memakai tanda kutip ganda untuk argumen shell,
dengan tanda kutip tunggal mengapit string teks MVG.Kalau Anda memang ingin menyisipkan 'variabel shell' ke dalam string yang digambar, argumen shell terluarnya harus memakai kutip ganda. Ini membuat seluruh urusannya jauh lebih rumit, karena perlindungan dari shell hilang dan kini bukan hanya tanda dolar '$' yang harus di-escape, tetapi backslash '\' juga. Di sisi lain, shell jadi tidak perlu memakai karakter kutip tunggal sebagai pembatas akhir argumen, jadi bagian itu menjadi lebih sederhana. Mari kita rangkum hasilnya untuk daftar pendek karakter khusus kita. |

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

[IM Output]
Perhatikan bahwa kalau backslash itu sendiri yang ingin digambar, string teks MVG menuntut backslash-nya digandakan (seperti pada contoh sebelumnya), tetapi shell-nya sendiri juga menuntut tiap backslash itu digandakan lagi, sehingga total ada empat backslash hanya untuk menghasilkan satu karakter tersebut. Penggandaan ini bisa dengan cepat menjadi membingungkan dan melelahkan, karena butuh banyak sekali backslash untuk mencapai yang diinginkan. Pelan-pelan saja, dan bentuk yang cocok untuk situasi Anda pasti ketemu. * Memakai tanda kutip tunggal untuk argumen shell,
dengan tanda kutip tunggal mengapit string teks MVG. Mari kita tutup dengan rangkuman dua kombinasi pengutipan terakhir. Bagaimana keduanya diurai oleh shell dan MVG, saya serahkan kepada Anda. |

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

[IM Output]
* Memakai tanda kutip ganda untuk argumen shell,
dengan tanda kutip ganda mengapit string teks MVG. |

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

[IM Output]

Seperti terlihat, argumen "-draw" dari baris perintah harus berurusan dengan shell baris perintah sekaligus dengan escape backslash dan tanda kutip di dalam string teks MVG. Hasilnya bisa membingungkan dan merepotkan. Ingat saja bahwa shell memperlakukan kedua jenis tanda kutip secara berbeda, sedangkan string teks MVG tidak. Tentu saja pada skrip yang rumit, cara yang lebih baik mungkin menghindari shell dan segala masalah skripnya sama sekali. Caranya, baca argumen "-draw" dari sebuah file gambar MVG.

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

Tentu saja karakter kutip apa pun yang dipakai tetap perlu diberi backslash, begitu pula tiap backslash di dalam teksnya. Namun ini jauh lebih sederhana daripada menghadapi sistem pengutipan dan escape milik shell berbarengan dengan milik IM. |

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

[IM Output]
[IM Output]
Gambar pertama berasal dari salah satu file teks "MVG" yang saya pakai. Di dalamnya tidak ada escape maupun pengutipan shell. Jadi yang ada hanyalah pengutipan dan escape MVG. Perhatikan bahwa pada contoh di atas, seandainya saya memakai kutip tunggal untuk string teks MVG, satu-satunya perubahan adalah saya perlu memberi backslash pada karakter kutip tunggal, bukan pada karakter kutip ganda di dalam string itu. Tentang karakter persen Satu hal terakhir tentang karakter 'escape' khusus pada operator "-draw text". Karakter persen '%' seharusnya tergambar 'apa adanya'. Tidak perlu melakukan apa pun yang khusus untuk menggambarnya. Kalau tidak tergambar 'apa adanya', berarti versi IM Anda sudah lama dan sebaiknya segera diperbarui. | Sampai dengan IM versi 6.2.4, karakter '%' dipakai sebagai karakter escape untuk menyertakan informasi gambar tambahan di dalam string teks yang digambar. Hal itu tidak berlaku lagi karena escape semacam itu membingungkan dan keliru ketika gambar SVG juga mencoba menggambar karakter persen.
Pemakaian 'escape' persen ini (juga escape baris baru '\n') dianggap tidak cocok dengan operator "-draw" dan dengan tujuan format MVG untuk menangani format gambar SVG. Karena itu, sejak IM versi 6.2.4 escape % tidak berfungsi lagi, dan backslash hanya meng-escape dirinya sendiri serta tanda kutip yang mengapitnya. |

    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]
Untuk keterangan lebih rinci tentang 'bug persen' ini, dan cara menghindarinya saat memakai "-draw" pada ImageMagick yang lebih lama, lihat halaman Drawing a Percent Bug. Annotate alih-alih draw Cara yang lebih baik untuk menghindari masalah semacam ini adalah memakai "-annotate" ketimbang draw untuk menggambar teks. Operator ini adalah pembungkus operator draw dan memungkinkan pemakaian seluruh kemampuan draw, tetapi dalam bentuk yang lebih sederhana. Pada dasarnya operator ini hanya perlu satu set pengutipan (untuk shell). Ini membuat urusan karakter khusus menjadi jauh lebih sederhana. Sayangnya, walau tanda kutip tidak perlu lagi di-escape untuk IM, kini ada escape persen, seperti pembacaan file '@', baris baru '\n', dan ekspansi escape persen lainnya. Sebagai contoh, dengan kutip tunggal... |

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

[IM Output]
dan untuk kutip ganda... |

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

[IM Output]
Namun semua tanda kutip dan escape anotasi diabaikan sama sekali kalau escape '@' dipakai untuk membaca string dari sebuah file. Sebagai contoh, di sini kita menyertakan informasi lebar dan tinggi sebuah gambar! |

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

[IM Output]
Namun semua escape diabaikan sama sekali ketika string anotasi dibaca dari sebuah file. |

    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]
Untuk keterangan lebih lanjut lihat Operator penggambaran teks Annotate, dan terutama Karakter escape Annotate.


Penanganan SVG oleh IM

Driver input SVG: RSVG vs MSVG

Menangani format gambar SVG yang sesungguhnya adalah urusan yang sangat rumit. Mesinnya harus menangani seluruh aspek format itu, sebagaimana didefinisikan dokumen SVG -- Scalable Vector Graphics. Sesuatu yang menuntut banyak sekali upaya pemrograman, dan waktu. Karena itu ImageMagick menyediakan dua metode dalam menangani gambar berformat SVG. Yang pertama memakai pustaka open source RSVG, untuk mengonversi format SVG menjadi gambar raster yang tidak menyulitkan IM. Mesin ini lengkap di hampir semua aspek penanganan SVG. Metode kedua, IM mencoba mengonversi SVG menjadi MVG, memakai metode bawaan bernama MSVG. MSVG berusaha mengonversi gambar SVG menjadi bahasa penggambaran "MVG" milik operator "-draw" IM. Banyak fungsi draw MVG dibuat khusus untuk keperluan ini. Sayangnya, walau penggambaran garis dan pewarnaan dasar sudah ada, ini masih jauh dari konvertor SVG yang lengkap. Pemakaian konvertor MSVG internal dapat dipaksakan dengan membaca gambar SVG lewat format input khusus "MSVG:" (ditambahkan di IM v6.3.4). Tetapi kalau pustaka RSVG tersedia, kebanyakan ImageMagick justru akan memakainya untuk merender gambar SVG. Untuk mengetahui apa yang akan dilakukan IM Anda, pakai...

  magick -list format | grep SVG

[IM Text]

Seperti terlihat dari "RSVG" di dalam kurung, IM saya sendiri akan memakai pustaka RSVG, dengan versi yang tertera, yang ada di komputer saya. Di sini saya 'menggambar' sebuah gambar SVG kecil buatan tangan, "diagonal.svg" (sumbangan pengguna forum penciledin), yang membuat persegi panjang dengan gradien diagonal sederhana, di atas latar belakang putih. |

  magick diagonal.svg  diagonal_rsvg.gif

[IM Output]
Sempurna. Gradien diagonal yang benar berhasil dihasilkan. Namun kalau ini dirender memakai MSVG internal (default kalau pustaka RSVG tidak tersedia)... |

  magick msvg:diagonal.svg  diagonal_msvg.gif

[IM Output]
Seperti terlihat, konversi MSVG internal gagal: yang dikembalikan gradien vertikal, bukan diagonal. Perintah MVG yang sebenarnya dibangkitkan IM juga bisa dilihat dengan mengonversi SVG langsung menjadi file MVG.

[IM Text]

  magick msvg:diagonal.svg mvg:diagonal.mvg

[IM Text]

Mungkin Anda bisa melihat bagaimana konvertor MSVG berusaha mengonversi SVG menjadi perintah penggambaran MVG. Hal-hal yang diketahui gagal ditangani MSVG internal saat ini antara lain...

  • Gradien non-vertikal (tidak ada konversi ke penanganan gradien MVG yang baru)
  • Teks yang mengikuti jalur melengkung
  • Perataan teks (yang terpisah dari gravity)

Namun sebagian besar aksi penggambaran dasar tetap tertangani. Ingat juga bahwa bahasa MVG sebenarnya sanggup menangani hal-hal yang tidak bisa dilakukan SVG, termasuk pemakaian gravity untuk memosisikan gambar dan teks. Gravity bukan bagian dari spesifikasi SVG, walau ia bagian tak terpisahkan dari penanganan teks dan font di IM. Ingat juga bahwa MVG tidak punya mekanisme kontainer seperti yang dimiliki SVG. Konvertor MSVG internal menggantikan kontainer XML dengan push dan pop konteks grafik (lihat keluaran MVG di atas), yang efeknya sama.

Pengaturan SVG

Format gambar SVG adalah format vektor (lihat Sepatah kata tentang format gambar vektor), sehingga gambarnya biasanya tidak punya 'ukuran' default. Sebagai gantinya, gambar itu 'digambar' atau 'dirender' pada "-density" tertentu, persis seperti postscript (density default 72 dpi). Selain itu, kalau SVG-nya tidak 'mengecat' latar belakang, warna latar belakang yang dipakai bisa ditentukan lewat pengaturan "-background". Sebagai contoh, ini gambar SVG kecil lainnya "home.svg", yang sudah 'dirender' memakai 3 density berbeda, dengan 3 latar belakang berbeda, termasuk latar belakang transparan.

  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]

Perhatikan bahwa saya memakai gambar berformat PNG untuk versi latar belakang transparan yang lebih besar pada contoh di atas. Ini menghasilkan gambar yang lebih bersih dibanding format GIF karena adanya piksel tepi yang semitransparan. PNG selalu disarankan bila transparansi terlibat pada gambar akhir. | _Saya menemukan bahwa sebagian gambar SVG tidak mau diskalakan. Artinya, gambar itu didefinisikan dalam satuan 'piksel', bukan panjang dunia nyata seperti 'point', 'inci', atau 'milimeter'. Akibatnya, walau pengaturan "-density" bisa mengubah ukuran gambar keseluruhan (dalam satuan dunia nyata), ukuran 'piksel' tidak berubah, sehingga gambarnya sendiri tidak berubah ukuran. Namun gambar SVG semacam itu cukup langka.

Lebih buruk lagi, ada beberapa gambar SVG yang memakai campuran satuan 'piksel' dan 'point', dan kecuali penulisnya sengaja melakukan itu, hasilnya bisa benar-benar berantakan bila Anda mencoba memakainya pada density yang berbeda dari yang dimaksudkan penulisnya. Untungnya yang seperti ini bahkan lebih langka lagi.

Perbaikan sederhananya biasanya cukup mengubah semua satuan 'piksel' di dalam SVG menjadi 'point', tetapi jangan dilakukan membabi buta, siapa tahu pemakaian 'piksel' itu memang disengaja._

Penanganan keluaran SVG

Sejak IM v6.4.2, IM bisa mengonversi gambar bitmap APA PUN menjadi grafik vektor SVG! Konversinya tidak selalu berhasil, tetapi gambar yang lebih besar dan/atau lebih sederhana (seperti mask bitmap) bisa dikonversi dengan sangat baik. Sebagai contoh, di sini saya mengonversi sebuah bentuk bitmap yang buruk menjadi gambar SVG, lalu mengonversinya kembali, supaya bitmap itu menjadi bentuk halus dengan anti-aliasing yang benar.

  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]

Namun supaya ini berhasil, pustaka 'development' "AutoTrace" harus terpasang, dan IM dikonfigurasi dengan switch "--with-autotrace". Kalau pustaka "AutoTrace" tidak terpasang dan tidak dikompilasi ke dalam IM, keluaran SVG yang dihasilkan akan berupa lingkaran satu piksel dalam jumlah sangat besar, sehingga hasilnya biner, bukan gambar SVG bergaris tepi yang halus. Gambar semacam itu jauh lebih besar sebagai perbandingan, dan sering butuh waktu sangat lama untuk dirender oleh mesin render SVG. Teknik raster ke vektor default yang lebih baik sebenarnya memang dibutuhkan, mungkin dengan teknik skeleton Morphology dan MAT. Dulu ada delegate input "autotrace:', untuk 'menghaluskan gambar bitmap masukan', yang melakukan semua langkah di atas sekaligus dengan memakai perintah "autotrace" secara langsung. Tapi terakhir kali saya lihat, delegate ini sudah lenyap. Begini dulu cara memakainya... |

  magick autotrace:A.gif  A_traced.png

[IM Output]
Tentu saja ini TIDAK akan memberi Anda keluaran SVG dari perintah "autotrace", melainkan hanya menyaring gambar masukan lewat SVG untuk menghaluskannya. Sebagai alternatif, perintah "autotrace" sebenarnya bisa dipakai langsung, seperti diperlihatkan pada contoh Pemberian tepi raster ke vektor dan Skeleton memakai Autotrace. Anda mungkin juga tertarik melihat hasil kerja cancerberosgx, di Generating SVG Images yang menelaah solusi untuk mengonversi foto.


Editor grafik vektor selain IM

ImageMagick adalah pemroses larik piksel. Umumnya ia tidak akan menyimpan gambar vektor ('MVG' satu-satunya pengecualian), hanya membacanya lalu mengonversinya menjadi larik piksel. Hal yang sama berlaku untuk editor gambar piksel lain, seperti Gimp, Photoshop, dan seterusnya. Untuk menyunting dan menangani gambar berbasis vektor, pakailah program seperti Sodipodi Editor grafik vektor berbasis SVG
Xfig Editor objek vektor yang sederhana, tetapi sangat bagus
(Bagus untuk papan tanda, peta, dan menata foto di satu halaman)
Dia
AutoTrace Mengonversi bentuk dalam larik bitmap menjadi garis tepi vektor
Sketch Editor vektor berbasis Python dengan teks melengkung.
Tentu saja ini bukan daftar yang lengkap. Bahkan banyak pengolah kata, seperti OpenOffice, Word, dan TeX, umumnya punya berbagai editor objek sederhana, walau sering sulit dipakai. Namun untuk sekadar mengonversi sebuah format grafik vektor ke format vektor lain, jangan pakai ImageMagick. ImageMagick pada dasarnya adalah, dan akan selalu jadi, pengonversi dan pengubah gambar raster atau grafik bitmap. Untuk informasi lebih lanjut lihat Sepatah kata tentang format gambar vektor.