Html2canvas: SVG ์บก์ฒ˜

์— ๋งŒ๋“  2012๋…„ 04์›” 26์ผ  ยท  64์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: niklasvh/html2canvas

์•ˆ๋…•ํ•˜์„ธ์š”,

html2canvas๋Š” SVG ์บก์ฒ˜๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ ‡๋‹ค๋ฉด ์–ด๋–ป๊ฒŒํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€์˜ ์˜ˆ์ œ๋Š” SVG๋ฅผ ์บก์ฒ˜ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋„์™€์ฃผ์„ธ์š”. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

Question

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„,
์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์•ฝ๊ฐ„ ๋ณ€๊ฒฝํ•˜์—ฌ์ด ๋ฌธ์ œ (firefox์—์„œ svg ์†์‹ค)๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
์ฒซ์งธ, SVG ์š”์†Œ์—๋Š” ํ”ฝ์…€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ๋†’์ด ๋ฐ ๋„ˆ๋น„ ์†์„ฑ์ด ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ ๋‹ค์Œ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ์—์„œ ๋ณ€๊ฒฝํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
self.image.src = " data : image / svg + xml ,"+ (์ƒˆ XMLSerializer ()). serializeToString (node);
์—:
self.image.src = " data : image / svg + xml ,"+ encodeURIComponent ((new XMLSerializer ()). serializeToString (node));

๋‹ค์Œ ๊ทธ๊ฒƒ์„ ์ฆ๊ธฐ์‹ญ์‹œ์˜ค.

๋ชจ๋“  64 ๋Œ“๊ธ€

์•„๋‹ˆ ๊ทธ๋ ‡์ง€ ์•Š์•„. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฐํ•จ์€ ์•„๋‹ˆ์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ฒ„๊ทธ์ž…๋‹ˆ๋‹ค (์ตœ์‹  ์•ˆ์ •์ ์ธ Firefox ๋ฒ„์ „ 12์—์„œ๋Š”์ด ๋ฌธ์ œ๊ฐ€ ์ˆ˜์ •๋˜์—ˆ์œผ๋ฉฐ ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š” ์œ ์ผํ•œ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค). ๋ฌธ์ œ๋Š” ๋ชจ๋“  SVG ์ด๋ฏธ์ง€๊ฐ€ ์บ”๋ฒ„์Šค๋ฅผ ์˜ค์—ผ์‹œ์ผœ ์ฝ์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ html2canvas๋Š” ์บ”๋ฒ„์Šค๋ฅผ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ด๋ฏธ์ง€๋ฅผ ์˜ค์—ผ์‹œํ‚ค๋Š” ์ฝ˜ํ…์ธ ๋ฅผ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค (์˜ˆ : toDataUrl ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ).

๊ทธ๋Ÿฌ๋‚˜, ๋‹น์‹ ์€ SVG ์ด๋ฏธ์ง€๊ฐ€ ์บ”๋ฒ„์Šค ๋”๋Ÿฌ์šด ๊ฒƒ์„ ๊ฑฑ์ •ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—, ๋‹น์‹ ์€ ์˜ต์…˜์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค allowTaint ์— true ํ•˜๊ณ  SVG์˜ ์ธ๋ผ์ธ SVG๋ฅผ ํ—ˆ์šฉ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๋Œ€๋กœ ๋ Œ๋”๋งํ•œ๋‹ค.

๋˜ํ•œ SVG ๋ Œ๋”๋ง์ด ๋ธŒ๋ผ์šฐ์ € ๊ฐ„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ฉด SVG๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTML์„ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ฑฐ์˜ ์“ธ๋ชจ ์—†๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. SVG ๋ Œ๋”๋ง์ด ์ž‘๋™ํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ € (์˜ˆ : FF12)์—์„œ ์บ”๋ฒ„์Šค ๋ Œ๋”๋ง์„ ํฌ๊ฒŒ ๊ฐ€์†ํ™”ํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ง€์›ํ•˜๋Š” ๋ชจ๋“  CSS ์†์„ฑ์— ๋Œ€ํ•œ ์ง€์›์„ ํ—ˆ์šฉํ•˜๋Š” ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ์ด๋ฏธ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ https://github.com/niklasvh/html2canvas/blob/master/src/Parse.js#L1227 ์„

์•ˆ๋…•ํ•˜์„ธ์š”,
๋น ๋ฅธ ๋‹ต๋ณ€์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.
๋‚˜๋Š” ๋‹น์‹ ์˜ ์ œ์•ˆ์œผ๋กœ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค : allowTaint๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด true๋กœ ์„ค์ •ํ•˜์‹ญ์‹œ์˜ค (test.js ์ˆ˜์ •).

setTimeout (function () {

        $(h2cSelector).html2canvas($.extend({
            flashcanvas: "../external/flashcanvas.min.js",
            logging: true,
            profile: true,
            useCORS: true,
            allowTaint: true
        }, h2cOptions));
    }, 100);

