- Skia Canvas memungkinkan penggunaan API drawing HTML Canvas di Node.js untuk rendering on-screen maupun off-screen, dan karena berbasis Google Skia, hasilnya sangat mirip dengan
<canvas>di Chrome - Output dapat diekspor sebagai format vektor seperti PDF·SVG maupun bitmap seperti JPEG·PNG·WEBP, serta dapat dihubungkan ke file, dataURL, Buffer, atau objek Sharp
- Menangani area di luar Canvas browser, serta menyediakan rendering GUI Window, framework event, Canvas multi-halaman, operasi path, transformasi perspektif 3D, CSS filter, dan kontrol tipografi tingkat lanjut
- Rendering asinkron dan file I/O diproses di thread native dalam worker pool yang dikonfigurasi pengguna, sehingga cocok untuk pembuatan gambar sisi server dan lingkungan serverless
- Benchmark mengukur mode serial dan async secara terpisah; pada mode async, beberapa pekerjaan berulang dimulai bersamaan untuk membandingkan efek multithreading
Implementasi Canvas untuk Node.js
- Skia Canvas adalah implementasi API drawing HTML Canvas untuk Node.js, yang mendukung rendering on-screen maupun off-screen
- Menggunakan engine grafis Google Skia sehingga menghasilkan output yang sangat mirip dengan elemen
<canvas>di Chrome - Juga mencakup fitur yang belum disediakan oleh Canvas browser
Format output dan cara ekspor
- Output gambar mendukung format vektor dan format bitmap
- Vektor: PDF, SVG
- Bitmap: JPEG, PNG, WEBP
- Hasil Canvas dapat dikirim ke berbagai tujuan
- Dapat menggambar langsung ke GUI Window interaktif, dan menyediakan framework event yang mirip browser
Rendering asinkron dan multi-halaman
- Rendering dan file I/O dijalankan secara asinkron di worker pool yang menggunakan thread native
- Worker pool dapat dikonfigurasi pengguna
- Satu Canvas dapat memiliki beberapa halaman
- Dapat diekspor sebagai satu PDF multi-halaman
- Juga dapat disimpan sebagai sequence gambar yang terbagi menjadi beberapa file
Fitur grafis yang melampaui Canvas browser
- Path Bézier mendukung operasi boolean dan interpolasi per titik
- Fitur transformasi menyediakan transformasi perspektif 3D selain scale, rotate, dan translate pada Canvas dasar
- Untuk mengisi bentuk, selain Pattern berbasis bitmap, dapat menggunakan Texture berbasis vektor
- Pada drawing garis, dapat menambahkan marker kustom
- Pemrosesan gambar mendukung seluruh rangkaian operator CSS filter
Kontrol tipografi
- Rendering teks menangani banyak baris dan word wrapping otomatis
- Menyediakan metrik teks per baris
- Fitur OpenType seperti small-caps dan ligature dapat digunakan dengan sintaks standar font-variant
- Letter spacing, word spacing, dan leading dapat dikontrol secara proporsional
- Mendukung variable fonts dan memetakan nilai weight secara transparan
- Font non-sistem yang dimuat dari file lokal juga dapat digunakan
Contoh penggunaan
- Contoh pembuatan file gambar membuat
Canvas, mendapatkan konteks 2D dengangetContext("2d"), lalu menggambar persegi panjang menggunakan gradient kerucut sebagai stroke style- Menyimpan gambar beresolusi tinggi dengan
saveAs("rainbox.png", {density:2}) canvas.pngdigunakan sebagai bentuk singkat daricanvas.toBuffer("png")- Hasil
toDataURL("png")dapat dimasukkan ke dalam string HTML - Penyimpanan sinkron di thread utama juga dapat dilakukan dengan
saveAsSync("rainbox.pdf")
- Menyimpan gambar beresolusi tinggi dengan
- Contoh sequence multi-halaman membuat halaman dengan warna berbeda menggunakan
canvas.newPage()lalu menyimpannya- Menyimpan PDF multi-halaman sebagai
all-pages.pdf - Membuat beberapa file seperti
page-01.png,page-02.pngdengan polapage-{2}.png
- Menyimpan PDF multi-halaman sebagai
- Contoh rendering Window membuat
Window(300, 300)dan menggambar lingkaran pada eventdrawdengan ketebalan garis yang berubah sesuai nilai frame - Contoh integrasi Sharp.js menunjukkan alur mengubah hasil Canvas menjadi objek Sharp untuk post-processing, atau menggambar gambar yang dibuat dengan Sharp ke Canvas menggunakan
loadImage
Metode dan hasil benchmark
- Benchmark menguji Skia Canvas dalam dua mode
- serial: menunggu setiap pekerjaan rendering selesai sebelum lanjut ke iterasi berikutnya
- async: memulai semua iterasi pengujian sekaligus dan menjalankannya secara paralel dengan dukungan multithreading
- Hasil lengkap dapat dilihat di halaman hasil canvas-benchmarks
- Pada uji latensi awal dengan 100 iterasi, skia-canvas mencatat kurang dari 1 ms per iterasi, total 33 ms
- canvaskit-wasm: 25 ms per iterasi, total 2,47 detik
- canvas: 88 ms per iterasi, total 8,77 detik
- @napi-rs/canvas: 69 ms per iterasi, total 6,87 detik
- Pada uji Bézier curves dengan 20 iterasi, terlihat perbedaan pemrosesan paralel di mode async
- skia-canvas serial: 137 ms per iterasi, total 2,74 detik
- skia-canvas async: 28 ms per iterasi, total 558 ms
- Pembandingnya adalah canvaskit-wasm 790 ms, canvas 486 ms, dan @napi-rs/canvas 230 ms
- Pada uji SVG to PNG dengan 100 iterasi, canvaskit-wasm tidak mendukungnya, sementara skia-canvas mencatat 58 ms per iterasi pada serial dan 11 ms per iterasi pada async
- skia-canvas serial: total 5,83 detik
- skia-canvas async: total 1,08 detik
- Hasil uji scale dan rotate gambar dengan 50 iterasi
- skia-canvas serial: 100 ms per iterasi, total 5,00 detik
- skia-canvas async: 19 ms per iterasi, total 935 ms
- Hasil uji teks dasar dengan 200 iterasi
- skia-canvas serial: 21 ms per iterasi, total 4,26 detik
- skia-canvas async: 4 ms per iterasi, total 819 ms
1 komentar
Komentar Hacker News
https://windowjs.org juga memiliki konsep yang sangat mirip
Ia membungkus Skia dan mengeksposnya sebagai Canvas API, tetapi alih-alih Node, ia menyertakan v8 sehingga berjalan sebagai runtime yang sangat kecil
Itu adalah proyek open source pertama yang saya rilis sekitar 3 tahun lalu, dan sempat ada rencana untuk menjadikannya platform game JavaScript untuk desktop dengan mengekspos WebGL, audio, dan lainnya, tetapi pengembangannya terhenti karena pekerjaan dan proyek lain
Senang melihat proyek seperti ini yang memungkinkan Canvas digunakan di luar browser
Kadang kita hanya ingin membuat request jaringan
Saya penasaran seberapa besar ukuran biner berkurang jika hanya menyertakan V8 alih-alih Node.js
Node.js juga memakai V8, jadi saya juga penasaran apakah sebagian besar ukuran biner Node bukan berasal dari V8 melainkan dari runtime-nya
Saya sudah melihat-lihat situs web dan repositori GitHub-nya, tetapi tidak menemukan berapa kB atau MB biasanya ukuran biner Window.js
Sekadar penasaran, library seperti ini dipakai untuk apa?
Kalau di desktop, rasanya ada library native yang lebih baik untuk menggambar bentuk
Di sisi server kami juga perlu membuat PDF vektor, jadi kami memakai library Node yang bisa menggunakan HTML Canvas API dan menghasilkan PDF
Dengan begitu, hasilnya persis sama dengan partitur yang dirender di browser web, dan itu bagus
Kesimpulannya, library seperti ini memungkinkan reuse kode di lingkungan non-browser
Keunggulan besar Skia adalah kemampuannya memanfaatkan grafis native secara efektif, dan itulah alasan ia dipakai dalam mesin browser sejak awal
Selain itu, target API yang hanya satu juga merupakan kelebihan
Di satu sisi ini lebih low-level, tetapi di sisi lain saya juga pernah memakai Puppeteer seperti library grafis 2D
Kita mendapatkan Canvas 2D, WebGL, WebGPU, seluruh HTML/CSS, serta bisa memakai efek teks, gambar latar, dan transformasi CSS
Pemuatan gambar dan video juga dimungkinkan, dan hasil gabungannya bisa dibuat menjadi gambar dengan fitur screenshot
Memang berlebihan, tetapi untuk kebutuhan saya tidak masalah; ia berfungsi, lintas platform, dan menyelesaikan masalah
Skia sedikit lebih cepat daripada Direct2D dan jauh lebih cepat daripada Cairo
Ia sangat teroptimasi dan juga memiliki backend berakselerasi GPU
Canvas juga merupakan API menggambar 2D yang sangat umum
iOS punya versi native, Android juga punya versi native, dan operasi menggambarnya pun sebagian besar mirip
Banyak hal bisa diperoleh dengan memanfaatkannya
Skia menyertakan CanvasKit, build WASM yang mendukung Node, https://www.npmjs.com/package/canvaskit-wasm, dan modul ini tampaknya adalah binding Rust
Saya penasaran kelebihan dan kekurangan kedua pendekatan ini
Hanya saja secara internal ia dihasilkan dari codebase campuran Rust/C++
Jadi perbedaan utamanya adalah WASM membutuhkan runtime terpisah, sedangkan biner Node tidak
Apakah ini semacam wrapper untuk crate Rust?
https://rust-skia.github.io/doc/skia_safe/canvas/struct.Canvas.html
Saya tidak melihat ada yang terlalu khusus untuk Node
Saya sudah lama menunggu yang seperti ini
Upaya-upaya sebelumnya untuk melakukan hal serupa membutuhkan instalasi Node-Gyp, dan itu benar-benar mimpi buruk
Ini lebih dari sekadar API rendering sederhana: ada bagian yang mengatakan “bisa merender ke jendela melalui pipeline grafis native OS dan menyediakan framework event UI seperti browser”
Bisa saja menambahkan wgpu untuk dukungan WebGPU dan ANGLE untuk dukungan WebGL
Ia mendukung banyak target rendering, termasuk WebGPU dan ANGLE
QPainter menangani image mentah dan jendela, dan ada juga widget yang lebih canggih dengan dukungan event
Selain itu ada fitur yang sudah lama saya cari: Qt memiliki graphicsview yang dapat merender secara independen dari resolusi jutaan objek pada bidang grafis yang lebih besar dari jendela, sekaligus menangani event
Jika tertarik pada implementasi Canvas yang kompatibel dengan Node, ada beberapa pilihan
canvaskit-wasm dari proyek Skia tampaknya tidak berakselerasi GPU: https://github.com/google/skia/tree/main/modules/canvaskit/npm_build
@napi-rs/canvas adalah binding tercepat: https://github.com/Brooooooklyn/canvas?tab=readme-ov-file#performance
node-canvas menggunakan Cairo, bukan Skia: https://github.com/Automattic/node-canvas
Saat membutuhkan jendela grafis sederhana untuk Advent of Code, saat ini saya memakainya bersama Deno
Ada juga window-example: https://skia-canvas.org/#rendering-to-a-window
Cukup tambahkan dengan
deno add npm:skia-canvas, masukkan"nodeModulesDir": "auto"kedeno.json, lalu jalankandeno install --allow-scriptsMelihat ini membuat saya benar-benar antusias
Sepertinya ini akan membuat penulisan grafis yang bisa berdiri sendiri sekaligus kompatibel dengan web menjadi jauh lebih nyaman
Kita juga tidak perlu lagi membangun dari source dan menghasilkan kode dengan bahasa skrip kedua hanya untuk mengompilasi library bagi bahasa skrip pertama
Menarik juga melihat seberapa cocok ini untuk rendering real-time kode Canvas di tempat seperti VS Code, atau untuk menjalankan kode yang memiliki lapisan transformasi agar bisa berjalan di Canvas web