/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2010 Miranda IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "..\..\core\commonheaders.h" typedef DWORD ARGB; void InitBitmapInfo(BITMAPINFO &bmi, const SIZE &size) { ZeroMemory(&bmi, sizeof(BITMAPINFO)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biWidth = size.cx; bmi.bmiHeader.biHeight = size.cy; } void ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE& sizImage, int cxRow) { BITMAPINFO bmi; InitBitmapInfo(bmi, sizImage); void *pvBits = malloc(sizImage.cx * 4 * sizImage.cy); if (GetDIBits(hdc, hbmp, 0, bmi.bmiHeader.biHeight, pvBits, &bmi, DIB_RGB_COLORS) == bmi.bmiHeader.biHeight) { ULONG cxDelta = cxRow - bmi.bmiHeader.biWidth; ARGB *pargbMask = (ARGB *)pvBits; for (ULONG y = bmi.bmiHeader.biHeight + 1; --y;) { for (ULONG x = bmi.bmiHeader.biWidth + 1; --x;) { if (*pargbMask++) { // transparent pixel *pargb++ = 0; } else { // opaque pixel *pargb++ |= 0xFF000000; } } pargb += cxDelta; } } free(pvBits); } bool HasAlpha(ARGB *pargb, SIZE& sizImage, int cxRow) { ULONG cxDelta = cxRow - sizImage.cx; for (ULONG y = sizImage.cy; y--;) { for (ULONG x = sizImage.cx; x--;) { if (*pargb++ & 0xFF000000) return true; } pargb += cxDelta; } return false; } void ConvertBufferToPARGB32(HANDLE hPaintBuffer, HDC hdc, HICON hIcon, SIZE& sizIcon) { RGBQUAD *prgbQuad; int cxRow; HRESULT hr = getBufferedPaintBits(hPaintBuffer, &prgbQuad, &cxRow); if (SUCCEEDED(hr)) { ARGB *pargb = (ARGB *)prgbQuad; if ( !HasAlpha(pargb, sizIcon, cxRow)) { ICONINFO info; if (GetIconInfo(hIcon, &info)) { if (info.hbmMask) ConvertToPARGB32(hdc, pargb, info.hbmMask, sizIcon, cxRow); DeleteObject(info.hbmColor); DeleteObject(info.hbmMask); } } } } HBITMAP ConvertIconToBitmap(HICON hicon, HIMAGELIST hIml, int iconId) { SIZE sizIcon; sizIcon.cx = GetSystemMetrics(SM_CXSMICON); sizIcon.cy = GetSystemMetrics(SM_CYSMICON); RECT rcIcon = { 0, 0, sizIcon.cx, sizIcon.cy }; HDC hdc = CreateCompatibleDC(NULL); BITMAPINFO bmi; InitBitmapInfo(bmi, sizIcon); HBITMAP hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); HBITMAP hbmpOld = (HBITMAP)SelectObject(hdc, hbmp); BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; BP_PAINTPARAMS paintParams = {0}; paintParams.cbSize = sizeof(paintParams); paintParams.dwFlags = BPPF_ERASE; paintParams.pBlendFunction = &bfAlpha; HDC hdcBuffer; HANDLE hPaintBuffer = beginBufferedPaint(hdc, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer); if (hPaintBuffer) { if (hIml) ImageList_Draw(hIml, iconId, hdc, 0, 0, ILD_TRANSPARENT); else DrawIconEx(hdcBuffer, 0, 0, hicon, sizIcon.cx, sizIcon.cy, 0, NULL, DI_NORMAL); // If icon did not have an alpha channel we need to convert buffer to PARGB ConvertBufferToPARGB32(hPaintBuffer, hdc, hicon, sizIcon); // This will write the buffer contents to the destination bitmap endBufferedPaint(hPaintBuffer, TRUE); } SelectObject(hdc, hbmpOld); DeleteDC(hdc); return hbmp; }