Created
December 22, 2023 06:48
-
-
Save smourier/9b546fe2b8fd17491af93331e72fe691 to your computer and use it in GitHub Desktop.
Some WIC Bitmap tests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <atlbase.h> | |
#include <stdio.h> | |
#include <wincodec.h> | |
#define HRASSERT(x) ATLASSERT(SUCCEEDED(x)) | |
HRESULT ConvertBitmapTo256(PCWSTR input, PCWSTR output, REFGUID outputFormat) | |
{ | |
HRESULT hr = S_OK; | |
CComPtr<IWICImagingFactory> fac; | |
HRASSERT(fac.CoCreateInstance(CLSID_WICImagingFactory)); | |
// or use fac->CreateBitmapFromHBITMAP(...) to start from HBITMAP | |
CComPtr<IWICBitmapDecoder> decoder; | |
HRASSERT(fac->CreateDecoderFromFilename(input, nullptr, GENERIC_READ, WICDecodeOptions::WICDecodeMetadataCacheOnDemand, &decoder)); | |
// create a converter | |
CComPtr<IWICFormatConverter> converter; | |
HRASSERT(fac->CreateFormatConverter(&converter)); | |
// get first frame (bmp only have one) | |
CComPtr<IWICBitmapFrameDecode> frame; | |
HRASSERT(decoder->GetFrame(0, &frame)); | |
// you can use your custom palette too (4th parameter) | |
HRASSERT(converter->Initialize(frame, GUID_WICPixelFormat8bppIndexed, WICBitmapDitherTypeOrdered16x16, nullptr, 0, WICBitmapPaletteTypeFixedHalftone216)); | |
// you can do B&W too, note not all combination of dithering & palette work, these works | |
//converter->Initialize(frame, GUID_WICPixelFormatBlackWhite, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeFixedBW); | |
//converter->Initialize(frame, GUID_WICPixelFormatBlackWhite, WICBitmapDitherTypeOrdered16x16, nullptr, 0, WICBitmapPaletteTypeFixedHalftone216); | |
// save back, create encoder | |
CComPtr<IWICBitmapEncoder> encoder; | |
HRASSERT(fac->CreateEncoder(outputFormat, nullptr, &encoder)); | |
// create output stream, here a file stream, but any stream can do (SHCreateMemStream for mem stream) | |
CComPtr<IStream> stream; | |
SHCreateStreamOnFile(output, STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, &stream); | |
HRASSERT(encoder->Initialize(stream, WICBitmapEncoderNoCache)); | |
// create new frame, write and commit | |
CComPtr<IWICBitmapFrameEncode> frameEncode; | |
HRASSERT(encoder->CreateNewFrame(&frameEncode, nullptr)); | |
HRASSERT(frameEncode->Initialize(nullptr)); | |
HRASSERT(frameEncode->WriteSource(converter, nullptr)); | |
HRASSERT(frameEncode->Commit()); | |
HRASSERT(encoder->Commit()); | |
return hr; | |
} | |
HRESULT ConvertHBITMAPTo256(HBITMAP input, PCWSTR output, REFGUID outputFormat) | |
{ | |
HRESULT hr = S_OK; | |
CComPtr<IWICImagingFactory> fac; | |
HRASSERT(fac.CoCreateInstance(CLSID_WICImagingFactory)); | |
CComPtr<IWICBitmap> bitmap; | |
HRASSERT(fac->CreateBitmapFromHBITMAP(input, nullptr, WICBitmapUseAlpha, &bitmap)); | |
// create a converter | |
CComPtr<IWICFormatConverter> converter; | |
HRASSERT(fac->CreateFormatConverter(&converter)); | |
// you can use your custom palette too (4th parameter) | |
HRASSERT(converter->Initialize(bitmap, GUID_WICPixelFormat8bppIndexed, WICBitmapDitherTypeOrdered16x16, nullptr, 0, WICBitmapPaletteTypeFixedHalftone216)); | |
// you can do B&W output too, note not all combination of dithering & palette work, these works | |
//converter->Initialize(frame, GUID_WICPixelFormatBlackWhite, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeFixedBW); | |
//converter->Initialize(frame, GUID_WICPixelFormatBlackWhite, WICBitmapDitherTypeOrdered16x16, nullptr, 0, WICBitmapPaletteTypeFixedHalftone216); | |
// save back, create encoder | |
CComPtr<IWICBitmapEncoder> encoder; | |
HRASSERT(fac->CreateEncoder(outputFormat, nullptr, &encoder)); | |
// create output stream, here a file stream, but any stream can do (SHCreateMemStream for mem stream) | |
CComPtr<IStream> stream; | |
SHCreateStreamOnFile(output, STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, &stream); | |
HRASSERT(encoder->Initialize(stream, WICBitmapEncoderNoCache)); | |
// create new frame, write and commit | |
CComPtr<IWICBitmapFrameEncode> frameEncode; | |
HRASSERT(encoder->CreateNewFrame(&frameEncode, nullptr)); | |
HRASSERT(frameEncode->Initialize(nullptr)); | |
HRASSERT(frameEncode->WriteSource(converter, nullptr)); | |
HRASSERT(frameEncode->Commit()); | |
HRASSERT(encoder->Commit()); | |
return hr; | |
} | |
// *warning* not sure this one works! | |
HRESULT ConvertHBITMAPTo256(HBITMAP input, HBITMAP* output, HPALETTE *palette) | |
{ | |
HRESULT hr = S_OK; | |
CComPtr<IWICImagingFactory> fac; | |
HRASSERT(fac.CoCreateInstance(CLSID_WICImagingFactory)); | |
CComPtr<IWICBitmap> bitmap; | |
HRASSERT(fac->CreateBitmapFromHBITMAP(input, nullptr, WICBitmapUseAlpha, &bitmap)); | |
// create a converter | |
CComPtr<IWICFormatConverter> converter; | |
HRASSERT(fac->CreateFormatConverter(&converter)); | |
// here we use 256 color format with predefined palette, but one can use a custom palette too (4th parameter) | |
HRASSERT(converter->Initialize(bitmap, GUID_WICPixelFormat8bppIndexed, WICBitmapDitherTypeOrdered16x16, nullptr, 0, WICBitmapPaletteTypeFixedHalftone256)); | |
// one can do B&W output too, note not all combination of dithering & palette work, these works | |
//converter->Initialize(frame, GUID_WICPixelFormatBlackWhite, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeFixedBW); | |
//converter->Initialize(frame, GUID_WICPixelFormatBlackWhite, WICBitmapDitherTypeOrdered16x16, nullptr, 0, WICBitmapPaletteTypeFixedHalftone216); | |
// save back, create encoder | |
CComPtr<IWICBitmapEncoder> encoder; | |
HRASSERT(fac->CreateEncoder(GUID_ContainerFormatBmp, nullptr, &encoder)); | |
// create output stream in memory | |
CComPtr<IStream> stream; | |
HRASSERT(CreateStreamOnHGlobal(nullptr, TRUE, &stream)); | |
HRASSERT(encoder->Initialize(stream, WICBitmapEncoderNoCache)); | |
// create new frame, write and commit | |
CComPtr<IWICBitmapFrameEncode> frame; | |
HRASSERT(encoder->CreateNewFrame(&frame, nullptr)); | |
HRASSERT(frame->Initialize(nullptr)); | |
HRASSERT(frame->WriteSource(converter, nullptr)); | |
HRASSERT(frame->Commit()); | |
HRASSERT(encoder->Commit()); | |
HGLOBAL h; | |
HRASSERT(GetHGlobalFromStream(stream, &h)); | |
auto file = (BITMAPFILEHEADER*)GlobalLock(h); | |
auto info = (BITMAPINFOHEADER*)((LPBYTE)file + sizeof(BITMAPFILEHEADER)); | |
auto bits = (LPBYTE)file + file->bfOffBits; | |
*output = CreateBitmap(info->biWidth, info->biHeight, info->biPlanes, info->biBitCount, bits); | |
if (*output) | |
{ | |
// bit of a hack, we write the memory file so we don't have to allocate for the palette | |
// but we won't need it anymore | |
auto lp = (LOGPALETTE*)&info->biClrImportant; | |
lp->palNumEntries = info->biClrUsed; | |
lp->palVersion = 0x300; | |
*palette = CreatePalette(lp); | |
if (!*palette) | |
{ | |
hr = E_FAIL; | |
DeleteObject(*output); | |
} | |
} | |
else | |
{ | |
hr = E_FAIL; | |
} | |
GlobalUnlock(h); | |
return hr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment