一次小而美的重构:使用 C# 在 Avalonia 中生成真正好看的词云
前言
我之前不是开发 StarBlogPublisher(一款 Markdown 文章发布工具)吗?
当时里面有个分类 词云(Word Cloud) 展示功能。
初版的词云虽然 "能用",但效果极其粗糙——基本只是简单堆叠文字,完全没有体现出词云那种灵动、密集、错落有致的美感。
于是,我决定 彻底重构 这一模块,重新寻找合适的词云生成方案。
选型
在 Avalonia 生态中是没有直接可用的词云组件的。
不过没事,C# 的生态还算丰富,基本要啥有啥,词云自然不在话下。
在调研阶段,我找到了两个比较流行的 C# 词云库:
简单对比一下:
| 特性 | Sdcb.WordCloud | KnowledgePicker.WordCloud |
|---|---|---|
| 渲染引擎 | SkiaSharp(跨平台) | SkiaSharp(跨平台) |
| 输出格式 | 图片(PNG)、SVG、JSON | 图片(Bitmap)、SVG(需要自绘) |
| 自定义程度 | 高(遮罩、字体、多方向、JSON输出等) | 中(字体、颜色、布局可定制,但不支持遮罩) |
| 遮罩功能 | 原生支持遮罩图生成特定形状词云 | 暂不支持遮罩,生成规则矩形词云 |
| 最近维护状态 | 活跃(2024年持续更新) | 活跃(2024年有提交) |
| 使用复杂度 | 中(配置多、自由度高) | 中(较简洁,适合快速集成) |
共同点
- 两者都使用
SkiaSharp,意味着可以在 Windows、Linux、macOS 等多平台运行。 - 都支持灵活配置字体、布局、颜色,并且速度非常快。
主要区别
- Sdcb.WordCloud 更注重视觉效果(支持复杂遮罩图案),适合追求自定义形状、炫酷效果的场景。
- KnowledgePicker.WordCloud 更注重性能和简洁性,适合标准矩形词云生成,不追求复杂形状。
最终,我选择了功能更强大、兼容性更好的 Sdcb.WordCloud。
Sdcb.WordCloud简介
Sdcb.WordCloud 是一个基于 SkiaSharp 的跨平台词云生成库,具备以下特点:
- 跨平台兼容:Windows、Linux、macOS 均可使用。
- 多种输出:支持生成图片、SVG文件或JSON数据。
- 高度可定制:自定义字体、颜色、遮罩图案、文本排列方式等。
- 无依赖System.Drawing:在服务器环境也能轻松部署。
- 开源友好:MIT License,开发者自由扩展。
安装
dotnet add package Sdcb.WordCloud
实战:在 StarBlogPublisher 中应用
重构后的词云生成逻辑主要分为两步:
获取词频数据
首先,从后端API请求分类词频数据,并进行简单扩充(让词云密度更高)。
private async Task<List<WordScore>?> GetWordScores() {
var response = await ApiService.Instance.Categories.GetWordCloud();
if (response.Data == null) throw new Exception("获取词云数据失败");
var originalScores = response.Data
.Select(e => new WordScore(Score: e.Value, Word: e.Name))
.ToList();
var extendedScores = new List<WordScore>();
foreach (var score in originalScores) {
for (int i = 0; i < 10; i++) {
extendedScores.Add(score);
}
}
return extendedScores;
}
这里小技巧:
将原本每个单词的词频复制多次,可以有效提升词云的视觉密度和丰富度。
生成词云图像
拿到词频数据后,使用 WordCloud.Create() 创建词云对象,并通过遮罩图案和字体定制,生成最终的词云图片。
private async Task GenerateWordCloudImage() {
var wordScores = await GetWordScores();
if (wordScores == null || !wordScores.Any()) {
ErrorMessage = "没有可用的词云数据";
return;
}
var wc = WordCloud.Create(new WordCloudOptions(900, 900, wordScores) {
FontManager = new FontManager([
SKTypeface.FromFamilyName("Times New Roman")
]),
Mask = MaskOptions.CreateWithForegroundColor(
SKBitmap.Decode(await new HttpClient().GetByteArrayAsync(
"https://io.starworks.cc:88/cv-public/2024/alice_mask.png"
)),
SKColors.White
)
});
using var skImage = wc.ToSKBitmap();
using var data = skImage.Encode(SKEncodedImageFormat.Png, 100);
using var stream = new MemoryStream(data.ToArray());
WordCloudImage = new Bitmap(stream);
}
这里用了两点增强体验的小技巧:
- 遮罩图:使用一张指定形状的透明图,词云可以呈现人物轮廓、LOGO形状等,极大提升美感。
- 自定义字体:更换字体可以让整体风格更符合网站/应用的设计感。
效果展示
话说之前的效果能算词云吗??
| 修改前 | 修改后 |
|---|---|
![]() |
![]() |
小结
通过这次重构,我总结出几点经验:
- 选对库很重要,跨平台、高扩展性是首要考虑。
- 词云美观与否,关键在于密度、遮罩形状、字体风格的搭配。
- 尽可能异步请求和局部优化,避免UI卡顿。
如果你也在C#项目中需要集成词云功能,推荐试试Sdcb.WordCloud —— 简单高效,而且效果不错
一次小而美的重构:使用 C# 在 Avalonia 中生成真正好看的词云的更多相关文章
- AIDE支持实时错误检查、代码重构、代码智能导航、生成APK
AIDE是一个Android Java集成开发环境,可以在Android系统内进行Android软件和游戏的开发.它不仅仅是一个编辑器,而是支持编写-编译-调试运行整个周期,开发人员可以在Androi ...
- 以.net core重构原有.net framework过程中的一些API变更记录(持续更新)
1)Type.IsGenericType类似属性变更 以下是.net framework 4.5中Type抽象类中泛型类型的几个个属性,用于泛型类型的相关信息判断: 以下是.net core(nets ...
- NetCloud——一个网易云音乐评论抓取和分析的Python库
在17的四月份,我曾经写了一篇关于网易云音乐爬虫的文章,还写了一篇关于评论数据可视化的文章.在这大半年的时间里,有时会有一些朋友给我发私信询问一些关于代码方面的问题.所以我最近抽空干脆将原来的代码整理 ...
- .NET重构—单元测试的代码重构
阅读目录: 1.开篇介绍 2.单元测试.测试用例代码重复问题(大量使用重复的Mock对象及测试数据) 2.1.单元测试的继承体系(利用超类来减少Mock对象的使用) 2.1.1.公用的MOCK对象: ...
- 重构第26天 移除双重否定(Remove Double Negative)
理解:”移除双重否定”是指把代码中的双重否定语句修改成简单的肯定语句,这样即让代码可读,同时也给维护带来了方便. 详解:避免双重否定重构本身非常容易实现,但我们却在太多的代码中见过因为双重否定降低了代 ...
- Eclipse 中的重构功能
Eclipse 中的重构功能使其成为了一个现代的 Java 集成开发环境 (IDE),而不再是一个普通的文本编辑器.使用重构,您可以轻松更改您的代码,而不必担心对别处造成破坏.有了重构,您可以只关注于 ...
- C# 利用范型与扩展方法重构代码
在一些C#代码中常常可以看到 //An Simple Example By Ray Linn class CarCollection :ICollection { IList list; public ...
- eclipse重构详解(转)
重构是对软件内部结构的一种调整,目的是在不改变软件行为的前提下,提高其可理解性,降低其修改成本.开发人员可以使用一系列重构准则,在不改变软件行为的前提下,调整软件的结构. 有很多种原因,开发人员应该重 ...
- .NET重构—单元测试重构
.NET重构—单元测试重构 阅读目录: 1.开篇介绍 2.单元测试.测试用例代码重复问题(大量使用重复的Mock对象及测试数据) 2.1.单元测试的继承体系(利用超类来减少Mock对象的使用) 2.1 ...
- lua中 table 元表中元方法的重构实现
转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...
随机推荐
- 天翼云发布边缘安全加速平台AccessOne,四大产品能力助力企业安全高速发展
本文分享自天翼云开发者社区<天翼云发布边缘安全加速平台AccessOne,四大产品能力助力企业安全高速发展>,作者:天翼云社区官方账号 2023年5月30日全国科技工作者日,以" ...
- redis安装、多实例和配置、及服务器性能优化
同一台服务器部署不同应用或者同一应用部署不同环境,需要redis服务多开防止数据冲突问题. 一.安装redis 需要安装gcc编译工具 yum install gcc -y 源码安装默认Redis程序 ...
- Amis坑
一.特殊字符 1.输入框.多行输入框输入$s字符默认替换成空. 如调用后端接口的输入框输入123$BB123,实际请求的参数为123,$后面的参数消息 解决办法:如确实需要输入$的话,在$前面加\即可 ...
- 用 just 简化项目命令管理
在软件开发过程中,高效管理项目命令是提升开发效率的关键, 它们可以帮助我们自动化重复的任务,简化项目管理流程,提高效率. 今天,我们来介绍一个名为 just 的任务运行器. 它由 Casey 发起,用 ...
- [NOI2014] 购票 题解
首先发现 \(p_x\times dis(x,y)+q_x\) 异常像是能斜率优化的样子,那先把求 \(f_x\) 的式子写出来(下设 \(d_x\) 表示 \(x\) 到根的距离): \[f_x=\ ...
- nginx 如何强制跳转 https
本项目 nginx 作为代理服务 项目上线,客户说要加个安全证书 ,于是安全证书是加上了,可是htttp和https都能访问网站,客户要求不行必须强制用带有https的地址访问 开整 这是 http ...
- OpenLayers 绘制带箭头的LineString
<!--******************************************************************** * Copyright 2000 - 2022 ...
- Cython与CUDA之Gather
技术背景 Cython是Python的一个超集,可以使用Pythonic的语法写出接近于C语言的性能,可以用于将Python编程过程中遇到的Bottleneck模块改写成Cython以达到加速的效果. ...
- 【由技及道】CI/CD的量子纠缠术:Jenkins与Gitea的自动化交响曲【人工智障AI2077的开发日志】
摘要:当代码提交触发量子涟漪,当构建流水线穿越时空维度--欢迎来到自动化构建的十一维世界.本文记录一个未来AI如何用Jenkins和Gitea搭建量子纠缠式CI/CD管道,让每次代码提交都成为时空交响 ...
- 【EX6-1】带孔平板拉伸的弹塑性分析
带孔平板拉伸的弹塑性分析 来源:<ABAQUS有限元分析实例详解>石亦平等 1. 建模 塑性数据: abaqus输入塑性数据见ABAQUS弹塑性分析 网格划分: 2. 分析设置 单元类型设 ...

