如何将SVG字符串渲染到画布?并导出为PNG或JPEG

2021年11月29日20:11:53 发表评论 1,452 次浏览

了解如何轻松地将 SVG 字符串渲染到画布中,然后将其导出为具有所需大小的 PNG 或 JPEG,而不会降低质量,包括具体的SVG字符串渲染到画布实例

如何将SVG字符串渲染到画布?并导出为PNG或JPEG
SVG字符串渲染到画布实例

图像的操作总是有点棘手,尤其是当你想使用 JavaScript 等语言进行操作时,如果还不够,可以直接在浏览器中操作。在过去的几天里,我一直在使用一个非常特殊的库,即dom-to-image,该库允许你使用纯 JavaScript 将任意 DOM 节点转换为矢量(SVG)或光栅(PNG 或 JPEG)图像. 我使用这个库来简单地在浏览器中捕获一个 DOM 元素,以允许用户下载图像,就是这样。

从理论上讲,它非常简单,因为 DOM 只是一组带有表情符号的按钮集合,它看起来像这样:

如何将SVG字符串渲染到画布?并导出为PNG或JPEG

请注意,上图是使用外部工具制作的屏幕截图,并保持原始大小。现在,如果我决定使用 JPEG 或 PNG 中提到的库导出 DOM 元素,它将大大降低质量:

如何将SVG字符串渲染到画布?并导出为PNG或JPEG

这当然不是库的错,因为它将 DOM 元素光栅化为 PNG 格式的图像,但是,它看起来很糟糕,因为我的屏幕上的按钮确实很小。因此,解决方案是要么使按钮更大,要么使用 SVG 而不是 DOM 元素的光栅化版本。如何将SVG字符串渲染到画布?你可能知道,你可以将 SVG 放大和缩小到你想要的任何尺寸,而不会降低质量。如果将 DOM 元素导出为 SVG,你可以将其调整为你想要的大小,例如,以下代码会将选定的 DOM 元素呈现为 SVG 并将其显示到新的浏览器选项卡中:

let domNode = document.getElementById("myDiv");

// 1. Render the selected node to SVG
domtoimage.toSvg(domNode).then(function(SVG){
    
    // 2. Load the SVG string (it looks something like this:
    // data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="1623" height="64"><foreignObject x="0" y="0" width="100%" height="100%"><div id="myDiv" ....
    let image = new Image();
    image.src = SVG;

    // 3. Launch a new tab in the browser and load the image to see the preview
    let newWindow = window.open("");
    newWindow.document.write(image.outerHTML);
});

然后,在新选项卡中,你将看到图像看起来非常清晰,你可以将图像调整到你想要的大小而不会降低质量(我们将其调整为3500 像素的图片,与原始大小相比,这是非常大的)纽扣):

如何将SVG字符串渲染到画布?并导出为PNG或JPEG

SVG字符串如何渲染到画布?你可以稍后将其光栅化为流行的格式,如 PNG 或 JPEG,但质量不错!在本教程中,我将向你展示如何轻松使用 JavaScript 将 SVG 字符串或 SVG 文件渲染为图像,并将其调整为你想要保持其原始质量的大小。

1. 创建/获取 SVG 数据 URL

SVG字符串渲染到画布实例:数据 URL(以data:方案为前缀的 URL)允许内容创建者在文档中嵌入小文件。在我们的例子中,我们的 SVG 文件数据方案将是:

重要提示:如果你对纯 SVG 数据进行 URL 编码以编码不应出现在 URL 中的字符会更好。

data:image/svg+xml;charset=utf-8,[The URL Encoded Plain Data of SVG should be here]

请注意,与使用 Base64 编码的其他格式不同,我们将需要数据 URL 中的纯数据。对于此示例,我们将使用来自 Wikipedia的广为人知的SVG Tiger。SVG 字符串可以来自任何地方,可以从 Web 资源下载,在浏览器中创建或作为 dom-to-image 库的输出,这一步的重点是你知道它需要在数据 URL 格式。

