首页
关于
Search
1
windows访问WSL出现\\wsl.localhost 无法访问
1,375 阅读
2
cmake配置cuda12.4+libtorch开发环境
743 阅读
3
[HYGUI开发] emoji绘制问题的解决
517 阅读
4
快速安装带有vnc的docker
492 阅读
5
基于ProtoAudio的语音录制/静音检测
485 阅读
默认分类
技术
杂谈
嵌入式开发
人工智能
HYGUI
记录
其他
登录
Search
回忆
累计撰写
16
篇文章
累计收到
4
条评论
首页
栏目
默认分类
技术
杂谈
嵌入式开发
人工智能
HYGUI
记录
其他
页面
关于
搜索到
2
篇与
的结果
2024-09-13
[HYGUI开发] emoji绘制问题的解决
寻找方案在使用skia绘制的时候无论如何都无法绘制emoji手动指定了一个支持emoji的字体恩。。。手动指定一个中文字体试试字体比之前更全了,事情开始变得有趣了起来🤔那么问题应该就在内置字体不全上,已知有些字体支持除了emoji以外的大部分字体,而emobj需要额外的字体支持,而库需要跨平台,那么只能识别emoji然后将符号特殊处理🤯那么去找unicode的emoji范围规范吧https://unicode.org/Public/emoji/latest/emoji-test.txtdump下来常用emoji之后需要找一个支持的字体,本来google的Noto Color Emoji是个不错的选择,但是吧skia无法渲染TWT那只能使用另一套开源但是风格略奇怪的字体openmoji,选用兼容性较好的 OpenMoji-color-colr0_svg尝试引入模拟skia的 ParagraphBuilderImpl 和 Paragraph由 ParagraphBuilderImpl构建段落布局信息,Paragraph进行渲染.// 预先定义字体信息 SkFontMetrics font_metrics{}; Font->getMetrics(&font_metrics); auto emoji_font = SkFont(g_app.EmojiTypeface->makeClone(SkFontArguments{}), Font->getSize()); SkFontMetrics emoji_font_metrics{}; emoji_font.getMetrics(&emoji_font_metrics); auto utils_font = SkFont(g_app.UtilsTypeface->makeClone(SkFontArguments{}), Font->getSize()); SkFontMetrics utils_font_metrics{}; utils_font.getMetrics(&utils_font_metrics);计算每个字符的位置for (auto textLayout: TextCache) { HYParagraph::LineLayout lineLayout; if (textLayout.empty()) { textLayout = U" "; } // 计算每个字符 textLayout.forEachUtf8CharBoundary([&](const char8_t *data, size_t start, size_t len, char32_t c) -> int { // 取出每个符号进行测量 HYString tests(c); auto tests_c = c; switch (c) { case U'\n': { // 也许暂时不需要? PrintError("未处理的换行符!!!"); } break; case U' ': { // 空格,一般会无法计算,使用a进行代替计算. tests = U"1"; tests_c = U' '; len = tests.size(); } break; default: break; } HYParagraph::CharacterLayout characterLayout; SkRect ts; SkScalar char_scalar; auto GlyphID = Font->unicharToGlyph(c); if (GlyphID == 0) { // 测量失败,测试特殊字符 GlyphID = utils_font.unicharToGlyph(c); if (GlyphID != 0) { char_scalar = utils_font.measureText(tests.c_str(), len, SkTextEncoding::kUTF8, &ts); characterLayout.glyphType = HYParagraph::CharacterGlyphType::Utils; } else { // 测量失败,测试emoji GlyphID = emoji_font.unicharToGlyph(c); if (GlyphID != 0) { char_scalar = emoji_font.measureText(tests.c_str(), len, SkTextEncoding::kUTF8, &ts); characterLayout.glyphType = HYParagraph::CharacterGlyphType::Emoji; } else { tests = U'☐'; tests_c = U'☐'; len = tests.size(); char_scalar = Font->measureText(tests.c_str(), len, SkTextEncoding::kUTF8, &ts); } } } else { char_scalar = Font->measureText(tests.c_str(), len, SkTextEncoding::kUTF8, &ts); } PrintDebug("{} {} {}x{} GlyphID:{}", tests.c_str(), char_scalar, ts.width(), ts.height(), GlyphID); characterLayout.metrics.fAscent = ts.top(); characterLayout.metrics.fDescent = ts.bottom(); characterLayout.metrics.fLeading = std::max(font_metrics.fLeading, emoji_font_metrics.fLeading); characterLayout.metrics.fMaxHeight = fabs(lineLayout.metrics.fAscent) + fabs(lineLayout.metrics.fDescent) + lineLayout.metrics.fLeading; lineLayout.metrics.fAscent = std::min(ts.top(), lineLayout.metrics.fAscent); lineLayout.metrics.fDescent = std::max(ts.bottom(), lineLayout.metrics.fDescent); lineLayout.metrics.fLeading = std::max(std::max(font_metrics.fLeading, emoji_font_metrics.fLeading), lineLayout.metrics.fLeading); characterLayout.len = len; characterLayout.value = tests_c; characterLayout.text = tests_c; characterLayout.rect = { .x = addLen, .y = addHeight, .width = char_scalar, .height = ts.height(), }; // 偏移 addLen += char_scalar; lineLayout.characterLayouts.emplace_back(characterLayout); return 0; }); lineLayout.metrics.fMaxHeight = std::fabs(lineLayout.metrics.fAscent) + std::fabs(lineLayout.metrics.fDescent) + std::fabs(lineLayout.metrics.fLeading); addHeight += lineLayout.metrics.fMaxHeight + LineSpacing; addLen = 0; layouts->emplace_back(lineLayout); }渲染void HYParagraph::Canvas(CanvasPtr canvas, PaintPtr paint, const HYRectf &rect, const HYPointf &offset) { auto emoji_font = SkFont(g_app.EmojiTypeface->makeClone(SkFontArguments{}), font->getSize()); auto utils_font = SkFont(g_app.UtilsTypeface->makeClone(SkFontArguments{}), font->getSize()); for (auto &line: *lineLayouts) { for (auto &word: line.characterLayouts) { SkFont *df = font; if (word.glyphType == HYParagraph::CharacterGlyphType::Emoji) { df = &emoji_font; } else if (word.glyphType == HYParagraph::CharacterGlyphType::Utils) { df = &utils_font; } canvas->drawString(word.text.c_str(), offset.x + word.rect.x, offset.y + word.rect.y - line.metrics.fAscent, *df, *paint); } } };成果看看尺寸9mb,考虑到是单文件无依赖静态链接,也能接受。结语这里尽可能使用最小成本实现了对多端友好(方便跨平台),但是因为裁减了font,会有部分字符显示不全.HYParagraphBuilderImpl只写了基本的计算,还可以进行超多优化:自动换行、字符/段落间距、超出区域停止渲染,为了最小化代码体积而关闭emoji扩展等相关项目HYGUI
2024年09月13日
517 阅读
0 评论
0 点赞
2024-04-18
[HYGUI开发] 一、基本概念
做一个UI框架的想法其实早在几年前就有了,但是因为期间因为各种原因导致没有时间来做这个,正好最近在自制一个ar眼镜,其中显示模块需要一个绘图程序来配合交互,正好趁这个机会把一直以来的想法实现了(笑)规划HYGUI理念遵循DirectUI理念库需要保持轻量,简洁,自由,单库模式下可以以单文件二进制模式发布需要兼容跨平台方案,Windows,Linux,MacOS,Android,(其实我还想兼容WebAssembly,这个以后看吧,感觉应该没多大问题)支持主题,发布时可以打包主题,单体调用布局需要支持传统的代码布局与XML动态布局,XML动态布局需要支持热更新支持多语言绑定(使用C导出接口)
2024年04月18日
195 阅读
0 评论
0 点赞