오염 된 캔버스는 내보낼 수 없습니다


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 : 'HTMLCanvasElement'에서 'toDataURL'을 (를) 실행하지 못했습니다. 오염 된 캔버스를 내보낼 수 없습니다.

어떻게해야합니까?


어떤 브라우저에서? stackoverflow.com/a/21362569/476716 은 이것이 버그라고 주장합니다.
OrangeDog

1
크롬 및 파이어 폭스
user3465096

답변:


180

보안상의 이유로 로컬 드라이브는 "기타 도메인"으로 선언되어 캔버스를 손상시킵니다.

(가장 민감한 정보가 로컬 드라이브에있을 수 있기 때문입니다!).

테스트하는 동안 다음 해결 방법을 시도하십시오.

  • 모든 페이지 관련 파일 (.html, .jpg, .js, .css 등)을 데스크탑 (하위 폴더가 아님)에 두십시오.

  • 도메인 간 공유를 지원하는 사이트 (dropbox.com 등)에 이미지를 게시하십시오. 이미지를 드롭 박스의 공용 폴더에 넣고 이미지를 다운로드 할 때 교차 원점 플래그를 설정해야합니다 (var img = new Image (); img.crossOrigin = "anonymous"...)

  • 개발 컴퓨터에 웹 서버를 설치하십시오 (IIS 및 PHP 웹 서버에는 로컬 컴퓨터에서 잘 작동하는 무료 버전이 있습니다).


16
감사합니다. img.crossOrigin 속성을 설정하면 도움이되었습니다.
zumek

5
@markE-파일이나 URL에서로드하는 대신 localStorage에서 이미지 데이터를로드 한 다음 텍스트를 추가하는 것처럼 약간의 조작을 수행했습니다. 그런 다음 toDataURL ()을 사용하여 localStorage에 다시 저장하려고했습니다. 그러나 "HTMLCanvasElement '에서'toDataURL '을 (를) 실행하지 못했습니다 : 오염 된 캔버스를 내보낼 수 없습니다"가 표시됩니다. 이 경우 도메인 간 문제를 해결하기 위해 exteranl 파일이나 url을 사용하지 않습니다. 그렇다면 왜이 오류가 발생합니까?
Sajith

2
@Saijth-이미지에 사용 된 경로를 확인할 수 있습니다. IP (127.0.xx /)를 통해 로컬 가상 서버에 직접 액세스하는 테스트를 수행했지만 일부 이미지가 도메인 (localhost /)을 통해 연결 되었기 때문에이 문제가 발생했습니다. 일단 localhost를 사용하면 해결되었습니다. 따라서 그런 식으로 실행되지 않아야합니다.
Victor D.

1
(1) c : / localdisk / file 대신 xampp 웹 서버, localhost / file에서 봅니다. 크롬은 보안 오류에 대해 불평하지 않습니다. (2) 또는 크롬을 시작할 때이 플래그를 사용하십시오 : --allow-file-access-from-files
mosh

1
다른 가능한 문제를 추가하는 것만으로, ForeignObject와 함께 svg가 포함 된 캔버스를 내보내려고하는 경우 일부 브라우저는 오염 된 것으로 표시합니다.
HairyFotr

128

img 태그에서 crossorigin을 Anonymous로 설정하십시오.

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

61
그러나 img 요소가 아닌 html5 canvas의 경우해야 할
graphics123

11
캔버스 요소의 경우 문제의 원인은 항상 그 위에 그리는 일부 이미지에 있습니다. 따라서로드하기 전에 이미지를 추적하고 표시된대로 crossOrigin 속성을 설정하면됩니다.
페르난도 Echeverria

3
이것은 나의 하루를 구했다!
Chang


9
오전 12시 임 사무실에서 나는이 간단한 답변을 찾을 수 있습니다, 이것은 순수한 행복입니다
Dheeraj

26

누군가 내 답변을 보면 다음과 같은 상태 일 수 있습니다.

