这是一个玩具性质库,为了把png, wav, ttf文件转成c code,或者做反转操作
stb_bin2c.h
#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)
#define MAX_PATH 260
#include <windows.h>
#else
#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
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);
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 #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)GetModuleFileNameA(NULL, out_dir, (DWORD)dir_size);char* last_sep = strrchr(out_dir, STB_BIN2C_PATH_SEP);if (last_sep) *last_sep = '\0';
#elseif (!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);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
准备文件
- logo.png
- alert.wav
- IosevkaNerdFont.tff
- 或者修改源码
resource_converter.c
#define STB_BIN2C_IMPLEMENTATION
#include "stb_bin2c.h"
#include <stdio.h>int main() {int png_ok = png_to_c_header("logo.png", "image.h", "logo_png" );if (png_ok) {printf("PNG转换成功:生成 image.h\n");} else {printf("PNG转换失败:检查文件路径或权限\n");}int font_ok = font_to_c_header("IosevkaNerdFont.ttf", "font.h", "main_font" );if (font_ok) {printf("字体转换成功:生成 font.h\n");} else {printf("字体转换失败:检查文件路径或权限\n");}int audio_ok = audio_to_c_header("alert.wav", "sound.h", "alert_sound" );if (audio_ok) {printf("音频转换成功:生成 sound.h\n");} else {printf("音频转换失败:检查文件路径或权限\n");}int bin_ok = bin_to_c_header("data.bin", "data.h", "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"
#include "font.h"
#include "sound.h" int main() {int png_ok = c_header_to_png(logo_png, logo_png_size, "output.png" );if (png_ok) {printf("PNG解包成功:生成 output.png\n");}int font_ok = c_header_to_font(main_font,main_font_size,"extracted_font.ttf");if (font_ok) {printf("字体解包成功:生成 extracted_font.ttf\n");}char temp_audio_path[MAX_PATH];int temp_ok = c_header_to_temp(alert_sound, alert_sound_size, "wav", temp_audio_path, sizeof(temp_audio_path) );if (temp_ok) {printf("音频解包到临时文件:%s\n", temp_audio_path);}return 0;
}
编译测试
PNG转换成功:生成 image.h
字体转换成功:生成 font.h
音频转换成功:生成 sound.hPNG解包成功:生成 output.png
字体解包成功:生成 extracted_font.ttf
音频解包到临时文件:C:\tmp_1755609664.wav
通用bin2c.c 命令行程序(没有测试)
#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"; 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;}
}