이 글은 canvas의 toDataURL()과 'origin-clean'에 관한 글이다.
Canvas Sample
getContext('2d') 메서드를 호출하면 canvas Element는 2D 이미지를 그릴 수 있는 CanvasRenderingContext2D 객체를 반환한다.
이렇게 반환받은 CanvasRenderingContext2D 객체로 여기다가 드로잉 질을 할 수 있다. 노랑색으로 바탕색을 깔고 텍스트 하나를 그려주자.
ctx.fillStyle = '#ffffaa';
ctx.fillRect(0, 0, 300, 300);
var text = "This is text drawn in canvas ";
ctx.font = "15px serif";
ctx.fillStyle="#ff0000";
ctx.fillText(text, 50, 140);
그런데, 이 객체에는 벡터 방식의 드로잉 뿐만 아니라 외부에서 비트맵 이미지도 넣을 수 있다.
var img = new Image();
img.src = "some_image_URL";
img.addEventListener('load', function(){
ctx.drawImage(img, 10, 10, 200, 100);
});
이미지 로딩이 끝나고 캔버스에서 써야 하므로 load 이벤트 핸들러로 처리한다.
toDataURL()
자 이제 이걸 PNG 이미지로 빼보자.
var btn = document.getElementsByTagName("button")[0];
btn.addEventListener('click', function(){
var snapshotPNG = canvas.toDataURL();
window.open(snapshotPNG, 'snapshot', 'width=300, height=300');
});
Security Error
초간단 canvas 데모다. 자 그럼 이제부터 본론.. ctx.drawImage()로 canvas에 넣을 이미지의 도메인을 현재 페이지 도메인과 다른 도메인으로 바꿔보자.
img.src = "other_image_URL";
이러면 canvas.toDataURL()라인에서 console에 다음과 같은 오류가 난다.
Uncaught Error: SECURITY_ERR: DOM Exception 18
이는 '동일 원본 정책'위반으로 canvas는 현재 문서와 다른 도메인의 리소스가 들어가면 toDataURL()를 허용하지 않는다. cross-origin information leak 를 방지하기 위해서라나... 어쨌든 이건 생각보다 룰이 강력해서 canvas에 현재 보이는지 와는 관계 없다. 뭔 말인고 하니..
만약 drawImage()를 한 다음에 다시 싹 지워 버리면 어떨까? canvas는 Flash, SVG같은 retain mode가 아닌 immediate mode 라서 매번 pixel drawing이 일어나므로 뭘 그렸든 다시 위에 몽땅 덧칠을 해버린다. 그러면 상관없지 않을까?
img.load = function(){
ctx.drawImage(img, 0, 0, 100, 100);
ctx.fillStyle = '#ffffaa';
ctx.fillRect(0, 0, 300, 300);
};
하지만 동일하게 에러. canvas.toDataURL()는 한번이라도 원본 정책이 손상되면 작동하지 않는다. 이것이 'Origin-Clean'이다. 한번이라도 더럽혀졌으면 용서없다. ㅡㅡ;
Origin-Clean
Origin-Clean은 플래그 값으로 canvas 가 시작할때 값은 true이다. 다음에 해당할때 false로 바뀌고 한번 바뀌면 true로 바뀌지 않는다.
- drawImage()가 현재 문서와 다른 도메인의 HTMLImageElement나 HTMLVideoElement를 호출되었을때.
- drawImage()가 origin-clean 값이 false인 HTMLCanvasElement를 호출되었을때.
- fiilStyle 속성이 현재 문서와 다른 도메인의 HTMLImageElement나 HTMLVideoElement의 CanvasPattern을 지정했을때.
- fillStyle 속성이 origin-clean 값이 false인 HTMLCanvasElement 으로 CanvasPattern을 지정했을때.
- strokeStyle 속성이 현재 문서와 다른 도메인의 HTMLImageElement나 HTMLVideoElement의 CanvasPattern 을 지정했을때.
- strokeStyle 속성이 origin-clean 값이 false인 HTMLCanvasElement 으로 CanvasPattern지정했을 때.
Origin_clean 값이 false이 되면, canvas.toDataURL()과 ctx.getImageData() 모두 보안오류가 난다.
샘플 전체 소스.
<!Doctype html> <html> <head> <title>canvas</title> </head> <body> <canvas width="300" height="300"></canvas> <button>snapshot</button> <script type="text/javascript"> var canvas = document.getElementsByTagName("canvas")[0]; var ctx = canvas.getContext('2d'); // return CanvasRenderingContext2D Object. ctx.fillStyle = '#ffffaa'; ctx.fillRect(0, 0, 300, 300); var text = "This is text drawn in canvas "; ctx.font = "15px serif"; ctx.fillStyle="#ff0000"; ctx.fillText(text, 50, 140); var img = new Image(); img.src = "some_image_URL"; img.addEventListener('load', function(){ console.log('inn'); ctx.drawImage(img, 10, 10, 200, 100); //ctx.fillStyle = '#ff0000'; //ctx.fillRect(0, 0, 300, 300); }); var btn = document.getElementsByTagName("button")[0]; btn.addEventListener('click', function(){ var snapshotPNG = canvas.toDataURL(); window.open(snapshotPNG, 'snapshot', 'width=300, height=300'); }); </script> </body> </html>


Comments List