Windows Imaging Component in Direct2D: Decoding and Processing Images
Windows Imaging Component (WIC) provides a set of COM interfaces for decoding compressed images from files, streams, or memory. Key objects include IWICBitmapDecoder as a container for frames and metadata, IWICBitmapFrameDecode for accessing pixels in individual frames, and IWICBitmapSourceTransform for on-the-fly transformations.
Additional interfaces like IWICBitmap for mutable raster data in memory, IWICFormatConverter for format changes, and IWICBitmapScaler, IWICBitmapClipper, and IWICBitmapFlipRotator for modifications are also used. All operations start with creating a factory: IWICImagingFactory or IWICImagingFactory2.
#include <wincodec.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
ComPtr<IWICImagingFactory> pFactory;
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void**>(&pFactory)
);
The factory uses CLSCTX_INPROC_SERVER context to load into the current process.
Decoding from Files, Streams, and Memory
To load from a file, use CreateDecoderFromFilename with the path (wchar_t*), preferred vendor (nullptr), GENERIC_READ mode, and WICDecodeMetadataCacheOnLoad caching.
ComPtr<IWICBitmapDecoder> pDecoder;
hr = pFactory->CreateDecoderFromFilename(
L"C:\\images\\photo.jpg",
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
From an IStream (via SHCreateStreamOnFile) — use CreateDecoderFromStream. For memory: CreateStream with InitializeFromMemory, then CreateDecoderFromStream.
ComPtr<IStream> pStream;
SHCreateStreamOnFile(L"C:\\images\\photo.jpg", STGM_READ, &pStream);
ComPtr<IWICBitmapDecoder> pDecoder;
pFactory->CreateDecoderFromStream(pStream.Get(), nullptr, WICDecodeMetadataCacheOnLoad, &pDecoder);
ComPtr<IWICStream> pStream;
pFactory->CreateStream(&pStream);
pStream->InitializeFromMemory(pBuffer, cbSize);
ComPtr<IWICBitmapDecoder> pDecoder;
pFactory->CreateDecoderFromStream(pStream.Get(), nullptr, WICDecodeMetadataCacheOnLoad, &pDecoder);
IWICBitmapDecoder Methods
This interface provides access to the image structure:
- *QueryCapability(IStream, DWORD)*: Checks decoder capabilities (bitmask: CanDecodeSomeImages, CanDecodeAllImages, etc.).
- *GetContainerFormat(GUID)**: GUID of the container format (e.g., GUID_ContainerFormatJpeg).
- *GetFrameCount(UINT)**: Number of frames.
- GetFrame(UINT, IWICBitmapFrameDecode) : Frame by index.
- GetPreview/IGetThumbnail(IWICBitmapSource) : Preview or thumbnail.
- GetMetadataQueryReader(IWICMetadataQueryReader) : Global metadata.
The full method list offers control over caching, palettes, and color contexts.
IWICBitmapFrameDecode Methods
Inherits IWICBitmapSource (GetSize, GetPixelFormat, GetResolution, CopyPixels, CopyPalette) plus:
- GetThumbnail(IWICBitmapSource**) — Frame thumbnail.
- GetColorContexts(UINT, IWICColorContext*, UINT) — ICC profiles.
- GetMetadataQueryReader(IWICMetadataQueryReader**) — Frame metadata (EXIF, XMP).
CopyPixels extracts data into a specified buffer, accounting for stride and region.
Full Decoding Example with Info Output
#include <windows.h>
#include <wincodec.h>
#include <wrl/client.h>
#include <iostream>
#include <vector>
#include <propvarutil.h>
using Microsoft::WRL::ComPtr;
void PrintGUID(const GUID& guid) {
wchar_t str[39];
StringFromGUID2(guid, str, 39);
wprintf(L"%s", str);
}
int wmain(int argc, wchar_t* argv[]) {
if (argc < 2) {
wprintf(L"Usage: WICFullDemo.exe <imagefile>\n");
return 1;
}
const wchar_t* filename = argv[1];
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr)) return 1;
ComPtr<IWICImagingFactory> pFactory;
hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFactory));
if (FAILED(hr)) {
CoUninitialize();
return 1;
}
ComPtr<IWICBitmapDecoder> pDecoder;
hr = pFactory->CreateDecoderFromFilename(filename, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder);
if (FAILED(hr)) {
CoUninitialize();
return 1;
}
wprintf(L"=== IWICBitmapDecoder methods ===\n");
ComPtr<IStream> pStream;
SHCreateStreamOnFile(filename, STGM_READ, &pStream);
if (SUCCEEDED(hr)) {
DWORD caps = 0;
hr = pDecoder->QueryCapability(pStream.Get(), &caps);
if (SUCCEEDED(hr)) {
wprintf(L"QueryCapability: capabilities = 0x%08X\n", caps);
}
}
// Further processing of frames, metadata, and pixels
CoUninitialize();
return 0;
}
This example shows COM initialization, factory creation, decoder setup, and QueryCapability. For production code, add GetFrame, CopyPixels, and transformations.
Key Takeaways
- WIC decodes images without loading everything into memory, supporting streams and metadata caching.
- IWICBitmapDecoder handles the container, while IWICBitmapFrameDecode manages individual frames and pixels.
- CreateDecoderFromFilename/Stream/Memory covers all input scenarios.
- GetFrameCount/GetFrame/GetMetadataQueryReader provide access to structure and EXIF data.
- Always check HRESULT and use ComPtr for RAII.
— Editorial Team
No comments yet.