如何在C语言中使用Kitty Terminal Graphics Protocol显示像素数组?
如何在C语言中使用Kitty Terminal Graphics Protocol显示像素数组?
我太懂你这种找不到具体实现例子的郁闷了——Kitty的文档明明说支持直接传输内存中的像素数据,但搜来搜去全是加载本地图片的示例,根本没人讲怎么把自己的像素数组直接扔给终端。别慌,我来给你一步步拆解,用C代码实现这个需求。
首先得搞清楚Kitty图形协议的核心逻辑:要显示内存里的像素,我们用i操作的直接传输模式,不需要读文件。整个流程就是:构造一个符合协议的控制序列,把像素数据转成Base64编码(Kitty要求的传输格式),然后把这个序列输出到标准输出就行。
关键步骤拆解
第一步:准备你的像素数组
Kitty支持多种像素格式,最直接的是RGBA32(每个像素4字节,顺序是红、绿、蓝、alpha)。如果你的模拟不需要透明,把alpha通道全设为0xFF(完全不透明)就行。比如我们可以生成一个简单的渐变测试数组。第二步:把像素数据Base64编码
因为Kitty的控制序列里要求传输的二进制数据必须是Base64格式的,而C标准库没有自带Base64编码,所以我们需要一个轻量的实现(下面的代码里会包含一个简化版)。第三步:构造并输出Kitty控制序列
控制序列的格式是这样的:\033_Ga=T,f=32,s=宽度,v=高度;Base64编码的像素数据\033\\解释一下关键参数:
a=T:表示直接传输内存中的图像数据f=32:指定像素格式为RGBA32(每个像素4字节)s=宽度:你的像素数组的宽度(比如100)v=高度:你的像素数组的高度(比如100)
完整C代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> // 简化的Base64编码实现,仅支持RGBA32像素数据(二进制转Base64) static const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; void base64_encode(const unsigned char *data, size_t data_len, char *out, size_t *out_len) { size_t i, j; unsigned char three_bytes[3]; unsigned char four_bytes[4]; *out_len = 0; for (i = 0; i < data_len; i += 3) { three_bytes[0] = data[i]; three_bytes[1] = (i + 1 < data_len) ? data[i + 1] : 0; three_bytes[2] = (i + 2 < data_len) ? data[i + 2] : 0; four_bytes[0] = (three_bytes[0] & 0xFC) >> 2; four_bytes[1] = ((three_bytes[0] & 0x03) << 4) + ((three_bytes[1] & 0xF0) >> 4); four_bytes[2] = ((three_bytes[1] & 0x0F) << 2) + ((three_bytes[2] & 0xC0) >> 6); four_bytes[3] = three_bytes[2] & 0x3F; for (j = 0; j < 4; j++) { out[*out_len] = base64_chars[four_bytes[j]]; (*out_len)++; } } // 处理填充 if (data_len % 3 == 1) { out[*out_len - 2] = '='; out[*out_len - 1] = '='; } else if (data_len % 3 == 2) { out[*out_len - 1] = '='; } } int main() { // 定义图像尺寸 const int width = 100; const int height = 100; const size_t pixel_count = width * height; const size_t data_size = pixel_count * 4; // RGBA32,每个像素4字节 // 分配并生成测试像素数据:从左到右红到蓝的渐变 unsigned char *pixels = malloc(data_size); if (!pixels) { perror("malloc failed"); return 1; } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { size_t idx = (y * width + x) * 4; pixels[idx] = (unsigned char)(255 * (1.0 - (double)x / width)); // 红分量从255到0 pixels[idx + 1] = 0; // 绿分量固定0 pixels[idx + 2] = (unsigned char)(255 * (double)x / width); // 蓝分量从0到255 pixels[idx + 3] = 0xFF; // 完全不透明 } } // 计算Base64编码后的长度 size_t b64_len = ((data_size + 2) / 3) * 4; char *b64_data = malloc(b64_len + 1); if (!b64_data) { perror("malloc failed"); free(pixels); return 1; } base64_encode(pixels, data_size, b64_data, &b64_len); b64_data[b64_len] = '\0'; // 确保字符串结束 // 构造并输出Kitty控制序列 printf("\033_Ga=T,f=32,s=%d,v=%d;%s\033\\\n", width, height, b64_data); fflush(stdout); // 确保数据立即输出到终端 // 清理内存 free(pixels); free(b64_data); return 0; }
代码说明
- Base64编码函数:这个简化版只处理我们需要的二进制转Base64,足够应付像素数据的编码需求,不需要依赖外部库。
- 像素数组生成:这里生成了一个横向的红蓝色渐变,你可以把这部分替换成你的模拟生成的像素数据。
- 控制序列输出:用
printf输出Kitty的控制序列,\033是ESC字符,_G和\\是协议的起始和结束标记,中间的参数指定了传输模式、像素格式、尺寸,然后是编码后的像素数据。
注意事项
- 必须用支持Kitty图形协议的终端运行:比如Kitty终端本身,或者WezTerm、Foot这些兼容该协议的终端。
- 如果你的像素数组很大,Kitty支持分块传输(用
a=P参数),不过小尺寸的模拟直接一次性传输就够了。 - 像素数据的顺序必须是RGBA,每个分量8位(0-255),别搞反成BGRA或者其他顺序,不然颜色会错。
- 运行代码前,确保终端没有禁用图形协议(Kitty默认是开启的)。
这样你就能直接把内存里的像素数组快速渲染到终端里了,完全不用绕路存成图片文件,刚好适合你的模拟场景~
内容来源于stack exchange




