You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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;
}

代码说明

  1. Base64编码函数:这个简化版只处理我们需要的二进制转Base64,足够应付像素数据的编码需求,不需要依赖外部库。
  2. 像素数组生成:这里生成了一个横向的红蓝色渐变,你可以把这部分替换成你的模拟生成的像素数据。
  3. 控制序列输出:用printf输出Kitty的控制序列,\033是ESC字符,_G\\是协议的起始和结束标记,中间的参数指定了传输模式、像素格式、尺寸,然后是编码后的像素数据。

注意事项

  • 必须用支持Kitty图形协议的终端运行:比如Kitty终端本身,或者WezTerm、Foot这些兼容该协议的终端。
  • 如果你的像素数组很大,Kitty支持分块传输(用a=P参数),不过小尺寸的模拟直接一次性传输就够了。
  • 像素数据的顺序必须是RGBA,每个分量8位(0-255),别搞反成BGRA或者其他顺序,不然颜色会错。
  • 运行代码前,确保终端没有禁用图形协议(Kitty默认是开启的)。

这样你就能直接把内存里的像素数组快速渲染到终端里了,完全不用绕路存成图片文件,刚好适合你的模拟场景~

内容来源于stack exchange

火山引擎 最新活动