Canvas toDataURL() возвращает пустое изображение только в Firefox

Я использую glfx.js для редактирования своего изображения, но когда я пытаюсь получить данные этого изображения, используя toDataURL() Функция Я получаю пустое изображение (ширина такого же размера, как исходное изображение).

Странно то, что в Chrome скрипт работает отлично.

Я хочу отметить, что изображение загружается в canvas используя событие onload:

           img.onload = function(){

                try {
                    canvas = fx.canvas();
                } catch (e) {
                    alert(e);
                    return;
                }

                // convert the image to a texture
                texture = canvas.texture(img);

                // draw and update canvas
                canvas.draw(texture).update();

                // replace the image with the canvas
                img.parentNode.insertBefore(canvas, img);
                img.parentNode.removeChild(img);

            }

Также путь моего изображения находится в том же домене;

Проблема (в Firefox) - когда я нажимаю кнопку "Сохранить". Chrome возвращает ожидаемый результат, но Firefox возвращает это:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA7YAAAIWCAYAAABjkRHCAAAHxklEQVR4nO3BMQEAAADCoPVPbQZ/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
... [ lots of A s ] ... 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAzwD6aAABkwvPRgAAAABJRU5ErkJggg==

Что может привести к такому результату и как я могу это исправить?

1 ответ

Решение

Скорее всего, существует какое-то асинхронное событие между временем рисования на холсте и временем вызова toDataURL, По умолчанию холст очищается после каждого композита. Либо предотвратите очистку холста, создав контекст WebGL с preserveDrawingBuffer: true как в

var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});

или убедитесь, что toDataURL вызывается перед выходом из любого события, которое вы используете для рендеринга. Например, если вы делаете это

function render() {
  drawScene(); 
  requestAnimationFrame(render);
}
render();

И где-то еще сделать это

someElement.addEventListener('click', function() {
  var data = someCanvas.toDataURL();
}, false);

Эти 2 события, animation frameи click не синхронизированы, и холст может быть очищен между вызовами их. Примечание. Холст не будет очищен, так как он имеет двойную буферизацию, но буфер toDataURL и другие команды, влияющие на этот буфер, очищаются.

Решение либо использовать preserveDrawingBuffer или позвоните toDataURL внутри того же события, что и рендеринг. Например

var captureFrame = false;

function render() {
  drawScene(); 

  if (captureFrame) {
    captureFrame = false;
    var data = someCanvas.toDataURL();
    ...
  }

  requestAnimationFrame(render);
}
render();

someElement.addEventListener('click', function() {
  captureFrame = true;
}, false);

Какой смысл preserveDrawingBuffer: false какой по умолчанию? Это может быть значительно быстрее, особенно на мобильных устройствах, чтобы не нужно было сохранять буфер рисования. Еще один способ взглянуть на это - браузеру нужны 2 копии вашего холста. Тот, к которому вы рисуете, и тот, который он отображает. У этого есть 2 способа иметь дело с этими 2 буферами. (А) двойной буфер. Позвольте вам рисовать один, отображать другой, менять местами буферы, когда вы закончите рендеринг, который выводится из выхода из любого события, которое выдает команды рисования (B) Скопируйте содержимое буфера, который вы рисуете, чтобы сделать буфер, который отображается, Обмен намного быстрее, чем копирование. Таким образом, замена по умолчанию. Это зависит от браузера, что на самом деле происходит. Единственное требование заключается в том, что если preserveDrawingBuffer является false что буфер рисования очищается после составного (что является еще одним асинхронным событием и, следовательно, непредсказуемым), если preserveDrawingBuffer является true затем он должен копироваться, чтобы содержимое чертежного буфера было сохранено.

Другие вопросы по тегам