/* * Windows Alpha Image Loader * * An image loader class to create 32 bits alpha channel bitmaps from various * image source formats using Microsoft Windows Imaging Component (WIC) which * is available since Windows XP SP2. * * Version 1.0 (20101015) * * Supported input formats: BMP, GIF, ICO, JPEG, PNG, TIFF (since Windows 7) * Supported output formats: BMP (BGRA32) * * Created by: Benjamin Kalytta, 2010 * * Licence: Free to use, URL to my source and my name is required in your source code. * * Source can be found at http://www.kalytta.com/AlphaBitmap.h */ #pragma once #include #pragma comment(lib, "windowscodecs.lib") class CAlphaImage { private: HBITMAP m_handle; bool m_managed; BITMAP GetBitmap(HBITMAP Handle = 0) { if (Handle == 0) { Handle = m_handle; } if (Handle == 0) { throw STATUS_INVALID_HANDLE; } BITMAP Bmp = {0}; if (GetObject(Handle, sizeof(BITMAP), &Bmp)) { } else { throw STATUS_INVALID_PARAMETER; } return Bmp; } static HBITMAP CreateHandleFromWICBitmapSource(IWICBitmapSource *BitmapSource) { HBITMAP Result = 0; UINT Width = 0, Height = 0; BitmapSource->GetSize(&Width, &Height); unsigned int Stride = (Width * 32 + 7) / 8; unsigned int BufferSize = Stride * Height; BYTE* Buffer = (BYTE*) HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS, BufferSize); HRESULT hr = BitmapSource->CopyPixels(0, Stride, BufferSize, Buffer); if (SUCCEEDED(hr)) { Result = CreateBitmap(Width, Height, 1, 32, Buffer); } HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS, Buffer); if (Result == 0) { throw STATUS_INVALID_PARAMETER; } return Result; } static CAlphaImage* FromStream(IWICImagingFactory* Factory, IWICStream* Stream) { CAlphaImage *Result = 0; IWICBitmapDecoder *Decoder = 0; IWICBitmapFrameDecode *Frame = 0; HRESULT hr = Factory->CreateDecoderFromStream(Stream, NULL, WICDecodeMetadataCacheOnDemand, &Decoder); if (SUCCEEDED(hr)) { hr = Decoder->GetFrame(0, &Frame); if (SUCCEEDED(hr)) { WICPixelFormatGUID Guid; Frame->GetPixelFormat(&Guid); if (Guid != GUID_WICPixelFormat32bppPBGRA) { IWICFormatConverter* Converter = 0; Factory->CreateFormatConverter(&Converter); if (SUCCEEDED(hr)) { hr = Converter->Initialize(Frame, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, 0, 0.0, WICBitmapPaletteTypeCustom); if (SUCCEEDED(hr)) { Result = new CAlphaImage(CreateHandleFromWICBitmapSource(Converter), true); } Converter->Release(); } } else { Result = new CAlphaImage(CreateHandleFromWICBitmapSource(Frame), true); } Frame->Release(); } Decoder->Release(); } return Result; } public: CAlphaImage(HBITMAP Handle, bool Managed = false) : m_handle(Handle), m_managed(Managed) { if (GetBitmap(Handle).bmBitsPixel != 32) { throw STATUS_INVALID_PARAMETER; } } CAlphaImage() : m_handle(0), m_managed(true) { } CAlphaImage(const CAlphaImage& Bitmap) : m_handle(Bitmap.m_handle), m_managed(Bitmap.m_managed) { } virtual ~CAlphaImage() { if (m_managed && m_handle) { DeleteObject(m_handle); } m_handle = 0; m_managed = true; } static CAlphaImage* FromFile(LPCWSTR Filename) { CAlphaImage* Result = 0; CoInitialize(0); IWICImagingFactory *Factory = 0; HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory)); if (SUCCEEDED(hr)) { IWICStream* Stream = 0; if (SUCCEEDED(Factory->CreateStream(&Stream))) { Stream->InitializeFromFilename(Filename, GENERIC_READ); Result = FromStream(Factory, Stream); } Factory->Release(); } CoUninitialize(); if (Result == 0) { throw STATUS_INVALID_PARAMETER; } return Result; } static CAlphaImage* FromResource(HINSTANCE hInstance, UINT Id, LPCWSTR Type = 0) { CAlphaImage* Result = 0; CoInitialize(0); IWICImagingFactory *Factory = 0; HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&Factory)); if (Type == 0) { Type = RT_RCDATA; } LPCWSTR Types[] = { RT_BITMAP, RT_ICON, L"PNG", L"GIF", L"JPEG", L"JPG" }; if (SUCCEEDED(hr)) { IWICStream* Stream = 0; HRSRC hRsrc = FindResource(hInstance, MAKEINTRESOURCE(Id), Type); if (hRsrc == 0) { for (int i = 0; i < sizeof(Types) / sizeof(LPCWSTR); i++) { hRsrc = FindResource(hInstance, MAKEINTRESOURCE(Id), Types[i]); if (hRsrc != 0) break; } } if (hRsrc) { HGLOBAL hGlobal = LoadResource(hInstance, hRsrc); if (hGlobal) { WICInProcPointer Data = (WICInProcPointer) LockResource(hGlobal); if (SUCCEEDED(Factory->CreateStream(&Stream))) { Stream->InitializeFromMemory(Data, SizeofResource(hInstance, hRsrc)); Result = FromStream(Factory, Stream); } } } Factory->Release(); } CoUninitialize(); if (Result == 0) { throw STATUS_INVALID_PARAMETER; } return Result; } /* GETTER */ SIZE GetDimension() { SIZE Dimension = { GetBitmap().bmWidth, GetBitmap().bmHeight }; return Dimension; } HBITMAP GetHandle() { return m_handle; } void SetHandle(HBITMAP Handle, bool Managed = false) { if (GetBitmap(Handle).bmBitsPixel != 32) { throw STATUS_INVALID_PARAMETER; } m_handle = Handle; m_managed = Managed; } /* GENERAL METHODS */ HIMAGELIST CreateImageList(UINT Tiles, UINT GrowSize = 0) { BITMAP Bmp = GetBitmap(); UINT TileWidth = Bmp.bmWidth / Tiles; UINT TileHeight = Bmp.bmHeight; UINT ScanLineWidth = (TileWidth * Bmp.bmBitsPixel + 7) / 8; HIMAGELIST hIml = ImageList_Create(TileWidth, TileHeight, ILC_COLOR32 | ILC_MASK, Tiles, Tiles + GrowSize); if (hIml == 0) { throw STATUS_INVALID_HANDLE; } LPVOID BitsBuffer = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS, Bmp.bmWidthBytes * Bmp.bmHeight); GetBitmapBits(m_handle, Bmp.bmWidthBytes * Bmp.bmHeight, BitsBuffer); LPVOID Buffer = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS, ScanLineWidth * TileHeight); for (int i = 0; i < Tiles; i++) { INT_PTR j = i * TileWidth * Bmp.bmBitsPixel / 8; INT_PTR k = 0; for (int y = 0; y < TileHeight; y++) { for (int x = 0; x < TileWidth * 4; x++) { ((unsigned char*) Buffer)[k + x] = ((unsigned char*) BitsBuffer)[j + x]; } j += Bmp.bmWidthBytes; k += ScanLineWidth; } HBITMAP hBmp = CreateBitmap(TileWidth, TileHeight, 1, 32, Buffer); if (hBmp) { ImageList_Add(hIml, hBmp, 0); DeleteObject(hBmp); } } HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS, Buffer); HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS, BitsBuffer); return hIml; } void Draw(HDC hDC, int x, int y, int w = 0, int h = 0, int alpha = 255) { if (w == 0 || h == 0) { BITMAP Bmp = GetBitmap(); if (w == 0) { w = Bmp.bmWidth; } if (h == 0) { h = Bmp.bmHeight; } } HDC hDCFrom = CreateCompatibleDC(hDC); SelectObject(hDCFrom, m_handle); BLENDFUNCTION Blend = { AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA }; GdiAlphaBlend(hDC, x, y, w, h, hDCFrom, 0, 0, w, h, Blend); DeleteDC(hDCFrom); } /* OPERATORS */ operator HBITMAP() { return m_handle; } HBITMAP operator=(HBITMAP Handle) { SetHandle(Handle, false); return m_handle; } };