Kanvas HTML5 tidak memiliki metode untuk secara eksplisit mengatur satu piksel.
Dimungkinkan untuk mengatur piksel menggunakan garis yang sangat pendek, tetapi kemudian antialising dan tutup garis mungkin mengganggu.
Cara lain mungkin untuk membuat ImageData
objek kecil dan menggunakan:
context.putImageData(data, x, y)
untuk meletakkannya di tempat.
Adakah yang bisa menggambarkan cara yang efisien dan andal dalam melakukan ini?
fillRect()
semi-baru-baru ini menjadi hampir 10x lebih cepat daripada putimagedata 1x1 pada Chromev24. Jadi ... jika kecepatan sangat penting dan Anda tahu audiens target Anda, jangan mengambil kata dari jawaban yang sudah ketinggalan zaman (bahkan milikku). Sebaliknya: tes!Salah satu metode yang belum disebutkan adalah menggunakan getImageData dan kemudian putImageData.
Metode ini bagus untuk saat Anda ingin menggambar banyak sekaligus, cepat.
http://next.plnkr.co/edit/mfNyalsAR2MWkccr
sumber
Saya tidak mempertimbangkan
fillRect()
, tetapi jawabannya mendorong saya untuk membandingkannyaputImage()
.Menempatkan 100.000 piksel berwarna secara acak di lokasi acak, dengan Chrome 9.0.597.84 pada MacBook Pro (lama), membutuhkan waktu kurang dari 100 milidetik
putImage()
, tetapi hampir 900 milidetikfillRect()
. (Kode benchmark di http://pastebin.com/4ijVKJcC ).Jika sebaliknya saya memilih satu warna di luar loop dan hanya plot warna itu di lokasi acak,
putImage()
membutuhkan 59ms vs 102msfillRect()
.Tampaknya overhead menghasilkan dan menguraikan spesifikasi warna CSS dalam
rgb(...)
sintaks bertanggung jawab atas sebagian besar perbedaan.Meletakkan nilai RGB mentah langsung ke
ImageData
blok di sisi lain tidak memerlukan penanganan string atau penguraian.sumber
sumber
putImageData()
setelah fungsi itu atau konteksnya akan diperbarui dengan referensi?Karena browser yang berbeda tampaknya lebih suka metode yang berbeda, mungkin masuk akal untuk melakukan tes yang lebih kecil dengan ketiga metode sebagai bagian dari proses pemuatan untuk mengetahui mana yang terbaik untuk digunakan dan kemudian menggunakannya di seluruh aplikasi?
sumber
Tampaknya aneh, tetapi meskipun demikian HTML5 mendukung menggambar garis, lingkaran, persegi panjang dan banyak bentuk dasar lainnya, itu tidak memiliki apa pun yang cocok untuk menggambar titik dasar. Satu-satunya cara untuk melakukannya adalah dengan mensimulasikan poin dengan apa pun yang Anda miliki.
Jadi pada dasarnya ada 3 solusi yang mungkin:
Masing-masing dari mereka memiliki kekurangan
Baris
Ingatlah bahwa kita sedang menuju ke arah Tenggara, dan jika ini adalah ujungnya, mungkin ada masalah. Tapi Anda juga bisa menggambar ke arah lain.
Empat persegi panjang
atau dengan cara yang lebih cepat menggunakan fillRect karena mesin render hanya akan mengisi satu piksel.
Lingkaran
Salah satu masalah dengan lingkaran adalah lebih sulit bagi mesin untuk membuat mereka
ide yang sama seperti dengan persegi panjang yang bisa Anda capai dengan mengisi.
Masalah dengan semua solusi ini:
Jika Anda bertanya-tanya, "Apa cara terbaik untuk menggambar titik? ", Saya akan pergi dengan persegi panjang penuh. Anda dapat melihat jsperf saya di sini dengan tes perbandingan .
sumber
Bagaimana dengan persegi panjang? Itu harus lebih efisien daripada menciptakan
ImageData
objek.sumber
putImageData
10x lebih cepat daripadafillRect
di Chrome. (Lihat jawaban saya untuk lebih lanjut.)Gambar kotak seperti yang dikatakan sdleihssirhc!
^ - harus menggambar kotak 1x1 di x: 10, y: 10
sumber
Hmm, Anda juga bisa membuat garis lebar 1 piksel dengan panjang 1 piksel dan membuat arahnya bergerak di sepanjang sumbu tunggal.
sumber
Untuk melengkapi jawaban Phrogz dengan sangat teliti, ada perbedaan kritis antara
fillRect()
danputImageData()
.Konteks penggunaan pertama untuk menarik lebih dengan menambahkan sebuah persegi panjang (TIDAK pixel), dengan menggunakan fillStyle nilai alpha DAN konteks globalAlpha dan matriks transformasi , topi garis dll ..
menggantikan kedua seluruh set piksel (mungkin satu, tapi mengapa ?)
Hasilnya berbeda seperti yang Anda lihat di jsperf .
Tidak ada yang ingin mengatur satu piksel pada satu waktu (artinya menggambarnya di layar). Itu sebabnya tidak ada API khusus untuk melakukan itu (dan memang demikian).
Kinerja bijaksana, jika tujuannya adalah untuk menghasilkan gambar (misalnya perangkat lunak ray-tracing), Anda selalu ingin menggunakan array yang diperoleh dengan
getImageData()
Uint8Array yang dioptimalkan. Kemudian Anda meneleponputImageData()
SEKALI atau beberapa kali per detik menggunakansetTimeout/seTInterval
.sumber
fillRect
menyakitkan karena akselerasi h / w Chrome tidak dapat mengatasi setiap panggilan ke GPU yang diperlukan. Saya akhirnya harus menggunakan data piksel pada 1: 1 dan kemudian menggunakan penskalaan CSS untuk mendapatkan hasil yang diinginkan. Ini jelek :(get/putImageData
, tetapi 194.893 untukfillRect
.1x1 image data
adalah 125.102 Ops / dtk. JadifillRect
menang jauh di Firefox. Jadi banyak hal berubah antara 2012 dan hari ini. Seperti biasa, jangan pernah mengandalkan hasil tolok ukur lama.Kode Demo HTML Cepat: Berdasarkan apa yang saya ketahui tentang perpustakaan grafik SFML C ++:
Simpan ini sebagai file HTML dengan Pengkodean UTF-8 dan jalankan. Merasa bebas untuk refactor, saya hanya suka menggunakan variabel Jepang karena mereka ringkas dan tidak memakan banyak ruang
Jarang Anda ingin mengatur SATU piksel sembarang dan menampilkannya di layar. Jadi gunakan
metode untuk menggambar banyak piksel sembarang ke buffer belakang. (panggilan murah)
Kemudian ketika siap untuk ditampilkan, panggil
metode untuk menampilkan perubahan. (panggilan mahal)
Kode file .HTML lengkap di bawah ini:
sumber
Jika Anda khawatir tentang kecepatan maka Anda juga bisa mempertimbangkan WebGL.
sumber
HANDY dan proposisi fungsi put pixel (pp) (ES6) (baca-pixel di sini ):
Tampilkan cuplikan kode
Fungsi ini menggunakan
putImageData
dan memiliki bagian inisialisasi (garis panjang pertama). Pada awalnya alih-alihs='.myCanvas'
gunakan pemilih CSS Anda untuk kanvas Anda.Jika Anda ingin menormalkan parameter menjadi nilai dari 0-1, Anda harus mengubah nilai default
a=255
menjadia=1
dan sejalan dengan:id.data.set([r,g,b,a]),ctx.putImageData(id, x, y)
menjadiid.data.set([r*255,g*255,b*255,a*255]),ctx.putImageData(id, x*c.width, y*c.height)
Kode praktis di atas baik untuk menguji algoritma grafis ad-hoc atau membuat bukti konsep, tetapi tidak baik untuk digunakan dalam produksi di mana kode harus dapat dibaca dan jelas.
sumber
putImageData
mungkin lebih cepat darifillRect
aslinya. Saya pikir ini karena parameter kelima dapat memiliki cara yang berbeda untuk ditugaskan (warna persegi panjang), menggunakan string yang harus ditafsirkan.Misalkan Anda melakukan itu:
Jadi, garisnya
adalah yang paling berat di antara semua. Argumen kelima dalam
fillRect
panggilan adalah string yang sedikit lebih panjang.sumber
context.fillStyle = ...
sebagai gantinya. developer.mozilla.org/en-US/docs/Web/API/…