2.测试是否可以在Image中渲染SVG

SVG字符串如何渲染到画布?要测试你创建的 SVG 数据 URL 是否有效,你可以轻松地将其用作 HTML 中图像元素的来源。在这个例子中,我们将使用 Wikipedia 中提到的 SVG Tiger,我们将手动创建它,将 SVG 存储到一个字符串变量中,然后将数据 URL 方案添加到 URL 编码的 SVG 中:

<!-- An image element where the DataURL will be displayed -->
<img src="" id="test" />
<script>
    // 1. Prepare SVG String
    let SVGString = `
        <svg id="svg2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 900" version="1.1">
            <g id="g4" fill="none" transform="matrix(1.7656463,0,0,1.7656463,324.90716,255.00942)">
                <g id="g6" stroke-width="0.17200001" stroke="#000" fill="#FFF">
                <path id="path8" d="m-122.3,84.285s0.1,1.894-0.73,1.875c-0.82-0.019-17.27-48.094-37.8-45.851,0,0,17.78-7.353,38.53,43.976z"/>
            </g>

            ....

            .... (rest of the SVG String, note that we remove the following string from the SVG: <?xml version="1.0" encoding="UTF-8" standalone="no"?>)

            ....
        </svg>
    `;

    // 2. Convert to Data URL
    let dataURL = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(SVGString);

    // 3. Set the DataURL as source of the test image
    document.getElementById("test").src = dataURL;
</script>

你可以在以下小提琴中看到这一点,它应该在 Image 元素中显示 SVG 老虎:

现在知道 SVG 数据 URL 是有效的(只要你期望从给定 SVG 获得的图像出现在 img 元素中),你就可以继续下一步。

3. 在 Canvas 中渲染 SVG 并将其导出为任意大小的图像

如何将SVG字符串渲染到画布?现在是时候实现你正在寻找的内容,将 SVG 渲染到画布中以将其调整为你想要的任何大小。实现的逻辑如下。你需要一个空画布,你应该在其中渲染具有自定义大小的 SVG,然后你可以将其导出为 PNG 或 JPEG:

<canvas id="myOutputCanvas"></canvas>

<script>
    // 1. Obtain the canvas element and access its context
    let canvas = document.getElementById('myOutputCanvas');
    let ctx = canvas.getContext("2d");

    // 2. Declare the new width of the image that you want to generate in pixels
    // e.g create an image of 1000 pixels of width from the given SVG
    // note: the height is automatically calculated to preserve aspect ratio
    let newWidth = 1000;

    // 3. Create an image element to load the SVG
    let img = new Image();

    // 4. Once the SVGDataURL is rendered in the Image element
    // proceed to render it in the empty canvas that will contain
    // the same image, but in the size that you want preserving the
    // sharpness of the SVG string
    img.onload = function() {
        // Declare initial dimensions of the image
        let originalWidth = img.width;
        let originalHeight = img.height;

        // Declare the new width of the image
        // And calculate the new height to preserve the aspect ratio
        img.width = newWidth;
        img.height = (originalHeight / originalWidth) * newWidth;

        // Set the dimensions of the canvas to the new dimensions of the image
        canvas.width = img.width;
        canvas.height = img.height;

        // Render image in Canvas 
        ctx.drawImage(img, 0, 0, img.width, img.height); 

        // That's it! If your canvas is visible, you may now see 
        // the image of the new size!
        // Export the canvas to blob
        // You may export this now as a base64 data URL or blob
        // canvas.toBlob(function(blob){
        //  do something with the blob
        //}, "image/png", 1);
    };

    // Load the DataURL of the SVG
    img.src = "data:image/svg+xml;charset=utf-8,[The URL Encoded Plain Data of SVG should be here, replace this with the data from step #1]";
</script>

你可以在以下小提琴中看到此实现的实时示例,你可以在其中简单地将 SVG 字符串提供到 textarea 中,设置输出图像的新宽度,然后将其导出为你想要的图像格式:

快乐编码❤️!

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: