SVG в PNG Base64 с использованием HTML5 Canvas не работает надежно на браузерах IOS (Chrome / Safari) - PullRequest
0 голосов
/ 05 июня 2018

Я создаю веб-приложение с использованием asp.net-core с угловыми 4 шаблонами и использую svg-edit, чтобы позволить пользователю рисовать / загружать / сохранять изображения на мобильных устройствах, особенно на устройствах IOS / устройствах Android.Svg-edit хорошо работает для того, что мне нужно, но я столкнулся с проблемой на устройствах IOS, касающейся генерации / преобразования пользовательского чертежа (svg) в другой формат (png base64), который будет POST для API как частьпроцесс сохранения.

Я использую следующий код, который использует HTML-холст для преобразования 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;
        }

Однако,иногда это работает только на устройстве IOS с использованием браузера Chrome или Safari.Метод 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 на стороне клиента, заключается в том, что я не могу установить библиотеку рендеринга C # SVG в решении dotnet-core(https://www.nuget.org/packages/Svg/)

Пожалуйста, помогите!

1 Ответ

0 голосов
/ 05 июня 2018

Ранее у меня была точно такая же проблема с решением 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 из StandardOutput.

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);
}
...