代码之家  ›  专栏  ›  技术社区  ›  Robert Chan

使用HTML5画布的SVG到PNG Base64在iOS浏览器上不可靠(Chrome/Safari)

  •  0
  • Robert Chan  · 技术社区  · 6 年前

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

    我使用以下代码使用html画布将svg转换为png base64

    SVG编辑器.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组件调用。

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

    我在客户端将svg转换为png的原因是,我无法在dotnet核心解决方案上安装c svg呈现库( https://www.nuget.org/packages/Svg/ )

    请帮助!

    1 回复  |  直到 6 年前
        1
  •  0
  •   Robert Chan    6 年前

    我以前在dotnetcore解决方案中也遇到过同样的问题,只是我没有使用svg edit。这是我解决这个问题的办法…

    使用dotnet framework创建一个新的控制台应用程序…并在包管理器上安装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核心端,需要将svg发布回api,将其保存在服务器上,作为进程运行consoleapp.exe,并从标准输出读取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);
    }