svg.js와 canvg를 사용하여 SVG 태그의 객체를 클라이언트 측에서만 이미지화합니다.

19096 단어 SVG
이 기사는 "SVG Advent Calendar 2014"의 8일째 기사입니다. 전날의 기사도 제가 쓰고 있어, 「svg.js와 svg.draggable.js를 사용하여 SVG 태그의 객체를 드래그 앤 드롭합니다. 」로서 정리하고 있습니다.

이 기사에서는, 서버를 사이에 두지 않고 클라이언트측의 처리만으로, SVG 태그를 화상화시킨다고 하는 것을 실현하고 있습니다.

방법은 간단하고 canvg을 사용합니다. canvg는 svg를 구문 분석하고 canvas화할 수 있는 도구입니다. canvas화해 버리면 「toDataURL()」를 사용할 수 있으므로, 클라이언트측만으로 처리가 완결한다고 하는 구조입니다.

실제 코드는 이런 식으로, canvg 함수에 canvas의 DOM 객체와 svg 태그를 인수로서 건네주고, 콜백 함수(renderCallback) 안에서, canvas의 toDataURL()를 호출하는 것 뿐입니다. 간단! ! (※ 물론, svg.js와 jQuery는 사용하지 않아도 쓸 수 있어요.)

HTML
<head>
    <!-- build:js(.) scripts/vendor.js -->
    <!-- bower:js -->
    <script src="bower_components/jquery/dist/jquery.js"></script>
    <script src="bower_components/svg.js/dist/svg.js"></script>
    <script src="bower_components/canvg/dist/canvg.js"></script>
    <!-- endbower -->
    <!-- endbuild -->
</head>
<body>
    <svg id="drawing" style="border:solid 1px;"></svg>

    <div><button id="button">convert to image</button></div>

    <script>
        var draw = SVG('drawing').size(500, 500);
        var image = draw.image('images/NKJ56_gatsudanshi500.jpg', 150, 100).dx(30).dy(30);
        var text = draw.text('SVGを画像化できますか?').move(150, 150).fill('#f06');
        var rect = draw.rect(100, 100).attr({fill: '#eee'}).dx(200).dy(200);
        var circle = draw.circle(100).attr({fill: '#ff0'}).dx(300).dy(300);

        $('#button').on('click', function () {
            var svgTag = $('svg').get(0).outerHTML;
            var canvas = $('<canvas>').get(0);
            canvg(canvas, svgTag, {
                renderCallback: function() {
                    $('body').find('.convImg').remove(); 
                    $('body')
                        .append($('<img>')
                        .css('border', 'solid 1px')
                        .addClass('convImg')
                        .attr('src', canvas.toDataURL())); 
                },
            }); 
        });
    </script>
</body>

그러나 이것을 실행해 보면 알 수 있지만 불행히도 이미지가 거칠어집니다.
canvg의 문서를 보아도, 퀄리티나 스무딩 등의 키워드를 찾을 수 없어, 이런 것인가라고 슬퍼하고 있습니다.

이러한 svg 태그는





이미징되었습니다. 하지만 거친. . . 폰트도 왠지 쟈기하고 있다. 왠지, 문자 자체가 작아지고 있다. . .





덧붙여서 이 코드, Chrome에서 동작 확인을 취했습니다만, IE에서는 움직여 주지 않았습니다. 여러가지 조사해 보면 IE에서는 한 궁리 필요한 것 같습니다 때문에, 꼭 조사해 보세요.

그리고, 이미지의 거칠기에 대해, 좀 더 개선하는 방법이 없는 것인지 조사해 보았을 때, canvg에는 canvas의 「 drawImage 」와 비슷한 「drawSvg」라고 하는 함수가 준비되고 있는 것을 알았습니다 .
canvas의 getContext 때에, 「imageSmoothingEnabled . . 불행히도 결과는 변함없이. (아무래도 아직 experimental 사양 같네요)

그 밖에도 svg의 「 shape-rendering 」나 canvas의 「 image-rendering 」라고 하는 파라미터가 있으므로, 이 변을 조합하면 혹시 개선할지도 모릅니다. 하지만 이번에는 미조사.

HTML
<body>
    <svg id="drawing" style="border:solid 1px;"></svg>

    <div><button id="button">convert to image</button></div>

    <script>
        var draw = SVG('drawing').size(500, 500);
        var image = draw.image('images/NKJ56_gatsudanshi500.jpg', 150, 100).dx(30).dy(30);
        var text = draw.text('SVGを画像化できますか?').move(150, 150).fill('#f06');
        var rect = draw.rect(100, 100).attr({fill: '#eee'}).dx(200).dy(200);
        var circle = draw.circle(100).attr({fill: '#ff0'}).dx(300).dy(300);

        $('#button').on('click', function () {
            var svgTag = $('svg').get(0).outerHTML;
            var $canvas = $('<canvas>').attr('width', '500px').attr('height', '500px').addClass('convCanvas');
            var context = $canvas.get(0).getContext('2d');
            context.imageSmoothingEnabled = true;
            context.drawSvg(svgTag, 0, 0);
            $('body').find('.convCanvas').remove(); 
            $('body').append($canvas); 
       });
    </script>
</body>

  • 이번 검증에 이용한 것
  • Yeoman 제너레이터의 generator-webapp (검증용 HTML의 편지지 작성)
  • Bower (svg.js 및 canvg 설치)
  • PAKUTASO의 츠요 폰 이미지 ([ photo by 팩타소. 작은 m ])


  • 참고 URL
  • D3.js로 만든 그래프(SVG)를 이미지로 저장
  • JAVASCRIPT로 SVG를 래스터 이미지로 변환
  • CANVG를 IE에서 이용할 때의 주의점
  • HTML에 포함된 SVG를 파일/데이터로 추출
  • D3.js 등에서 출력되는 svg를 이미지로 표시하는 방법
  • SVG를 PNG로 변환
  • SVG를 Canvas에서 사용하는 방법
  • btoa base64

  • 좋은 웹페이지 즐겨찾기