Загрязненные полотна не могут быть экспортированы

187

Я хочу сохранить свой холст в 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': испорченные полотна не могут быть экспортированы.

Что я должен делать?

user3465096
источник
В каком браузере? stackoverflow.com/a/21362569/476716 утверждает, что это ошибка.
OrangeDog
1
на Chrome и Firefox
user3465096

Ответы:

180

По соображениям безопасности ваш локальный диск объявлен как «other-domain» и испортит холст.

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

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

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

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

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

MARKE
источник
16
Спасибо, установка свойства img.crossOrigin помогла мне!
Zumek
5
@markE - я загружал данные изображения из localStorage вместо загрузки из файла или любого URL-адреса, затем сделал некоторые манипуляции с ним, такие как добавление текста. Затем попытался вернуть его в localStorage с помощью toDataURL (). Но он показывает «Не удалось выполнить toDataURL на HTMLCanvasElement: испорченные холсты могут не экспортироваться». В этом случае я не использую какой-либо файл exteranl или URL-адрес для получения междоменной проблемы. Тогда почему это приводит к этой ошибке?
Саджит
2
@Saijth - вы можете проверить путь, используемый для изображений. У меня также была эта проблема, потому что я тестировал прямой доступ к своему локальному виртуальному серверу через его IP-адрес (127.0.xx /), но некоторые образы были связаны через домен (localhost /). Однажды я использовал localhost, вместо этого все получилось. Поэтому убедитесь, что вы не столкнетесь с чем-то подобным.
Виктор Д.
1
(1) Просмотрите его с веб-сервера xampp, localhost / file вместо c: / localdisk / file; тогда Chrome не будет жаловаться на ошибку безопасности. (2) Или используйте этот флаг при запуске chrome: --allow-file-access-from-files
mosh
1
Просто добавьте еще одну возможную проблему: если вы пытаетесь экспортировать холст, содержащий svg с ForeignObject, некоторые браузеры помечают его как испорченный.
HairyFotr
128

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

<img crossorigin="anonymous"></img>
Анния Мартинес
источник
61
Но что делать в случае html5 canvas, а не элементов img
graphics123
11
В случае элемента canvas источником проблемы всегда является какое-либо изображение (или изображения), которые вы рисуете на нем. Поэтому вам просто нужно отследить изображение и установить его атрибут crossOrigin, как указано, перед его загрузкой.
Фернандо Эчеверриа
3
Это спасло мой день!
Чанг
1
Рад помочь :)
Анна Мартинес
9
его 12 утра я нахожусь в офисе, и я нахожу этот простой ответ, это чистое счастье
Dheeraj
26

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

1. Попытка получить скриншот карты на холсте, используя openlayers (версия> = 3)
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"
         })
     });
sknight
источник
1
фантастика. Полезно для всех источников, таких как TileImage и тому подобное.
Фил
Fatastic! Именно то, что я искал для себя, легко исправить для демонстрации OpenLayers, которую я делаю.
Марк
Я использую векторные слои листов и после добавляю это свойство к источнику, но оно тоже не работает!
Махди N75
Именно то, что мне было нужно :)
Рэй
17

Если вы используете 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

mehulmpt
источник
6
Это не сработало для меня. Все еще получаю Tainted canvases may not be exported.сообщение об ошибке.
Сэм
1
меня устраивает. Спасибо. @SamSverko убедитесь, что установили атрибут перед img.src.
aijogja
14

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

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

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

Прасанна Аарти
источник
Не могли бы вы быть более точным в своем ответе, потому что я на самом деле не знаю всей этой концепции. Как мне получить это изображение с моего сервера?
user3465096
откуда вы берете это изображение, с вашего сервера или с какого-то другого?
Прасанна Аарти
Это выглядит так: loadImage ("example.jpg", 0, 0, 500, 300); Я могу поместить случайный URL-адрес изображения или изображение в одну и ту же папку на моем компьютере, но все равно
user3465096
да, но я только что создал изображение на краске, и он все тот же
user3465096
1
Я дал Access-Control-Allow-Origin: * для файла, но все равно он показывает ошибку
Харикришнан
5

Я решил проблему с помощью 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();
    });
Ахмад Захаби
источник
3

Посмотрите [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>

Вы сможете сохранить эти изображения в DOM Storage, как если бы они обслуживались с вашего домена, иначе вы столкнетесь с проблемой безопасности.

var img = new Image,
    canvas = document.createElement("canvas"),
    ctx = canvas.getContext("2d"),
    src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"; // insert image url here

img.crossOrigin = "Anonymous";

img.onload = function() {
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage( img, 0, 0 );
    localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
}
img.src = src;
// make sure the load event fires for cached images too
if ( img.complete || img.complete === undefined ) {
    img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    img.src = src;
}

BerlinaLi
источник
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. - Из обзора
Гаутам Шива
Спасибо за уведомление. Я просто добавляю контент по ссылке MDN :)
BerlinaLi
1

Просто как ответ на вопрос @ markE - если вы хотите создать локальный сервер. У вас не будет этой ошибки на локальном сервере.

Если на вашем компьютере установлен PHP:

  1. Откройте свой терминал / CMD
  2. Перейдите в папку, где находятся файлы вашего сайта
  3. Находясь в этой папке, выполните команду php -S localhost:3000← Обратите внимание на заглавную 'S'
  4. Откройте браузер и в адресной строке перейдите на localhost: 3000 . Ваш сайт должен работать там.

или

Если на вашем компьютере установлен Node.js:

  1. Откройте свой терминал / CMD
  2. Перейдите в папку, где находятся файлы вашего сайта
  3. Находясь в этой папке, выполните команду npm init -y
  4. Запустить npm install live-server -gили sudo npm install live-server -gна макинтош
  5. Запустите, live-serverи он должен автоматически открыть новую вкладку в браузере с открытым вашим сайтом.

Примечание: не забудьте иметь файл index.html в корне вашей папки, иначе у вас могут возникнуть некоторые проблемы.

Ludolfyn
источник
0

Я также решил эту ошибку, добавив useCORS : true,в свой код, как -

html2canvas($("#chart-section")[0], {
        useCORS : true,
        allowTaint : true,
        scale : 0.98,
        dpi : 500,
        width: 1400, height: 900
    }).then();
Джит
источник