Splamione płótna nie mogą być eksportowane

187

Chcę zapisać moje płótno na obrazie. Mam tę funkcję:

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

Daje mi błąd:

Uncaught SecurityError: Nie udało się wykonać polecenia „toDataURL” na „HTMLCanvasElement”: skażonych płócien nie można wyeksportować.

Co powinienem zrobić?

użytkownik3465096
źródło
W jakiej przeglądarce? stackoverflow.com/a/21362569/476716 twierdzi, że to błąd.
OrangeDog
1
na chromie i na
firefoxie

Odpowiedzi:

180

Ze względów bezpieczeństwa twój dysk lokalny jest zadeklarowany jako „inna domena” i zepsuje obszar roboczy.

(Jest tak, ponieważ Twoje najbardziej poufne informacje są prawdopodobnie przechowywane na dysku lokalnym!).

Podczas testowania wypróbuj następujące obejścia:

  • Umieść wszystkie pliki związane ze stroną (.html, .jpg, .js, .css itp.) Na pulpicie (nie w podfolderach).

  • Opublikuj swoje zdjęcia w witrynie, która obsługuje udostępnianie między domenami (np. Dropbox.com). Pamiętaj, aby umieścić swoje zdjęcia w folderze publicznym Dropbox, a także ustawić flagę cross origin podczas pobierania obrazu (var img = new Image (); img.crossOrigin = "anonimowy" ...)

  • Zainstaluj serwer WWW na swoim komputerze programistycznym (zarówno serwery sieci Web IIS, jak i PHP mają darmowe wersje, które działają dobrze na komputerze lokalnym).

markE
źródło
16
Dzięki, ustawienie właściwości img.crossOrigin pomogło mi!
zumek
5
@markE - Załadowałem dane obrazu z localStorage zamiast ładować z pliku lub dowolnego adresu URL, a następnie wykonałem pewne manipulacje, takie jak dodanie tekstu. Następnie próbował przywrócić go do localStorage za pomocą toDataURL (). Ale pokazuje „Nie można wykonać„ toDataURL ”na„ HTMLCanvasElement ”: Zanieczyszczone płótna mogą nie zostać wyeksportowane”. W tym przypadku nie używam żadnego pliku zewnętrznego ani adresu URL do uzyskania problemu z domeną. To dlaczego powoduje ten błąd?
Sajith,
2
@Saijth - Możesz zweryfikować ścieżkę użytą do zdjęć. Miałem również ten problem, ponieważ testowałem bezpośredni dostęp do mojego lokalnego wirtualnego serwera przez jego adres IP (127.0.xx /), ale niektóre obrazy były połączone przez domenę (localhost /). Kiedyś zamiast tego użyłem localhost, zadziałało. Upewnij się więc, że nie napotykasz czegoś takiego.
Victor D.,
1
(1) Zobacz go z serwera xampp, localhost / file zamiast c: / localdisk / file; wtedy chrome nie będzie narzekać na błąd bezpieczeństwa. (2) Lub użyj tej flagi podczas uruchamiania Chrome: --allow-file-access-from-files
mosh
1
Właśnie dodajemy kolejny możliwy problem: jeśli próbujesz wyeksportować płótno zawierające plik svg z ForeignObject, niektóre przeglądarki oznaczą go jako skażony.
HairyFotr
128

W znaczniku img ustaw crossorigin na Anonimowy.

<img crossorigin="anonymous"></img>
Annia Martinez
źródło
61
Ale co zrobić w przypadku płótna HTML5, a nie elementów IMG
Graphics123
11
W przypadku elementu canvas źródłem problemu zawsze jest jakiś obraz (lub obrazy), na którym rysujesz. Musisz tylko wyśledzić obraz i ustawić jego atrybut crossOrigin, jak wskazano, przed załadowaniem go.
Fernando Echeverria,
3
To uratowało mi dzień!
Chang
1
Chętnie pomożemy :)
Annia Martinez
9
jest o 12 rano w biurze i znajduję tę prostą odpowiedź, to jest czyste szczęście
Dheeraj
26

Jeśli ktoś wyświetli moją odpowiedź, być może w tym stanie:

1. Próbuję uzyskać zrzut ekranu mapy w obszarze roboczym przy użyciu openlayers (wersja> = 3)
2. I przeglądałem przykład eksportowania mapy
3. Używając ol.source.XYZ do renderowania warstwy mapy

Bingo!

Używanie ol.source.XYZ.crossOrigin = 'Anonimowy', aby rozwiązać problem. Lub podobny kod:

     var baseLayer = new ol.layer.Tile({
         name: 'basic',
         source: new ol.source.XYZ({
             url: options.baseMap.basic,
             crossOrigin: "Anonymous"
         })
     });
