My doubt is about how to use the value returned by the API to reconstruct the image.
Also, does the way I'm creating the Bitmap
preserve the picture transparency?
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
LPCWSTR base64 = L"";
DWORD dwSkip;
DWORD dwFlags;
DWORD dwDataLen;
CryptStringToBinary(
base64,
_tcslen(base64),
CRYPT_STRING_BASE64,
NULL,
&dwDataLen,
&dwSkip,
&dwFlags);
DWORD imageSize = dwDataLen;
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
LPVOID pImage = ::GlobalLock(hMem);
memcpy(pImage, ???? , imageSize);
IStream* pStream = NULL;
::CreateStreamOnHGlobal(hMem, FALSE, &pStream);
Gdiplus::Image image(pStream);
image.GetWidth();
int wd = image.GetWidth();
int hgt = image.GetHeight();
auto format = image.GetPixelFormat();
Bitmap* bmp = new Bitmap(wd, hgt, format);
auto gg = std::unique_ptr<Graphics>(Graphics::FromImage(bmp));
gg->Clear(Color::Transparent);
gg->DrawImage(&image, 0, 0, wd, hgt);
HICON hIcon;
bmp->GetHICON(&hIcon);
pStream->Release();
GlobalUnlock(hMem);
GlobalFree(hMem);
wc.hIcon = hIcon;
CodePudding user response:
My doubt is about how to use the value returned by the API to reconstruct the image.
You are calling CryptStringToBinary()
only 1 time, to calculate the size of the decoded bytes. You are even allocating memory to receive the decoded bytes. But, you are not actually decoding the base64 string to produce the bytes. You need to call CryptStringToBinary()
a second time for that, eg:
LPCWSTR base64 = L"...";
DWORD dwDataLen = 0;
if (!CryptStringToBinaryW(
base64,
wcslen(base64),
CRYPT_STRING_BASE64,
NULL,
&dwDataLen,
NULL,
NULL))
{
// error handling...
}
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwDataLen);
if (!hMem)
{
// error handling...
}
LPVOID pImage = ::GlobalLock(hMem);
if (!CryptStringToBinaryW(
base64,
wcslen(base64),
CRYPT_STRING_BASE64,
pImage,
&dwDataLen,
NULL,
NULL))
{
// error handling...
}
::GlobalUnlock(hMem);
// use hMem as needed...
::GlobalFree(hMem);
CodePudding user response:
we can use CreateIconFromResourceEx
instead gdi . example of convert base64 to HICON (assumed that wholea icon file is converted to base64)
struct ICONDIRENTRY
{
BYTE bWidth; // Width of the image
BYTE bHeight; // Height of the image (times 2)
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // how many bytes in this resource?
DWORD dwImageOffset; // where in the file is this image
};
struct ICONDIR
{
WORD NotInFile; // not in file
WORD Reserved; // Reserved
WORD Type; // resource type (IMAGE_ICON for icons)
WORD Count; // how many images?
ICONDIRENTRY Entries[]; // the entries for each image
};
HICON LoadIcon(_In_ ICONDIR* pid, _In_ ULONG cb, _In_ ULONG cxDesired, _In_ ULONG cyDesired)
{
if (cb < sizeof(ICONDIR) || pid->Type != IMAGE_ICON)
{
return 0;
}
if (ULONG Count = pid->Count)
{
if (cb < sizeof(ICONDIR) Count * sizeof(ICONDIRENTRY))
{
return FALSE;
}
ICONDIRENTRY* Entry = pid->Entries;
do
{
if (Entry->bWidth == cxDesired && Entry->bHeight == cyDesired)
{
if (Entry->wPlanes != 1)
{
return 0;
}
switch (Entry->bColorCount)
{
case 0:
case 1:
case 4:
case 8:
case 16:
case 24:
case 32:
break;
default:
return 0;
}
DWORD dwImageOffset = Entry->dwImageOffset FIELD_OFFSET(ICONDIR, Reserved);
if (cb < dwImageOffset)
{
return 0;
}
DWORD dwBytesInRes = Entry->dwBytesInRes;
if (cb - dwImageOffset < dwBytesInRes)
{
return 0;
}
return CreateIconFromResourceEx((PBYTE)pid dwImageOffset, dwBytesInRes, TRUE, 0x00030000, cxDesired, cyDesired, 0);
}
} while (Entry , --Count);
}
return 0;
}
HICON LoadIcon(_In_ PSTR psz, _In_ ULONG cch, _In_ int cxDesired, _In_ int cyDesired)
{
ULONG cb = 0;
PUCHAR pb = 0;
PUCHAR buf = 0;
HICON hi = 0;
while (CryptStringToBinaryA(psz, cch, CRYPT_STRING_BASE64, pb, &cb, 0, 0))
{
if (pb)
{
hi = LoadIcon((ICONDIR*)buf, cb FIELD_OFFSET(ICONDIR, Reserved), cxDesired, cyDesired);
break;
}
if (cb < sizeof(ICONDIR))
{
break;
}
if (!(buf = new UCHAR[cb FIELD_OFFSET(ICONDIR, Reserved)]))
{
break;
}
pb = buf FIELD_OFFSET(ICONDIR, Reserved);
}
if (buf) delete [] buf;
return hi;
}
for convert icon file to base 64 can use next code:
BOOL IsValidIcon(_In_ ICONDIR* pid, _In_ ULONG cb)
{
if (cb < sizeof(ICONDIR) || pid->Type != IMAGE_ICON)
{
return FALSE;
}
if (ULONG Count = pid->Count)
{
if (cb < sizeof(ICONDIR) Count * sizeof(ICONDIRENTRY))
{
return FALSE;
}
ICONDIRENTRY* Entry = pid->Entries;
do
{
if (Entry->wPlanes != 1)
{
return FALSE;
}
switch (Entry->bColorCount)
{
case 0:
case 1:
case 4:
case 8:
case 16:
case 24:
case 32:
break;
default:
return FALSE;
}
DWORD dwImageOffset = Entry->dwImageOffset FIELD_OFFSET(ICONDIR, Reserved);
if (cb < dwImageOffset)
{
return FALSE;
}
DWORD dwBytesInRes = Entry->dwBytesInRes;
if (cb - dwImageOffset < dwBytesInRes)
{
return FALSE;
}
} while (Entry , --Count);
}
return FALSE;
}
BOOL mi(_In_ PCWSTR lpIconName, _Out_ PSTR* ppsz, _Out_ ULONG* pcch)
{
HANDLE hFile = CreateFileW(lpIconName, FILE_GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL f = FALSE;
FILE_STANDARD_INFO fsi;
if (GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)))
{
if ((ULONG64)fsi.EndOfFile.QuadPart - 1 < 0x100000)
{
if (PBYTE buf = new UCHAR[fsi.EndOfFile.LowPart FIELD_OFFSET(ICONDIR, Reserved)])
{
PBYTE pb = buf FIELD_OFFSET(ICONDIR, Reserved);
if (ReadFile(hFile, pb, fsi.EndOfFile.LowPart, &fsi.EndOfFile.LowPart, 0) &&
IsValidIcon((ICONDIR*)buf, fsi.EndOfFile.LowPart) FIELD_OFFSET(ICONDIR, Reserved))
{
ULONG cch = 0;
PSTR psz = 0;
while (CryptBinaryToStringA(pb, fsi.EndOfFile.LowPart, CRYPT_STRING_BASE64|CRYPT_STRING_NOCRLF, psz, &cch))
{
if (psz)
{
*pcch = cch, *ppsz = psz, psz = 0, f = TRUE;
break;
}
if (!(psz = new CHAR[cch]))
{
break;
}
}
if (psz)
{
delete [] psz;
}
}
delete [] buf;
}
}
}
CloseHandle(hFile);
return f;
}
for test icon:
ULONG cch;
PSTR psz;
if (mi(L"...ico", &psz, &cch))
{
HICON hi = LoadIcon(psz, cch, 48, 48);
delete [] psz;
if (hi)
{
TASKDIALOGCONFIG TaskConfig = {
sizeof(TaskConfig), 0, 0, TDF_USE_HICON_MAIN, TDCBF_CLOSE_BUTTON, 0, {hi}
};
TaskDialogIndirect(&TaskConfig, 0, 0, 0);
DestroyIcon(hi);
}
}