Тонкие холсты могут не экспортироваться

Я хочу сохранить свой холст в img. У меня есть эта функция:

function save() {
    document.getElementById("canvasimg").style.border = "2px solid";
    var dataURL = canvas.toDataURL();
    document.getElementById("canvasimg").src = dataURL;
    document.getElementById("canvasimg").style.display = "inline";
}

Это дает мне ошибку:

Uncaught SecurityError: не удалось выполнить 'toDataURL' в 'HTMLCanvasElement': теневые холсты могут не экспортироваться.

Что мне делать?

Ответ 1

Из соображений безопасности ваш локальный диск объявлен как "другой домен" и будет испорчен на холсте.

(Это потому, что ваша самая чувствительная информация, скорее всего, на вашем локальном диске!).

Во время тестирования попробуйте обходные пути:

  • Поместите все связанные с страницей файлы (.html,.jpg,.js,.css и т.д.) на свой рабочий стол (не в подпапках).

  • Отправьте свои изображения на сайт, поддерживающий совместное использование домена (например, dropbox.com). Убедитесь, что вы поместили свои изображения в общую папку Dropbox, а также установили флаг перекрестного происхождения при загрузке изображения (var img = new Image(); img.crossOrigin = "anonymous"...)

  • Установите веб-сервер на своем компьютере разработки (у веб-серверов IIS и PHP есть бесплатные выпуски, которые хорошо работают на локальном компьютере).

Ответ 2

В теге img установите перекрестное происхождение в Anonymous.

<img crossorigin="anonymous"></img>

Ответ 3

Если кто-то просматривает мой ответ, вы можете быть в таком состоянии:

1. Попытка получить скриншот карты на холсте, используя openlayers 3 или 4
2. И просмотрел пример экспорта карты
3. Использование ol.source.XYZ для рендеринга слоя карты

Бинго!

Используя ol.source.XYZ.crossOrigin = 'Anonymous', вы решите проблему. Или как следующий код:

     var baseLayer = new ol.layer.Tile({
         name: 'basic',
         source: new ol.source.XYZ({
             url: options.baseMap.basic,
             crossOrigin: "Anonymous"
         })
     });

Ответ 4

В моем случае я рисовал на холсте теги из видео. Чтобы решить проблему испорченного холста, мне пришлось сделать две вещи:

<video id="video_source" crossorigin="anonymous">
    <source src="http://crossdomain.example.com/myfile.mp4">
</video>
  • Убедитесь, что заголовок заголовка Access-Control-Allow-Origin установлен в ответе источника видео (правильная настройка crossdomain.example.com)
  • Установите тег видео, который будет иметь crossorigin = "anonymous"

Ответ 5

Похоже, вы используете изображение с URL-адреса, который не установил правильный заголовок Access-Control-Allow-Origin и, следовательно, проблему. Вы можете получить это изображение с вашего сервера и получить его со своего сервера, чтобы избежать проблем с CORS..

Ответ 6

Если вы используете функцию ctx.drawImage(), вы можете сделать следующее:

var img = loadImage('../yourimage.png', callback);

function loadImage(src, callback) {
    var img = new Image();

    img.onload = callback;
    img.setAttribute('crossOrigin', 'anonymous'); // works for me

    img.src = src;

    return img;
}

И в своем обратном вызове теперь вы можете использовать ctx.drawImage и экспортировать его с помощью toDataURL

Ответ 7

Посмотрите [CORS enabled image] [1] из MDN. Обычно у вас должен быть сервер, на котором размещены изображения с соответствующим заголовком Access-Control-Allow-Origin.

<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        <FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
            SetEnvIf Origin ":" IS_CORS
            Header set Access-Control-Allow-Origin "*" env=IS_CORS
        </FilesMatch>
    </IfModule>
</IfModule>

Ответ 8

Я решил проблему, используя опцию useCORS: true

 html2canvas(document.getElementsByClassName("droppable-area")[0], { useCORS:true}).then(function (canvas){
        var imgBase64 = canvas.toDataURL();
        // console.log("imgBase64:", imgBase64);
        var imgURL = "data:image/" + imgBase64;
        var triggerDownload = $("<a>").attr("href", imgURL).attr("download", "layout_"+new Date().getTime()+".jpeg").appendTo("body");
        triggerDownload[0].click();
        triggerDownload.remove();
    });