当前位置: 首页 > news >正文

make stb style code: bin2c and reverse

这是一个玩具性质库,为了把png, wav, ttf文件转成c code,或者做反转操作

stb_bin2c.h

/*stb_bin2c.h - 跨平台STB风格资源转换库功能:二进制文件与C数组的双向转换
*/#ifndef STB_BIN2C_H
#define STB_BIN2C_H#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>// 跨平台必要头文件和宏定义
#if defined(_WIN32) || defined(_WIN64)
// https://blog.csdn.net/louObaichu/article/details/140496066
#define MAX_PATH 260
// Windows系统:引入必要头文件
#include <windows.h>
#else
// 类Unix系统(macOS/Linux):定义缺失的Windows宏
#define MAX_PATH 260
#define _stricmp strcasecmp
#endif// 跨平台路径分隔符
#if defined(_WIN32) || defined(_WIN64)
#define STB_BIN2C_PATH_SEP '\\'
#else
#define STB_BIN2C_PATH_SEP '/'
#endif#ifdef __cplusplus
extern "C" {
#endif// -------------------------- 正向转换:资源文件 → C头文件 --------------------------
int png_to_c_header(const char* input_png_path, const char* output_h_path, const char* var_name);
int font_to_c_header(const char* input_font_path, const char* output_h_path, const char* var_name);
int audio_to_c_header(const char* input_audio_path, const char* output_h_path, const char* var_name);
int bin_to_c_header(const char* input_bin_path, const char* output_h_path, const char* var_name);// -------------------------- 反向转换:C数组 → 资源文件 --------------------------
int c_header_to_png(const unsigned char* data, size_t data_len, const char* output_png_path);
int c_header_to_font(const unsigned char* data, size_t data_len, const char* output_font_path);
int c_header_to_audio(const unsigned char* data, size_t data_len, const char* output_audio_path);
int c_header_to_bin(const unsigned char* data, size_t data_len, const char* output_bin_path);// -------------------------- 临时文件解包 --------------------------
int c_header_to_temp(const unsigned char* data, size_t data_len, const char* ext, char* out_temp_path, size_t out_temp_path_size);#ifdef __cplusplus
}
#endif#endif // STB_BIN2C_H#ifdef STB_BIN2C_IMPLEMENTATION// -------------------------- 辅助函数:获取文件大小 --------------------------
static size_t stb_bin2c_get_file_size(const char* file_path) {FILE* fp = fopen(file_path, "rb");if (!fp) return 0;fseek(fp, 0, SEEK_END);size_t size = ftell(fp);fclose(fp);return size;
}// -------------------------- 辅助函数:读取文件到内存 --------------------------
static unsigned char* stb_bin2c_read_file(const char* file_path, size_t* out_len) {*out_len = 0;FILE* fp = fopen(file_path, "rb");if (!fp) return NULL;size_t size = stb_bin2c_get_file_size(file_path);if (size == 0) {fclose(fp);return NULL;}unsigned char* buf = (unsigned char*)malloc(size);if (!buf) {fclose(fp);return NULL;}size_t read = fread(buf, 1, size, fp);fclose(fp);if (read != size) {free(buf);return NULL;}*out_len = size;return buf;
}// -------------------------- 辅助函数:获取程序当前目录 --------------------------
static void stb_bin2c_get_current_dir(char* out_dir, size_t dir_size) {
#if defined(_WIN32) || defined(_WIN64)// Windows:通过系统API获取程序路径GetModuleFileNameA(NULL, out_dir, (DWORD)dir_size);// 移除文件名,保留目录char* last_sep = strrchr(out_dir, STB_BIN2C_PATH_SEP);if (last_sep) *last_sep = '\0';
#else// 类Unix:使用getcwd获取当前工作目录if (!getcwd(out_dir, dir_size)) {strncpy(out_dir, ".", dir_size - 1);out_dir[dir_size - 1] = '\0';}
#endif
}// -------------------------- 通用正向转换实现 --------------------------
static int stb_bin2c_gen_header(const char* input_path, const char* output_path, const char* var_name, const char* type_desc) {if (!input_path || !output_path || !var_name || strlen(var_name) == 0) {return 0;}size_t data_len;unsigned char* data = stb_bin2c_read_file(input_path, &data_len);if (!data || data_len == 0) {return 0;}FILE* fp = fopen(output_path, "w");if (!fp) {free(data);return 0;}// 生成防重复包含宏char guard[128];snprintf(guard, sizeof(guard), "%s_H", var_name);for (size_t i = 0; guard[i]; i++) {if (guard[i] == '-' || guard[i] == '.' || guard[i] == ' ') {guard[i] = '_';}}// 写入头文件内容fprintf(fp, "// 自动生成:%s → C头文件\n", type_desc);fprintf(fp, "#ifndef %s\n", guard);fprintf(fp, "#define %s\n\n", guard);fprintf(fp, "const unsigned char %s[] = {\n", var_name);// 写入数组数据(每行16个元素)for (size_t i = 0; i < data_len; i++) {fprintf(fp, "0x%02X", data[i]);if (i != data_len - 1) fprintf(fp, ", ");if ((i + 1) % 16 == 0) fprintf(fp, "\n");}// 写入数组长度fprintf(fp, "\n};\n");fprintf(fp, "const size_t %s_size = %zu;\n\n", var_name, data_len);fprintf(fp, "#endif // %s\n", guard);fclose(fp);free(data);return 1;
}// -------------------------- 正向转换函数实现 --------------------------
int png_to_c_header(const char* input_png_path, const char* output_h_path, const char* var_name) {const char* ext = strrchr(input_png_path, '.');if (!ext || _stricmp(ext, ".png") != 0) return 0;return stb_bin2c_gen_header(input_png_path, output_h_path, var_name, "PNG图像文件");
}int font_to_c_header(const char* input_font_path, const char* output_h_path, const char* var_name) {const char* ext = strrchr(input_font_path, '.');if (!ext || (_stricmp(ext, ".ttf") != 0 && _stricmp(ext, ".otf") != 0)) return 0;return stb_bin2c_gen_header(input_font_path, output_h_path, var_name, "字体文件");
}int audio_to_c_header(const char* input_audio_path, const char* output_h_path, const char* var_name) {const char* ext = strrchr(input_audio_path, '.');if (!ext || (_stricmp(ext, ".wav") != 0 && _stricmp(ext, ".mp3") != 0)) return 0;return stb_bin2c_gen_header(input_audio_path, output_h_path, var_name, "音频文件");
}int bin_to_c_header(const char* input_bin_path, const char* output_h_path, const char* var_name) {return stb_bin2c_gen_header(input_bin_path, output_h_path, var_name, "通用二进制文件");
}// -------------------------- 反向转换函数实现 --------------------------
int c_header_to_png(const unsigned char* data, size_t data_len, const char* output_png_path) {return c_header_to_bin(data, data_len, output_png_path);
}int c_header_to_font(const unsigned char* data, size_t data_len, const char* output_font_path) {return c_header_to_bin(data, data_len, output_font_path);
}int c_header_to_audio(const unsigned char* data, size_t data_len, const char* output_audio_path) {return c_header_to_bin(data, data_len, output_audio_path);
}int c_header_to_bin(const unsigned char* data, size_t data_len, const char* output_bin_path) {if (!data || data_len == 0 || !output_bin_path) return 0;FILE* fp = fopen(output_bin_path, "wb");if (!fp) return 0;size_t written = fwrite(data, 1, data_len, fp);fclose(fp);return (written == data_len) ? 1 : 0;
}// -------------------------- 临时文件解包实现 --------------------------
int c_header_to_temp(const unsigned char* data, size_t data_len, const char* ext, char* out_temp_path, size_t out_temp_path_size) {if (!data || data_len == 0 || !ext || !out_temp_path || out_temp_path_size < 32) return 0;char current_dir[MAX_PATH] = {0};stb_bin2c_get_current_dir(current_dir, sizeof(current_dir));// 生成唯一临时文件名time_t now = time(NULL);snprintf(out_temp_path, out_temp_path_size, "%s%ctmp_%lld.%s", current_dir, STB_BIN2C_PATH_SEP, (long long)now, ext);// 移除路径中的空格for (size_t i = 0; out_temp_path[i]; i++) {if (out_temp_path[i] == ' ') out_temp_path[i] = '_';}return c_header_to_bin(data, data_len, out_temp_path);
}#endif // STB_BIN2C_IMPLEMENTATION

