Skip to content

Latest commit

 

History

History
192 lines (153 loc) · 5.38 KB

File metadata and controls

192 lines (153 loc) · 5.38 KB

flutter_noaa_text

基于路径绘制的无抗锯齿(No Anti-Alias)文本渲染插件。

特性

  • 路径绘制:解析 TTF 字体文件,通过矢量路径绘制文本
  • 无抗锯齿:禁用抗锯齿渲染,获得清晰锐利的边缘
  • 合成加粗:使用描边+填充技术模拟加粗效果,无需额外字体文件
  • 合成斜体:使用 Matrix4 剪切变换实现斜体效果
  • 精确缩放:使用 unitsPerEm 计算精确的缩放比例,与原生 Text 大小一致
  • 简洁 API:参考 Flutter Text widget API 设计,易于使用

使用方法

1. 准备字体文件

在项目中添加 TTF 字体文件到 assets 文件夹:

# pubspec.yaml
flutter:
  assets:
    - assets/微软雅黑.ttf

2. 加载字体

import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_noaa_text/flutter_noaa_text.dart';

// 加载字体
final data = await rootBundle.load('assets/微软雅黑.ttf');
final parser = TtfParser();
final font = parser.parse(data.buffer.asUint8List());

3. 使用 NoaaText

NoaaText(
  '你好世界',
  font: font,
  style: NoaaTextStyle(
    fontSize: 48,
    color: Colors.black,
    fontWeight: FontWeight.bold,     // 合成加粗
    fontStyle: FontStyle.italic,     // 合成斜体
    letterSpacing: 2.0,              // 字符间距
    disableAntiAlias: true,          // 禁用抗锯齿
  ),
)

NoaaTextStyle 参数

参数 类型 默认值 说明
fontSize double? 14.0 字体大小(像素)
color Color? 黑色 文本颜色
fontWeight FontWeight? normal 字体粗细(用于判断是否加粗)
fontStyle FontStyle? normal 字体样式(用于判断是否斜体)
letterSpacing double? 0.0 字符间距
height double? 1.0 行高倍数
disableAntiAlias bool? true 是否禁用抗锯齿
boldStrokeWidthFactor double? 0.03 加粗描边宽度系数
italicSkewFactor double? -0.2 斜体剪切系数

完整示例

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_noaa_text/flutter_noaa_text.dart';

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  TtfFont? font;

  @override
  void initState() {
    super.initState();
    _loadFont();
  }

  Future<void> _loadFont() async {
    final data = await rootBundle.load('assets/微软雅黑.ttf');
    final parser = TtfParser();
    setState(() {
      font = parser.parse(data.buffer.asUint8List());
    });
  }

  @override
  Widget build(BuildContext context) {
    if (font == null) {
      return CircularProgressIndicator();
    }

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 普通文本
            NoaaText(
              '你好世界',
              font: font!,
              style: NoaaTextStyle(fontSize: 48),
            ),
            SizedBox(height: 20),
            // 加粗文本
            NoaaText(
              'Bold Text',
              font: font!,
              style: NoaaTextStyle(
                fontSize: 48,
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: 20),
            // 斜体文本
            NoaaText(
              'Italic Text',
              font: font!,
              style: NoaaTextStyle(
                fontSize: 48,
                fontStyle: FontStyle.italic,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

技术细节

路径生成

使用 text_to_path_maker 库解析 TTF 字体文件,通过 unitsPerEm 计算精确的缩放比例:

scale = fontSize / unitsPerEm

合成加粗

使用描边+填充技术:

  1. 先绘制描边:strokeWidth = fontSize * 0.03
  2. 再填充中心

合成斜体

使用 Matrix4 水平剪切变换:

Matrix4.identity()..setEntry(0, 1, -0.2)  // 约 12 度倾斜

与原生 Text 对比

特性 原生 Text NoaaText
渲染方式 系统字体引擎 矢量路径
抗锯齿 默认开启 可禁用
加粗/斜体 需要字体文件 合成生成
动画/特效 有限 可扩展
性能 中等

宽度对齐与注意事项

  • 进行对比时请使用相同的字体文件(示例中 TextNoaaText 均使用 fzwb.ttf)。
  • NoaaText 以字体的 advanceWidth 作为测量依据,并按 unitsPerEm 线性缩放:pixel = advanceWidth * fontSize / unitsPerEm
  • 若字体缺少某个字符的 glyph,会退回到边界估算/启发式宽度(中文≈1.0×size,西文≈0.6×size),可能导致偏差;建议选择字符集完整的字体。
  • 暂未实现 kerning/ligature/shaping,字偶距与连字在少数字体上可能与原生引擎存在 1px 级误差。

近期修复

  • 修复 cmap Format 4 解析条件(由 == 0 改为 == null),避免遗漏 glyph 映射,解决长英文/数字串宽度被低估的问题。
  • 新增 charCode -> glyphId 快速映射,使 getGlyphIdForCharacter 由 O(n) 扫描变为 O(1) 查找,测量更稳定。

License

MIT