/** * @file XTGraphicUtils.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ #include "stdafx.h" #include "GraphicLibrary/GdiPlus/XTPGdiPlus.h" #include "XTGraphicUtils.h" #include "Common/XTPCasting.h" #include "Common/XTPResourceManager.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # undef THIS_FILE static char THIS_FILE[] = __FILE__; # define new DEBUG_NEW #endif using namespace Gdiplus; using namespace Gdiplus::DllExports; BOOL AFX_CDECL GetEncoderClsid(const WCHAR* pFormat, CLSID* pClsid) { UINT num, size; GdipGetImageEncodersSize(&num, &size); ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); GdipGetImageEncoders(num, size, pImageCodecInfo); BOOL found = FALSE; for (UINT ix = 0; !found && ix < num; ++ix) { if (_wcsicmp(pImageCodecInfo[ix].MimeType, pFormat) == 0) { *pClsid = pImageCodecInfo[ix].Clsid; found = TRUE; break; } } free(pImageCodecInfo); return found; } LPCWSTR AFX_CDECL GetMimeType(LPCTSTR lpszFileName) { int len = (int)_tcslen(lpszFileName); if (len > 3 && _tcsicmp(lpszFileName + len - 4, _T(".png")) == 0) return L"image/png"; if (len > 3 && _tcsicmp(lpszFileName + len - 4, _T(".jpg")) == 0) return L"image/jpeg"; if (len > 3 && _tcsicmp(lpszFileName + len - 4, _T(".gif")) == 0) return L"image/gif"; return L"image/bmp"; } BOOL AFX_CDECL CXTPGraphicUtils::SaveBitmapToFile(HBITMAP hBitmap, LPCTSTR lpszFileName) // static { GpBitmap* pGpBitmap = NULL; if (Gdiplus::Ok != GdipCreateBitmapFromHBITMAP(hBitmap, 0, &pGpBitmap)) return FALSE; BOOL bResult = FALSE; CLSID encoder; if (!GetEncoderClsid(GetMimeType(lpszFileName), &encoder)) goto Cleanup; if (Gdiplus::Ok != GdipSaveImageToFile(pGpBitmap, XTP_CT2CW(lpszFileName), &encoder, NULL)) goto Cleanup; bResult = TRUE; Cleanup: if (NULL != pGpBitmap) GdipDisposeImage(pGpBitmap); return bResult; } // this function used a bit long way of creating Gdiplus::Bitmap from Gdiplus::GpBitmap, but found // no other way to create Gdiplus::Bitmap from Gdiplus::GpBitmap Gdiplus::Status AFX_CDECL CXTPGraphicUtils::GdipCreateBitmapFromHICON_Fixed(HICON hicon, Gdiplus::Bitmap** bitmap) { Gdiplus::Status retStatus = Gdiplus::GenericError; Gdiplus::GpBitmap* nativeBmp = NULL; GdipCreateBitmapFromHICON_Fixed_Native(hicon, &nativeBmp); if (nativeBmp) { HICON hIconFixed = NULL; DllExports::GdipCreateHICONFromBitmap(nativeBmp, &hIconFixed); if (hIconFixed) { if (bitmap) { *bitmap = Gdiplus::Bitmap::FromHICON(hIconFixed); retStatus = (*bitmap)->GetLastStatus(); } ::DestroyIcon(hIconFixed); } // GpBitmap is not required to be freed } return retStatus; } Gdiplus::Status AFX_CDECL CXTPGraphicUtils::GdipCreateBitmapFromHICON_Fixed_Native( HICON hicon, Gdiplus::GpBitmap** bitmap) { Gdiplus::GpStatus returnStatus = Gdiplus::Ok; Gdiplus::GpStatus stat; BITMAP bm; int width = 0, height = 0; Gdiplus::Rect rect; Gdiplus::BitmapData lockeddata; BOOL has_alpha; BITMAPINFOHEADER bih; DWORD* src = NULL; BYTE* dst_row = NULL; ICONINFO iinfo; ZeroMemory(&iinfo, sizeof(ICONINFO)); BYTE* pbBitmapBits = NULL; HDC hScreenDC = NULL; do { if (!bitmap || !GetIconInfo(hicon, &iinfo)) { returnStatus = Gdiplus::InvalidParameter; break; } // get the size of the icon if (!GetObject(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm)) { returnStatus = Gdiplus::GenericError; break; } width = bm.bmWidth; if (iinfo.hbmColor) height = abs(bm.bmHeight); else // combined bitmap + mask height = abs(bm.bmHeight) / 2; pbBitmapBits = (BYTE*)HeapAlloc(GetProcessHeap(), 0, XTPToSizeTChecked(4 * width * height)); if (!pbBitmapBits) { returnStatus = Gdiplus::OutOfMemory; break; } stat = DllExports::GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB, NULL, bitmap); rect.X = 0; rect.Y = 0; rect.Width = width; rect.Height = height; stat = DllExports::GdipBitmapLockBits(*bitmap, &rect, Gdiplus::ImageLockModeWrite, PixelFormat32bppPARGB, &lockeddata); bih.biSize = sizeof(bih); bih.biWidth = width; bih.biHeight = -height; bih.biPlanes = 1; bih.biBitCount = 32; bih.biCompression = BI_RGB; bih.biSizeImage = 0; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; hScreenDC = GetDC(NULL); if (iinfo.hbmColor) { GetDIBits(hScreenDC, iinfo.hbmColor, 0, XTPToUIntChecked(height), pbBitmapBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS); if (bm.bmBitsPixel == 32) { has_alpha = FALSE; // If any pixel has a non-zero alpha, ignore hbmMask src = (DWORD*)pbBitmapBits; XTP_BEGIN_PARALLEL_FOR(int, x, 0, width, 1) { PDWORD pRow = reinterpret_cast(pbBitmapBits) + x * height; for (int y = 0; y < height; y++) { if ((pRow[y] & 0xff000000) != 0) has_alpha = TRUE; } } XTP_END_PARALLEL_FOR } else has_alpha = FALSE; } else { GetDIBits(hScreenDC, iinfo.hbmMask, 0, XTPToUIntChecked(height), pbBitmapBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS); has_alpha = FALSE; } // copy the image data to the Bitmap src = (DWORD*)pbBitmapBits; dst_row = (BYTE*)lockeddata.Scan0; XTP_BEGIN_PARALLEL_FOR(int, y, 0, height, 1) { memcpy(dst_row + y * lockeddata.Stride, src + y * width, XTPToSizeTChecked(width * 4)); } XTP_END_PARALLEL_FOR if (!has_alpha) { if (iinfo.hbmMask) { // read alpha data from the mask if (iinfo.hbmColor) GetDIBits(hScreenDC, iinfo.hbmMask, 0, XTPToUIntChecked(height), pbBitmapBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS); else GetDIBits(hScreenDC, iinfo.hbmMask, XTPToUIntChecked(height), XTPToUIntChecked(height), pbBitmapBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS); src = (DWORD*)pbBitmapBits; dst_row = (BYTE*)lockeddata.Scan0; XTP_BEGIN_PARALLEL_FOR(int, y, 0, height, 1) { PDWORD dst = reinterpret_cast(dst_row + lockeddata.Stride * y); for (int x = 0; x < width; x++) { DWORD src_value = src[y * width + x]; if (src_value) dst[x] = 0; else dst[x] |= 0xff000000; } } XTP_END_PARALLEL_FOR } else { // set constant alpha of 255 dst_row = pbBitmapBits; XTP_BEGIN_PARALLEL_FOR(int, y, 0, height, 1) { PDWORD dst = reinterpret_cast(dst_row + lockeddata.Stride * y); for (int x = 0; x < width; x++) dst[x] |= 0xff000000; } XTP_END_PARALLEL_FOR } } } while (false); if (hScreenDC) ReleaseDC(0, hScreenDC); if (iinfo.hbmColor) DeleteObject(iinfo.hbmColor); if (iinfo.hbmMask) DeleteObject(iinfo.hbmMask); if (bitmap && *bitmap) stat = DllExports::GdipBitmapUnlockBits(*bitmap, &lockeddata); if (pbBitmapBits) HeapFree(GetProcessHeap(), 0, pbBitmapBits); return returnStatus; }