问题描述
看见一个有趣的页面,可以把输入的文字信息,直接输出SVG图片,还可以实现动图模式。
示例URL:
示例效果:
那么,用.NET API怎么来快速实现这个目的呢?
问题解答
通过查看示例URL的Response Headers 和 Body Content,发现其使用的Content-Type 为image/svg+xml , 内容使用svg , path , animate , text元素组合而成的HTML代码。
Content-Type(内容类型),一般是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件
SVG 意为可缩放矢量图形(Scalable Vector Graphics)。 SVG 使用 XML 格式定义图像。
SVG 路径 - <path> 元素用于定义一个路径。 <path d="M150 0 L75 200 L225 200 Z" /> 它开始于位置150 0,到达位置75 200,然后从那里开始到225 200,最后在150 0关闭路径。
<animate> 随时间动态改变属性
所以是不是只要API的返回体相类似就可以呢?
试验开始
**第一步:**在Visual Studio 2022中,创建一个.NET Core WEBAPI项目,使用top-level statements.
**第二步:**设置app.MapGet("/", ...),添加 httpResponse 参数并在函数体中设置 httpResponse.ContentType = "image/svg+xml"
**第三步:**直接把示例URL中的全部返回作为 httpResponse 内容输出,F5运行项目测试效果。
app.MapGet("/", async (HttpResponse httpResponse) =>
{
httpResponse.ContentType = "image/svg+xml";
string content = "<!-- https://github.com/DenverCoder1/readme-typing-svg/ -->\r\n<svg xmlns='http://www.w3.org/2000/svg'\r\n xmlns:xlink='http://www.w3.org/1999/xlink'\r\n viewBox='0 0 435 50'\r\n style='background-color: #233911F6;'\r\n width='435px' height='50px'>\r\n <path id='path0'>\r\n <!-- Single line -->\r\n <animate id='d0' attributeName='d' begin='0s;d0.end'\r\n dur='6000ms' fill='remove'\r\n values='m0,25 h0 ; m0,25 h435 ; m0,25 h435 ; m0,25 h0' keyTimes='0;0.66666666666667;0.83333333333333;1' />\r\n </path>\r\n <text font-family='\"Fira Code\", monospace' fill='#F7F7F7' font-size='20'\r\n dominant-baseline='middle'\r\n x='50%' text-anchor='middle'>\r\n <textPath xlink:href='#path0'>\r\n 把字变动动图输出\r\n </textPath>\r\n </text>\r\n</svg>\r\n";
await httpResponse.WriteAsync(content);
await httpResponse.Body.FlushAsync();
});
测试成功,达到预期的效果。
第四步:优化代码,把文本和颜色变为参数
获取 Request中携带的参数 name 和 hex来替换HTML中的文本与颜色值。
PS: 如果有更多的需求,如多行字体,字体,大小,SVG的长宽等,都可以把提取出来变为参数。
完整代码如下:
app.MapGet("/tosvg", async (HttpRequest request, HttpResponse httpResponse) =>
{
string name = request.Query["name"];
string colorHex = request.Query["hex"];
name = name ?? "No Name";
colorHex = colorHex ?? "3943BB";
httpResponse.ContentType = "image/svg+xml";
if (name.Contains("("))
{
name = name.Substring(0, name.IndexOf('('));
}
await httpResponse.WriteAsync(GenerateSVGcontent(name, colorHex));
await httpResponse.Body.FlushAsync();
});
string GenerateSVGcontent(string name, string colorHex = "#3943BB")
{
StringBuilder sb = new StringBuilder();
sb.Append("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 200 100' style='background-color:" + colorHex + ";' width='200px' height='100px'>");
sb.Append("<path id='path0'><animate id='d0' attributeName='d' begin='0s' dur='3000ms' fill='freeze' values='m0,50 h0 ; m0,50 h200 ; m0,50 h200 ; m0,50 h200' keyTimes='0;0.72727272727273;0.81818181818182;1' /></path>");
sb.Append("<text font-family='\"Arial\", monospace' fill='#FFFFFF' font-size='20' dominant-baseline='middle' x='50%' text-anchor='middle'>");
sb.Append("<textPath xlink:href='#path0'>");
sb.Append(name);
sb.Append("</textPath></text>\r\n</svg>");
return sb.ToString();
}
第五步:在VS2022中,一键部署到Azure App Service,轻松提供一个HTTP/S API实现文字转动图功能。
附录:完整的示例代码
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var app = builder.Build();
app.MapGet("/", async (HttpResponse httpResponse) =>
{
httpResponse.ContentType = "image/svg+xml";
string content = "<!-- https://github.com/DenverCoder1/readme-typing-svg/ -->\r\n<svg xmlns='http://www.w3.org/2000/svg'\r\n xmlns:xlink='http://www.w3.org/1999/xlink'\r\n viewBox='0 0 435 50'\r\n style='background-color: #233911F6;'\r\n width='435px' height='50px'>\r\n <path id='path0'>\r\n <!-- Single line -->\r\n <animate id='d0' attributeName='d' begin='0s;d0.end'\r\n dur='6000ms' fill='remove'\r\n values='m0,25 h0 ; m0,25 h435 ; m0,25 h435 ; m0,25 h0' keyTimes='0;0.66666666666667;0.83333333333333;1' />\r\n </path>\r\n <text font-family='\"Fira Code\", monospace' fill='#F7F7F7' font-size='20'\r\n dominant-baseline='middle'\r\n x='50%' text-anchor='middle'>\r\n <textPath xlink:href='#path0'>\r\n 把字变动动图输出\r\n </textPath>\r\n </text>\r\n</svg>\r\n";
await httpResponse.WriteAsync(content);
await httpResponse.Body.FlushAsync();
});
app.MapGet("/tosvg", async (HttpRequest request, HttpResponse httpResponse) =>
{
string name = request.Query["name"];
string colorHex = request.Query["hex"];
//name = name:? "Name";
name = name ?? "No Name";
colorHex = colorHex ?? "3943BB";
httpResponse.ContentType = "image/svg+xml";
if (name.Contains("("))
{
name = name.Substring(0, name.IndexOf('('));
}
await httpResponse.WriteAsync(GenerateSVGcontent(name, colorHex));
await httpResponse.Body.FlushAsync();
});
string GenerateSVGcontent(string name, string colorHex = "#3943BB")
{
StringBuilder sb = new StringBuilder();
sb.Append("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 200 100' style='background-color:" + colorHex + ";' width='200px' height='100px'>");
sb.Append("<path id='path0'><animate id='d0' attributeName='d' begin='0s' dur='3000ms' fill='freeze' values='m0,50 h0 ; m0,50 h200 ; m0,50 h200 ; m0,50 h200' keyTimes='0;0.72727272727273;0.81818181818182;1' /></path>");
//sb.Append("<path id='path0'><animate id='d0' attributeName='d' begin='0s;d0.end' dur='2200ms' fill='remove' values='m0,50 h0 ; m0,50 h200 ; m0,50 h200 ; m0,50 h0' keyTimes='0;0.72727272727273;0.81818181818182;1' /> </path>");
sb.Append("<text font-family='\"Arial\", monospace' fill='#FFFFFF' font-size='20' dominant-baseline='middle' x='50%' text-anchor='middle'>");
sb.Append("<textPath xlink:href='#path0'>");
sb.Append(name);
sb.Append("</textPath></text>\r\n</svg>");
return sb.ToString();
}
app.Run();
参考资料
Readme Typing SVG : https://readme-typing-svg.demolab.com/demo/
HTTP content-type : https://www.runoob.com/http/http-content-type.html
<animate> : https://www.runoob.com/svg/svg-reference.html