使用 HTML5 Canvas 将 Svg 转为 png base64 在 IOS 浏览器(Chrome / Safari)上无法可靠地工作

Svg to png base64 using HTML5 Canvas does not work reliably on IOS browsers (Chrome / Safari)

我正在使用 asp.net-core 和 angular 4 个模板构建一个网络应用程序,并使用 svg-edit 允许用户在移动设备上绘制/加载/保存图像,特别是在 IOS 台设备/android 台设备。 svg-edit 可以很好地满足我的需要,但我在 IOS 设备上遇到了一个问题,涉及生成/将用户绘图 (svg) 转换为另一种格式 (png base64),即 POST 到 api 作为保存过程的一部分。

我使用下面的代码,它使用 html canvas 将 svg 转换为 png base64

svg-editor.js

editor.getDrawingPngBase64 = function (svgString) {
            if (!$('#export_canvas').length) {
                $('<canvas>', { id: 'export_canvas' }).hide().appendTo('body');
            }

            var canvas = $('#export_canvas')[0];
            canvas.width = $("#svgcanvas").width();  // svgCanvas.contentW;
            canvas.height = $("#svgcanvas").height();  // svgCanvas.contentH;
            var ctx = canvas.getContext("2d");

            var promise = new Promise(function (resolve, reject) {
                function drawInlineSVG(ctx, rawSVG, callback) {
                    var svg = new Blob([rawSVG], { type: "image/svg+xml;charset=utf-8" }),
                        domURL = self.URL || self.webkitURL || self,
                        url = domURL.createObjectURL(svg),
                        img = new Image;

                    img.onload = function () {
                        ctx.drawImage(this, 0, 0);
                        var base64 = canvas.toDataURL("image/png");
                       resolve(base64);
                    };

                    img.src = url;
                } 

                drawInlineSVG(ctx, svgString);
            });

            return promise;
        }

但是,这仅在使用 chrome 或 safari 浏览器的 IOS 设备上有时有效。 onload 方法根本没有被调用。我猜 svg 图像可能太大而无法转换。

我也试过这个方法,但也不可靠....

editor.getDrawingPngBase64 = function (svgString) {
            if (!$('#export_canvas').length) {
                $('<canvas>', { id: 'export_canvas' }).hide().appendTo('body');
            }

            var canvas = $('#export_canvas')[0];
            canvas.width = svgCanvas.contentW;
            canvas.height = svgCanvas.contentH;
            var ctx = canvas.getContext("2d");

            var promise = new Promise(function (resolve, reject) {
                function webkitNamespaceBugWorkaround(pText) {
                    var lText = pText.replace(/\ xlink=/g, " xmlns:xlink=", "g");
                    lText = lText.replace(/\ href=/g, " xlink:href=", "g");
                    return lText;
                }

                canvg(canvas, webkitNamespaceBugWorkaround(svgString), {
                    renderCallback: function () {
                        var base64 = canvas.toDataURL("image/png");
                        resolve(base64);
                    }
                });
            });

            return promise;
        }

我也试过 canvg 库,它也不能可靠地工作

这些方法由 angular4 component.ts

调用
    public save() {
const svgString: String = svgEditor.getSvgString();
(<any>window).svgEditor.getDrawingPngBase64(svgString).then(pngBase64: string) => {
             // Call api and save the image
         }
     }

我在客户端将 svg 转换为 png 的原因是我无法在 dotnet-core 解决方案上安装 C# SVG 渲染库 (https://www.nuget.org/packages/Svg/)

请帮忙!

除了我没有使用 svg-edit 之外,我之前在 dotnetcore 解决方案上遇到过完全相同的问题。这是我针对此问题的解决方法....

使用 dotnet 框架创建一个新的控制台应用程序...并在包管理器上安装 Svg 库

>> Install-Package Svg -Version 2.3.0

在 Program.cs 控制台应用程序中,读取 svg 文件并使用 Svg 库将其转换为 png 并使用 Console.WriteLine

输出
class Program
{
    static void Main(string[] args)
    {
        if (args.Length == 0)
            return;

        using (var oStream = new System.IO.MemoryStream())
        {
            string svgPath = args[0];

            if (string.IsNullOrWhiteSpace(svgPath))
                return;

            var text = System.IO.File.ReadAllText(svgPath);
            using (var xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(text)))
            {
                xmlStream.Position = 0;
                var svgDocument = Svg.SvgDocument.Open<SvgDocument>(xmlStream);

                SetupThumbnailImage(svgDocument, out Bitmap bitmap, out Graphics graphics, 250, 120);
                svgDocument.Draw(graphics);

                bitmap.Save(oStream, ImageFormat.Png);

                string pngBase64String = Convert.ToBase64String(oStream.ToArray());
                Console.WriteLine(pngBase64String);
            }
        }
    }
}

在您的 dotnet-core 端,您需要将 SVG post 返回到 api,将其保存在服务器上,运行 将 consoleApp.exe 作为处理并从 StandardOutput 读取 base64。

private async Task<string> SaveThumbnailImage(string svgString)
{
    // Save the svg
    var filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "SvgHelper", Path.Combine(Guid.NewGuid() + ".svg"));
    using (StreamWriter streamWriter = System.IO.File.CreateText(filePath))
    {
        streamWriter.WriteLine(svgString);
    }

    Process process = new Process();
    process.StartInfo.FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "SvgHelper", "lib.svgToPng.exe");
    process.StartInfo.Arguments = filePath;
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.CreateNoWindow = true;
    process.Start();

    // Read the base64String from StandardOutput
    string base64String = process.StandardOutput.ReadToEnd();
    process.WaitForExit();

    // Clean up the file
    System.IO.File.Delete(filePath);
}