stb_image与stb_image_write是轻量跨平台首选方案;gdi+仅限windows且初始化复杂易出错。stb方案单头文件、免编译、支持多格式读写,需注意通道顺序、手动释放内存及alpha处理;gdi+适合缩放/水印等高级操作,但依赖com、unicode路径和编码器clsid,错误提示不明确。

直接用 stb_image 和 stb_image_write 是最轻量、跨平台、无依赖的方案;GDI+ 仅限 Windows,且需手动初始化/清理,容易内存泄漏或初始化失败。
用 stb_image + stb_image_write 一次性读写转换
这是绝大多数 C++ 项目首选:单头文件、无需编译、支持 PNG/JPEG/BMP/TGA/PSD/GIF(读)和 PNG/JPEG/BMP/TGA(写)。关键点是注意色彩通道顺序和内存管理。
-
stbi_load()默认返回 RGB 或 RGBA 数据(取决于图片),但 JPEG 总是 RGB,PNG 可能是 RGBA —— 转换前先用int channels参数确认源格式 - 写入时若目标格式不支持 Alpha(如 JPEG),需手动丢弃 A 通道:
stbi_write_jpg(..., data, w, h, 3, ...) - 务必调用
stbi_image_free(ptr)释放stbi_load()分配的内存,否则每次转换都泄漏 - 示例:BMP → JPEG
int w, h, comp; unsigned char* img = stbi_load("in.bmp", &w, &h, &comp, 0); // comp=3 or 4 if (img) { stbi_write_jpg("out.jpg", w, h, comp, img, 95); // 95=quality stbi_image_free(img); }
GDI+ 在 Windows 上做有损转换(如缩放+转格式)
GDI+ 适合需要插值缩放、旋转、加文字水印后再保存的场景,但初始化繁琐,错误码不直观,且对 JPEG 压缩质量控制较弱。
- 必须调用
GdiplusStartup(),并保存ULONG_PTR gdiplusToken,结束前调用GdiplusShutdown(gdiplusToken) - 加载图像用
Gdiplus::Image::FromFile(),但路径必须是宽字符(L"xxx"),ANSI 路径会静默失败 - 保存时需通过
GetEncoderClsid(L"image/jpeg", &clsid)获取编码器 CLSID,硬编码 CLSID 极易出错 - JPEG 质量靠
EncoderQuality参数传入,但需构造EncoderParameters结构体,稍不注意就崩溃
常见报错与绕过方式
两类库都常因路径、内存、编解码器缺失失败,但表现不同:
立即学习“C++免费学习笔记(深入)”;
-
stbi_load()返回nullptr:检查文件是否存在、是否被占用、扩展名是否匹配真实格式(如 .jpg 文件实际是 WebP) -
Gdiplus::Image::FromFile()返回NULL或状态码InvalidParameter:大概率是路径没用L""包裹,或当前线程未启用 COM(需CoInitialize(NULL)) -
stbi_write_png()写出黑图:确认传入的data指针有效、w/h正确、且数据是 8-bit 未压缩原始像素(非 OpenGL 纹理绑定后的指针) - Windows 上 GDI+ 保存 JPEG 失败且无提示:确保系统有
WindowsCodecs.dll(Win7+ 默认有,XP 需额外部署)
真正麻烦的不是调用函数,而是处理不一致的通道数、隐式内存生命周期、以及 Windows 下 GDI+ 对 Unicode 路径和 COM 环境的强依赖——这些地方一漏,程序就静默失败或崩溃,调试时得逐行打日志看哪个指针为空、哪个 API 返回了非零状态码。










