4 poin oleh GN⁺ 2024-12-04 | 1 komentar | Bagikan ke WhatsApp
  • 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
  • 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

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 dengan getContext("2d"), lalu menggambar persegi panjang menggunakan gradient kerucut sebagai stroke style
    • Menyimpan gambar beresolusi tinggi dengan saveAs("rainbox.png", {density:2})
    • canvas.png digunakan sebagai bentuk singkat dari canvas.toBuffer("png")
    • Hasil toDataURL("png") dapat dimasukkan ke dalam string HTML
    • Penyimpanan sinkron di thread utama juga dapat dilakukan dengan saveAsSync("rainbox.pdf")
  • 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.png dengan pola page-{2}.png
  • Contoh rendering Window membuat Window(300, 300) dan menggambar lingkaran pada event draw dengan 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

 
GN⁺ 2024-12-04
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

    • Cukup keren, tetapi jika isolasi tidak benar-benar diperlukan, lingkungan yang hanya berisi v8 terasa kurang memuaskan
      Kadang kita hanya ingin membuat request jaringan
    • Proyek yang keren
      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 Soundslice, kami memakai library grafis rendering partitur kustom yang dibuat dengan JavaScript/Canvas di frontend
      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
    • Dalam menggambar 2D, sebenarnya tidak banyak hal yang sekuat Skia dan lazim disebut “native”
      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
    • Bukankah portabilitas adalah keunggulannya? Saya penasaran library rendering 2D berakselerasi GPU lain apa saja yang ada
      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
    • Saya akan terkejut jika ada platform yang bisa disebut memiliki API menggambar grafis 2D yang lebih baik daripada Canvas
      Skia sedikit lebih cepat daripada Direct2D dan jauh lebih cepat daripada Cairo
      Ia sangat teroptimasi dan juga memiliki backend berakselerasi GPU
    • Kemampuan menjalankan kode yang sama di banyak platform adalah bonus besar
      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

    • Daripada “binding Rust”, ini lebih mendekati biner Node yang sudah dikompilasi sebelumnya
      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 memahami Skia Canvas bisa berjalan di hampir semua bahasa pemrograman selama ada binding-nya https://www.swig.org/
      Saya tidak melihat ada yang terlalu khusus untuk Node
    • Benar, dibuat dengan napi-rs
  • 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

    • Skia adalah library yang banyak digunakan; yang langsung terpikir saja, Chrome, Firefox, dan LibreOffice memakainya
      Ia mendukung banyak target rendering, termasuk WebGPU dan ANGLE
    • Cukup mirip dengan yang sudah disediakan Qt
      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" ke deno.json, lalu jalankan deno install --allow-scripts

  • Melihat 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