【免费下载链接】ghostlingA minimum viable terminal emulator built on top of the libghostty C API. Ex minimo, infinita nascuntur. 项目地址https://gitcode.com/gh_mirrors/gh/ghostling点击查看免费下载Ghostling 是一个基于 libghostty C API 的极简 C 语言终端模拟器支持通过 Kitty 图形协议Kitty Graphics Protocol在终端里显示 PNG 图片 。本文以这个单文件项目为例带你走通图像字节 → 屏幕像素的完整链路并重点拆解一个极易踩坑的细节——延迟纹理清理。Kitty图形协议终端里的图片传输通道传统终端只能显示字符而 Kitty 图形协议让应用程序可以通过转义序列把 PNG 像素直接送进终端由终端负责存储和摆放。在 libghostty 的架构下责任划分非常清晰层职责由谁提供协议解析解析图像数据、存储图片、计算摆放位置libghostty-vt库内置PNG 解码图像字节 → RGBA 像素Ghostling 的decode_png渲染像素 → GPU 纹理 → 画到屏幕Ghostling 的render_kitty_imagesGhostling 要做的只有后两件事这正是它最小可运行终端定位的体现。第一步在终端创建前注册 PNG 解码器Ghostling 用一行代码注册了解码器这是进程级全局设置必须先于终端创建见 main.c#L1269-L1273ghostty_sys_set(GHOSTTY_SYS_OPT_DECODE_PNG, (const void *)decode_png);decode_png的实现main.c#L1054-L1083有两个值得注意的细节用 Raylib 的LoadImageFromMemory底层是 stb_image把 PNG 解码并统一转换为 RGBA 格式解码出的像素拷贝到ghostty_alloc分配的内存中——这块内存由 libghostty 的分配器管理库之后才能安全释放。如果这里用自己的malloc分配库就没法回收会埋下泄漏隐患。第二步打开图像存储开关默认情况下终端会拒绝所有图像数据。必须显式开启存储上限Ghostling 设置为 64 MiBuint64_t kitty_storage_limit 64 * 1024 * 1024; ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_STORAGE_LIMIT, kitty_storage_limit);紧接着还开启了 file、temp file、shared memory 三种传输介质main.c#L1331-L1343让大图片可以绕过内联inline通道。另一个容易忽略的点启动时必须先做一次初始 resize把单元格的像素尺寸写入终端否则 Kitty 摆放计算会除以零main.c#L1286-L1290。第三步渲染——三层 z 轴 逐图摆放渲染入口是 main.c#L662-L778 的render_kitty_images。它借助 libghostty 提供的迭代器按层过滤逐个取出摆放记录placement每张图完成五步placement_viewport_pos取视口内坐标——屏幕外或 Unicode 占位摆放都会返回 NO_VALUE一次调用兼顾两种情况读取尺寸、格式只处理 RGBA和像素缓冲区placement_grid_size得到图像占用的网格数乘以单元格尺寸得到屏幕目标矩形placement_source_rect取源矩形自动处理0 表示整图的语义并做边界裁剪LoadTextureFromImage上传 GPU 纹理DrawTexturePro绘制。三层 z 轴的调用位置在 main.c#L827-L985层绘制时机典型场景BELOW_BG单元格背景之前整页背景图BELOW_TEXT背景之后、文本之前文字衬底图ABOVE_TEXT光标之后浮层图片延迟纹理清理为什么不能画完就释放这是本文的核心。关键点一句话帧中上传的纹理不能当场释放。原因Raylib 是先记录、后提交的 API。BeginDrawing()之后DrawTexturePro只是把绘制命令入队直到EndDrawing()才真正提交给 GPU。如果在入队后立即调用UnloadTextureGPU 可能仍在引用这块纹理属于未定义行为。Ghostling 的方案是一个延迟队列main.c#L630-L649static Texture2D deferred_textures[MAX_DEFERRED_TEXTURES]; // 上限 256defer_unload_texture()帧内不释放纹理先登记进队列队列满时立即释放——注释很坦诚可能闪一下但不会泄漏flush_deferred_textures()每帧EndDrawing()之后把本帧登记的纹理一次性释放main.c#L1574-L1579。这个帧内使用资源、提交后再释放的模式在任何立即模式渲染器包括 Vulkan/DirectX 的 fence 逻辑里都是通用思路值得记住。⚠️ 作者在注释里也承认这套实现刻意简单但非常低效——每帧都为每张可见图片重新上传并销毁纹理。真实终端应该按 image ID 缓存纹理只在图片重传或从存储中被驱逐时重新上传。动手构建一键体验完整流程git clone https://gitcode.com/gh_mirrors/gh/ghostling cd ghostling cmake -B build -G Ninja cmake --build build ./build/ghostling启动后用支持 Kitty 图形协议的工具如kitty kitten icat xxx.png把一张 PNG 送进终端就能看到上面的渲染链路完整跑通。构建依赖Raylib 5.5 libghostty-vt 的 FetchContent 拉取见 CMakeLists.txt完整说明见 README.md。小结终端显示图片三步走注册解码器 → 打开图像存储 → 按层迭代 placement 渲染库经手的内存要走库的分配器生命周期才能闭环提交后再释放的延迟清理模式是帧循环 GPU 场景下的必修课。Ghostling 用单文件 main.c 证明站在 libghostty 的肩膀上一个支持 Kitty 图形协议的终端真的可以很小。赞分享【免费下载链接】ghostlingA minimum viable terminal emulator built on top of the libghostty C API. Ex minimo, infinita nascuntur. 项目地址https://gitcode.com/gh_mirrors/gh/ghostling点击查看免费下载相关推荐在终端里显示真·图片Onefetch 三大图像协议Kitty/Sixel/iTerm背后的原理在终端里显示真·图片Onefetch 三大图像协议Kitty/Sixel/iTerm背后的原理 还在用字母拼 logoOnefetch 是一款命令行 G开发工具如何在 C 程序中为 Ghostty 终端注册 PNG 解码器并发送 Kitty 图形协议图片如何在 C 程序中为 Ghostty 终端注册 PNG 解码器并发送 Kitty 图形协议图片 当你在自己的 C 程序里嵌入 Ghostty 的 C 库 gh桌面应用开发工具Onefetch 终端图片显示指南Kitty / Sixel / iTerm 协议的原理与实战Onefetch 终端图片显示指南Kitty / Sixel / iTerm 协议的原理与实战 本篇指南围绕 onefetch 的终端内图片显示能力展开介绍开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?