example images.html์—์„œ SVG๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ SVG๊ฐ€ ๋” ๋ณต์žกํ•œ ๊ฒฝ์šฐ ํฌ๋กœ์Šค ๋ธŒ๋ผ์šฐ์ €์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ : Chrome์—์„œ ์ฐจํŠธ (http://www.highcharts.com/demo/)๋ฅผ ์บก์ฒ˜ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ฐจํŠธ๊ฐ€ ์ธ๋ผ์ธ SVG๋กœ ๋ Œ๋”๋ง ๋  ๋•Œ ์ฐจํŠธ์˜ x ์ถ•๊ณผ y ์ถ•๋งŒ ์บก์ฒ˜ํ•ฉ๋‹ˆ๋‹ค. extenal svg ํŒŒ์ผ์˜ ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ img๋กœ ๋ Œ๋”๋งํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์บก์ฒ˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋ฐ˜๋Œ€๋กœ Chrome์€ Firefox์—์„œ ์ฐจํŠธ๊ฐ€ ์ธ๋ผ์ธ SVG๋กœ ๋ Œ๋”๋ง ๋  ๋•Œ ์•„๋ฌด๊ฒƒ๋„ ์บก์ฒ˜ํ•˜์ง€ ์•Š์ง€๋งŒ ์ฐจํŠธ๊ฐ€ ์™ธ๋ถ€ svg ํŒŒ์ผ์˜ ์ด๋ฏธ์ง€ ์ผ ๋•Œ ์„ฑ๊ณต์ ์œผ๋กœ ์ฐจํŠธ๋ฅผ ์บก์ฒ˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ์•…์˜ ๊ฒฝ์šฐ๋Š” IE9์ด๋ฉฐ ์•„๋ฌด๊ฒƒ๋„ ์บก์ฒ˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด๋ฏธ์ง€๋กœ ์‚ฌ์šฉํ•˜๋ฉด FF / Chrome์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์‹œ๋„ํ•ด ๋ณผ ์ˆ˜์žˆ๋Š” ๊ฒƒ์€ drawImage๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์บ”๋ฒ„์Šค ๋ Œ๋”๋ง์ด SVG์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•ด +1. babyhero์™€ ๋™์ผํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.๋ณด๊ณ  ๋„๊ตฌ๋ฅผ ์œ„ํ•ด highcharts SVG ๊ทธ๋ž˜ํ”„์˜ ์Šคํฌ๋ฆฐ ์ƒท์„ ์บก์ฒ˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ํ•˜์ด ์ฐจํŠธ SVG๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฐ€์ ธ ์˜ค๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•  ์ˆ˜ ์žˆ์ง€๋งŒ "์Šคํฌ๋ฆฐ ์ƒท์— ์ €์žฅ"๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋‹ค๋ฅธ ์ •๋ณด๊ฐ€ ํฌํ•จ ๋œ ๋ทฐ ๋‚ด์—์„œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

@ babyhero184 canvg (http://code.google.com/p/canvg/)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ highcharts SVG๋ฅผ PNG๋กœ ์ฆ‰์‹œ ๋ณ€ํ™˜ํ•˜๊ณ  SVG ์š”์†Œ๋ฅผ ์ˆจ๊ธฐ๊ณ  PNG๋ฅผ ํ‘œ์‹œํ•˜์—ฌ html2canvas์—์„œ์ด ์ œํ•œ์„ ๊ทน๋ณตํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ html2canvas๋กœ ์ฆ‰์„์—์„œ ์Šคํฌ๋ฆฐ ์ƒท์„ ์ฐ๊ณ  PNG๋ฅผ ์ˆจ๊ธฐ๊ณ  ํ•˜์ด ์ฐจํŠธ SVG๋ฅผ ๋‹ค์‹œ ๋ณด์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๋กœํ„ฐ๋ฆฌ ํ”„๋กœ์„ธ์Šค (SVG-> ์บ”๋ฒ„์Šค-> PNG-> ์บ”๋ฒ„์Šค-> PNG)์ด์ง€๋งŒ ๋‚ด ํ•„์š”์— ๋”ฐ๋ผ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@joeyrobert ๋‚˜๋Š” ๋˜ํ•œ highcharts์™€ html2canvas์—์„œ ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์˜ ์š”์ง€๋ฅผ ๊ณต์œ  ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋ฏธ๋ฆฌ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

@joeyrobert @ Jagdeep1 ๋˜ ๋‹ค๋ฅธ ์˜ต์…˜์€ Fabric.js ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์บ”๋ฒ„์Šค์— SVG๋ฅผ ๋ Œ๋”๋ง ํ•œ ๋‹ค์Œ ์ด๋ฏธ์ง€๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

+1

+1

+1

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@majuansari _SVG_ to _Canvas_ ๋ฐ _Canvas_ to _image_๋Š” firefox์—์„œ ์ž‘๋™ํ•˜์ง€๋งŒ Chrome์—๋Š” ๋ณด์•ˆ ์ž ๊ธˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐจํŠธ ์š”์†Œ๋ฅผ ์บก์ฒ˜ํ•˜๊ธฐ ์œ„ํ•ด jQuery๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ๊ทธ๋ ‡๊ฒŒํ–ˆ์„ ๋•Œ Highcharts SVG๊ฐ€ ์ œ๋Œ€๋กœ ๊ตฌ๋ฌธ ๋ถ„์„๋˜์ง€ ์•Š์•˜ ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ์ฐจํŠธ์˜ jQuery ์„ ํƒ๊ธฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒฝ์šฐ SVG๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@mbritton http://code.google.com/p/canvg/ ์‹œ๋„ (foreignObject๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š์Œ)

์˜ˆ, ๊ทธ๊ฒƒ์ด ์ œ ํ•ด๊ฒฐ์ฑ…์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์บก์ฒ˜ํ•˜๋Š” ๋™์•ˆ svg ์š”์†Œ๋ฅผ canvg ์ƒ์„ฑ ์บ”๋ฒ„์Šค ์š”์†Œ๋กœ ๋Œ€์ฒดํ•˜์—ฌ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ์€ ๋‚ด ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

// targetElem is a jquery obj
function take (targetElem) {
    var nodesToRecover = [];
    var nodesToRemove = [];

    var svgElem = targetElem.find('svg');

    svgElem.each(function(index, node) {
        var parentNode = node.parentNode;
        var svg = parentNode.innerHTML;

        var canvas = document.createElement('canvas');

        canvg(canvas, svg);

        nodesToRecover.push({
            parent: parentNode,
            child: node
        });
        parentNode.removeChild(node);

        nodesToRemove.push({
            parent: parentNode,
            child: canvas
        });

        parentNode.appendChild(canvas);
    });

    html2canvas(targetElem, {
        onrendered: function(canvas) {
            var ctx = canvas.getContext('2d');
            ctx.webkitImageSmoothingEnabled = false;
            ctx.mozImageSmoothingEnabled = false;
            ctx.imageSmoothingEnabled = false;

            canvas.toBlob(function(blob) {
                nodesToRemove.forEach(function(pair) {
                    pair.parent.removeChild(pair.child);
                });

                nodesToRecover.forEach(function(pair) {
                    pair.parent.appendChild(pair.child);
                });
                saveAs(blob, 'screenshot_'+ moment().format('YYYYMMDD_HHmmss')+'.png');
            });
        }
    });
}

์ฐธ๊ณ  :
canvg๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•˜์ง€๋งŒ SVG๋ฅผ ์บ”๋ฒ„์Šค๋กœ ๋ณ€ํ™˜ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์—ฌ๊ธฐ ์— ์„ค๋ช… ๋œ ๊ฐ„๋‹จํ•œ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€์— svg๋ฅผ๋กœ๋“œ ํ•œ ๋‹ค์Œ ์ด๋ฏธ์ง€ ์ฝ˜ํ…์ธ ๋ฅผ dataURL๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var image = new Image();
var xml = '<svg xmlns=....></svg>';
image.src = 'data:image/svg+xml,' + escape(xml); 
document.getElementById('container').appendChild(image);
image.onload = function() {
    image.onload = function() {};
    var canvas = document.createElement('canvas');
    canvas.width = image.width;
    canvas.height = image.height;
    var context = canvas.getContext('2d');
    context.drawImage(image, 0, 0);
    image.src = canvas.toDataURL();
}

@steren : ์ด๊ฒƒ์€ Chrome์—์„œ ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ Firefox์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด

@gifarangw ์ฝ”๋“œ๋Š” highcharts์—์„œ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ฉ‹์ง„ ์ฝ”๋“œ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. : +1 : ๋‚ด๊ฐ€ ์ œ๊ฑฐํ•œ ์œ ์ผํ•œ ๊ฒƒ์€ canvas.toBlob ๋ถ€๋ถ„์ด์—ˆ์Šต๋‹ˆ๋‹ค.

@steren ์†”๋ฃจ์…˜์— ๊ฐ์‚ฌ ๋“œ๋ฆฌ๋ฉฐ ์ž˜ ์ž‘๋™ํ•˜๋ฉฐ (์ตœ์‹  ํฌ๋กฌ ๋ฐ ํŒŒ์ด์–ด ํญ์Šค์—์„œ ํ…Œ์ŠคํŠธ ๋จ) ์ข‹์€ ์ถ”๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  @gifarangw ์˜ ์ฝ”๋“œ์™€ ๊ฒฐํ•ฉํ•˜์—ฌ ๋‹ค์Œ์„ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.

    function take(targetElem) {
        // First render all SVGs to canvases
        var elements = targetElem.find('svg').map(function() {
            var svg = $(this);
            var canvas = $('<canvas></canvas>');
            svg.replaceWith(canvas);

            // Get the raw SVG string and curate it
            var content = svg.wrap('<p></p>').parent().html();
            content = content.replace(/xlink:title="hide\/show"/g, "");
            content = encodeURIComponent(content);
            svg.unwrap();

            // Create an image from the svg
            var image = new Image();
            image.src = 'data:image/svg+xml,' + content;
            image.onload = function() {
                canvas[0].width = image.width;
                canvas[0].height = image.height;

                // Render the image to the canvas
                var context = canvas[0].getContext('2d');
                context.drawImage(image, 0, 0);
            };
            return {
                svg: svg,
                canvas: canvas
            };
        });
        targetElem.imagesLoaded(function() {
            // At this point the container has no SVG, it only has HTML and Canvases.
            html2canvas(targetElem[0], {
                onrendered: function(canvas) {
                    // Put the SVGs back in place
                    elements.each(function() {
                        this.canvas.replaceWith(this.svg);
                    });

                    // Do something with the canvas, for example put it at the bottom
                 $(canvas).appendTo('body');
                }
            })
        })
    }

(https://github.com/desandro/imagesloaded ์‚ฌ์šฉ)

์•ˆ๋…•ํ•˜์„ธ์š”, @Remiremi ์†”๋ฃจ์…˜์ด ์ €์—๊ฒŒ ์ž˜

@Remiremi @fbotti , ์–ด๋–ค ์ด์œ ๋กœ ๋“ 

amcharts์™€ ํ•จ๊ป˜ ์ผํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ์ƒ๊ฐ?

@guypaskar ๊ท€ํ•˜์˜ svg๋ฅผ ์ถ”๊ฐ€๋กœ ํ๋ ˆ์ดํŒ…ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค $(image).appendTo('body'); ์ตœ์ €์น˜๋ฅผํ•˜๊ธฐ ์ „์— ์ฝ”๋“œ์— image.onload , ๋‹ค์Œ ํŒŒ์ด์–ด ํญ์Šค์—์„œ ๋‹น์‹ ์ด ์ž˜๋ชป๋œ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ์•„์ด์ฝ˜์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค, ๋‹น์‹ ์€ ๋ฐ”๋กœ>๋ณด๊ธฐ ์ด๋ฏธ์ง€๋ฅผ ํด๋ฆญํ•˜๊ณ  ์˜ค๋ฅ˜๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

amcharts svg์— ๋น ๋ฅด๊ฒŒ ์‹œ๋„ํ•ด ๋ณด์•˜๊ณ  ์ž‘๋™ํ•˜๋„๋กํ•˜๋ ค๋ฉด svg ํƒœ๊ทธ์— xmlns="http://www.w3.org/2000/svg" width="1400" height="500" ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์•ผํ–ˆ์Šต๋‹ˆ๋‹ค. (๋†’์ด์™€ ๋„ˆ๋น„๋Š” CSS ์†์„ฑ์œผ๋กœ ์ง€์ •๋˜์—ˆ์ง€๋งŒ ์–ด๋–ค ์ด์œ ๋กœ ์„ ํƒ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.)

๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

svg ์ด๋ฏธ์ง€์— ๋„ˆ๋น„์™€ ๋†’์ด๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

SVG๋Š” ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ ์ธก์ • ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ถฉ๋ถ„ํ•œ ์ธ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์š”์•ฝ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์›๋ž˜ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ ๋˜์—ˆ์Šต๋‹ˆ๊นŒ? ์—ฌ๊ธฐ์— ์–ธ๊ธ‰ ๋œ ๋Œ€๋ถ€๋ถ„์˜ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ ํŠน์ • ๋ธŒ๋ผ์šฐ์ € ๋ฌธ์ œ๊ฐ€ 2012 ๋…„ ์ดํ›„๋กœ ์ˆ˜์ • ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์ผ๋ถ€ ์˜๊ฒฌ์— ๋”ฐ๋ฅด๋ฉด canvg์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ๋” ์ด์ƒ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๊นŒ?

๋‚˜๋จธ์ง€ ๋ฌธ์ œ์— ๋Œ€ํ•ด์„œ๋Š” # 197 ๋ฐ / ๋˜๋Š” # 267์ด ์ ์šฉ๋ฉ๋‹ˆ๊นŒ? ์ด๊ฑด ๋‹ซ์„ ์ˆ˜ ์žˆ๋‚˜์š”?

์ ์–ด๋„ ์ผ๋ถ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์—ฌ์ „ํžˆ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

0.5๋Š” SVG์— ๋Œ€ํ•œ ์ง€์›์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

0.5๊ฐ€ @niklasvh๋กœ ๋‚˜์˜ฌ ๋•Œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

@IvoPereira # 421์—์„œ 0.5์˜ ์ƒํƒœ๋ฅผ ๋”ฐ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@niklasvh ๋ฒ„์ „ 0.5๊ฐ€ ์žˆ๊ณ  SVG๋Š” ์—ฌ์ „ํžˆ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? (์ธ๋ผ์ธ SVG)

@nikolang html2canvas.js ๋ฐ html2canvas.svg.js ๋‘˜ ๋‹ค ํฌํ•จํ•˜์…จ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ ‡๋‹ค๋ฉด ํŠน์ • ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด jsFiddle ๋˜๋Š” jsbin์„ ์ œ๊ณต ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ์ด๊ฒƒ์„ ์ž‘๋™์‹œ์ผฐ๋‹ค. ๋ฌธ์ œ๋Š” ๋‚ด๊ฐ€ html2canvas๋ฅผ ํ•  ๋•Œ SVG๊ฐ€ ์™„์ „ํžˆ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ Œ๋”๋ง์—๋Š” ์—ฌ์ „ํžˆ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์˜ˆ : http://d3pie.org

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œ์‹œ๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

screen

์ด๊ฒƒ์€ html2canvas ์ดํ›„์˜ ๋ชจ์Šต์ž…๋‹ˆ๋‹ค.

canvas

์›Œ, ๊ฝค ์œผ์Šค์Šคํ•˜๋„ค์š”. ์ด๋ ‡๊ฒŒ ์‰ฝ๊ฒŒ ์ถ”์  ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋™์ผํ•œ ์Šคํฌ๋ฆฐ ์ƒท์œผ๋กœ ๋ณ„๋„์˜ ๋ฌธ์ œ๋ฅผ ์—ด๊ณ  ๋ฐ๋ชจ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ jsFiddle์— ๋Œ€ํ•œ ๋งํฌ ๋งŒ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ์˜ค๋ž˜ ์ „์— ์ข…๊ฒฐ ๋œ ์›๋ž˜ ๋ฌธ์ œ์—์„œ ๋„ˆ๋ฌด ๋ฉ€์–ด์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ ๊ณ  ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ํ•˜๊ณ  ์‹ถ์ง€๋งŒ jsfiddle์— ์ƒˆ๋กœ์šด html2canvas๋ฅผ ํฌํ•จํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๋Š” ์™ธ๋ถ€ ๋งํฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

@nikolang http://rawgit.com/niklasvh/html2canvas/master/dist/html2canvas.js ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜

๊ฐ์‚ฌ. ๊ทธ๋ฆฌ๊ณ  SVG ๋ฒ„์ „?

์•ˆ๋…•ํ•˜์„ธ์š”,

SVG๋Š” ๋‚ด ์ชฝ์—์„œ ๋ Œ๋”๋ง๋˜์ง€๋งŒ ์•„๋ž˜ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€๋ณด๊ณ  ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๊ฒ€์€ ์ƒ‰์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. svg ์š”์†Œ์˜ "์ฑ„์šฐ๊ธฐ"์†์„ฑ์„ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@brainra , ๋‚˜๋Š” ์ฑ„์šฐ๊ธฐ๋ฅผ ํฐ์ƒ‰์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

// Create dummy canvas to get a white background
var destinationCanvas = document.createElement("canvas");
destinationCanvas.width = canvas.width;
destinationCanvas.height = canvas.height;

var destCtx = destinationCanvas.getContext('2d');

//create a rectangle with the desired color
destCtx.fillStyle = "#FFFFFF";
destCtx.fillRect(0,0,canvas.width,canvas.height);

//draw the original canvas onto the destination canvas
destCtx.drawImage(canvas, 0, 0);

var img = destinationCanvas.toDataURL("image/png");

'CanvasRenderingContext2D'์—์„œ 'drawImage'์‹คํ–‰ ์‹คํŒจ : ์ œ๊ณต๋œ HTMLImageElement๊ฐ€ '๊นจ์ง„'์ƒํƒœ์ž…๋‹ˆ๋‹ค. "

HTML์— svg ์š”์†Œ๊ฐ€์žˆ์„ ๋•Œ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ allowTaint๋ฅผ true๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ๋‚˜๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‹ค์‹œ ์—ด์–ด์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. svg ์š”์†Œ๋Š” Firefox๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๋Œ€๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

NS_ERROR_NOT_AVAILABLE : ์ด๊ฒƒ์€ Firefox ๋ฒ„๊ทธ์ž…๋‹ˆ๋‹ค : https://bugzilla.mozilla.org/show_bug.cgi?id=700533 (AFAICT) ๋ฌธ์ œ๋ฅผ ๊ฐ•์กฐํ•˜๋Š” ํ…Œ์ŠคํŠธ ํŽ˜์ด์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค (๋ฒ„๊ทธ์—์„œ ๋งํฌ ๋จ) http://phrogz.net/ SVG / svg_to_png.xhtml

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• / ์ˆ˜์ •์„ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ฉด ๋ˆ„๊ตฐ๊ฐ€ @mozilla ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. :)

ํ•ด๊ฒฐ์ฑ…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
http://stackoverflow.com/questions/18271898/html-and-svg-to-canvas-javascript/32457864#32457864

๋‚˜๋Š” ๊ฐ๋„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๊ฒƒ์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์˜ค์—ผ ๋œ ์บ”๋ฒ„์Šค๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค. ์›์‹œ SVG๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ?

<img svg-2-canvas-src="/assets/your.svg"/>

angular.module('APP')
    .directive('svg2CanvasSrc', function() {
        return {
            restrict: 'A',
            scope: false,
            link: function($scope, $element, $attrs) {

                var svgSrc = $attrs['svg2CanvasSrc'];

                var image = new Image();

                image.onload = function() {
                    image.onload = function() {};
                    var canvas = document.createElement('canvas');
                    canvas.width = image.width;
                    canvas.height = image.height;
                    var context = canvas.getContext('2d');
                    context.drawImage(image, 0, 0);
                    $element[0].src = canvas.toDataURL();
                };

                image.src = svgSrc;
            }
        };
    });

@remiremi ๋‚ด๊ฐ€ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ๊ฒฐ๊ณผ๋Š” ๋™์ผํ•˜๊ณ  svg๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค ..
์›๋ณธ-https: //s29.postimg.org/5lkprhx93/with_SVG.png
๊ฒฐ๊ณผ-https: //s23.postimg.org/j1otj2por/without_SVG.png

@remiremi ...์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋‚ด๊ฐ€

๊ธฐ๋ณธ์ ์œผ๋กœ html2canvas๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ง์ „์— SVG์— ๋ช…์‹œ์ ์ธ ๋„ˆ๋น„ / ๋†’์ด๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ๊ฐ€ ์ˆ˜์ •๋ฉ๋‹ˆ๋‹ค.
๋‚ด๊ฐ€ํ•˜๋Š” ์ผ์€ ๊ด€์‹ฌ์žˆ๋Š” ๋‹ค์–‘ํ•œ SVG ์š”์†Œ๋ฅผ ๋ฐ˜๋ณตํ•˜๊ณ , .getBoundingClientRect ()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋„ˆ๋น„ / ๋†’์ด๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ์š”์†Œ์— ๋„ˆ๋น„ ๋†’์ด ์†์„ฑ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ Œ๋”๋งํ•˜์ง€ ์•Š์ง€๋งŒ ํ”ฝ์…€๋กœ Booyah

๊ทธ๋ž˜๋„ ์—ฌ๋Ÿฌ ์ค„ ๋ฒ”์œ„ ๋ฐ div๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„,
์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์•ฝ๊ฐ„ ๋ณ€๊ฒฝํ•˜์—ฌ์ด ๋ฌธ์ œ (firefox์—์„œ svg ์†์‹ค)๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
์ฒซ์งธ, SVG ์š”์†Œ์—๋Š” ํ”ฝ์…€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ๋†’์ด ๋ฐ ๋„ˆ๋น„ ์†์„ฑ์ด ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ ๋‹ค์Œ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ์—์„œ ๋ณ€๊ฒฝํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
self.image.src = " data : image / svg + xml ,"+ (์ƒˆ XMLSerializer ()). serializeToString (node);
์—:
self.image.src = " data : image / svg + xml ,"+ encodeURIComponent ((new XMLSerializer ()). serializeToString (node));

๋‹ค์Œ ๊ทธ๊ฒƒ์„ ์ฆ๊ธฐ์‹ญ์‹œ์˜ค.

๋ˆ„๊ตฌ๋“ ์ง€ DOM์˜ SVG ์š”์†Œ์— ๋Œ€ํ•ด html2canvas ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ๊ฐ€ ์ข‹์Šต๋‹ˆ๋‹ค!

+1์€ ํŒŒ์ด์–ด ํญ์Šค์—์„œ SVG ์š”์†Œ ์Šคํฌ๋ฆฐ ์ƒท์„ ์บก์ฒ˜ํ•˜๋Š” ๋ฐ ์—ฌ์ „ํžˆ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

{
  profile: true,
  allowTaint: false,
  onrendered: function() {
    //...done()
  }
}

์ด ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜์žˆ์—ˆ์Šต๋‹ˆ๋‹ค (jQuery์—†์ด).
ํ•ด๊ฒฐ์ฑ…

targetElem =document.getElementById ( 'body');
let nodesToRecover = [];
let nodesToRemove = [];

    let svgElem = targetElem.querySelector('svg')

    let parentNode = svgElem.parentNode;
        // let svg = parentNode.innerHTML;
        let svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" id=\"svg-annotations\" style=\"opacity: 1;\" _ngcontent-c7=\"\">\n\t\t\t<defs><marker id=\"arrow-start\" refY=\"4.5\" markerWidth=\"9.9\" markerHeight=\"9\" orient=\"auto\"><path fill=\"black\" d=\"M 9.9 0 L 9.9 9 L 0 4.5 Z\" /></marker><marker id=\"arrow-end\" refX=\"9.9\" refY=\"4.5\" markerWidth=\"9.9\" markerHeight=\"9\" orient=\"auto\"><path fill=\"black\" d=\"M 0 0 L 0 9 L 9.9 4.5 Z\" /></marker></defs><g class=\"annotation-group\" id=\"measurement-36122\" style=\"opacity: 1;\"><g class=\"annotations\"><g class=\"annotation callout elbow editable \" transform=\"translate(758.541 408.978)\"><g class=\"annotation-connector\"><path class=\"connector\" fill=\"none\" stroke=\"black\" d=\"M 0 0 L 137 137 L 162 137\" /></g><g class=\"annotation-note\" transform=\"translate(162 137)\"><g class=\"annotation-note-content\" transform=\"translate(0 3)\"><rect class=\"annotation-note-bg\" fill=\"white\" fill-opacity=\"0\" x=\"0\" width=\"104.79\" height=\"41.36\" /><text class=\"annotation-note-label\" fill=\"black\" y=\"41.36\" dx=\"0\"><tspan x=\"0\" dy=\"0.8em\" /></text><text class=\"annotation-note-title\" font-weight=\"bold\" fill=\"black\"><tspan x=\"0\" dy=\"0.8em\">Face</tspan><tspan x=\"0\" dy=\"1.2em\">:5453831.5mmยฒ</tspan></text></g><path class=\"note-line\" stroke=\"black\" d=\"M 0 0 L 104.79 0\" /><circle class=\"handle \" cursor=\"move\" fill=\"grey\" fill-opacity=\"0.1\" stroke=\"grey\" stroke-dasharray=\"5\" cx=\"0\" cy=\"0\" r=\"10\" /></g></g></g></g><g class=\"annotation-group\" id=\"measurement-59622\" style=\"opacity: 1;\"><g class=\"annotations\"><g class=\"annotation callout elbow editable \" transform=\"translate(889.656 387.507)\"><g class=\"annotation-connector\"><path class=\"connector\" fill=\"none\" stroke=\"black\" d=\"M 0 0 L 137 137 L 162 137\" /></g><g class=\"annotation-note\" transform=\"translate(162 137)\"><g class=\"annotation-note-content\" transform=\"translate(0 3)\"><rect class=\"annotation-note-bg\" fill=\"white\" fill-opacity=\"0\" x=\"0\" width=\"104.79\" height=\"41.36\" /><text class=\"annotation-note-label\" fill=\"black\" y=\"41.36\" dx=\"0\"><tspan x=\"0\" dy=\"0.8em\" /></text><text class=\"annotation-note-title\" font-weight=\"bold\" fill=\"black\"><tspan x=\"0\" dy=\"0.8em\">Face</tspan><tspan x=\"0\" dy=\"1.2em\">:5453831.5mmยฒ</tspan></text></g><path class=\"note-line\" stroke=\"black\" d=\"M 0 0 L 104.79 0\" /><circle class=\"handle \" cursor=\"move\" fill=\"grey\" fill-opacity=\"0.1\" stroke=\"grey\" stroke-dasharray=\"5\" cx=\"0\" cy=\"0\" r=\"10\" /></g></g></g></g></svg>";

        this.canvas = document.createElement('canvas');
        this.canvas.setAttribute('id', '_canvas');

        canvg(this.canvas, svg, {renderCallback: function(){
            console.log(this);
        }});

        nodesToRecover.push({
            parent: parentNode,
            child: svgElem
        });
        parentNode.removeChild(svgElem);

        nodesToRemove.push({
            parent: parentNode,
            child: this.canvas
        });

        parentNode.appendChild(this.canvas);
        let data = this.canvas.toDataURL('image/png', 0.5);
        console.log(data);

๋‚˜๋Š” ์ด๊ฒƒ์„ํ•˜๊ณ  ์žˆ์ง€๋งŒ IE11์—์„œ ๋นˆ ์ด๋ฏธ์ง€ ๋งŒ ์–ป์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์›น ํŽ˜์ด์ง€์—์„œ ์บ”๋ฒ„์Šค๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ฌด๋„ ๋‚ด๊ฐ€ ์—ฌ๊ธฐ์„œ ๋ญ˜ ์ž˜๋ชปํ•˜๊ณ  ์žˆ๋Š”์ง€ ๋„์™€ ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์•ˆ๋…•ํ•˜์„ธ์š”. <image> ํƒœ๊ทธ๊ฐ€์žˆ์„ ๋•Œ SVG๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
barchart (24)

์ƒ˜ํ”Œ SVG

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <image xlink:href="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200" width="200"/>
</svg>

jsfiddle http://jsfiddle.net/maestro888/fmjywksq/์˜ ์ƒ˜ํ”Œ

๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

svg ์ด๋ฏธ์ง€์— ๋„ˆ๋น„์™€ ๋†’์ด๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

SVG๋Š” ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ ์ธก์ • ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ถฉ๋ถ„ํ•œ ์ธ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์‚ฌ์‹ค์ด์ง€๋งŒ IE11์—๋Š” ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ •๋ฆฌํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
๋ฐฉ๊ธˆ JS Fiddle์„ ํ™•์ธํ•˜๋ฉด ์ด๋ฏธ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

๋ฌธ์•ˆ ์ธ์‚ฌ,

๋ฒ„๋‚˜๋“œ TA ๋ฒ ์ด์ปค

2019 ๋…„ 3 ์›” 27 ์ผ ์ˆ˜์š”์ผ ์˜คํ›„ 4:34 Alessandro Candini [email protected]
์ผ๋‹ค :

๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

svg ์ด๋ฏธ์ง€์— ๋„ˆ๋น„์™€ ๋†’์ด๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด SVG๋ฅผ ์ธก์ • ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ธ์ˆ˜๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด๋ฏธ์ง€ ์บ”์ฒ˜๋Ÿผ.

์ด๊ฒƒ์€ ์‚ฌ์‹ค์ด์ง€๋งŒ IE11์—๋Š” ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

โ€”
๋Œ“๊ธ€์„ ๋‹ฌ์•˜ ๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜์‹  ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/niklasvh/html2canvas/issues/95#issuecomment-477242192 ,
๋˜๋Š” ์Šค๋ ˆ๋“œ ์Œ์†Œ๊ฑฐ
https://github.com/notifications/unsubscribe-auth/AM7ZzLPsl0WJS7gGI9npSsRxR33FCnN9ks5va52bgaJpZM4AD-Sb
.

์—ฌ๊ธฐ์— ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ ์— ๋Œ€ํ•ด๋ณด๊ณ  ๋œ canvg ์†”๋ฃจ์…˜์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. IE11์—์„œ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค!

๋‹ค์‹œ ์ •๊ตํ•ด์ง„ ์Šค ๋‹ˆํŽซ, jQuery ์ข…์†์„ฑ ์ œ๊ฑฐ :

let svgIcons = document.querySelectorAll('.svg-icon');

for (let i = 0; i < svgIcons.length; ++i) {
  let curSvg = svgIcons[i];
  let canvas;
  let xml;

  // Size and color needed for every browser
  curSvg.setAttribute('width', curSvg.parentNode.offsetWidth);
  curSvg.setAttribute('height', curSvg.parentNode.offsetHeight);
  curSvg.setAttribute('style', 'fill: blue');

  canvas = document.createElement('canvas');
  canvas.className = 'screenShotTempCanvas';
  xml = new XMLSerializer().serializeToString(curSvg);
  canvg(canvas, xml);
  curSvg.parentNode.insertBefore(canvas, curSvg.nextSibling);
  curSvg.style.display = 'none';
 }

ํฐ

2019 ๋…„ 3 ์›” 28 ์ผ ๋ชฉ์š”์ผ 08:49 Alessandro Candini, [email protected]
์ผ๋‹ค :

canvg https://github.com/canvg/canvg ์†”๋ฃจ์…˜์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์— ๋Œ€ํ•ด๋ณด๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค.
https://stackoverflow.com/questions/34042440/using-html2canvas-to-render-a-highcharts-chart-to-pdf-doesnt-work-on-ie-and-fir :
IE11์—์„œ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค!

โ€”
๋Œ“๊ธ€์„ ๋‹ฌ์•˜ ๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜์‹  ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/niklasvh/html2canvas/issues/95#issuecomment-477503221 ,
๋˜๋Š” ์Šค๋ ˆ๋“œ ์Œ์†Œ๊ฑฐ
https://github.com/notifications/unsubscribe-auth/AM7ZzKNy1GOgQU9TVv7PGCi4fJvYSxDVks5vbIIOgaJpZM4AD-Sb
.

์•ˆ๋…•ํ•˜์„ธ์š” @niklasvh html2canvas ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ
"๋ฟ๋งŒ ์•„๋‹ˆ๋ผ anguar6 ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜"1.0.0-rc.1 "๋ฒ„์ „๋„ ๋ฌธ์ œ ๋ชฉ๋ก์˜ ์‘๋‹ต์— ๋”ฐ๋ผ ๋ฌธ์ œ๊ฐ€ ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค svg๋Š” ๋†’์ด์™€ ๋„ˆ๋น„๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์ง€๋งŒ ์ œ ๊ฒฝ์šฐ์—๋Š” Svg๊ฐ€ 100 % ๋†’์ด์™€ ๋„ˆ๋น„์™€ ์ค‘์ฒฉ ๋œ div์—๋Š” svg ํƒœ๊ทธ๋„ ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๊ธฐ์กด ์บ”๋ฒ„์Šค๋„ ์ค‘์ฒฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ํŽ˜์ด์ง€๋ฅผ png ์ด๋ฏธ์ง€๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋ฏธ์ง€์—๋Š” ์ถฉ๋Œ ๋œ svg ์•„์ด์ฝ˜ ๋งŒ ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๊ธฐ์กด ์บ”๋ฒ„์Šค๋„ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด ๋‹ค๋ฅธ ํŽ˜์ด์ง€ svg๋Š” ๋ชจ๋‘ ์ถฉ๋Œ ์ด๋ฏธ์ง€๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋ฅผ ์œ„ํ•ด ์—ฌ๊ธฐ์— ์Šคํฌ๋ฆฐ ์ƒท์„ ์ฒจ๋ถ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ ๋ณด์‹œ๊ณ  ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
html2canvas (this.screen.nativeElement, {useCORS : true}). then (canvas => {
this.canvas.nativeElement.src = canvas.toDataURL ( 'image / png');
this.downloadLink.nativeElement.href = canvas.toDataURL ( 'image / png');
this.downloadLink.nativeElement.download = 'screenshot.png';
this.downloadLink.nativeElement.click ();
});

html2canvas_orginal_Before export
html2canvas_orginal_after export
html2canvas_exported image

testpdf (1) .pdf
์•ˆ๋…•ํ•˜์„ธ์š”,
์ถ•์„ ์–ป๊ณ  ์žˆ์ง€๋งŒ ์ฐจํŠธ์˜ ๋‚˜๋จธ์ง€ ์˜์—ญ์€ ๊ฒ€์€ ์ƒ‰์ž…๋‹ˆ๋‹ค. ์–ด๋– ํ•œ ์ œ์•ˆ

์•ˆ๋…•ํ•˜์„ธ์š” @niklasvh html2canvas ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ
"๋ฟ๋งŒ ์•„๋‹ˆ๋ผ anguar6 ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜"1.0.0-rc.1 "๋ฒ„์ „๋„ ๋ฌธ์ œ ๋ชฉ๋ก์˜ ์‘๋‹ต์— ๋”ฐ๋ผ ๋ฌธ์ œ๊ฐ€ ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค svg๋Š” ๋†’์ด์™€ ๋„ˆ๋น„๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์ง€๋งŒ ์ œ ๊ฒฝ์šฐ์—๋Š” Svg๊ฐ€ 100 % ๋†’์ด์™€ ๋„ˆ๋น„์™€ ์ค‘์ฒฉ ๋œ div์—๋Š” svg ํƒœ๊ทธ๋„ ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๊ธฐ์กด ์บ”๋ฒ„์Šค๋„ ์ค‘์ฒฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ํŽ˜์ด์ง€๋ฅผ png ์ด๋ฏธ์ง€๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋ฏธ์ง€์—๋Š” ์ถฉ๋Œ ๋œ svg ์•„์ด์ฝ˜ ๋งŒ ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๊ธฐ์กด ์บ”๋ฒ„์Šค๋„ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด ๋‹ค๋ฅธ ํŽ˜์ด์ง€ svg๋Š” ๋ชจ๋‘ ์ถฉ๋Œ ์ด๋ฏธ์ง€๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋ฅผ ์œ„ํ•ด ์—ฌ๊ธฐ์— ์Šคํฌ๋ฆฐ ์ƒท์„ ์ฒจ๋ถ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ ๋ณด์‹œ๊ณ  ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
html2canvas (this.screen.nativeElement, {useCORS : true}). then (canvas => {
this.canvas.nativeElement.src = canvas.toDataURL ( 'image / png');
this.downloadLink.nativeElement.href = canvas.toDataURL ( 'image / png');
this.downloadLink.nativeElement.download = 'screenshot.png';
this.downloadLink.nativeElement.click ();
});

html2canvas_orginal_Before export
html2canvas_orginal_after export
html2canvas_exported image

๊ฐ™์€ ๋ฌธ์ œ, ๋ณต์ œ ๋œ ๋ฌธ์„œ์—์„œ svg๋ฅผ ์ฐพ๋Š” ๋™์•ˆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

html2canvas๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ์ผ์‹œ์ ์œผ๋กœ ๋†’์ด์™€ ๋„ˆ๋น„๋ฅผ SVG๋กœ ์„ค์ •ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒํ•˜๋ฉด svg๋ฅผ ์บก์ฒ˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var selectedItem = document.querySelector ( ". chartWrapper");
var svgElements = selectedItem.querySelectorAll ( 'svg');
for (let i = 0; i <svgElements.length; i ++) {
selectedItem.getElementsByTagName ( "svg") [i] .style.height = document.getElementsByTagName ( "svg") [i] .getBoundingClientRect (). height;
selectedItem.getElementsByTagName ( "svg") [i] .style.width = document.getElementsByTagName ( "svg") [i] .getBoundingClientRect (). width;
}
html2canvas (selectedItem, {backgroundColor : '# 000', allowTaint : true}). then (canvas => {
var myImage = canvas.toDataURL ( "image / png"). replace ( "image / png", "image / octet-stream");
window.location.href = myImage;
})
for (let i = 0; i <svgCount; i ++) {
selectedItem.getElementsByTagName ( "svg") [i] .style.height = '100 %';
selectedItem.getElementsByTagName ( "svg") [i] .style.width = '100 %';
}

// use html2canvas in react project when i need a screenshot for the svg
/**
 * svg to canvas
 * <strong i="5">@param</strong> targetElem
 * <strong i="6">@return</strong> {Promise<[]>} // return svg elements
 */
async function svgToCanvas(targetElem) {
  let nodesToRecover = [], nodesToRemove = [], svgElems = targetElem.querySelectorAll('svg');

  for (let i = 0; i < svgElems.length; i++) {
    let node = svgElems[i], parentNode = node.parentNode, svg = parentNode.innerHTML,
      canvas = document.createElement('canvas'),
      ctx = canvas.getContext('2d');
    canvas.setAttribute('data-cover', 'svg');
    const v = await Canvg.from(ctx, svg);
    v.start();
    // record svg elements
    nodesToRecover.push({
      parent: parentNode,
      child: node
    });
    parentNode.removeChild(node);
    //  record canvas elements
    nodesToRemove.push({
      parent: parentNode,
      child: canvas
    });

    parentNode.appendChild(canvas);
  }
  return nodesToRecover;
}

/**
 * recover canvas to svg
 * <strong i="7">@param</strong> targetElem
 * <strong i="8">@param</strong> svgElems // need to recover svg elements
 * <strong i="9">@return</strong> *
 */
function recoverCanvasToSvg(targetElem, svgElems) {
  let canvasElems = targetElem.querySelectorAll("canvas[data-cover='svg']");
  if(!targetElem){
    throw new Error('must have targetElem param')
  }
  if(!isArray(svgElems) && svgElems.length !== canvasElems.length) {
    throw new Error('svgElems must be an Array, and it`s length equal to canvasElems`s length')
  }
  for(let i = 0; i < canvasElems.length; i++){
    let node = canvasElems[i], parentNode = node.parentNode;
    parentNode.removeChild(node);
    parentNode.appendChild(svgElems[i]?.child);
  }
}
์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