GifLib 基础示例

功能说明

演示如何使用 GifLib 库解析 GIF 文件。本示例展示了如何从内存中读取 GIF 数据、解析 GIF 文件结构、获取 GIF 信息和图像帧信息,以及解析扩展块(如图形控制扩展块)。

GifLib 是一个用于操作 GIF 文件的 C 语言库,支持读取 GIF 文件并将其转换为 RGB 位图,也支持将 RGB 位图写入为 GIF 文件。

硬件连接

无需外部连接,GifLib 为纯软件 GIF 处理库。

示例内容

  1. 定义内置的测试 GIF 数据(1x1 像素的简单 GIF,包含黑白两色)

  2. 实现自定义内存读取函数 memory_read_func

  3. 使用 DGifOpen() 打开 GIF 文件(使用自定义读取函数从内存读取)

  4. 使用 DGifSlurp() 解析整个 GIF 文件内容

  5. 打印 GIF 基本信息:

    • 逻辑屏幕宽度和高度

    • 颜色分辨率

    • 背景色索引

    • 图像总数

    • 全局调色板信息(颜色数、BitsPerPixel、颜色值)

  6. 遍历所有图像帧,打印每帧信息:

    • 图像位置(左上角坐标)

    • 图像宽度和高度

    • 交错标志

    • 局部调色板信息

    • 扩展块信息(功能码、大小)

    • 图形控制扩展块详细信息(处理方式、用户输入、透明度、延迟时间)

  7. 使用 DGifCloseFile() 关闭 GIF 文件

编译

重要提示:在编译前,请先确认您使用的开发板型号。SDK 目前支持以下开发板:

  • arcs_evb - ARCS EVB 评估板

  • arcs_mini - ARCS Mini 开发板

根据您的开发板型号,选择对应的编译命令:

在示例目录下执行编译:

# 使用 arcs_evb 开发板
./build.sh -C -DBOARD=arcs_evb

# 或使用 arcs_mini 开发板
./build.sh -C -DBOARD=arcs_mini

Note

如果在 SDK 根目录执行,需要指定示例路径:

# 使用 arcs_evb 开发板
./build.sh -C -S samples/<示例路径> -DBOARD=arcs_evb

# 或使用 arcs_mini 开发板
./build.sh -C -S samples/<示例路径> -DBOARD=arcs_mini

Note

确保已安装对应的工具链。

烧录

编译完成后,使用 SDK tools 目录下的 cskburn 工具烧录固件:

./tools/burn/cskburn -s /dev/ttyUSB0 -b 3000000 0x0 build/arcs.bin -C arcs

Note

烧录参数说明

  • -s /dev/ttyUSB0:串口设备路径,需要根据实际情况修改 - Linux 系统:通常是 /dev/ttyUSB0/dev/ttyACM0 - 可通过 ls /dev/tty* 命令查看可用串口设备 - 不同开发板或 USB 转串口芯片可能使用不同的设备名

  • -b 3000000:烧录波特率(3Mbps)

  • 0x0:烧录起始地址

  • build/arcs.bin:编译生成的固件路径

  • -C arcs:芯片类型

注意事项

  • 确保开发板已正确连接到电脑

  • 如果无法识别串口设备,请检查 USB 连接线是否正常,或尝试其他 USB 端口

预期输出

********Arcs SDK 0.1.0 @ v0.0.23.temp.docs-96-gf56c5084660d********
Running on hart-id: 1
I/elog            [1034:42:44.159 1 elog_async] EasyLogger V2.2.99 is initialize success.
[I][sample] 正在打开GIF数据
[I][sample] 正在解析GIF数据
[I][sample] GIF信息
[I][sample]   宽度: 1
[I][sample]   高度: 1
[I][sample]   颜色分辨率: 1
[I][sample]   背景色索引: 0
[I][sample]   图像总数: 1
[I][sample]   全局调色板
[I][sample]     颜色数: 2
[I][sample]     BitsPerPixel: 1
[I][sample]     颜色#0: RGB(0, 0, 0)
[I][sample]     颜色#1: RGB(255, 255, 255)
[I][sample] GIF包含 1 个图像
[I][sample] 图像 #0
[I][sample]   帧信息
[I][sample]     左上角: (0, 0)
[I][sample]     宽度: 1
[I][sample]     高度: 1
[I][sample]     交错: 
[I][sample]     无局部调色板
[I][sample] GifLib sample completed successfully

说明

  • 输出开头包含系统启动信息和日志系统初始化信息

  • 示例使用内置的 1x1 像素 GIF 数据,包含黑白两色

  • GIF 信息包括逻辑屏幕尺寸、颜色分辨率、背景色、图像数量和调色板信息

  • 图像帧信息包括位置、尺寸、交错标志和调色板信息

  • 如果 GIF 包含图形控制扩展块,会显示处理方式、透明度、延迟时间等信息

核心 API

API

说明

DGifOpen()

打开 GIF 文件(支持自定义读取函数)

DGifSlurp()

解析整个 GIF 文件内容到内存

DGifCloseFile()

关闭 GIF 文件并释放资源

GifErrorString()

将错误代码转换为错误描述字符串

关键代码

// 自定义内存读取函数
typedef struct {
    const unsigned char *data;
    size_t size;
    size_t pos;
} MemoryBuffer;