准备文件

  1. logo.png
  2. alert.wav
  3. IosevkaNerdFont.tff
  4. 或者修改源码

resource_converter.c

#define STB_BIN2C_IMPLEMENTATION
#include "stb_bin2c.h"
#include <stdio.h>int main() {// 1. 转换PNG图片为C头文件// 对应CLI:bin2c.exe logo.png image.h logo_pngint png_ok = png_to_c_header("logo.png",       // 输入PNG文件路径"image.h",        // 输出C头文件路径"logo_png"        // 生成的C数组变量名);if (png_ok) {printf("PNG转换成功:生成 image.h\n");} else {printf("PNG转换失败:检查文件路径或权限\n");}// 2. 转换TTF字体为C头文件// 对应CLI:bin2c.exe IosevkaNerdFont.ttf font.h main_fontint font_ok = font_to_c_header("IosevkaNerdFont.ttf",  // 输入字体文件路径"font.h",               // 输出C头文件路径"main_font"             // 生成的C数组变量名);if (font_ok) {printf("字体转换成功:生成 font.h\n");} else {printf("字体转换失败:检查文件路径或权限\n");}// 3. 转换WAV音频为C头文件// 对应CLI:bin2c.exe alert.wav sound.h alert_soundint audio_ok = audio_to_c_header("alert.wav",      // 输入音频文件路径"sound.h",        // 输出C头文件路径"alert_sound"     // 生成的C数组变量名);if (audio_ok) {printf("音频转换成功:生成 sound.h\n");} else {printf("音频转换失败:检查文件路径或权限\n");}// 4. 转换任意二进制文件(示例:数据文件)int bin_ok = bin_to_c_header("data.bin",       // 输入二进制文件"data.h",         // 输出C头文件"raw_data"        // 变量名);if (bin_ok) {printf("二进制文件转换成功:生成 data.h\n");}return 0;
}