sknight
źródło
1
fantastyczny. Przydatny dla wszystkich źródeł, takich jak TileImage i tym podobnych.
Phil
Fatastyczny! Dokładnie to, czego szukałem, łatwa naprawa dema OpenLayers.
Marc
Używam wektorowych warstw kafelków i po dodaniu tej właściwości do źródła, ale też nie działa!
mahdi n75
Dokładnie to, czego potrzebowałem :)
Ray
17

Jeśli używasz ctx.drawImage()funkcji, możesz wykonać następujące czynności:

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;
}

W oddzwanianiu możesz go teraz używać ctx.drawImagei eksportować za pomocątoDataURL

mehulmpt
źródło
6
To mi nie zadziałało. Nadal pojawia się Tainted canvases may not be exported.komunikat o błędzie.
Sam Sverko,
1
mi to pasuje. dzięki. @SSSverko upewnij się, że ustawiłeś atrybut przed img.src.
aijogja
14

W moim przypadku rysowałem na płótnie tag z filmu. Aby rozwiązać problem skażonego płótna, musiałem zrobić dwie rzeczy:

<video id="video_source" crossorigin="anonymous">
    <source src="http://crossdomain.example.com/myfile.mp4">
</video>
  • Upewnij się, że nagłówek Access-Control-Allow-Origin jest ustawiony w odpowiedzi źródła wideo (prawidłowe ustawienie crossdomain.example.com)
  • Ustaw tag wideo, aby crossorigin = "anonimowy"
jdramer
źródło
5

Wygląda na to, że używasz obrazu z adresu URL, który nie ustawił prawidłowego nagłówka Access-Control-Allow-Origin i stąd problem. Możesz pobrać ten obraz z serwera i pobrać go z serwera, aby uniknąć problemów z CORS.

Prasanna Aarthi
źródło
Czy mógłbyś być bardziej precyzyjny w swojej odpowiedzi, ponieważ tak naprawdę nie znam całej tej koncepcji. Jak mogę pobrać ten obraz z mojego serwera?
user3465096
skąd pobierasz ten obraz, czy pochodzi on z serwera, czy z innego?
Prasanna Aarthi
Wygląda to tak: loadImage ("example.jpg", 0, 0, 500, 300); Mogę umieścić losowy adres URL obrazu lub obraz w tym samym folderze na moim komputerze, nadal jest taki sam
user3465096
tak, ale właśnie utworzyłem obraz na farbie i nadal jest taki sam
3465096
1
Dałem Access-Control-Allow-Origin: * dla pliku, ale nadal pokazuje błąd
Harikrishnan
5

Rozwiązałem problem za pomocą useCORS: trueopcji

 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();
    });
Ahmad Zahabi
źródło
3

Sprawdź [obraz włączony CORS] [1] z MDN. Zasadniczo musisz mieć serwer obsługujący obrazy z odpowiednim nagłówkiem 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>

Będziesz mógł zapisać te obrazy w DOM Storage tak, jakby były dostarczone z Twojej domeny, w przeciwnym razie wystąpią problemy z bezpieczeństwem.

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
źródło
Chociaż ten link może odpowiedzieć na pytanie, lepiej dołączyć tutaj istotne części odpowiedzi i podać link w celach informacyjnych. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli zmieni się połączona strona. - Z recenzji
Gowtham Shiva
Dzięki za powiadomienie. Właśnie
dodałem
1

Podobnie jak kompilacja odpowiedzi @ markE - jeśli chcesz utworzyć serwer lokalny. Ten błąd nie wystąpi na serwerze lokalnym.

Jeśli masz zainstalowany PHP na swoim komputerze:

  1. Otwórz terminal / cmd
  2. Przejdź do folderu, w którym znajdują się pliki Twojej witryny
  3. W tym folderze uruchom polecenie php -S localhost:3000← Zwróć uwagę na duże „S”
  4. Otwórz przeglądarkę i na pasku adresu URL przejdź do localhost: 3000 . Twoja strona powinna tam być uruchomiona.

lub

Jeśli masz Node.js na swoim komputerze:

  1. Otwórz terminal / cmd
  2. Przejdź do folderu, w którym znajdują się pliki Twojej witryny
  3. W tym folderze uruchom polecenie npm init -y
  4. Uruchom npm install live-server -glub sudo npm install live-server -gna komputerze Mac
  5. Uruchom live-serveri powinien automatycznie otworzyć nową kartę w przeglądarce z otwartą witryną.

Uwaga: pamiętaj, aby mieć plik index.html w katalogu głównym folderu, w przeciwnym razie możesz mieć problemy.

Ludolfyn
źródło
0

Rozwiązałem również ten błąd, dodając useCORS : true,w kodzie mój kod, taki jak -

html2canvas($("#chart-section")[0], {
        useCORS : true,
        allowTaint : true,
        scale : 0.98,
        dpi : 500,
        width: 1400, height: 900
    }).then();
Jeet
źródło