Почему putImageData так медленно?

Я работаю с относительно большим canvasом, на который нарисованы различные (сложные) вещи. Затем я хочу сохранить состояние Canvas, поэтому я могу быстро сбросить его до состояния, которое оно сейчас находится в более поздней точке. Для этого я использую getImageData и сохраняю данные в переменной. Затем я нарисую еще немного материала на canvas и позже сброшу Canvas туда, где он был, когда я сохранил его состояние, используя putImageData.

Однако, оказывается, что putImageData очень медленный. Infact, он медленнее, чем просто перерисовывает весь canvas с нуля, что включает в себя несколько drawImage, покрывающих большую часть поверхности, и более 40 000 операций lineTo, за которыми следуют штрихи и заливки.

Перерисовывание canvasа размером примерно 2000 х 5000 пикселей с нуля занимает ~ 170 мс, используя putImageData, хотя и занимает колоссальные 240 мс. Почему putImageData так медленно по сравнению с перерисованием canvasа, хотя перерисовывание canvasа включает в себя заполнение почти всего canvasа drawImage, а затем снова заполнение примерно 50% canvasа полигонами с использованием lineTo, штрихов и заполнения. Таким образом, каждый пиксель, по крайней мере, когда-то касался при перерисовке.

Поскольку drawImage кажется намного быстрее, чем putImageData (в конце концов, drawImage часть перерисовки canvasа занимает менее 30 мс). Я решил попытаться сохранить состояние canvas, не используя getImageData, но вместо этого используя canvas.toDataURL, а затем создав изображение из URL-адреса данных, который я бы вставлял в drawImage, чтобы нарисовать его на canvasе. Оказывается, вся эта процедура выполняется намного быстрее и занимает примерно 35 мс.

Итак, почему putImageData намного медленнее, чем альтернативы (используя getDataURL или просто перерисовку)? Как я мог ускорить процесс? Есть ли и если, что вообще лучший способ сохранить состояние canvasа?

(Все номера измеряются с помощью Firebug из Firefox)

Просто небольшое обновление о том, что лучший способ сделать это. Я на самом деле написал свою диплом бакалавра по высокоэффективным ECMAScript и HTML5 Canvas (pdf, немецкий), поэтому я уже собрал некоторые знания по этой теме. Лучшим решением является использование нескольких элементов canvasа. Рисование из одного canvasа на другой canvas так же быстро, как рисование сурового изображения на canvas. Таким образом, «сохранение» состояния canvasа так же быстро, как и восстановление его позже, при использовании двух элементов canvasа.

Этот тестовый тест jsPerf очень четко показывает различные подходы и их преимущества и недостатки.

Просто для полноты, вот как вы действительно должны это делать:

// setup var buffer = document.createElement('canvas'); buffer.width = canvas.width; buffer.height = canvas.height; // save buffer.getContext('2d').drawImage(canvas, 0, 0); // restore canvas.getContext('2d').drawImage(buffer, 0, 0); 

Это решение, в зависимости от браузера, до 5000 раз быстрее, чем тот, который получает upvotes.

В Firefox 3.6.8 я смог обойти медленность putImageData, используя вместо этого toDataUrl / drawImage. Для меня он работает достаточно быстро, и я могу назвать это при обработке события mousemove:

Сохранить:

 savedImage = new Image() savedImage.src = canvas.toDataURL("image/png") 

Чтобы восстановить:

 ctx = canvas.getContext('2d') ctx.drawImage(savedImage,0,0) 

Во-первых, вы говорите, что вы измеряете с помощью Firebug. Я действительно нахожу, что Firebug значительно замедляет выполнение JS, поэтому вы можете не получать хорошие показатели производительности.

Что касается putImageData , я подозреваю, что это потому, что функции принимают большой массив JS, содержащий много объектов Number , все из которых должны быть проверены для диапазона (0..255) и скопированы в собственный буфер canvasа.

Возможно, когда будут доступны типы WebGL ByteArray, такие вещи можно сделать быстрее.

Кажется странным, что base64-декодирование и разжатие данных (с URL-адресами PNG) выполняется быстрее, но это вызывает только одну JS-функцию с одной строкой JS, поэтому она использует в основном собственный код и типы.

  • Эффективность чисто функционального программирования
  • Что случилось с использованием ассоциативности компиляторами?
  • Android - предотrotation белого экрана при запуске
  • Производительность бритвы ASP.NET MVC 3
  • Как выполнить UPSERT, чтобы я мог использовать как новые, так и старые значения в части обновления
  • Цикл с вызовом функции быстрее, чем пустой цикл
  • Установка свойства изображения UIImageView вызывает серьезное отставание
  • Что более эффективно: System.arraycopy vs Arrays.copyOf?
  • Внедрение средства просмотра журналов с помощью WPF
  • Производительность встроенных типов: char vs short vs int vs. float vs. double
  • Является ли использование double быстрее, чем float?
  • Давайте будем гением компьютера.