You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SkiaSharp Canvas绘制文本不显示问题求助

SkiaSharp绘制文本在using块释放流后不显示的解决方案

这个问题我之前也踩过坑,核心原因在于SkiaSharp的SKTypeface.FromStream并不会直接复制字体数据到内存——它只是持有一个对传入流的引用,依赖流始终处于可用状态来读取字体信息。当你用using块释放流后,SKTypeface就失去了字体数据的来源,导致SKPaint的FontMetrics、FontSpacing等属性失效,最终无法绘制文本。

下面给你两种可靠的解决办法:

方案一:用SKData将字体加载到内存(推荐)

把流的内容读取到SKData中,让SKTypeface基于内存中的字体数据创建,这样即使原流被释放,也不会影响Typeface的正常使用:

SKPaint _paint = new SKPaint();
// 记得设置文本大小,默认TextSize可能为0,也会导致不显示
_paint.TextSize = 48;

using(Stream stream = _assembly.GetManifestResourceStream(fontPath))
{
    if (stream == null)
    {
        // 这里可以加资源不存在的异常处理
        throw new FileNotFoundException("字体资源未找到", fontPath);
    }
    
    // 将流内容复制到内存SKData中
    using(var fontData = SKData.Create(stream))
    {
        _paint.Typeface = SKTypeface.FromData(fontData);
    }
}

canvas.DrawText("12345", X, Y, _paint);

SKData会把流的全部内容缓存到内存缓冲区,SKTypeface.FromData创建的Typeface完全独立于原流,后续流释放也不会影响字体的使用,这是最安全的方式。

方案二:手动管理流的生命周期(不推荐)

如果你坚持使用SKTypeface.FromStream,可以去掉using块,在完成所有文本绘制操作后再手动释放流。但这种方式要特别注意内存泄漏问题,必须确保流最终被释放:

SKPaint _paint = new SKPaint();
_paint.TextSize = 48;
Stream stream = null;

try
{
    stream = _assembly.GetManifestResourceStream(fontPath);
    _paint.Typeface = SKTypeface.FromStream(stream);
    canvas.DrawText("12345", X, Y, _paint);
}
finally
{
    // 确保流最终被释放
    stream?.Dispose();
}

这种方式风险较高,一旦代码分支遗漏了流的释放,就会造成内存泄漏,所以优先推荐方案一。

另外还要注意两个细节:

  • 确认fontPath是正确的嵌入资源路径(比如命名空间+资源文件名),避免流加载失败导致Typeface为null;
  • 务必设置SKPaint.TextSize属性,默认值为0的话,即使Typeface正常,也会绘制出看不见的文本。

内容的提问来源于stack exchange,提问作者Han Nhu Thien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:49:41