1. openlayers (버전> = 3)를 사용하여 캔버스에서 맵 스크린 샷을 가져 오려고 시도
2. 맵 내보내기 예제를
보았습니다. ol.source.XYZ를 사용하여 맵 레이어 렌더링

빙고!

ol.source.XYZ.crossOrigin = '익명' 을 사용 하여 혼동을 해결하십시오. 또는 다음 코드와 같이 :

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

1
환상적입니다. TileImage와 같은 모든 소스에 유용합니다.
Phil

치명적입니다! 내가 직접 찾고 있던 것은 OpenLayers 데모를 쉽게 고칠 수 있습니다.
Marc

벡터 타일 레이어를 사용하고 있으며 소스 에이 특성을 추가했지만 작동하지 않습니다!
mahdi n75

정확히 내가 필요한 것 :)
Ray

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


6
이것은 나를 위해 작동하지 않았습니다. 여전히 Tainted canvases may not be exported.오류 메시지가 나타납니다.
Sam Sverko

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"가되도록 비디오 태그를 설정하십시오.

5

올바른 Access-Control-Allow-Origin 헤더를 설정하지 않은 URL의 이미지를 사용하는 것 같습니다. 따라서 이미지를 서버에서 가져와 서버에서 가져와 CORS 문제를 피할 수 있습니다.


나는 그 개념을 모두 알지 못하기 때문에 대답에 대해 더 정확할 수 있습니까? 서버에서 해당 이미지를 가져 오려면 어떻게합니까?
user3465096

해당 이미지를 어디에서 가져오고 있습니까? 서버 또는 다른 이미지에서 가져 왔습니까?
Prasanna Aarthi

다음과 같습니다. loadImage ( "example.jpg", 0, 0, 500, 300); 컴퓨터의 동일한 폴더에 임의의 이미지 URL 또는 이미지를 넣을 수 있습니다. 여전히 동일
user3465096

예,하지만 페인트에 이미지를 만들었는데 여전히 동일합니다.
user3465096

1
파일에 대해 Access-Control-Allow-Origin : *을 주었지만 여전히 오류가 표시됩니다.
Harikrishnan

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

MDN에서 [CORS 가능 이미지] [1]를 확인하십시오. 기본적으로 적절한 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 스토리지에 저장할 수 있습니다. 그렇지 않으면 보안 문제가 발생합니다.

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


이 링크가 질문에 대답 할 수 있지만 여기에 답변의 필수 부분을 포함시키고 참조 할 수있는 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않을 수 있습니다. - 검토에서
Gowtham 시바

통지 해 주셔서 감사합니다. MDN 링크의 내용을 추가하기
만하면

1

로컬 서버를 만들려면 @markE의 답변을 기반으로합니다. 로컬 서버에는이 오류가 없습니다.

컴퓨터에 PHP가 설치되어있는 경우 :

  1. 터미널 / cmd를 엽니 다
  2. 웹 사이트 파일이있는 폴더로 이동
  3. 이 폴더에있는 동안 php -S localhost:3000← 대문자 'S'를 확인하십시오.
  4. 브라우저를 열고 URL 표시 줄에서 localhost : 3000으로 이동하십시오 . 귀하의 웹 사이트가 실행 중이어야합니다.

또는

컴퓨터에 Node.js가 설치되어있는 경우 :

  1. 터미널 / cmd를 엽니 다
  2. 웹 사이트 파일이있는 폴더로 이동
  3. 이 폴더에있는 동안 명령을 실행하십시오 npm init -y
  4. 실행 npm install live-server -g또는 sudo npm install live-server -gMac에서
  5. 실행 live-server하면 웹 사이트가 열린 상태에서 브라우저에 새 탭이 자동으로 열립니다.

참고 : 폴더의 루트에 index.html 파일이 있어야합니다. 그렇지 않으면 문제가있을 수 있습니다.


0

또한 다음 useCORS : true,과 같은 코드 를 추가 하여이 오류를 해결했습니다.

html2canvas($("#chart-section")[0], {
        useCORS : true,
        allowTaint : true,
        scale : 0.98,
        dpi : 500,
        width: 1400, height: 900
    }).then();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.