# WICImage **Repository Path**: Gaaagaa/wicimage ## Basic Information - **Project Name**: WICImage - **Description**: Windows环境下,使用WIC组件进行图片的加载和存储(编码/解码)。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-01 - **Last Updated**: 2026-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 使用 WIC 实现图片的加载与存储 ### 一、概述 WICImage 是一个基于 Windows Imaging Component (WIC) 的图片编解码库,提供了简洁的 C 语言接口用于加载和保存多种格式的图片文件。本文将详细介绍其使用流程、核心数据结构以及完整的代码示例。 *** ### 二、核心数据结构 #### 1. WICColorFormat - 颜色格式枚举 定义了解码输出和编码输入的像素颜色格式: ```C 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 - 文件格式枚举 定义了支持的输出文件格式: ```C 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 - 图片信息结构体 用于传递图片像素数据和相关参数: ```C typedef struct WICImageInfo { LPBYTE hBuffer; ///< 像素数据缓冲区 UINT nLength; ///< 像素数据缓冲区长度 UINT nStride; ///< 行间距(每行字节数) UINT cFormat; ///< 颜色格式 UINT nImageW; ///< 图片宽度 UINT nImageH; ///< 图片高度 } WICImageInfo, * HWICImageInfo; ``` **行距最小值计算宏**: ```C #define WIC_MIN_STRIDE(hImageInfo) \ WIC_ALIGN4((hImageInfo)->nImageW * WIC_COLOR_NUMC((hImageInfo)->cFormat)) ``` #### 4. WICAllocator - 缓冲区管理器 用于自定义缓冲区的分配和释放: ```C typedef struct WICAllocator { WIC_ALLOC xFnAlloc; ///< 缓冲区分配函数 WIC_FREE xFnFree; ///< 缓冲区释放函数 DWORD_PTR dwContext; ///< 上下文参数 } WICAllocator, * HWICAllocator; ``` **默认实现**: - `WICAllocator_DefaultAlloc()` - 使用 `malloc` 分配 - `WICAllocator_DefaultFree()` - 使用 `free` 释放 *** ### 三、使用流程 #### 1. 初始化 COM 库 在使用 WICImage 之前,必须先初始化 COM 库: ```C #include // 初始化 COM 库(通常在程序启动时调用) CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); ``` #### 2. 创建 WICImage 对象 ```C HWICImage hWICImage = WICImage_Create(); if (NULL == hWICImage) { // 创建失败,处理错误 return -1; } ``` #### 3. 加载图片(解码流程) **步骤说明**: 1. 配置 `WICImageInfo`(`cFormat` 为必填项) 2. 设置 `WICAllocator`(可使用默认实现) 3. 调用 `WICImage_LoadFromFile()` **完整示例**: ```C #include "WICImage.h" #include 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 纹理加载),由于坐标系方向差异,需要对图片进行垂直翻转: ```C // 加载图片并垂直翻转(适用于纹理加载场景) WICImage_LoadFromFile(hWICImage, wzFileName, TRUE, &stImageInfo, &stAllocator); ``` #### 4. 保存图片(编码流程) **步骤说明**: 1. 填充 `WICImageInfo` 的所有必填字段 2. 调用 `WICImage_SaveToFile()` **完整示例**: ```C 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; } ``` *** ### 四、完整应用示例 以下是一个完整的图片格式转换示例: ```C #include #include #include "WICImage.h" int wmain(int argc, wchar_t* argv[]) { if (argc != 3) { printf("Usage: WICImageDemo \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 库 *** ### 六、注意事项 1. **COM 初始化**:使用前必须调用 `CoInitializeEx()`,使用完后调用 `CoUninitialize()` 2. **缓冲区管理**:加载图片时,缓冲区由 `WICAllocator` 管理,使用完毕后需要调用对应的释放函数 3. **垂直翻转**:OpenGL/DirectX 纹理坐标系与图片坐标系不同,加载纹理时通常需要设置 `bFlipV = TRUE` 4. **格式支持**:支持 BMP、JPEG、PNG、GIF、TIFF 格式的读取和写入 5. **行对齐**:行间距(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()` | 默认缓冲区释放 | *** ### 八、源码下载地址 gitee: [https://gitee.com/Gaaagaa/wicimage](https://gitee.com/Gaaagaa/wicimage) ***