이 글은 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>

2012/01/01 00:16 2012/01/01 00:16
Trackback address :: http://zziuni.pe.kr/zziuni/trackback/580

Comments List

Write a comment.

[로그인][오픈아이디란?]