resource_unpacker.c

#define STB_BIN2C_IMPLEMENTATION
#include "stb_bin2c.h"
#include <stdio.h>// 引入转换后的资源头文件(上面步骤生成的)
#include "image.h"    // 包含 logo_png[] 和 logo_png_size
#include "font.h"     // 包含 main_font[] 和 main_font_size
#include "sound.h"    // 包含 alert_sound[] 和 alert_sound_sizeint main() {// 1. 解包PNG到指定文件(保存为 output.png)int png_ok = c_header_to_png(logo_png,             // C数组数据logo_png_size,        // 数据长度"output.png"          // 输出文件路径);if (png_ok) {printf("PNG解包成功:生成 output.png\n");}// 2. 解包字体到程序当前目录(保存为 extracted_font.ttf)int font_ok = c_header_to_font(main_font,main_font_size,"extracted_font.ttf");if (font_ok) {printf("字体解包成功:生成 extracted_font.ttf\n");}// 3. 解包音频到临时文件(自动生成唯一路径,适合程序运行时使用)char temp_audio_path[MAX_PATH];int temp_ok = c_header_to_temp(alert_sound,          // C数组数据alert_sound_size,     // 数据长度"wav",                // 临时文件扩展名temp_audio_path,      // 输出临时路径缓冲区sizeof(temp_audio_path)  // 缓冲区大小);if (temp_ok) {printf("音频解包到临时文件:%s\n", temp_audio_path);// 此处可添加播放音频的代码(如使用SDL或系统API)}return 0;
}

编译测试

  • 编译直接gcc编译,只在Windows测试过
PNG转换成功:生成 image.h
字体转换成功:生成 font.h
音频转换成功:生成 sound.hPNG解包成功:生成 output.png
字体解包成功:生成 extracted_font.ttf
音频解包到临时文件:C:\tmp_1755609664.wav
  • 打开文件观察,确实能转换回来,哈哈

通用bin2c.c 命令行程序(没有测试)

