Pracuję ze stosunkowo dużym płótnem, na którym rysuje się różne (złożone) rzeczy. Następnie chcę zapisać stan Canvas, więc mogę szybko zresetować go do stanu, w którym znajduje się teraz. Używam do tego getImageData i przechowuję dane w zmiennej. Następnie narysuję trochę więcej rzeczy na płótnie, a potem zmienię płótno na miejsce, w którym zapisałem jego stan, używając putImageData.Dlaczego plik putImageData jest tak wolny?
Jednak okazuje się, że putImageData działa bardzo wolno. W rzeczywistości, jest wolniejszy niż zwykłe przerysowywanie całego płótna od zera, co wiąże się z kilkoma rysunkami, które obejmują większość powierzchni, oraz ponad 40 000 operacji lineTo, po których następuje uderzenie i wypełnienie.
Ponowne rysowanie płótna o wymiarach 2000 x 5000 pikseli od zera trwa ~ 170 ms, a użycie metody putImageData zajmuje nawet 240 ms. Dlaczego putImageData jest tak powolny w porównaniu do przerysowywania płótna, chociaż ponowne rysowanie płótna wymaga wypełnienia niemal całego płótna drawImage, a następnie ponownego wypełnienia około 50% płótna wielobokami za pomocą lineTo, stroke i fill. Zasadniczo każdy piksel jest dotykany co najmniej raz podczas przerysowywania.
Ponieważ drawImage wydaje się być znacznie szybszy niż putImageData (w końcu część drawImage przerysowywania płótna zajmuje mniej niż 30 ms). Postanowiłem spróbować zapisać stan płótna bez użycia getImageData, ale zamiast tego użyć canvas.toDataURL, a następnie utworzyć obraz z adresu URL danych, który wstawiłbym do drawImage, aby narysować go na płótnie. Okazuje się, że ta cała procedura jest znacznie szybsza i zajmuje tylko około 35 ms.
Dlaczego więc putImageData jest o wiele wolniejszy niż alternatywy (używając getDataURL lub po prostu przerysowywania)? Jak mogę przyspieszyć dalszy rozwój? Czy istnieje i, jeśli w ogóle, jaki jest najlepszy sposób przechowywania stanu płótna?
(wszystkie liczby są mierzone za pomocą Firebug z poziomu Firefoksa)
Byłoby interesujące, gdyby można opublikować demonstrację swojego problemu w Internecie gdzieś. W noVNC (http://github.com/kanaka/noVNC) używam putImageData dla wielu małych i średnich macierzy danych obrazu i nie widzę problemu z wydajnością z putImageData. Być może masz do czynienia z konkretnym przypadkiem wydajności pesymu, który powinien być bug'd. – kanaka
Możesz zajrzeć tutaj http://www.danielbaulig.de/A3O/ To nie zadziała w 100%, jeśli konsola firebug zostanie przełączona, więc upewnij się, że ją włączysz. Wersja wyewidencjonowana to ta, która używa putImageData. Możesz go uruchomić, klikając dowolny "kafelek". Odświeży to płótno buforowe za pomocą putImageData, a następnie "podświetli" wybrany kafelek. W a3o_oo.js zostało skomentowanych kilka linii, które mogą być użyte do przełączania pomiędzy putImageData (current), za pomocą getDataURL (dwa wiersze wspominające this.boardBuffer) i zwykłego przerysowywania (linia drawBoard) obszaru roboczego bufora. –
Świetne pytanie i świetne rozwiązania. Ale czy kiedykolwiek odkryłeś prawdziwy powód, dlaczego putImageData jest tak powolny w porównaniu do drawImage? – cherouvim