[Windows编程]使用 WIC 实现图片的加载与存储
使用 WIC 实现图片的加载与存储
一、概述
WICImage 是一个基于 Windows Imaging Component (WIC) 的图片编解码库,提供了简洁的 C 语言接口用于加载和保存多种格式的图片文件。本文将详细介绍其使用流程、核心数据结构以及完整的代码示例。
二、核心数据结构
1. WICColorFormat - 颜色格式枚举
定义了解码输出和编码输入的像素颜色格式:
typedef enum WICColorFormat
{
WICColor_24RGB = 0x00010318, ///< 24位 RGB 格式
WICColor_24BGR = 0x00020318, ///< 24位 BGR 格式
WICColor_32RGBA = 0x00030420, ///< 32位 RGBA 格式
WICColor_32BGRA = 0x00040420, ///< 32位 BGRA 格式
} WICColorFormat;
辅助宏:
WIC_COLOR_BITS(format)- 获取每像素比特数(24 或 32)WIC_COLOR_NUMC(format)- 获取通道数量(3 或 4)WIC_ALIGN4(x)- 4 字节对齐
2. WICFileFormat - 文件格式枚举
定义了支持的输出文件格式:
typedef enum WICFileFormat
{
WICFile_NONE = 0x00000000, ///< 未指定格式(根据扩展名自动判断)
WICFile_BMP = 0x00010001, ///< BMP 格式
WICFile_JPEG = 0x00020001, ///< JPEG 格式
WICFile_PNG = 0x00030001, ///< PNG 格式
WICFile_GIF = 0x00040001, ///< GIF 格式
WICFile_TIFF = 0x00050001, ///< TIFF 格式
} WICFileFormat;
3. WICImageInfo - 图片信息结构体
用于传递图片像素数据和相关参数:
typedef struct WICImageInfo
{
LPBYTE hBuffer; ///< 像素数据缓冲区
UINT nLength; ///< 像素数据缓冲区长度
UINT nStride; ///< 行间距(每行字节数)
UINT cFormat; ///< 颜色格式
UINT nImageW; ///< 图片宽度
UINT nImageH; ///< 图片高度
} WICImageInfo, * HWICImageInfo;
行距最小值计算宏:
#define WIC_MIN_STRIDE(hImageInfo) \
WIC_ALIGN4((hImageInfo)->nImageW * WIC_COLOR_NUMC((hImageInfo)->cFormat))
4. WICAllocator - 缓冲区管理器
用于自定义缓冲区的分配和释放:
typedef struct WICAllocator
{
WIC_ALLOC xFnAlloc; ///< 缓冲区分配函数
WIC_FREE xFnFree; ///< 缓冲区释放函数
DWORD_PTR dwContext; ///< 上下文参数
} WICAllocator, * HWICAllocator;
默认实现:
WICAllocator_DefaultAlloc()- 使用malloc分配WICAllocator_DefaultFree()- 使用free释放
三、使用流程
1. 初始化 COM 库
在使用 WICImage 之前,必须先初始化 COM 库:
#include <Windows.h>
// 初始化 COM 库(通常在程序启动时调用)
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2. 创建 WICImage 对象
HWICImage hWICImage = WICImage_Create();
if (NULL == hWICImage)
{
// 创建失败,处理错误
return -1;
}
3. 加载图片(解码流程)
步骤说明:
- 配置
WICImageInfo(cFormat为必填项) - 设置
WICAllocator(可使用默认实现) - 调用
WICImage_LoadFromFile()
完整示例:
#include "WICImage.h"
#include <stdio.h>
BOOL LoadImageExample(LPCWSTR wzFileName)
{
HWICImage hWICImage = NULL;
WICImageInfo stImageInfo = { 0 };
WICAllocator stAllocator = { 0 };
// 1. 创建 WICImage 对象
hWICImage = WICImage_Create();
if (NULL == hWICImage)
return FALSE;
// 2. 配置颜色格式(必填)
stImageInfo.cFormat = WICColor_32BGRA; // 解码为 32 位 BGRA 格式
// 3. 配置缓冲区管理器(使用默认实现)
stAllocator.xFnAlloc = WICAllocator_DefaultAlloc;
stAllocator.xFnFree = WICAllocator_DefaultFree;
stAllocator.dwContext = 0;
// 4. 加载图片(bFlipV = FALSE 表示不垂直翻转)
if (!WICImage_LoadFromFile(
hWICImage,
wzFileName,
FALSE, // 是否垂直翻转
&stImageInfo,
&stAllocator))
{
printf("Failed to load image!\n");
WICImage_Destroy(hWICImage);
return FALSE;
}
// 5. 使用图片数据
printf("Image loaded successfully!\n");
printf("Width : %u\n", stImageInfo.nImageW);
printf("Height : %u\n", stImageInfo.nImageH);
printf("Stride : %u\n", stImageInfo.nStride);
printf("Format : 32BGRA\n");
// 图片像素数据存储在 stImageInfo.hBuffer 中
// 每行数据长度为 stImageInfo.nStride
// 总数据长度为 stImageInfo.nLength
// 6. 释放缓冲区(使用自定义的释放函数)
if (NULL != stImageInfo.hBuffer)
{
stAllocator.xFnFree(
stImageInfo.hBuffer,
stImageInfo.nLength,
stAllocator.dwContext
);
}
// 7. 销毁 WICImage 对象
WICImage_Destroy(hWICImage);
return TRUE;
}
垂直翻转选项说明:
bFlipV 参数控制是否垂直翻转图片。在某些场景下(如 OpenGL/DirectX 纹理加载),由于坐标系方向差异,需要对图片进行垂直翻转:
// 加载图片并垂直翻转(适用于纹理加载场景)
WICImage_LoadFromFile(hWICImage, wzFileName, TRUE, &stImageInfo, &stAllocator);
4. 保存图片(编码流程)
步骤说明:
- 填充
WICImageInfo的所有必填字段 - 调用
WICImage_SaveToFile()
完整示例:
BOOL SaveImageExample(
LPCWSTR wzFileName,
LPBYTE hPixelBuffer,
UINT nWidth,
UINT nHeight,
UINT nStride)
{
HWICImage hWICImage = NULL;
WICImageInfo stImageInfo = {0};
// 1. 创建 WICImage 对象
hWICImage = WICImage_Create();
if (NULL == hWICImage)
return FALSE;
// 2. 配置图片信息(所有字段均为必填)
stImageInfo.hBuffer = hPixelBuffer; // 像素数据缓冲区
stImageInfo.nLength = nStride * nHeight; // 总数据长度
stImageInfo.nStride = nStride; // 行间距
stImageInfo.cFormat = WICColor_32BGRA; // 颜色格式
stImageInfo.nImageW = nWidth; // 图片宽度
stImageInfo.nImageH = nHeight; // 图片高度
// 3. 保存图片
// 方式一:指定文件格式
if (!WICImage_SaveToFile(
hWICImage,
&stImageInfo,
FALSE, // 是否垂直翻转
wzFileName,
WICFile_PNG)) // 指定 PNG 格式
{
printf("Failed to save image!\n");
WICImage_Destroy(hWICImage);
return FALSE;
}
// 方式二:根据文件扩展名自动判断格式
// WICImage_SaveToFile(hWICImage, &stImageInfo, FALSE, wzFileName, WICFile_NONE);
printf("Image saved successfully!\n");
// 4. 销毁 WICImage 对象
WICImage_Destroy(hWICImage);
return TRUE;
}
四、完整应用示例
以下是一个完整的图片格式转换示例:
#include <Windows.h>
#include <stdio.h>
#include "WICImage.h"
int wmain(int argc, wchar_t* argv[])
{
if (argc != 3)
{
printf("Usage: WICImageDemo <input_image> <output_image>\n");
return -1;
}
// 1. 初始化 COM 库
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HWICImage hWICImage = NULL;
WICImageInfo stImageInfo = { 0 };
WICAllocator stAllocator = { 0 };
// 2. 创建 WICImage 对象
hWICImage = WICImage_Create();
if (NULL == hWICImage)
{
printf("Failed to create WICImage!\n");
CoUninitialize();
return -1;
}
// 3. 配置加载参数
stImageInfo.cFormat = WICColor_32BGRA;
stAllocator.xFnAlloc = WICAllocator_DefaultAlloc;
stAllocator.xFnFree = WICAllocator_DefaultFree;
stAllocator.dwContext = 0;
// 4. 加载源图片
printf("Loading image: %ls\n", argv[1]);
if (!WICImage_LoadFromFile(hWICImage, argv[1], FALSE, &stImageInfo, &stAllocator))
{
printf("Failed to load image!\n");
WICImage_Destroy(hWICImage);
CoUninitialize();
return -1;
}
printf("Image info: %ux%u, %u bytes per row\n",
stImageInfo.nImageW, stImageInfo.nImageH, stImageInfo.nStride);
// 5. 保存为新格式(根据扩展名自动判断)
printf("Saving image: %ls\n", argv[2]);
if (!WICImage_SaveToFile(hWICImage, &stImageInfo, FALSE, argv[2], WICFile_NONE))
{
printf("Failed to save image!\n");
stAllocator.xFnFree(stImageInfo.hBuffer, stImageInfo.nLength, 0);
WICImage_Destroy(hWICImage);
CoUninitialize();
return -1;
}
// 6. 清理资源
stAllocator.xFnFree(stImageInfo.hBuffer, stImageInfo.nLength, 0);
WICImage_Destroy(hWICImage);
CoUninitialize();
printf("Conversion completed successfully!\n");
return 0;
}
五、依赖库
wincodec.lib- WIC 库
六、注意事项
- COM 初始化:使用前必须调用
CoInitializeEx(),使用完后调用CoUninitialize() - 缓冲区管理:加载图片时,缓冲区由
WICAllocator管理,使用完毕后需要调用对应的释放函数 - 垂直翻转:OpenGL/DirectX 纹理坐标系与图片坐标系不同,加载纹理时通常需要设置
bFlipV = TRUE - 格式支持:支持 BMP、JPEG、PNG、GIF、TIFF 格式的读取和写入
- 行对齐:行间距(stride)必须是 4 的倍数;为 0 时,内部通过
WIC_MIN_STRIDE(info)计算最小行间距进行对齐
七、API 速查表
| 函数 | 功能 |
|---|---|
WICImage_Create() |
创建 WICImage 对象 |
WICImage_Destroy() |
销毁 WICImage 对象 |
WICImage_LoadFromFile() |
从文件加载图片 |
WICImage_SaveToFile() |
保存图片到文件 |
| 辅助宏 | 功能 |
|---|---|
WIC_COLOR_BITS(format) |
获取每像素比特数 |
WIC_COLOR_NUMC(format) |
获取通道数量 |
WIC_ALIGN4(x) |
4 字节对齐 |
WIC_MIN_STRIDE(info) |
计算最小行间距 |
| 默认函数 | 功能 |
|---|---|
WICAllocator_DefaultAlloc() |
默认缓冲区分配 |
WICAllocator_DefaultFree() |
默认缓冲区释放 |

浙公网安备 33010602011771号