/*bin2c - 基于stb_bin2c库的资源转换命令行工具功能:将任意二进制文件转换为C头文件(包含数组和长度变量)用法:bin2c <输入文件> <输出头文件> <变量名> [类型标记]类型标记:png/font/audio/bin(默认bin,用于格式校验)示例:bin2c logo.png image.h logo_png pngbin2c font.ttf font.h main_font fontbin2c sound.wav sound.h alert_sound audiobin2c data.bin data.h raw_data*/#define STB_BIN2C_IMPLEMENTATION
#include "stb_bin2c.h"
#include <stdio.h>
#include <string.h>// 显示帮助信息
static void print_help(const char* program_name) {printf("bin2c - 二进制文件转C头文件工具\n");printf("用法:%s <输入文件> <输出头文件> <变量名> [类型标记]\n", program_name);printf("类型标记(可选):\n");printf("  png    - 校验输入文件为PNG格式\n");printf("  font   - 校验输入文件为TTF/OTF字体\n");printf("  audio  - 校验输入文件为WAV/MP3音频\n");printf("  bin    - 不校验格式(默认)\n");printf("示例:\n");printf("  %s image.png img.h my_image png\n", program_name);printf("  %s music.wav sound.h bgm audio\n", program_name);
}int main(int argc, char* argv[]) {// 检查命令行参数if (argc < 4) {fprintf(stderr, "错误:参数不足!\n");print_help(argv[0]);return 1;}// 解析参数const char* input_file = argv[1];const char* output_file = argv[2];const char* var_name = argv[3];const char* type = (argc >= 5) ? argv[4] : "bin";  // 默认类型为bin// 执行转换int result = 0;if (strcmp(type, "png") == 0) {result = png_to_c_header(input_file, output_file, var_name);} else if (strcmp(type, "font") == 0) {result = font_to_c_header(input_file, output_file, var_name);} else if (strcmp(type, "audio") == 0) {result = audio_to_c_header(input_file, output_file, var_name);} else if (strcmp(type, "bin") == 0) {result = bin_to_c_header(input_file, output_file, var_name);} else {fprintf(stderr, "错误:未知类型标记 '%s'\n", type);print_help(argv[0]);return 1;}// 输出结果if (result) {printf("成功:已生成 %s\n", output_file);printf("变量名:%s 和 %s_size\n", var_name, var_name);return 0;} else {fprintf(stderr, "失败:无法生成 %s\n", output_file);fprintf(stderr, "可能原因:文件不存在、权限不足或格式不匹配\n");return 1;}
}
http://www.dtcms.com/a/339818.html

相关文章:

  • 开发中使用——APP层级相关知识
  • bit-Agent正式接入GPT-5,九科信息智能体能力再升级!
  • 海滨浴场应急广播:守护碧海蓝天的安全防线
  • 皮带跑偏?智慧煤矿靠AI摄像机+检测算法实现实时预警
  • Docker学习--常用命令
  • vue3动态获取高度用在轮播图上
  • Diamond开发经验(1)
  • 代码随想录刷题Day37
  • C++的二叉搜索树(二叉排序树)
  • AC 应用控制技术
  • Vulkan笔记(十一)-渲染通道(RenderPass)详解
  • 厂区能源管理智能化改造物联网解决方案
  • 沈昕医编---因为上岸了医疗编,来说一下e类联考的强度
  • YggJS RLogin暗黑霓虹主题登录注册页面 版本:v0.1.1
  • js 怎么调用 deepseekAPI
  • 雷卯针对香橙派Orange Pi 5 Pro开发板防雷防静电方案
  • 从密度到聚类:DBSCAN算法的第一性原理解析
  • MyCAT2的主从配置
  • Ubuntu、CentOS、AlmaLinux 9.5的 rc.local实现 开机启动
  • 第2章 组件设计与架构
  • IEEE GRSM 2025:Vision Foundation Models in Remote Sensing
  • 基于 STM32 和 NB-IoT 的智慧家居多设备联动控制系统设计
  • Windows Server DNS优化,网络响应速度提升方案
  • 让AI学会“边做边想“:ReAct的实战指南
  • 前端 React 实现数据懒加载-滚动触底加载数据
  • Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
  • 移动端网页调试实战,内存泄漏问题的发现与优化
  • Qt原对象系统工作机制
  • 运维面试题
  • LWIP协议栈实现ARP协议