A small but elegant refactoring: Generate truly beautiful word clouds using C# in Avalonia
The process of refactoring the word cloud display feature in StarBlogPublisher. The author compared two popular C# word cloud libraries and ultimately selected the more powerful Sdcb.WordCloud. The article details how to use this library to obtain word frequency data and generate word cloud images, and presents a comparison of the effects before and after refactoring.
目录11 个章节
Preface
Didn't I previously develop StarBlogPublisher (a Markdown article publishing tool designed for StarBlog) using Avalonia?
At the time, it included a Word Cloud category display feature. Although the initial version of the word cloud was "usable," the result was extremely crude—essentially just a simple stacking of text, with none of the lively, dense, and staggered aesthetic that a word cloud should have.
Therefore, I decided to completely refactor this module and search anew for a suitable word cloud generation solution.
Selection
Within the Avalonia ecosystem, there is no readily available word cloud component.
However, that's not an issue. The C# ecosystem is relatively rich, offering almost everything you need, and word clouds are certainly no exception.
During my research phase, I found two fairly popular C# word cloud libraries:
Here's a brief comparison:
| Feature | Sdcb.WordCloud | KnowledgePicker.WordCloud |
|---|---|---|
| Rendering Engine | SkiaSharp (cross-platform) | SkiaSharp (cross-platform) |
| Output Format | Image (PNG), SVG, JSON | Image (Bitmap), SVG (requires custom drawing) |
| Customization Level | High (masks, fonts, multi-direction, JSON output, etc.) | Medium (fonts, colors, layout customizable, but no mask support) |
| Mask Functionality | ✅ Natively supports mask images to generate word clouds in specific shapes | ❌ Does not support masks, generates standard rectangular word clouds |
| Recent Maintenance | Actively updated (continuous updates in 2024) | Active (commits in 2024) |
| Usage Complexity | Medium (more configuration, high flexibility) | Medium (simpler, suitable for quick integration) |
Common Points
- Both use
SkiaSharp, which means they can run on Windows, Linux, macOS and other platforms. - Both support flexible configuration of fonts, layouts, and colors, and are very fast.
Key Differences
- Sdcb.WordCloud focuses more on visual effects (supports complex mask patterns), making it suitable for scenarios that pursue custom shapes and cool effects.
- KnowledgePicker.WordCloud prioritizes performance and simplicity, making it ideal for standard rectangular word cloud generation without pursuing complex shapes.
Ultimately, I chose Sdcb.WordCloud for its stronger functionality and better compatibility.
Introduction to Sdcb.WordCloud
Sdcb.WordCloud is a cross-platform word cloud generation library based on SkiaSharp, featuring the following characteristics:
- Cross-platform compatibility: Usable on Windows, Linux, and macOS.
- Multiple output options: Supports generating images, SVG files, or JSON data.
- Highly customizable: Customize fonts, colors, mask patterns, text layout arrangements, and more.
- No dependency on System.Drawing: Easy to deploy in server environments as well.
- Open-source friendly: Licensed under the MIT License, allowing developers to extend it freely.
Installation
dotnet add package Sdcb.WordCloud
Application in StarBlogPublisher: Practical Implementation
The refactored word cloud generation logic primarily consists of two steps:
Get Word Frequency Data
First, request the categorized word frequency data from the backend API and perform a simple expansion (to increase the word cloud density).
private async Task<List<WordScore>?> GetWordScores() {
var response = await ApiService.Instance.Categories.GetWordCloud();
if (response.Data == null) throw new Exception("Failed to retrieve word cloud data");
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;
}
A small tip here: 👉 Duplicating the original frequency for each word multiple times can effectively enhance the visual density and richness of the word cloud.
Generating a Word Cloud Image
Once you have the word frequency data, use WordCloud.Create() to create a word cloud object. By customizing it with a mask pattern and font, you can generate the final word cloud image.
private async Task GenerateWordCloudImage() {
var wordScores = await GetWordScores();
if (wordScores == null || !wordScores.Any()) {
ErrorMessage = "No available word cloud data.";
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);
}
Two simple techniques are used here to enhance the experience:
- 📄 Mask Image: By using a transparent image with a specific shape, the word cloud can form silhouettes like people or logos, greatly improving its visual appeal.
- 🖋 Custom Font: Changing the font allows the overall style to better match the design of your website or application.
Effect Demonstration
Could that really count as a word cloud from before??
| Before Modification | After Modification |
|---|---|
![]() | ![]() |
Summary
Through this refactoring, I've summarized a few key takeaways:
- Choosing the right library is crucial—cross-platform support and high extensibility are the top priorities.
- The aesthetics of a word cloud hinge on the combination of density, mask shape, and font style.
- Prioritize asynchronous requests (异步请求) and local optimization (局部优化) whenever possible to prevent UI lag.
If you also need to integrate word cloud functionality into your C# project, give Sdcb.WordCloud a try—it's simple, efficient, and delivers great results.
_EOF_
A small but elegant refactoring: Generate truly beautiful word clouds using C# in Avalonia
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
并行化优化KD树算法:使用C#实现高效的最近邻搜索
本文介绍了如何使用并行计算技术优化 KD 树算法,并使用 C# 编程语言实现了高效的最近邻搜索。首先,我们简要介绍了 KD 树的原理和构建过程,然后详细讨论了如何利用并行计算库在多个 CPU 核心上并行构建 KD 树,从而加速搜索过程。通过实验验证,我们证明了并行化优化能够显著提高 KD 树的构建速度和搜索效率,为大规模数据集下的最近邻搜索问题提供了一种高效的解决方案。
2024-03-10 · C# · 约 1 分钟
纯 C#实现+AOT 打造的多功能图片处理工具 ImageGlider
纯C#+AOT打造的ImageGlider,图像处理功能堆得像山,还非得标榜零依赖?ImageSharp封装得倒是挺顺溜,就是不知道这模块化架构能走多远。Web API和CLI工具有点东西,但别指望我夸太离谱。
2025-08-05 · C# · 约 1 分钟
SharpIco:用纯C#打造零依赖的.ico图标生成器,支持.NET9与AOT编译
SharpIco 是一款纯 C# 实现的跨平台图标生成工具,支持 AOT 编译,无需外部依赖。它能将 PNG 图片分解为多尺寸(16x16至512x512)合成 ICO 图标,并支持图标结构分析。工具提供命令行界面,可通过 dotnet tool 一键安装,并已发布至 NuGet 和 Scoop。项目旨在简化图标生成与验证,追求轻量、纯粹、易集成的使用体验。
2025-05-26 · C# · 约 1 分钟
C#移除字符串中的不可见Unicode字符
背景 最近发现某个数据采集的系统拿下来的数据,有些字段的JSON被莫名截断了,导致后续数据分析的时候解析JSON失败。 类似这样 {title: 你好 或者这样,多了个双引号啥的 {title:你好} 因为数据库是Oracle,起初以为是Oracle这老古董出问题了,结果一番折腾,把每条写入数据的SQL语句都拿出来,看起来里面的JSON格式都没问题。 这也太诡异了吧,看起来没毛病,但就为啥JSON
2023-02-02 · C# · 约 1 分钟
讨论
共 0 条加载评论中…

