Contoh penggunaan ImageMagick -- API & scripting
- Windows dan DOS
- PHP
- PHP dengan perintah shell
- PHP Imagick (API ImageMagick untuk PHP)
-
PerlMagick (skrip Perl Magick)
-
Kiat menulis skrip shell/PHP ImageMagick yang lebih baik Mengapa menggunakan beberapa perintah "magick" Membuat IM lebih cepat (secara umum) Mengompilasi ImageMagick dari kode sumber
- ImageMagick dari kode sumber di Ubuntu
- ImageMagick di MacOSX
- Mengompilasi IM versi HDRI
- Membuat instalasi ImageMagick pribadi
Antarmuka baris perintah (CLI) ImageMagick yang dibahas contoh-contoh ini hanyalah salah satu metode untuk menggunakan, mengubah, dan mengendalikan gambar dengan pustaka inti fungsi ImageMagick (MagickCore). Pada dasarnya ini adalah antarmuka API 'shell'. Ada banyak Antarmuka Pemrograman Aplikasi (API) lain yang dapat digunakan secara lebih langsung dari berbagai bahasa pemrograman, lihat API ImageMagick. Di sini saya membahas cara memperbaiki skrip dan program IM Anda, perbedaan antara skrip Windows dan Unix, serta dasar-dasar penggunaan IM dari API dan bahasa pemrograman lain.
API dan metode lain penggunaan IM
API (Antarmuka Pemrograman Aplikasi) untuk pemrosesan gambar yang sesungguhnya nyatanya tidak lebih cepat daripada perintah CLI (seperti "magick", yang sendirinya merupakan sejenis API shell). Pustaka 'inti' yang sama dipakai untuk semua pemrosesan gambar di IM. Jadi untuk tugas kompleks seperti distorsi gambar, memakai API alih-alih "magick" dari shell nyaris tidak berpengaruh pada 'kecepatan' pemrosesan secara keseluruhan. Lalu mengapa memakai API alih-alih baris perintah? Shell terus-menerus melakukan 'fork' atas banyak perintah berbeda (bukan hanya perintah "magick" IM, meski shell punya sejumlah 'built-in'), yang masing-masing harus dimuat dan diinisialisasi setiap kali dijalankan. Setiap perintah IM juga harus menginisialisasi ulang file konfigurasinya, mengurai argumen baris perintah, membaca ulang gambar yang sedang dikerjakan, dan sering kali menyimpan hasil kembali ke disk. Semua itu memakan waktu sehingga membuatnya lebih lambat. Artinya, seluruh langkah ekstra itu menyita waktu dan daya pemrosesan, jadi bila sering dilakukan, API mulai masuk akal. API juga memungkinkan hal-hal lain yang tidak bisa dilakukan baris perintah.
- Jika API sudah berjalan, waktu penyiapannya hampir nol.
- Menyimpan di memori larik berisi banyak daftar gambar yang dapat diproses dalam urutan apa pun. Misalnya saya punya program yang membaca ratusan gambar, membuat thumbnail 32x32 piksel saat membacanya, lalu membandingkan semuanya berpasangan satu demi satu (9.900 pembandingan untuk 100 gambar). Contoh lain: mengurutkan gambar menurut warna umumnya di memori!
- Banyak alur pemrosesan gambar yang berbeda dapat dijalankan, dalam urutan apa pun. Tidak perlu 'menyelesaikan' satu rangkaian pemrosesan sebelum menggarap gambar atau langkah berikutnya. Bayangkan misalnya program yang memecahkan puzzle jigsaw!
- Informasi dapat diambil dari gambar, lalu dipakai dengan cara yang kompleks untuk mengubah pemrosesan gambar tanpa harus menginisialisasi ulang pemrosesan (membaca ulang konfigurasi dan gambar) berulang kali. Misalnya mengambil ukuran gambar sebelum menghitung kebutuhan pemasangan frame untuk gambar itu.
- Melakukan loop atas gambar-gambar, dengan perlakuan yang sangat berbeda untuk tiap gambar! Misalnya membangkitkan urutan animasi, dengan tiap frame didistorsi dengan cara yang sedikit berbeda.
- Akses langsung dan sepenuhnya acak ke data gambar. Misalnya mencari 'wajah' dalam sebuah gambar.
Namun untuk kebanyakan hal yang tidak melibatkan gambar dalam jumlah besar, atau pemrosesan gambar secara umum dengan cara yang terdefinisi baik, baris perintah praktis sama cepatnya. Meski begitu, banyak waktu dan pemrosesan ulang dapat dihemat dengan... * Memanfaatkan penyimpanan gambar MPC (agar pembacaan ulang lebih cepat) untuk gambar antara. Lihat skrip saya divide_vert * Pemrosesan paralel dengan pipe-lining (bahkan memakai mesin berbeda untuk langkah berbeda!), untuk memanfaatkan prosesor lebih baik dan menghindari penyimpanan gambar antara ke disk. Lihat enlarge_image untuk contoh skrip ber-pipeline yang tiap langkahnya menyalurkan gambar ke langkah berikutnya (kadang opsional) dalam rangkaian. * Memakai loop untuk memproses tiap gambar satu per satu, sebelum menyalurkan aliran hasil gambar ke langkah akhir 'gabungkan semuanya'. Saya punya banyak skrip seperti ini... Lihat penempatan terprogram gambar layer untuk salah satu contohnya.
Tentu saja di API tersedia juga teknik lain yang lebih cepat, yang bisa dipakai untuk tugas pemrosesan khusus yang membutuhkan akses ke gambar. Dan begitu kami menemukannya dan sempat, teknik semacam itu sering kami programkan ke dalam pustaka inti. Distorsi gambar dan berbagai ekspresi FX adalah salah satu contohnya.
Windows dan DOS
Contoh-contoh penggunaan skrip Windows dan DOS dengan API CLI telah dipindahkan ke Penggunaan di Windows.
PHP (perintah IM dari fungsi "system()")
Pengguna PHP punya tiga cara memakai ImageMagick,
- Antarmuka PECL "
imagick" - Antarmuka "
MagicWand" - Memakai fungsi "system()" dan "exec()" untuk menjalankan perintah CLI "
magick".
Berkat keberadaan contoh penggunaan IM, cara terakhir ini (dan yang pertama akan kita lihat berikutnya) dalam beberapa tahun terakhir menjadi cara paling umum memakai IM dari PHP. Tentu untuk beberapa hal cara ini mungkin bukan yang terbaik (lihat di atas); dalam hal itu antarmuka API tersedia, meski mungkin butuh administrator sistem untuk menyediakannya di lingkungan PHP Anda.
PHP dengan perintah shell
Sumber informasi terbaik yang spesifik tentang teknik ini adalah pengguna forum IM Bonzo dan situs webnya RubbleWebs. Perlu dicatat, PHP menjalankan "magick" dengan lingkungan yang berbeda, dan mungkin bahkan sebagai pengguna yang berbeda, dari yang didapat di baris perintah. Karena itu, apa yang berhasil di baris perintah mungkin perlu sedikit penyesuaian agar berjalan dari skrip web PHP. Berikut prosedur yang direkomendasikan untuk pengujian awal antarmuka IM baris perintah milik sebuah ISP, dengan asumsi tidak ada akses 'shell' baris perintah langsung di sistem jarak jauh tersebut. Artinya, yang bisa dilakukan hanyalah mengunggah file web untuk dieksekusi. Jadi hal pertama yang perlu kita lakukan adalah mencoba menemukan perintah "magick" di sistem itu, versi mana yang terpasang, dan lingkungan tempat PHP berjalan. Pada layanan web Linux, unggah dan akses skrip PHP ini dari server web ISP...
<?php
header('Content-Type: text/plain');
system("exec 2>&1; pwd");
system("exec 2>&1; type magick");
system("exec 2>&1; locate */magick");
system("exec 2>&1; magick -version");
system("exec 2>&1; magick -list type"); <!-- before IM v6.3.5-7 -->
system("exec 2>&1; magick -list font");
print("------ENVIRONMENT VARIABLES-------\n");
system("exec 2>&1; env");
?>
Skrip ini menjalankan cukup banyak perintah untuk melihat seperti apa lingkungan Anda. Perintah pertama "pwd" memberi tahu direktori kerja tempat skrip PHP dijalankan. Ini bisa jadi bukan direktori tempat skrip PHP berada, dan mungkin tidak bisa ditulisi dari skrip PHP. Dua perintah berikutnya memberi tahu apakah "magick" tersedia pada PATH perintah bawaan lewat "type", dan jika ya, di mana lokasinya. Perintah "locate" seharusnya menemukan semua perintah "magick" yang ada di server (dengan asumsi servernya Linux), tetapi bisa juga menemukan perintah, file, dan direktori "magick" lain yang bukan ImageMagick. Hasilnya perlu ditafsirkan sendiri. Tiga perintah berikutnya berasumsi "magick" ada pada PATH perintah, dan memintanya melaporkan nomor versinya serta font apa saja yang menurut IM dapat diaksesnya. Perintah mana yang melaporkan font bergantung pada seberapa tua versi IM yang terpasang. Jika yang terlihat hanya error, berarti "magick" tidak ada pada path baris perintah, dan penyedia ISP Anda TIDAK menginisialisasi "PATH" dan "LD_LIBRARY_PATH" server web dengan benar untuk menyertakannya. Lihat keluaran perintah "env" untuk mengetahui apa saja yang mereka definisikan. Bila demikian, Anda perlu mencari tahu persis di mana lokasinya dan memakai skrip PHP seperti berikut. Ini membuat skrip Anda kurang portabel, karena di-hard-code untuk ISP tertentu itu. Misalnya, andaikan perintah "magick" berada di "/opt/php5extras/ImageMagick/bin", sebuah variabel dapat diset untuk menunjuk lokasinya. Hal ini sering dilakukan sebagai bagian dari proses konfigurasi dan instalasi aplikasi, untuk skrip PHP yang dipakai di berbagai host ISP),
<?php
$im_path="/opt/php5extras/ImageMagick/bin"
header('Content-Type: text/plain');
system("exec 2>&1; $im_path/magick -version");
system("exec 2>&1; $im_path/magick -list type");
system("exec 2>&1; $im_path/magick -list font");
?>
Jika muncul error pustaka "ldd", berarti "LD_LIBRARY_PATH"-nya salah, dan ISP jelas lalai saat instalasinya; Anda perlu melaporkan error itu dan meminta mereka memperbaiki pengaturan variabel lingkungan "LD_LIBRARY_PATH" server web, atau memasang ulang ImageMagick. Alih-alih mengeset lokasi perintah magick, variabel lingkungan PATH juga dapat disesuaikan dengan baris seperti ini di bagian atas. Namun cara ini sering 'ditolak' secara bawaan oleh konfigurasi sistem PHP pada umumnya...
putenv("PATH=" . $_ENV["PATH"] . ":/opt/php5extras/ImageMagick/bin");
putenv("LD_LIBRARY_PATH=" . $_ENV["LD_LIBRARY_PATH"] .
":/opt/php5extras/ImageMagick/lib");
Setelah itu, cobalah beberapa contoh sederhana dari contoh penggunaan IM dan usahakan berjalan. Misalnya mengeluarkan gambar 'rose' IM sebagai file gambar JPEG kembali ke pengguna web...
<?php
header( 'Content-Type: image/jpeg' );
passthru("magick rose: jpg:-");
?>
Jika lokasi perintah magick perlu diset, gunakan...
<?php
header( 'Content-Type: image/jpeg' );
$magick="/opt/php5extras/ImageMagick/bin/magick"
passthru("$magick rose: jpg:-");
?>
atau jika ada masalah pustaka, cobalah sesuatu seperti...
<?php
header( 'Content-Type: image/jpeg' );
$magick="/opt/php5extras/ImageMagick/bin/magick";
$libs="LD_LIBRARY_PATH=\'" . $_ENV["LD_LIBRARY_PATH"] .
":/opt/php5extras/ImageMagick/bin/magick\'";
system("$libs $magick rose: jpg:-");
?>
Jika masih tidak terlihat apa-apa, lihat file mentah PHP Hints and Tips saya untuk informasi teknik pengalihan pesan error.
Setelah skrip dasar itu berjalan, cobalah salah satu font yang terdaftar dari skrip uji PHP tadi (sesuaikan contoh berikut dengan server PHP Anda). Misalnya, pada sebuah server Solaris yang saya punya waktu itu, saya melihat set font 'Utopia' tersedia, jadi saya bisa mencoba membuat label dengan font itu...
<?php
header('Content-Type: image/gif');
passthru("magick -pointsize 72 -font Utopia-Italic label:'Font Test' gif:-");
?>
Contoh konversi shell ke PHP
Di sini kita punya perintah ImageMagick yang cukup tipikal...
magick -background none -fill red -gravity center \
-font Candice -size 140x92 caption:"A Rose by any Name" \
\( rose: -negate -resize 200% \) +swap -composite output.gif
Saat dikonversi ke PHP, perintah itu menjadi kira-kira...
<?php
header('Content-Type: image/gif');
$color="red";
$image="rose:";
$scale="200%";
$size="140x96";
$string="A Rose by any Name";
passthru( "magick -background none -fill '$color' -gravity center" .
" -font Candice -size '$size' caption:'$string'" .
" \\( '$image' -negate -resize '$scale' \\) +swap -composite" .
" gif:-" );
?>
Perhatikan bahwa saya tetap memecah baris perintah panjang dari perintah "magick" agar urutan pemrosesan gambar lebih mudah diikuti dan diedit nanti. Kali ini pemecahan dilakukan dengan penyambungan string PHP, bukan dengan lanjutan baris shell seperti pada skrip shell. Perhatikan juga spasi ekstra di awal baris-baris lanjutan. Dan penggandaan backslash lain yang ada di perintah aslinya. Sebagai alternatif, opsi-opsi itu dapat dilindungi dengan tanda kutip tunggal alih-alih backslash. Saya juga memakai beberapa variabel PHP agar gambar yang dihasilkan skrip PHP lebih mudah disesuaikan, demi kendali hasil yang lebih baik. Namun saat menyisipkan opsi-opsi itu ke dalam "magick", saya memakai kutip tunggal untuk melindunginya dari modifikasi lebih lanjut oleh shell. Tetapi awas kutip tunggal di dalam string yang disisipkan itu! Opsi-opsi itu bisa dijadikan argumen masukan PHP, sehingga skrip dapat membangkitkan gambar untuk teks masukan apa pun yang diterima dari permintaan web. Anda juga dapat menjalankan beberapa perintah shell dalam satu string pemanggilan system. Bahkan satu pemanggilan system bisa berisi skrip shell lengkap kalau mau! Jadi loop shell dan banyak perintah (berikut bersih-bersihnya) bisa dilakukan dalam satu pemanggilan system. Sesuatu yang tidak banyak orang sadari bisa dilakukan. Pada dasarnya, dengan hati-hati Anda bisa memanfaatkan kemampuan matematika PHP sekaligus kemampuan skrip shell. Semuanya bersamaan. Awasi saja tanda kutipnya. Untuk berbagai contoh pemanggilan perintah ImageMagick dari PHP, lihat Rubble Web, Writing IM code in PHP yang menjelaskan sekitar empat teknik berbeda.
Perhatikan tanda kutip ekstra
Perhatikan bahwa perintah IM di PHP biasanya dibungkus satu lapis tanda kutip ekstra (umumnya kutip ganda), sehingga perlu kehati-hatian untuk memperhitungkan lapisan kutip tambahan ini. Ingat, ketika PHP mengeksekusi sebuah string.... PHP melakukan substitusi kutip, backslash, dan variabelnya sendiri; shell kemudian memecah argumen dan melakukan substitusi variabel dan kutipnya sendiri. Shell juga akan memproses pengalihan deskriptor file semacam "2>&1" bila ada. ImageMagick menerima larik argumen, tetapi juga melakukan penanganan meta-karakter nama file-nya sendiri, khususnya untuk DOS (lingkungan dos tidak menangani meta-karakter) dan untuk argumen seperti coder:*.gif[50x50] yang gagal diekspansi shell karena prefiks coder: atau pengubah baca [...]. Singkatnya, BANYAK sekali penguraian argumen! Yang bisa berarti banyak penanganan kutip dan backslash. Kehati-hatian dan pertimbangan matang diperlukan. Saya sarankan setidaknya membaca manual PHP tentang Program Execution Functions, yang mencakup: PHP exec(), system(), dan passthru(). Lihat juga Backtick Operator. Yang terpenting, pahami persis apa yang dikembalikan (umumnya hanya baris terakhir) dan apa yang diteruskan ke klien pemanggil (semua sisanya).
Keamanan PHP
Ingatlah...
_Di internet, satu-satunya pengguna yang bisa dipercaya tidak berpotensi memusuhi
adalah mereka yang *secara aktif* memusuhi.
-- Programming Perl - Camel Book, r3_
Semua argumen masukan dari pengguna yang diteruskan ke perintah IM harus diperiksa dengan saksama. Pastikan argumennya persis seperti yang diharapkan. Jauh lebih baik terlalu ketat daripada kurang ketat ketika berurusan dengan World Wide Web. Beberapa hal umum yang perlu diwaspadai antara lain
- Karakter biner dalam argumen - teknik cracker yang umum
- Spasi, tab, baris baru, dan karakter return tak terduga dalam argumen.
- Backslash (pemisah direktori) dan path '
..', juga '\' dan ';' dalam nama file di Windows. - Meta-karakter ekspansi file termasuk "
~*?[]{}<>" plus meta-karakter khusus "@" yang spesifik ImageMagick. - Meta-karakter shell lain termasuk "
$#;" dan tiga karakter kutip ''', '"', '```' - Argumen yang tidak cocok dengan yang diharapkan ImageMagick. Gunakan "
-list" untuk membaca jenis argumen apa yang dipahami IM untuk opsi tertentu. Misalnya opsi "-gravity" dari masukan pengguna hanya punya 10 pengaturan berbeda. - Dan seterusnya...
Untuk pekerjaan pemrograman web apa pun, pemahaman tentang keamanan dan bagaimana peretas memakai argumen yang dirancang khusus untuk menyelewengkan perintah yang dipanggil adalah hal vital. Bukan hanya untuk PHP, tetapi juga untuk shell dan ImageMagick. IM butuh perhatian khusus karena, misalnya, ia bisa membaca file password dan mengubahnya menjadi gambar untuk dikembalikan. Sekali lagi... Jauh lebih baik terlalu ketat daripada membuka lubang keamanan tak terduga ketika web terlibat.
Menulis ke sistem file
Seperti disinggung di atas, dan jika prosedur awal tadi diikuti, Anda akan tahu pasti bahwa PHP umumnya berjalan sebagai pengguna yang berbeda dan lebih terbatas di server. Karena itu biasanya ia TIDAK dapat menulis ke direktori yang berisi skrip (atau di mana pun ia sebenarnya berjalan). Demi keamanan, umumnya Anda memang tidak ingin menulis ke direktori itu! Jika Anda benar-benar ingin PHP menulis file, minta ia menyimpan gambar (atau data) dengan nama file unik di "/tmp", dan yang terpenting bersihkan setelahnya, baik saat keluar normal maupun pada error APA PUN. Mengejutkan betapa cepat disk bisa penuh oleh sisa file sementara dari aplikasi yang tidak bersih-bersih dengan benar. Jika file yang disimpan (gambar) harus terlihat oleh server web, buat subdirektori khusus 'ditulis oleh program' untuk file-file itu. Bagaimana seharusnya. Kebanyakan aplikasi PHP justru menghindari menulis apa pun ke sistem file dengan memakai backend basis data. Artinya, cookie, token, data pengguna, gambar, dan sebagainya semuanya ditulis ke basis data, seperti (urut kompleksitas dan skala) SQLite, PostgresSQL, MySQL, dan Oracle. Tidak ada yang disimpan di sistem file sama sekali. Pemrogram sistem biasanya mengonfigurasi aplikasi PHP dengan informasi itu saat aplikasi dipasang. Gambar biasanya direproduksi oleh skrip PHP yang sama atau terpisah yang mencari 'blob' gambar dan mengeluarkannya ke klien. Gambar dapat dikirim sebagai gambar 'inline' bersama HTML-nya (lihat format "inline:", yang memuat demonstrasi gambar inline HTML), atau sebagai satu gambar gabungan 'semua jadi satu', sehingga HTML/JAVA klien hanya membuat satu permintaan gambar alih-alih 20 permintaan terpisah. Satu hal terakhir. Selalu sediakan mekanisme pembersihan data lama. Pengguna yang tidak login selama 2 tahun mungkin sudah selayaknya datanya dihapus.
Mendapatkan keluaran error
Coba salah satu cara berikut...
<?php
exec("/usr/local/bin/magick -version",$out,$returnval);
print_r($out[0]);
?>
atau
<?php
exec("/usr/local/bin/magick -list",$out,$returnval);
print_r($out);
?>
atau gunakan shell_exec seperti berikut
<?php
$IM_version=shell_exec("/usr/local/bin/magick -version");
echo $IM_version
?>
Untuk menyertakan keluaran STDERR...
<?php
$array=array();
echo "<pre>";
exec("magick read_test.png write_test.png 2>&1", $array);
echo "<br>".print_r($array)."<br>";
echo "</pre>";
?>
Contoh di atas berasal dari diskusi forum pengguna IM... How to show IM error info in php?. Lihat juga catatan PHP Debugging Error Log saya sendiri. Yang merujuk ke manual PHP tentang pencatatan error PHP Error Handling and Logging; terutama lihat bagian contoh-contohnya.
Perintah ImageMagick yang lebih aman...
Idealnya, demi keamanan sebaiknya hindari pemakaian shell untuk mengurai satu string panjang menjadi perintah dan argumen terpisah. Lebih baik lakukan sendiri! Artinya, argumen perintah disediakan sebagai larik string terpisah, bukan sebagai satu string yang diurai shell. Dengan begitu Anda mencegah kemungkinan error sintaksis shell, beban kutip ekstra yang dibutuhkan shell, dan kemungkinan peretas membobol perintah shell lalu menjalankan perintahnya sendiri (sangat buruk). Di sisi lain skrip shell, pipe, dan pengalihan file jadi hilang, tetapi itu biasanya bukan kerugian besar bila Anda sudah memakai PHP atau bahasa pembungkus lain. Di PHP, satu-satunya fungsi yang saya temukan untuk memanggil perintah langsung tanpa shell adalah fungsi pcntl_exec(). Fungsi ini pada dasarnya melewati shell dan memanggil perintah secara langsung. Namun ia benar-benar system call 'execl()', yang menggantikan proses saat ini dengan perintah yang diberikan. Artinya, ia tidak melakukan 'fork()' dan penautan deskriptor file yang dibutuhkan untuk menjalankannya sebagai subproses. Karena itu pcntl_exec() sebenarnya terlalu rendah levelnya untuk pemakaian umum, dan mengimplementasikan pemanggilan perintah 'tanpa shell' bisa menjadi cukup rumit. Saya sangat heran pemanggilan perintah 'hindari shell' yang lebih sederhana dan lebih aman belum juga disediakan antarmuka PHP. Tapi memang saya bukan pemrogram PHP. Perl, sebaliknya, menyediakan sejumlah cara memanggil subperintah dan proses secara aman, yang sering membuatnya lebih disukai sebagai antarmuka web daripada PHP. Ada yang paham keamanan PHP dan berkenan mencerahkan atau memberi rujukan informasi lebih lanjut?
API 'IMagick' PHP
Untuk menguji apakah modul PHP PECL Imagick benar-benar bekerja, unggah sebuah gambar uji sederhana "image.jpg" dan skrip PHP ini ke direktori yang sama yang dapat diakses web.
<?php
$handle = imagick_readimage( getcwd() . "image.jpg" );
if ( imagick_iserror( $handle ) ) {
$reason = imagick_failedreason( $handle ) ;
$description = imagick_faileddescription( $handle ) ;
print "Handle Read failed!<BR>\n";
print "Reason: $reason<BR>\n";
print "Description: $description<BR>\n";
exit ;
}
header( "Content-type: " . imagick_getmimetype( $handle ) );
print imagick_image2blob( $handle );
?>
Sebuah buku PHP IMagick tersedia online, dan lebih banyak contoh penggunaan IMagick dapat ditemukan di blog Mikko. Satu-satunya masalah IMagick adalah ia tidak lagi dipelihara dan dimutakhirkan, sehingga mungkin ada sejumlah fungsi yang tidak bekerja atau hilang. Pastikan memakai IMagick v3.x dan versi IM terkini. Ia memang bekerja, dan untuk kebanyakan hal bekerja baik; tetapi jika Anda perlu melakukan hal-hal lain, metode PHP lain mungkin pilihan yang lebih baik.
'MagickWand' PHP
Periksa apakah modul PHP MagickWand merupakan bagian dari instalasi PHP dengan...
<?php
if (extension_loaded('magickwand')) {
echo "PHP MagickWand is available!\n";
} else {
echo "PHP MagickWand is NOT available!\n";
}
?>
Namun untuk memastikan ia benar-benar bekerja, unggah gambar uji "image.png" dan skrip ini...
<?php
$image = NewMagickWand();
if( MagickReadImage( $image, 'image.png' ) ) {
header( 'Content-Type: image/jpeg' );
MagickSetImageFormat( $image, 'JPEG' );
MagickEchoImageBlob( $image );
} else {
echo "Error in MagickReadImage()";
echo MagickGetExceptionString($image);
}
?>
Tidak ada jaminan untuk contoh di atas, tetapi masukan lebih lanjut dipersilakan. Saya umumnya tidak memprogram dalam PHP, tetapi memakai contoh di atas untuk menguji instalasi uji SunONE-PHP5 (dengan ketiga metode: baris perintah, magick, MagickWand).
Skrip PHP yang kompleks...
Jika HTML sekaligus GAMBAR perlu dibangkitkan dan dikeluarkan, pertimbangkan merancang skrip PHP Anda sedemikian sehingga permintaan HTML atau opsi masukan yang terpisah membangkitkan berbagai bagian yang dibutuhkan pada dokumen web, dari skrip PHP yang sama atau berbeda. Artinya, skrip PHP tingkat atas dapat mengeluarkan HTML dengan tag <IMG> yang sesuai, yang memanggil dirinya sendiri (atau skrip PHP lain) dengan opsi yang sesuai, untuk membuat atau memodifikasi gambar yang ditampilkan pada skrip PHP tingkat atas tadi. Beginilah cara kerja banyak skrip PHP album foto dan pembuat grafik. Semuanya dikendalikan lewat ekstensi GET dan PATH_INFO pada pemanggilan URL. Perhatikan bahwa POST tidak bisa dipakai di dalam tag IMG. Dengan cara ini Anda semestinya dapat sepenuhnya menghindari kebutuhan membangkitkan, menyimpan, dan membersihkan gambar sementara untuk halaman web yang dibangkitkan PHP. Solusi gambar sementara itu penuh masalah, seperti keterbatasan sumber daya dan pengumpulan sampah, sehingga merupakan teknik pemrograman yang sangat buruk. Teknik ini dibahas di kedua buku ImageMagick, meski versi ImageMagick yang dipakainya mulai agak usang.
Skrip Perl Magick
API PerlMagick adalah cara yang baik untuk mengonversi perintah "magick" menjadi skrip yang juga dapat menangani basis data, gambar dalam jumlah besar, atau pemrosesan gambar yang lebih kompleks daripada yang bisa dilakukan dengan cara lain. Bantuan terbaik adalah melihat skrip 'demo' PerlMagick, yang ada di kode sumber dan biasanya terpasang di area dokumentasi PerlMagick. Di sistem saya itu ada di "/usr/share/doc/ImageMagick-perl-*/demo/". Di direktori ini ada makin banyak contoh sederhana membaca, menulis, dan memproses berbagai gambar. Ada juga skrip "demo.pl" yang mendaftar hampir semua opsi pemrosesan gambar umum dan cara memakainya. Saat mengonversi perintah "magick" baris perintah ke perl, ada beberapa hal yang perlu diingat.
- Hal pertama yang perlu diingat: PerlMagick tidak otomatis menghapus gambar baru hasil pemrosesan. Banyak operator membuat gambar baru yang dimodifikasi dari gambar lama, sementara yang lain langsung memodifikasi gambar yang ada.
- Selain itu banyak operator tidak menerapkan operasi tertentu ke seluruh daftar gambar, melainkan hanya ke gambar pertama dalam daftar yang diberikan. Artinya Anda perlu me-loop sendiri urutan gambar (larik perl) tersebut.
- Anda dapat memiliki banyak urutan gambar. Bahkan biasanya tiap gambar dibaca ke urutan gambarnya sendiri yang terpisah, alih-alih harus puas dengan satu urutan gambar seperti di baris perintah.
- Begitu gambar ada di memori, ukuran gambar yang ada juga mudah diambil. Artinya kanvas baru bisa langsung dibuat tanpa perlu meng-clone dan mengosongkan gambar yang ada seperti di baris perintah. Namun meng-clone gambar juga menyalin metadata gambar, jadi Anda mungkin ingin melacak metadata itu untuk gambar seperti foto digital.
- Periksa error gambar (seperti ditunjukkan di halaman PerlMagick) setelah tiap proses besar, terutama saat membaca gambar.
Untuk mengonversi baris perintah ke perl, pada dasarnya operasi yang dilakukan persis sama, dalam urutan yang persis sama. Namun karena gambar umumnya tidak dihapus, dan banyak urutan gambar adalah hal biasa, penggunaan tanda kurung dan operasi clone ekstra dalam perintah "magick" biasanya bukan masalah. Bagian tersulit dalam mengonversi skrip biasanya memetakan opsi baris perintah ke pemanggilan fungsi PerlMagick. Cara tercepat yang saya temukan adalah mengambil kode sumber IM dan melihat file "MagickWand/mogrify.c" lalu mencari opsi baris perintah yang menyulitkan Anda. Misalnya untuk opsi -threshold, cari "threshold" berikut tanda kutipnya. Akan ada dua kecocokan: satu untuk penguraian sintaksis cepat guna memastikan semua opsi ditemukan, dan yang kedua berisi pemanggilan internal sesungguhnya untuk opsi itu. Di situ akan terlihat nama fungsi pustaka yang dipakai, yang biasanya terpetakan langsung ke fungsi Perl-nya. Dalam kasus ini... BilevelImageChannel()
Peringatan keamanan
Saat menulis skrip untuk pemakaian publik, apalagi skrip PHP berbasis web yang bisa dijalankan SIAPA PUN di dunia, sangatlah penting memeriksa segala sesuatu yang mungkin berasal dari pengguna tak dikenal (atau bahkan yang dikenal). Dan maksud saya SEGALANYA, mulai dari argumen, nama file, URL, sampai gambar juga. Selama suatu argumen masukan belum diverifikasi, argumen itu bisa berisi huruf, angka, spasi, tanda baca, bahkan karakter 'null' dan karakter kendali. Sebelum diperiksa saksama, ia harus dianggap mencurigakan dan tidak boleh dipakai. Tidak peduli bahwa formulir masukan yang dipakai dikendalikan web. Orang yang sedikit paham dapat dengan mudah memanggil PHP Anda dengan argumennya sendiri tanpa memakai formulir itu sama sekali. Dan jangan percaya mereka tidak akan melakukannya; robot berkeliaran di luar sana, membaca formulir masukan dan membuat argumen 'retasan' mereka sendiri untuk mencoba membobol skrip acak.
Meta-karakter dalam nama file
Sebagai isu keamanan, yang terutama perlu diwaspadai adalah nama file yang mengandung spasi, tanda kutip, tanda baca, karakter kendali, atau meta-karakter lain, karena IM maupun shell dapat mencoba mengekspansinya. Masalahnya, file bernama '*?@${&) .jpg' sebenarnya nama file yang sepenuhnya legal di UNIX, tetapi BANYAK program akan kesulitan menanganinya jika program itu (seperti shell dan IM) juga melakukan ekspansi nama file. Ingat, sekalipun shell dicegah melakukan ekspansi meta-karakter 'glob', IM sendiri juga melakukan ekspansi ini (untuk pemakaian DOS). Karena itu, melarang semua karakter semacam itu (dan menghasilkan error) mungkin langkah bijak. Sebagai langkah keamanan, sering kali baik untuk memunculkan error lalu berhenti jika nama file mengandung karakter APA PUN yang tak dikenal atau tidak lazim, apa pun yang bukan huruf, angka, atau bagian dari akhiran yang diharapkan. Sebelum meneruskan nama file semacam itu ke perintah shell, atau IM. Lebih baik JAUH lebih ketat dan melarang, daripada permisif dan meloloskan sesuatu yang buruk.
Kiat menulis skrip shell/PHP ImageMagick yang lebih baik
Berikut beberapa poin dasar pemrograman skrip yang saya sampaikan tentang sebuah skrip shell kontribusi yang dikirim ke milis IM untuk dipakai orang lain. Awalnya saya kirim ini secara pribadi ke penulisnya (yang akan tetap anonim), dan ia berterima kasih. Tidak semuanya spesifik IM, tetapi tetap layak diterapkan sebagai praktik pemrograman standar. Apalagi jika program atau skrip Anda akan dipakai, dibaca, dan/atau diperbaiki bugnya oleh orang lain. Pada gilirannya ini membuat skrip itu lebih berguna.
- Letakkan 'help' atau 'doc' di bagian atas skrip dan program. Ini memudahkan orang lain memahami kegunaan sebuah program tanpa perlu memasang atau menjalankannya. Saya sendiri sering membuang program yang tidak punya komentar jelas semacam itu ketimbang mencoba mengompilasi atau menjalankan skrip tak dikenal. Bahkan saya pernah melihat proyek raksasa yang file README pertamanya tidak menyebutkan apa fungsi proyek besar dan kompleks itu! Pemrogramnya berasumsi kalau sudah mengunduhnya, Anda pasti tahu fungsinya! Pastikan juga bahwa 'opsi salah' seperti '-?' mencetak sinopsis bukan hanya opsi-opsinya, tetapi juga rangkuman singkat tentang apa yang dilakukan program, atau di mana bantuan semacam itu ditemukan. Jangan hanya menunjuk ke situs web jauh yang bisa lenyap 10 tahun kemudian! Untuk contoh skrip yang mencetak 'komentar pembuka'-nya sendiri, lihat skrip "jigsaw" di area skrip IM. Perl dapat memakai POD untuk dokumentasi mandiri (lihat modul perl "
Pod::Usage"). Contohnya skrip kontribusi dpx_timecode.pl. Menaruh help sebagai 'here file' di subrutin pertama juga bisa diterima, dan berlaku untuk kebanyakan bahasa. Tetapi taruh subrutin itu DI ATAS, bukan di bawah atau di tengah skrip atau program. - Pastikan kode Anda rapi: buang kode dan komentar usang, buat semuanya sebersih dan serapi mungkin. Ringkas, dengan tahap-tahap yang dikomentari sederhana (bila mungkin). Sekali lagi lihat skrip "jigsaw".
- Pastikan file sementara dibersihkan di akhir. Gunakan perintah shell "trap" untuk menghapusnya saat keluar atau saat interupsi. Satu file sementara tentu bisa dipakai ulang berkali-kali, jadi tidak butuh banyak, apalagi dengan perintah magick IM v6. Sekali lagi lihat skrip "jigsaw", dan cari "trap".
- Ingat pula tidak semua orang memakai sistem X, meski bagi Anda mungkin terasa begitu. Jangan merujuk kebutuhan sistem tertentu, atau cara memperbaiki masalahnya. Yang berhasil bagi Anda bisa jadi sama sekali tidak cocok untuk sistem dan pengaturan mereka. Bahkan mereka mungkin tidak punya akses Internet! Cukup katakan bahwa perintah "
magick" dari ImageMagick tidak ditemukan. Jika ingin menambahkan persyaratan instalasi atau saran, jadikan itu bagian dari dokumentasi terpisah yang lebih lengkap. - Periksa bahwa IM yang dipakai versinya cukup tinggi, atau tambahkan penyesuaian untuk kompatibilitas mundur. Saya sengaja memberi catatan 'peringatan versi' di sepanjang contoh penggunaan IM tentang kapan berbagai fitur khusus ditambahkan, untuk keperluan ini. Ini memudahkan pembuatan skrip dengan satu pemeriksaan versi minimal. Berikut satu cara sederhana mendapatkan satu nomor versi untuk keperluan pengujian dalam skrip shell. Ia mengekstrak 4 angka versi, dan menyisipkan nol secukupnya agar tiap angka menjadi 2 digit, menghasilkan angka sederhana 8 digit.
IM_VERSION=`magick -list configure | \ sed '/^LIB_VERSION_NUMBER /!d; s//,/; s/,/,0/g; s/,0*\([0-9][0-9]\)/\1/g'`
Misalnya IM v6.3.5-10 menghasilkan "06030510" sementara rilis berikutnya IM v6.3.6.0 menghasilkan "06030600". Versi PHP dari cara di atas tersedia di halaman contoh RubbleWeb, Font List. String hasilnya dapat diuji, dengan pembandingan numerik atau string sederhana, untuk mengetahui apakah versi ImageMagick yang tersedia cukup baru untuk apa yang skrip Anda coba lakukan. Misalnya...
if [ "$IM_VERSION" -lt '06030600' ]; then
echo >&2 "The perspective distortion operator is not available."
echo >&2 "Sorry your installed ImageMagick is too old -- ABORTING"
exit 10
fi
Perhatikan juga bagaimana saya mengeluarkan alasan persis penghentian ke pengguna, khususnya fitur khusus yang menjadi sasaran pemeriksaan versi itu. Jika tidak, kelak mudah lupa mengapa versi itu (atau yang lebih tinggi) dibutuhkan. Perilaku IM juga dapat diubah untuk versi tertentu. Misalnya, katakanlah saya ingin mendapatkan daftar font yang tersedia. Sebelum IM versi v6.3.5-7, pengaturan "type" pada "-list" mengembalikan daftar 'font yang dikenal'. Pada versi lebih baru, Anda harus memakai pengaturan "font". Jadi di sini saya bisa melakukan pemeriksaan versi untuk memakai pengaturan yang tepat guna mendapatkan informasi yang dibutuhkan.
if [ "$IM_VERSION" -lt '06030507' ];
then font_list="type";
else font_list="font";
fi
avail_fonts=`magick -list $font_list | cut -d\ -f1 |\
egrep -v '^($|----|Path:|Name$)'`
PERINGATAN: string yang diawali '0' di PERL bisa ditafsirkan sebagai bilangan oktal!!! Namun membandingkan dua bilangan oktal tetap benar hasilnya, selama digit pertamanya tetap '0'. Kehati-hatian dan pengecekan atas uji versi disarankan. Alternatif lain untuk menguji versi adalah memakai "expr" alih-alih uji "['...
if expr + "$im_version" \>= "06030507" >/dev/null; then
...
PERINGATAN: tanda '+' ekstra di atas biasanya tidak diperlukan, setidaknya untuk uji ini, tetapi diperlukan bila variabelnya bisa berisi kata kunci khusus 'match" yang akan menyulitkan "expr", terutama jika dipakai untuk operasi string atau substring.
* Keluaran informasi "-list" juga dapat dimanfaatkan untuk memeriksa apakah suatu fitur khusus telah ditambahkan ke ImageMagick yang terpasang.
magick -list distort | grep 'Arc' >/dev/null 2>&1
if [ "$?" -ne 0 ]; then
echo >&2 "Arc distortion method not available."
echo >&2 "Sorry your installed ImageMagick is too old -- ABORTING"
exit 10
fi
Namun berhati-hatilah: metode baru, seperti "-distort Arc", sering muncul selama pengembangan IM sebelum benar-benar siap untuk pemakaian umum. Karena itu pemeriksaan versi mungkin tetap ide yang lebih baik. Itulah sebabnya di contoh penggunaan IM saya berusaha mencatat (perhatikan simbol-simbolnya) versi IM ketika sebuah fitur baru sudah cukup stabil untuk pemakaian umum.
* Jangan memakai satu baris yang sangat-sangat panjang. Terutama untuk perintah 'convert' yang kompleks. Pecah dengan metode lanjutan-baris (ditunjukkan di atas), seperti '\' di UNIX, '^' di DOS, dan penyambungan string '.' di PHP. Namun maksud saya bukan menaruh SETIAP pengaturan dan operasi di baris terpisah. Lakukan satu operasi atau tahap besar per baris: membuat gambar baru, memodifikasi gambar, menggabungkan dengan gambar lain, dst. Taruh semua pengaturan operasional yang dibutuhkan operator tertentu tepat sebelum operator itu. Anggap tiap baris sebagai satu langkah pemrosesan. Ini memungkinkan baris dipisah agar tiap langkah pemrosesan lebih mudah dibaca dan dipahami. Makin jelas pemisahan antar-operator, makin mudah proses gambar yang kompleks diikuti. Memakai tanda kurung ekstra, mengindentasi baris pada berbagai tahap, atau bahkan menambah baris kosong di antara blok pemrosesan besar, dapat makin memudahkan melihat tahap-tahap utama operasi yang besar dan panjang. Saya memakai teknik-teknik ini di seluruh contoh penggunaan IM agar contohnya lebih mudah diikuti dan dipahami, jadi lihat-lihat saja! Terakhir, komentar tambahan tentang apa yang dilakukan sebuah perintah tertentu bisa sangat membantu orang lain (atau Anda sendiri 2 bulan kemudian) membaca dan memahami skrip Anda. Sayang sekali saat ini komentar belum bisa disisipkan di baris perintah yang panjang!
* Usahakan tidak bergantung pada terlalu banyak program eksternal, atau pakai hanya jika tersedia (dengan alternatif bila mungkin). Orang lain mungkin tidak punya program itu, atau lebih suka memakai yang lain. Jika pemakaian sebuah program bisa opsional, jadikan opsional, entah di bawah kendali pengguna, entah otomatis dipakai jika ditemukan. Sebisa mungkin jangan jadikan persyaratan mutlak. Misalnya "pngcrush", "optipng", dan "pngnq" bisa dimanfaatkan untuk mengompres PNG lebih baik daripada yang biasa disediakan IM (IM dirancang untuk yang umum, bukan yang spesifik). Juga "gifsicle", "intergif", atau pengoptimal kompresi LZW lain untuk animasi GIF, masing-masing punya sisi baik dan buruk. Hanya saja, jangan jadikan mereka persyaratan mutlak agar skrip bekerja. Sebagai contoh praktis, versi lama "gif2anim" tidak memakai "magick identify" ImageMagick untuk mencari metadata khusus GIF, melainkan bergantung pada versi yang dipatch dari "giftrans". Persyaratan itu kemudian tak lagi dibutuhkan berkat perbaikan pada "magick identify" ImageMagick, jadi saya menghapusnya agar skrip lebih luas kegunaannya. ImageMagick sendiri punya BANYAK persyaratan opsional, seperti "ghostscript" untuk membaca dokumen postscript dan PDF, atau "librsvg" untuk penanganan gambar vektor SVG yang benar. IM tetap bekerja dengan baik bila mereka tersedia. IM memperlakukan pustaka-pustaka ini sebagai opsional, hanya membutuhkannya jika Anda ingin memproses gambar format tersebut. Berikut cuplikan kode untuk memeriksa dependensi skrip (terutama berguna di lingkungan cygwin yang sangat minimal)...
# Check Dependencies to scripts correct working
DEPENDENCIES="sed awk grep tr bc magick identify" # adjust to suit
for i in $DEPENDENCIES; do
type $i >/dev/null 2>&1 ||
Usage "Required program dependency \"$i\" missing"
done
- Melanjutkan poin terakhir. Jika butuh matematika floating point di skrip shell yang memakai IM, IM sendiri bisa dipakai untuk menghitungnya, alih-alih bergantung pada program lain seperti '
awk' atau 'bc' yang mungkin tidak tersedia (terutama di cygwin pada windows). Misalnya, di sini kita menghitung sin() dari sudut tertentu dalam derajat memakai 'magick'...angle=-20 sine=`magick xc: -format "%[fx:sin( $angle *pi/180)]" info:` echo $sine
Keluaran perintah di atas adalah nilai '-0.34202'. Jumlah tempat desimal dapat diatur memakai kendali operasional presisi. Bawaannya 6 digit.
* Biarkan pengguna menentukan format gambar masukan/keluaran yang dipakai. ImageMagick pada dasarnya adalah pengonversi gambar dan mampu memakai banyak format berbeda. Ia bisa mengeluarkan ke layar, postscript, printer, atau menyalurkan gambar lewat pipe ke perintah lain untuk diproses lebih lanjut. Jangan batasi pengguna pada satu format tertentu. Misalnya skrip "jigsaw" dan "gif_anim_montage" membiarkan pengguna menentukan gambar masukan atau keluaran apa pun. Dengan begitu pengguna dapat menyalurkan gambar masuk atau keluar dari skrip itu, untuk pemrosesan lanjutan dengan program dan skrip lain. Misalnya, saya sering memakai perintah seperti...
gif_anim_montage animation.miff show:
untuk menampilkan hasil skrip di layar tampilan saya, alih-alih menyimpannya ke file. Bahkan di banyak skrip saya, jika keluarannya tidak diberikan, bawaannya memakai "show:". Saya tidak membatasinya HANYA menerima masukan dari file animasi GIF, atau membatasi keluaran hanya ke format gambar GIF, PNG, atau JPEG, tetapi membiarkan skrip membaca dan memproses format apa pun yang bisa ditangani ImageMagick. Bahkan IM bisa membaca dari file, pipeline, tampilan saat ini, atau bahkan dari World Wide Web memakai format masukan "URL:" atau "HTTP:". Jangan batasi kemungkinan-kemungkinan ini, kecuali menjadi masalah keamanan (misalnya untuk pemakaian web).
* Baca gambar masukan, dan keluarkan multi-gambar, hanya SEKALI! Jika pengguna memberikan nama file pipeline atau URL, gambar itu tidak boleh dibaca lebih dari sekali, atau semuanya bisa kacau. Gunakan file sementara, clone gambar, atau simpan salinan gambar masukan dengan "MPC:" saat gambar itu perlu dirujuk berkali-kali. Kalau Anda bisa menangani banyak gambar dari pipeline, lebih baik lagi. Sekali lagi lihat skrip "jigsaw" untuk contoh menyimpan gambar masukan ke file sementara ketika Anda terpaksa memproses gambar masukan berkali-kali, atau dalam urutan yang berbeda dari yang tersirat oleh argumen program.
Hal-hal ini pada dasarnya memberi pengguna program Anda lebih banyak kebebasan melakukan yang MEREKA mau, bukan yang ANDA kira mereka mau. Jangan batasi mereka maupun diri Anda dengan berasumsi untuk apa skrip itu akan dipakai. NB: Keahlian utama saya adalah penulisan skrip UNIX, di banyak arsitektur dan 'rasa' UNIX, LINUX, dan sistem mirip UNIX lainnya, dengan pengalaman lebih dari 25 tahun di belakang saya. Semestinya saya cukup tahu apa yang saya bicarakan soal hal-hal di atas.
Mengapa menggunakan beberapa perintah "magick"
- Willem menulis pada Rabu, 25 Okt 2006...
- Saya penasaran; kadang di contoh-contoh Anda, saya melihat Anda memanggil Convert lebih dari sekali untuk memperoleh hasil yang diinginkan. Umumnya saya menduga memanggil magick lebih dari sekali tidak diperlukan; semestinya semuanya bisa dalam 1 pemanggilan (meski perintahnya jadi lebih kompleks). Setujukah Anda dengan pernyataan ini?
Saya sepenuhnya setuju. Namun sebelum IM versi 6, itu sebenarnya mustahil, karena IM waktu itu tidak dirancang untuk melakukan lebih dari satu atau mungkin dua operasi per perintah. IMv7 semestinya memungkinkan seluruh pemrosesan dilakukan dalam satu perintah tunggal. Tapi sayangnya itu pun tidak selalu bisa. Saya memakai banyak perintah karena sejumlah alasan. Biasanya di halaman contoh, saya melakukannya agar bisa menampilkan hasil gambar antara, untuk mendemonstrasikan tahap-tahap pemrosesan antara yang terlibat dengan lebih baik. Belakangan di area contoh yang sama saya mungkin mengulang prosesnya dengan satu perintah tunggal, dengan sedikit tambahan kompleksitas. Jadi pada prinsipnya, ya, satu perintah dapat melakukan semua pemrosesan gambar. Anda sangat dipersilakan menggabungkan semua teknik pemrosesan gambar ke dalam satu perintah. Saya sendiri selalu melakukannya. Pengecualiannya adalah ketika saya perlu mengekstrak informasi dan belakangan menyisipkan info itu ke perintah berikutnya. Contohnya teknik Fuzzy Trim yang mengharuskan Anda mengekstrak hasil trim pada salinan gambar yang di-blur. Hasil itu lalu dipakai untuk memangkas gambar aslinya. Saya juga melakukannya pada pembaruan contoh sudut membulat thumbnail; di situ saya memakai IM sendiri untuk membangkitkan perintah draw memakai ukuran gambar untuk perintah berikutnya. Namun ada proposal yang akan memungkinkan opsi dibangkitkan langsung dari gambar yang sudah dibaca ke memori. Dalam skrip, seperti skrip 'jigsaw' (lihat teknik lanjutan, Jigsaw Pieces), saya sering berujung memakai banyak perintah karena alasan lain -- pemrosesan opsional. Ini memungkinkan berbagai opsi masukan dari pengguna memilih langkah tambahan dalam rangkaian pemrosesan gambar. Jadi untuk pemrosesan opsional saya juga biasanya memakai perintah terpisah untuk tiap tahap pemrosesan. Dalam kasus begitu, file sementara pada dasarnya tak terhindarkan. Namun biasanya saya hanya butuh paling banyak satu-dua gambar sementara, dan tiap langkah memproses gambar kembali ke nama file sementara yang sama atau sebelumnya, untuk dilanjutkan langkah pemrosesan opsional berikutnya. Misalnya memproses gambar dengan menimpa gambar sumbernya.
magick /tmp/image1.png ..operations.. /tmp/image1.png
Dalam kasus ini, file MPC dapat mempercepat pembacaan file antara hingga nyaris seketika pada langkah pemrosesan berikutnya, karena gambar sekadar dibuang dari memori ke disk, lalu di-'page' kembali oleh perintah berikutnya. Ini menghindarkan IM dari keharusan memformat dan mengurai format file gambar, meski membuat file sementaranya lebih besar karena berupa isi memori tak terkompresi. Alternatif lain yang saya pakai untuk menghindari file sementara adalah menyalurkan gambar kerja lewat pipeline dari satu perintah shell (if-then-else-fi atau loop while) ke perintah lain. Ini dikenal sebagai pipeline gambar dan didemonstrasikan di sejumlah contoh. Salah satunya ada di MIFF Image Streaming, di mana banyak gambar dibangkitkan satu demi satu ke pipeline keluaran yang sama, untuk diambil perintah berikutnya yang menggabungkan semuanya menjadi gambar akhir. Dan terakhir, gaya pemrosesan mungkin perlu diubah berdasarkan hasil langkah pemrosesan sebelumnya. Misalnya dalam pembandingan gambar, saya sering perlu menemukan informasi tertentu untuk dipakai di langkah berikutnya, atau untuk mengubah cara gambar diproses pada tahap lanjut. Membandingkan diagram atau kartun bisa menuntut teknik pembandingan yang sangat berbeda dari foto kehidupan nyata. Jika pemakaian banyak perintah mulai jadi masalah, mungkin sudah waktunya beralih ke antarmuka API seperti PerlMagick, yang mampu menyimpan banyak urutan gambar sekaligus di memori demi menghindari IO disk yang tak perlu.
Membuat IM lebih cepat (secara umum)
Ada banyak cara membuat IM bekerja lebih cepat. Berikut aspek-aspek terpenting yang perlu diingat. Makin ke bawah daftar, percepatannya makin kecil, atau butuh perubahan yang makin rumit pada instalasi IM.
- IM Q8 (atau 8 bit per nilai warna, 3 sampai 4 byte per piksel) jauh lebih cepat (3 sampai 4 kali lebih cepat) daripada bawaan IM Q16 dengan resolusi warnanya yang lebih tinggi. Jika Q16 tidak dibutuhkan untuk gambar Anda, mungkin sebaiknya ganti IM Anda dengan versi Q8. Namun berhati-hatilah: memakai kualitas internal hanya 8 bit dapat memengaruhi pemrosesan gambar keseluruhan karena gambar antara kehilangan informasi. Lihat HDRI untuk kebalikannya.
- Gunakan satu perintah "
magick" bila mungkin, sehingga seluruh pemrosesan untuk satu gambar selesai sekaligus. Ini menghemat inisialisasi, keharusan membuat file sementara atau pipeline antar-perintah, bahkan encode/decode ke format file gambar untuk pipeline itu serta I/O disk. Tentu kadang beberapa perintah tetap diperlukan, untuk langkah pemrosesan gambar opsional, seperti perhitungan yang melibatkan ukuran gambar, warna, atau langkah pemrosesan opsional lainnya. Skrip IMv7 akan membantu dalam hal ini. - Skrip shell pada dasarnya lambat. Ia diinterpretasi, butuh banyak langkah dan penanganan file ekstra ke disk. Ini tentu sudah lebih baik berkat penanganan opsi baru IM v6, yang memungkinkan banyak operasi pemrosesan gambar dalam satu perintah. Meski begitu semuanya jarang bisa dilakukan dalam satu perintah "
magick", jadi sering harus memakai beberapa perintah untuk mencapai yang diinginkan. Karena itu API seperti perl, ruby, atau modul magick PHP lebih cepat, karena menghapus seluruh aspek interpretasi baik shell maupun API baris perintah IM. Ia juga mengurangi langkah inisialisasi yang dijalani IM dalam membaca definisi font dan warna. - API juga dapat menyimpan semua gambar, bahkan banyak daftar gambar, selama masa hidup program (selama memorinya cukup). Artinya gambar yang sedang dikerjakan bisa digonta-ganti tanpa perlu mengocok dan memindah-mindah gambar seperti di baris perintah. Ini terutama berguna saat Anda juga perlu melakukan perhitungan ekstra berdasarkan langkah pemrosesan gambar sebelumnya.
- Menulis file format gambar GIF itu lambat. IM harus bekerja keras mereduksi warna (kuantisasi) gambar agar muat ke warna terbatas format file itu. Bahkan setelahnya sering masih perlu kerja ekstra agar hasilnya benar, terutama untuk animasi GIF. PNG dan JPEG lebih cepat, tetapi dengan ongkos ukuran untuk PNG, dan kehilangan kualitas untuk JPEG. Meski sebenarnya gambar GIF lebih buruk lagi dari segi kualitas!
- Menyiapkan dan meng-cache gambar di muka, seperti latar belakang, overlay, frame, mask, atau membangkitkan lebih dulu tabel pencarian warna, peta distorsi, templat, mask, dsb. Semua itu dapat membuat perbedaan besar pada waktu pemrosesan Anda. Pikirkan apa yang bisa dikerjakan di muka. Pustaka besar gambar yang sudah dibangkitkan bisa jauh lebih cepat daripada mencoba membuat gambar saat dibutuhkan. Lihat juga pemakaian "MPC:" untuk gambar antara dan cache. Ini adalah gambar yang dipetakan ke memori di disk, dan waktu bacanya praktis nol, tetapi tidak berguna untuk hal lain atau di mesin lain. Buat hanya di awal proses penanganan gambar besar, dan jangan disimpan lama-lama, karena pemutakhiran perangkat lunak atau sistem sekecil apa pun akan membuatnya tak berlaku dan kemungkinan menyebabkan Segmentation Fault..
- Hindari FX, operator efek khusus jika masih bisa memakai komposisi alpha, atau Evaluate, operasi matematika sederhana yang lebih simpel, atau teknik lain. Jika memang harus memakainya, usahakan membatasi pemakaiannya pada gambar sekecil mungkin, atau pada satu kanal gambar saja (saat menangani grayscale).
- Hindari blur gambar berukuran besar bila beberapa yang lebih kecil bisa lebih cepat. Lakukan uji waktu untuk melihat mana yang lebih cepat. Hal yang sama berlaku untuk morfologi dan operator konvolusi lain seperti operator Gaussian dan Shadow.
- Gunakan subgambar atau region yang lebih kecil untuk pemrosesan kompleks pada area kecil. Misalnya, menemukan dan mengekstrak mata seseorang (memakai region) sebelum me-mask dan mewarnai ulang dapat memberi peningkatan kecepatan sangat besar dibanding memproses versi besar gambar itu secara penuh. Makin besar selisihnya, makin besar penghematannya.
- Saat membaca gambar besar atau bahkan gambar dalam jumlah besar, lebih baik memakai pengubah baca untuk mengubah ukuran atau memangkasnya segera setelah tiap gambar dibaca, sehingga mengurangi kebutuhan memori keseluruhan. Untuk JPEG, pengubah pustaka khusus '
jpeg:size' bahkan dapat dipakai untuk menghindari alokasi memorinya. Ini pada gilirannya mencegah 'disk thrashing' (yang membuat komputer SANGAT lambat). Terutama saat banyak gambar besar terlibat, seperti saat membangkitkan indeks direktori ber-montage atau kolase multi-gambar lainnya. - Untuk gambar yang benar-benar sangat masif yang harus diproses dari disk, mungkin lebih baik memprosesnya dalam potongan-potongan kecil.
- Juga untuk gambar besar... Jika OS Anda Windows 64-bit, pakai distribusi ImageMagick 64-bit. Ia memakai ruang alamat lebih besar dan dapat memuat gambar lebih besar ke memori daripada Windows 32-bit.
- IM secara bawaan memakai banyak thread untuk tiap operasi pemrosesan gambar. Artinya komputer dengan dua 'core' atau lebih umumnya memproses gambar lebih cepat daripada mesin satu CPU. Untuk gambar besar, kemampuan multi-thread OpenMP dapat memberi keunggulan kecepatan nyata karena memakai lebih banyak CPU untuk menyelesaikan tiap operasi pemrosesan gambar. Perhatikan bahwa di dalam IM hanya operasi pemrosesan gambar individual yang diparalelkan. Jadi penghematannya lebih terasa pada pemrosesan gambar besar, bukan pada pemrosesan gambar dalam jumlah besar (lihat berikutnya).
- Untuk gambar kecil, kemampuan multi-thread IM tidak banyak memberi keuntungan. Dalam kasus ini, menjalankan beberapa convert serentak pada gambar berbeda bisa menghasilkan throughput lebih tinggi. Ini juga bisa terjadi ketika beberapa permintaan web PHP meluncurkan beberapa perintah gambar "magick" sekaligus. Pada kedua situasi itu, multi-threading yang aktif justru bisa sangat merugikan akibat perebutan CPU, dan lebih baik menonaktifkan OpenMP dengan mengeset variabel lingkungan '
MAGICK_THREAD_LIMIT' ke '1'. Lihat diskusi forum IM Threading slows down 'convert'. Ada baiknya juga melihatMAGICK_THROTTLEagar ImageMagick lebih sering melepaskan kendali CPU pada titik-titik yang lebih tepat. - Jika banyak operasi kecil dilakukan pada gambar (misalnya menggambar), coba jangan memakai nama warna apa pun. Tentukan warna dengan warna hash, seperti "
#00AA99", atau angka rgb, seperti "rgb(0,160,100)", agar IM tidak perlu memuat tabel nama warna (yang cukup besar!). Coba juga menghapus atau memangkas file definisi daftar 'font' sistem (dari "type.xml". Atau hapus file-file itu sepenuhnya dan tentukan font langsung lewat nama file. Intinya, kurangi pemuatan informasi konfigurasi ekstra, yang akan dibaca dan diinisialisasi IM saat dibutuhkan untuk suatu proses gambar. Jadi jangan dipakai, atau kurangi ukuran dan dampak file konfigurasinya. - Membangun ImageMagick sebagai pustaka bersama (bawaan) dapat sangat mengurangi waktu muat. Pustaka dan modul coder hanya dimuat saat dibutuhkan, jadi IM versi dinamis tidak akan memuat apa pun yang tidak dipakainya selama pemrosesan gambar. Pustaka bersama juga cenderung tetap tersedia sehingga mungkin tak perlu dimuat ulang pada eksekusi kedua.
- Jika ImageMagick dipanggil sebagai bagian modul Apache, waktu mulainya juga berkurang, karena bagian-bagiannya dimuat sekali dan tetap tersedia untuk dipakai berkali-kali, alih-alih perlu dimuat ulang terus-menerus. Ini mungkin makin praktis di masa depan dengan proses 'daemon' IM yang berjalan permanen.
Mengompilasi ImageMagick dari kode sumber
Membangun RPM ImageMagick untuk Linux dari SRPM
Root TIDAK dibutuhkan untuk membangun RPM, meski tetap dibutuhkan untuk memasang RPM. Saya memakai cara ini untuk membangkitkan dan memasang IM di sistem Fedora Linux, tetapi juga dilaporkan bekerja untuk sistem Linux CentOS 5.4 (Enterprise Redhat) (lihat catatan IM di CentOS yang lebih spesifik). Pertama, ambil rilis RPM sumber terbaru dari Linux Source RPMs. Pertama pastikan mesin Anda punya semua kompiler dan alat yang dibutuhkannya.
sudo yum groupinstall "Development Tools"
sudo yum install rpmdevtool libtool-ltdl-devel
| "sudo" adalah program untuk menjalankan perintah sebagai root, jika diizinkan; jika tidak, gunakan shell root dan hapus bagian "sudo" dari perintah di atas.
Untuk sistem lebih tua seperti CentOS 5.5, tampaknya Anda juga butuh paket-paket ini
sudo yum compat-libstdc++ gcc-c++ gcc-objc++ libstdc++ libstdc++-devel
Berikutnya, paket development untuk pustaka-pustaka yang juga dibutuhkan IM saat build sebaiknya dipasang juga. Cara sederhana mendapatkan yang paling umum adalah memasang dulu versi development IM, meski nanti kita membangun yang baru untuk menggantikannya.
sudo yum install ImageMagick-devel
Pastikan juga paket-paket berikut beserta dependensinya (seperti pustaka development jpeg dan png) terpasang:
freetype-devel ghostscript-devel libwmf-devel jasper-devel lcms-devel bzip2-devel librsvg2 librsvg2-devel liblpr-1 liblqr-1-devel libtool-ltdl-devel autotrace-devel
Beberapa contoh di "contoh penggunaan ImageMagick" juga memakai program dari paket dan pustaka opsional berikut, tetapi ini tidak dibutuhkan untuk proses build.
gnuplot autotrace
Umumnya semua paket ini opsional, tetapi jika tidak terpasang, 'coder' dan operator yang memakai pustaka itu mungkin tidak ikut ter-build otomatis. Misalnya modul "liblqr" dibutuhkan untuk mengaktifkan operator Liquid Rescale. Sekarang unduh paket SRPM (RPM sumber) untuk membangun RPM biner Anda. ATAU bangun SRPM dari unduhan TAR atau SVN yang ada dengan...
rm config.status config.log
nice ./configure
rm *.src.rpm
make srpm
Perhatikan bahwa begitu SRPM ada, RPM yang sebenarnya dapat dibangun untuk dipasang.
nice rpmbuild --nodeps --rebuild ImageMagick*.src.rpm
Ini akan membuat subdirektori "rpmbuild" di home Anda, tempat sumber SRPM diekstrak dan paket RPM terkompilasi dari IM dibangun. |
Pada Fedora dan Redhat versi lama, ini dilakukan di "/usr/src" yang umumnya terbatas untuk root saja. Namun direktori itu bisa dijadikan milik Anda atau dapat ditulisi sehingga tetap bisa dikerjakan tanpa perlu akses root penuh untuk build. |
|---|---|
| Sekarang ambil RPM yang baru dibangun dari direktori build. Perintah ini hanya mengambil paket inti ImageMagick dan PerlMagick; Anda mungkin ingin mengambil lebih dari dua itu, tetapi terserah Anda... |
cp -p ~/rpmbuild/RPMS/*/ImageMagick-[6p]*.i[36]86.rpm .
Bersihkan dan hapus area build (termasuk yang mungkin dibuatkan untuk Anda)...
rm -rf /var/tmp/rpm-tmp.* ~/rpmbuild
Sekarang paket RPM yang Anda bangun dapat dipasang. Untuk ini Anda perlu jadi root (lihat catatan tentang perintah "sudo" di atas)...
sudo rpm -ihv --force --nodeps ImageMagick-*.i[36]86.rpm
Opsi "--nodeps" biasanya diperlukan karena adanya dependensi tak lazim yang kadang ada di sistem Linux. Untuk memutakhirkan instalasi yang ada, saya umumnya melakukan ini (sebagai root).
sudo rpm -Uhv --force --nodeps ImageMagick-*.i[36]86.rpm
Jika ingin melangkah lebih jauh, saya sarankan melihat Advanced Unix Source Installation Guide di situs web IM.
Untuk menghapus IM nanti, cukup hapus paketnya, seperti ini (lagi-lagi sebagai root)...
sudo rpm -e --nodeps ImageMagick\*
Kadang saya hanya ingin membersihkan dan menyapu habis semua jejak IM dari sistem. Untuk itu saya mula-mula memakai perintah sebelumnya untuk menghapus paketnya dari sistem (variasinya ditunjukkan di bawah). Lalu saya menjalankan perintah-perintah penghapusan berikut. CATATAN: saya tidak memberi jaminan apa pun soal ini, dan saya akan memeriksa perintah-perintah itu dengan saksama lebih dulu untuk memastikan tidak menghapus sesuatu yang seharusnya tidak dihapus. Jika ada yang terlewat, atau terhapus padahal seharusnya tidak, tolong beri tahu saya agar bisa saya perbarui.
rpm -e --nodeps `rpm -q ImageMagick ImageMagick-perl`
rpm -e --nodeps `rpm -q ImageMagick-devel`
rm -rf /usr/lib/ImageMagick-*
rm -rf /usr/lib/lib{Magick,Wand}*
rm -rf /usr/share/ImageMagick-*
rm -rf /usr/share/doc/ImageMagick-*
rm -rf /usr/include/{ImageMagick,Magick++,magick,wand}
rm -rf /usr/lib/perl5/site_perl/*/i386-linux-thread-multi/Image/Magick*
rm -rf /usr/lib/perl5/site_perl/*/i386-linux-thread-multi/auto/Image/Magick*
rm -rf /usr/share/man/man?/*Magick*
rm -f /usr/lib/pkgconfig/ImageMagick.pc
Awas, paket lain mungkin membutuhkan IM terpasang; jadi jika IM dihapus, saya sarankan segera memperbarui paket sistem komputer Anda, sehingga versi bawaan asli (dan biasanya cukup tua) ImageMagick yang disertakan untuk sistem Linux Anda terpasang kembali. Ini umumnya lewat paket 'GUI Software Update' atau perintah "yum upgrade". Selamat menikmati.
ImageMagick dari kode sumber di Ubuntu
Untuk mendapatkan semua pustaka development guna membangun ImageMagick, gunakan berikut ini
sudo apt-get install imagemagick libmagick++-dev
Sebuah halaman web oleh "Shane" menjelaskan cara memasang ImageMagick dari sumber di Ubuntu 8.04. Saya belum mencobanya, tetapi cara itu memasang IM langsung ke "/usr/local" memakai "make". Ia tidak membangkitkan paket instalasi 'DEB', yang bukan solusi ideal. Jika ada yang tahu cara membuat paket 'DEB' untuk Ubuntu, tolong beri tahu saya. Mungkin memakai Intro into Debian Packaging
Mengompilasi di MacOSX
Cara termudah memasang ImageMagick di MacOSX adalah memakai MacPorts. Tetapi berikut beberapa rujukan informasi tentang kompilasi untuk MacOSX. Saya tidak tahu apakah berhasil atau akan membantu, karena saya tidak pernah memakainya. Tapi lihat Install ImageMagick without Fink or MacPorts dan Install ImageMagick in Snow Leopard. Uraian di atas diparafrasakan dari sebuah diskusi di forum pengguna IM.
Mengompilasi IM versi HDRI
Untuk informasi kompilasi IM versi HDRI, lihat Enabling HDRI in ImageMagick di situs web utama IM; untuk informasi khusus Windows dan Ubuntu Linux, lihat juga Fourier Transforms Announcement Discussion di forum pengguna.
Membuat ImageMagick pribadi
Kemewahan akses superuser tidak selalu tersedia di mesin tempat Anda mengerjakan gambar, dan sering kali mereka yang punya akses itu tidak mau memutakhirkan instalasi ImageMagick mereka. Mungkin karena urusan manajemen paket, atau masalah kompatibilitas. Jika ada akses baris perintah (misalnya via SSH), belum semuanya hilang. Versi ImageMagick pribadi dapat dipasang dan dipakai. Kabar buruknya, administrator sistem tetap dibutuhkan untuk memasang kompiler dan paket development (lihat di atas), tetapi sering kali ini sudah ada, jadi tidak selalu jadi masalah. Pertama, tentukan di subdirektori mana versi IM Anda akan dipasang. Direktori khusus adalah pilihan terbaik, karena berarti cukup menghapus seluruh direktori itu untuk mencopot instalasi Anda. Dalam kasus saya, saya memasang ke subdirektori "apps/im" di home saya.
export MAGICK_HOME=$HOME/apps/im
Sekarang, untuk memasang versi pribadi: unduh, ekstrak, dan masuk ke direktori sumber ImageMagick. Lalu konfigurasikan sebagai versi 'uninstalled'.
rm config.status config.log
nice ./configure --prefix=$MAGICK_HOME --disable-installed \
--enable-shared --disable-static --without-modules --with-x \
--without-perl --without-magick-plus-plus --disable-openmp \
--with-wmf --with-gslib --with-rsvg --with-xml \
CFLAGS=-Wextra \
;
nice make clean
nice make
nice make install
Yang penting pada definisi di atas adalah "--disable-installed" bersama "--prefix". Bagian lain menonaktifkan kompilasi aspek-aspek yang lebih opsional dari ImageMagick versi pribadi Anda. Silakan ubah sesuka Anda. Kini, untuk memakai versi terpasang Anda sendiri alih-alih versi sistem normal, cukup set variabel lingkungan berikut.
export MAGICK_HOME=$HOME/apps/im
export PATH="$MAGICK_HOME/bin:$PATH"
export LD_LIBRARY_PATH="$MAGICK_HOME/lib:$LD_LIBRARY_PATH"
Sekarang jika saya mengetik
magick -version
Saya melihat versi IM lebih mutakhir yang baru saya pasang, secara bawaan. Perhatikan bahwa variabel "$MAGICK_HOME" wajib diset untuk Imagemagick yang dibuat dengan opsi "--disable-installed". Dua variabel lingkungan lainnya memastikan kita memakai versi pribadi, bukan versi sistem mana pun yang mungkin juga terpasang.
PERINGATAN: jangan campur aduk variabel-variabel di atas. Definisikan semuanya, atau jangan definisikan sama sekali dengan cara ini. Eksekutabel IM yang dipakai HARUS memakai pustaka, coder, dan file konfigurasi yang di-build bersama eksekutabel itu. Mencampur versi sistem dan versi pribadi kemungkinan besar menyebabkan segmentation fault dan kesalahan memori.
Lokasi IM pribadi dapat dipindahkan tanpa kompilasi ulang, tetapi selain mengubah variabel lingkungan di atas, perlu juga mengubah (atau menghapus) path yang di-hard-code ke program "magick display" yang dipakai delegate "show:" dalam file "delegate.xml" versi terpasang pribadi Anda. Lihat Delegates untuk informasi lebih lanjut tentang aspek IM ini.
Agar mudah bagi saya berpindah antara IM terpasang sistem dan beberapa versi pribadi, biasanya saya tidak mengeset variabel-variabel di atas sama sekali. Sebagai gantinya saya memanggil skrip yang mengeset variabel itu sebelum memanggil versi IM tertentu. Misalnya saya punya versi IM pribadi yang dikompilasi dengan HDRI, yang hanya saya pakai untuk contoh-contoh tertentu di contoh penggunaan ImageMagick. Biasanya saya tidak ingin memakai versi ini, dan lebih suka versi sistem non-HDRI untuk kebanyakan kerja gambar. Karena itu saya memasang versi 'HDRI' IM di area pribadi saya "$HOME/apps/im_hdri", dan membuat skrip bernama "hdri" berisi...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Sekarang jika saya mengetik...
hdri magick -version
Saya melihat bahwa saya menjalankan ImageMagick versi kualitas HDRI saya, tetapi hanya saat membutuhkannya. Jika saya tidak membubuhkan "hdri" di depan perintah di atas, maka yang berjalan adalah IM versi sistem normal. PERINGATAN: jika versi IM pribadi Anda tidak ditemukan oleh skrip, ia diam-diam kembali memakai versi sistem. Pemeriksaan 'versi' di atas adalah uji penting untuk memastikan saya benar-benar memakai versi pribadi saya, bukan versi sistem. Perintah magick mana yang coba dieksekusi skrip juga dapat diperiksa persis dengan 'which'.
hdri which convert
Artinya, skrip itu cukup luwes sehingga yang dijalankan tidak harus "magick", tetapi bisa perintah apa pun, misalnya skrip shell ImageMagick, sehingga skrip itu memakai magick HDRI alih-alih convert sistem normal.
hdri some_im_script image.png image_result_hdri.png
![[IM Text]](../static/img/api/hdri_version.txt.gif)