Są dwa najlepsze podmioty:
Utwórz dane obrazu 1 × 1, ustaw kolor i putImageData
w miejscu:
var id = myContext.createImageData(1,1); // only do this once per page
var d = id.data; // only do this once per page
d[0] = r;
d[1] = g;
d[2] = b;
d[3] = a;
myContext.putImageData( id, x, y );
Użyj, fillRect()
aby narysować piksel (nie powinno być problemów z aliasingiem):
ctx.fillStyle = "rgba("+r+","+g+","+b+","+(a/255)+")";
ctx.fillRect( x, y, 1, 1 );
Możesz przetestować ich szybkość tutaj: http://jsperf.com/setting-canvas-pixel/9 lub tutaj https://www.measurethat.net/Benchmarks/Show/1664/1
Polecam testowanie pod kątem przeglądarek, na których Ci zależy, pod kątem maksymalnej prędkości. Od lipca 2017 r. fillRect()
Jest 5-6 razy szybszy w Firefoksie v54 i Chrome v59 (Win7x64).
Inne, głupsze alternatywy to:
używanie getImageData()/putImageData()
na całym płótnie; jest to około 100 × wolniej niż w przypadku innych opcji.
tworzenie niestandardowego obrazu za pomocą adresu URL danych i drawImage()
wyświetlanie go:
var img = new Image;
img.src = "data:image/png;base64," + myPNGEncoder(r,g,b,a);
// Writing the PNGEncoder is left as an exercise for the reader
tworząc kolejny obraz lub płótno wypełnione wszystkimi pikselami, których chcesz, i użyj, drawImage()
aby przesunąć tylko piksel, który chcesz w poprzek. Byłoby to prawdopodobnie bardzo szybkie, ale ma ograniczenie, które wymaga wstępnego obliczenia potrzebnych pikseli.
Zauważ, że moje testy nie próbują zapisywać i przywracać kontekstu obszaru roboczego fillStyle
; spowolniłoby to fillRect()
wydajność. Zauważ też, że nie zaczynam od czystego konta ani nie testuję dokładnie tego samego zestawu pikseli dla każdego testu.
fillRect()
ostatnio stał się prawie 10 razy szybszy niż putimagedata 1x1 na Chromev24. Więc ... jeśli prędkość ma kluczowe znaczenie i znasz swoich docelowych odbiorców, nie wierz w przestarzałą odpowiedź (nawet moją). Zamiast tego: przetestuj!Jedną z metod, o której nie wspomniano, jest użycie getImageData, a następnie putImageData.
Ta metoda jest dobra, gdy chcesz szybko narysować dużo za jednym razem.
http://next.plnkr.co/edit/mfNyalsAR2MWkccr
źródło
Nie zastanawiałem się
fillRect()
, ale odpowiedzi zachęciły mnie do porównaniaputImage()
.Umieszczenie 100 000 losowo kolorowych pikseli w losowych lokalizacjach z Chrome 9.0.597.84 na (starym) MacBooku Pro zajmuje mniej niż 100 ms
putImage()
, ale prawie 900 msfillRect()
. (Kod testu na stronie http://pastebin.com/4ijVKJcC ).Jeśli zamiast tego wybiorę pojedynczy kolor poza pętlami i po prostu
putImage()
wykreślę ten kolor w losowych miejscach, zajmie to 59 ms w porównaniu do 102 msfillRect()
.Wygląda na to, że narzut związany z generowaniem i analizowaniem specyfikacji kolorów CSS w
rgb(...)
składni jest odpowiedzialny za większość różnic.ImageData
Z drugiej strony wstawianie surowych wartości RGB bezpośrednio do bloku nie wymaga obsługi ciągów ani parsowania.źródło
źródło
putImageData()
po tej funkcji lub kontekst będzie aktualizowany przez odniesienie?Ponieważ różne przeglądarki wydają się preferować różne metody, może warto przeprowadzić mniejszy test przy użyciu wszystkich trzech metod w ramach procesu ładowania, aby dowiedzieć się, który najlepiej użyć, a następnie użyć go w aplikacji?
źródło
Wydaje się to dziwne, ale mimo to HTML5 obsługuje rysowanie linii, okręgów, prostokątów i wielu innych podstawowych kształtów, nie ma nic odpowiedniego do rysowania podstawowego punktu. Jedynym sposobem na to jest symulacja punktu z tym, co masz.
Zasadniczo istnieją 3 możliwe rozwiązania:
Każda z nich ma swoje wady
Linia
Pamiętaj, że zbliżamy się do kierunku południowo-wschodniego, a jeśli jest to krawędź, może być problem. Ale możesz także rysować w dowolnym innym kierunku.
Prostokąt
lub w szybszy sposób przy użyciu fillRect, ponieważ silnik renderujący wypełnia tylko jeden piksel.
okrąg
Jednym z problemów z kręgami jest to, że silnik jest trudniejszy do ich renderowania
ten sam pomysł jak w przypadku prostokąta, który można osiągnąć dzięki wypełnieniu.
Problemy ze wszystkimi tymi rozwiązaniami:
Jeśli zastanawiasz się: „Jak najlepiej narysować punkt? ”, Wybrałbym wypełniony prostokąt. Możesz zobaczyć mój jsperf tutaj z testami porównawczymi .
źródło
Co z prostokątem? To musi być bardziej wydajne niż tworzenie
ImageData
obiektu.źródło
putImageData
go, jest 10 razy szybszy niżfillRect
w Chrome. (Zobacz moją odpowiedź, aby dowiedzieć się więcej.)Narysuj prostokąt, jak powiedział sdleihssirhc!
^ - powinien narysować prostokąt 1x1 o wymiarach x: 10, y: 10
źródło
Hmm, możesz też po prostu utworzyć linię o szerokości 1 piksela i długości 1 piksela, a jej kierunek przesunie się wzdłuż jednej osi.
źródło
Aby udzielić bardzo dokładnej odpowiedzi na pytanie, istnieje krytyczna różnica między
fillRect()
iputImageData()
.Pierwszy kontekst zastosowania wyciągnąć ponad poprzez dodanie prostokąt (nie pikseli), stosując fillStyle wartość alfa i kontekst globalAlpha oraz macierz transformacji , czapki linii itp ..
The drugi zastępuje cały zestaw pikseli (może jeden, ale dlaczego ?)
Wynik jest inny, jak widać na jsperf .
Nikt nie chce ustawiać jednego piksela na raz (co oznacza rysowanie go na ekranie). Dlatego nie ma specyficznego API do tego (i słusznie).
Jeśli chodzi o wydajność, jeśli celem jest wygenerowanie obrazu (na przykład oprogramowania do śledzenia promieni), zawsze chcesz użyć tablicy uzyskanej za
getImageData()
pomocą zoptymalizowanej macierzy Uint8Array. Następnie dzwoniszputImageData()
RAZ lub kilka razy na sekundę za pomocąsetTimeout/seTInterval
.źródło
fillRect
było bolesne, ponieważ przyspieszenie sprzętowe Chrome nie radzi sobie z poszczególnymi połączeniami do GPU, których wymagałoby. Skończyło się na tym, że musiałem użyć danych pikselowych w stosunku 1: 1, a następnie użyć skalowania CSS, aby uzyskać pożądany wynik. To brzydkie :(get/putImageData
operacji na sekundę , ale 194,893 zafillRect
.1x1 image data
wynosi 125 102 Oper / s. TakfillRect
wygrywa zdecydowanie w Firefoksie. Więc wiele się zmieniło między 2012 r. A dniem dzisiejszym. Jak zawsze, nigdy nie polegaj na starych wynikach testów.Szybki kod demonstracyjny HTML: Na podstawie tego, co wiem o bibliotece graficznej SFML C ++:
Zapisz to jako plik HTML z kodowaniem UTF-8 i uruchom. Zapraszam do refaktoryzacji, po prostu lubię używać japońskich zmiennych, ponieważ są one zwięzłe i nie zajmują dużo miejsca
Rzadko będziesz chciał ustawić JEDEN dowolny piksel i wyświetlić go na ekranie. Więc użyj
metoda narysowania wielu dowolnych pikseli w buforze wstecznym. (tanie rozmowy)
Następnie, gdy będziesz gotowy do pokazu, zadzwoń pod numer
metoda wyświetlania zmian. (kosztowne połączenie)
Pełny kod pliku .HTML poniżej:
źródło
Jeśli obawiasz się o szybkość, możesz również rozważyć WebGL.
źródło
HANDY i propozycja funkcji put pixel (pp) (ES6) (read-pixel tutaj ):
Pokaż fragment kodu
Ta funkcja korzysta z
putImageData
części inicjalizacyjnej (pierwsza długa linia). Na początku zamiast tegos='.myCanvas'
użyj selektora CSS na swoim płótnie.Chcę normalizować parametry do wartości od 0-1, powinieneś zmienić wartość domyślną
a=255
naa=1
i dopasować do:id.data.set([r,g,b,a]),ctx.putImageData(id, x, y)
doid.data.set([r*255,g*255,b*255,a*255]),ctx.putImageData(id, x*c.width, y*c.height)
Przydatny powyższy kod jest przydatny do testowania algorytmów graficznych ad hoc lub sprawdzania koncepcji, ale nie jest dobry do użycia w produkcji, w której kod powinien być czytelny i przejrzysty.
źródło
putImageData
jest prawdopodobnie szybszy niżfillRect
natywnie. Myślę, że to dlatego, że piąty parametr może mieć różne sposoby przypisywania (kolor prostokąta), używając ciągu, który należy interpretować.Załóżmy, że robisz to:
Więc linia
jest najcięższy ze wszystkich. Piąty argument w
fillRect
wywołaniu jest nieco dłuższy.źródło
context.fillStyle = ...
zamiast tego użyć . developer.mozilla.org/en-US/docs/Web/API/…