First, initialize COM, and create the imaging factory.
1 2 3 4 | CoInitialize(NULL); IWICImagingFactory *imagingFactory; CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (void **) &imagingFactory); |
You'll need to include the following headers:
1 2 3 | #include <windows.h> #include <wincodec.h> #include <shlwapi.h> |
...and you'll need to link with the following libraries:
windowscodecs.lib shlwapi.lib
Declare our variables, so we can handle errors with goto
:
1 2 3 4 5 6 7 8 9 10 | HANDLE handle = INVALID_HANDLE_VALUE; BYTE *buffer = NULL; IStream *stream = NULL; IWICBitmapDecoder *decoder = NULL; IWICBitmapFrameDecode *frame = NULL; IWICFormatConverter *converter = NULL; DWORD bytesRead = 0, fileSize = 0, fileSizeHigh = 0; bool success = false; UINT imageWidth = 0, imageHeight = 0; BYTE *imageBits = NULL; |
To load an image, we must first read the file into memory:
1 2 3 4 5 6 7 8 9 10 11 12 | handle = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (handle == INVALID_HANDLE_VALUE) goto error; fileSize = GetFileSize(handle, &fileSizeHigh); if (fileSizeHigh || fileSize == 0xFFFFFFFF) goto error; buffer = (BYTE *) malloc(fileSize); if (!buffer) goto error; if (!ReadFile(handle, buffer, fileSize, &bytesRead, NULL)) goto error; if (bytesRead != fileSize) goto error; |
Then we create a memory stream and a decoder. This allows us to decode the frame.
1 2 3 4 5 6 | stream = SHCreateMemStream(buffer, fileSize); if (!stream) goto error; if (S_OK != imagingFactory->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder)) goto error; if (S_OK != decoder->GetFrame(0, &frame)) goto error; |
We then convert the frame to a format we can work with. A full list of format GUIDs is available here: Native Pixel Formats.
1 2 3 | if (S_OK != imagingFactory->CreateFormatConverter(&converter)) goto error; if (S_OK != converter->Initialize(frame, GUID_WICPixelFormat32bppBGRA, WICBitmapDitherTypeNone, 0, 0, WICBitmapPaletteTypeCustom)) goto error; |
Finally, we can retrieve the bitmap from the converted frame.
1 2 3 4 5 | if (S_OK != converter->GetSize(&imageWidth, &imageHeight)) goto error; imageBits = (BYTE *) malloc(imageWidth * imageHeight * 4); if (!imageBits) goto error; if (S_OK != converter->CopyPixels(NULL, imageWidth * 4, imageWidth * imageHeight * 4, imageBits)) goto error; |
Cleanup:
1 2 3 4 5 6 7 8 9 | success = true; error:; if (handle != INVALID_HANDLE_VALUE) CloseHandle(handle); if (frame) frame->Release(); if (decoder) decoder->Release(); if (stream) stream->Release(); if (converter) converter->Release(); if (buffer) free(buffer); if (imageBits && !success) free(imageBits); |
You can now draw the bitmap to a HDC, or use with another graphics API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | if (message == WM_PAINT) { PAINTSTRUCT paint; BeginPaint(window, &paint); BITMAPINFOHEADER info = {}; info.biSize = sizeof(info); info.biWidth = imageWidth; info.biHeight = -imageHeight; info.biPlanes = 1; info.biBitCount = 32; info.biCompression = BI_RGB; info.biSizeImage = 4 * imageWidth * imageHeight; StretchDIBits(paint.hdc, 0, 0, imageWidth, imageHeight, 0, 0, imageWidth, imageHeight, imageBits, (BITMAPINFO *) &info, DIB_RGB_COLORS, SRCCOPY); EndPaint(window, &paint); } |