使用 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);
}
我正在使用 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);
}