int memory_read_func(GifFileType *gif, GifByteType *buf, int len) {
    MemoryBuffer *buffer = (MemoryBuffer *)gif->UserData;
    
    if (buffer->pos >= buffer->size) {
        return 0;
    }
    
    int remaining = buffer->size - buffer->pos;
    int read_size = (remaining < len) ? remaining : len;
    
    memcpy(buf, buffer->data + buffer->pos, read_size);
    buffer->pos += read_size;
    
    return read_size;
}

// 打开 GIF 文件
MemoryBuffer buffer = {
    .data = sample_gif,
    .size = sizeof(sample_gif),
    .pos = 0
};

int error = 0;
GifFileType *gif = DGifOpen(&buffer, memory_read_func, &error);
if (!gif) {
    LOGI("无法打开GIF: %s", GifErrorString(error));
    return 1;
}

// 解析 GIF 内容
if (DGifSlurp(gif) != GIF_OK) {
    LOGI("无法读取GIF内容: %s", GifErrorString(gif->Error));
    DGifCloseFile(gif, &error);
    return 1;
}

// 访问 GIF 信息
LOGI("宽度: %d", gif->SWidth);
LOGI("高度: %d", gif->SHeight);
LOGI("图像总数: %d", gif->ImageCount);

// 访问全局调色板
if (gif->SColorMap) {
    LOGI("颜色数: %d", gif->SColorMap->ColorCount);
    for (int i = 0; i < gif->SColorMap->ColorCount; i++) {
        GifColorType color = gif->SColorMap->Colors[i];
        LOGI("颜色#%d: RGB(%d, %d, %d)", i, color.Red, color.Green, color.Blue);
    }
}

// 遍历所有图像帧
for (int i = 0; i < gif->ImageCount; i++) {
    SavedImage *image = &gif->SavedImages[i];
    LOGI("图像 #%d", i);
    LOGI("  宽度: %d", image->ImageDesc.Width);
    LOGI("  高度: %d", image->ImageDesc.Height);
    
    // 访问扩展块
    for (int j = 0; j < image->ExtensionBlockCount; j++) {
        ExtensionBlock *ext = &image->ExtensionBlocks[j];
        if (ext->Function == GRAPHICS_EXT_FUNC_CODE) {
            // 解析图形控制扩展块
            int delay = ext->Bytes[1] | (ext->Bytes[2] << 8);
            LOGI("  延迟时间: %d/100秒", delay);
        }
    }
}

// 关闭 GIF 文件
if (DGifCloseFile(gif, &error) != GIF_OK) {
    LOGI("关闭GIF文件时出错: %s", GifErrorString(error));
    return 1;
}

GIF 数据结构说明

GifFileType 结构

GIF 文件的主要结构,包含以下重要字段:

  • SWidth, SHeight: 逻辑屏幕宽度和高度

  • SColorResolution: 颜色分辨率(位数)

  • SBackGroundColor: 背景色索引

  • ImageCount: 图像帧数量

  • SColorMap: 全局调色板指针

  • SavedImages: 保存的图像数组

SavedImage 结构

每个图像帧的信息:

  • ImageDesc: 图像描述符(位置、尺寸、交错标志等)

  • RasterBits: 图像像素数据

  • ExtensionBlocks: 扩展块数组

  • ExtensionBlockCount: 扩展块数量

扩展块类型

  • GRAPHICS_EXT_FUNC_CODE: 图形控制扩展块,包含处理方式、透明度、延迟时间等信息

  • COMMENT_EXT_FUNC_CODE: 注释扩展块

  • PLAIN_TEXT_EXT_FUNC_CODE: 纯文本扩展块

  • APPLICATION_EXT_FUNC_CODE: 应用程序扩展块

配置说明

必需配置

  • CONFIG_SDK_MODULE_GIFLIB=y: 启用 GifLib 模块

可选配置

  • CONFIG_MEM_CONFIG=y: 启用内存配置(如果需要)

注意事项

  1. 内存读取函数: 使用 DGifOpen() 时,可以提供自定义读取函数从内存、网络或其他数据源读取 GIF 数据,而不是从文件系统读取

  2. 错误处理: 所有 GifLib API 在失败时会设置错误代码,使用 GifErrorString() 可以获取可读的错误描述

  3. 资源管理: 使用 DGifOpen() 打开 GIF 后,必须使用 DGifCloseFile() 关闭并释放资源

  4. DGifSlurp 使用: DGifSlurp() 会将整个 GIF 文件解析到内存中,适合处理较小的 GIF 文件;对于大文件,可能需要使用流式读取方式

  5. 调色板访问: 图像可以使用全局调色板(gif->SColorMap)或局部调色板(image->ImageDesc.ColorMap),访问前应检查指针是否为 NULL

  6. 扩展块解析: 扩展块的数据格式取决于功能码,图形控制扩展块(GRAPHICS_EXT_FUNC_CODE)的格式是固定的,其他扩展块格式可能不同

  7. 像素数据: SavedImage->RasterBits 包含解码后的像素数据,每个像素是一个索引值,需要通过调色板转换为 RGB 颜色

  8. 交错图像: 如果 ImageDesc.Interlace 为真,图像是交错存储的,需要按照 GIF 规范的交错顺序进行解码