CreateDIBSection ERROR_TAG_NOT_FOUND when transforming a PNG type resource into a cv::Mat - c++

I'm currently using a modified version of the following code I found here to try and convert a .png resource in my project to a HBITMAP and then into a cv::Map.
cv::Mat Resource2mat(const HMODULE hModule, const LPCSTR lpPNGName) {
cv::Mat src;
HRSRC found = FindResource(hModule, lpPNGName, "PNG");
unsigned int size = SizeofResource(hModule, found);
HGLOBAL loaded = LoadResource(hModule, found);
void* resource_data = LockResource(loaded);
/* Now we decode the PNG */
vector<unsigned char> raw;
unsigned long width, height;
int err = decodePNG(raw, width, height, (const unsigned char*)resource_data, size);
if (err != 0)
{
cout<<"\nError while decoding png splash: "<< err <<endl;
return src;
}
// copy from the window device context to the bitmap device context
BITMAPV5HEADER bmpheader = { 0 };
bmpheader.bV5Size = sizeof(BITMAPV5HEADER);
bmpheader.bV5Width = width;
bmpheader.bV5Height = height;
bmpheader.bV5Planes = 1;
bmpheader.bV5BitCount = 32;
bmpheader.bV5Compression = BI_BITFIELDS;
bmpheader.bV5SizeImage = width * height * 4;
bmpheader.bV5RedMask = 0x00FF0000;
bmpheader.bV5GreenMask = 0x0000FF00;
bmpheader.bV5BlueMask = 0x000000FF;
bmpheader.bV5AlphaMask = 0xFF000000;
bmpheader.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
bmpheader.bV5Intent = LCS_GM_BUSINESS;
void* converted = NULL;
HDC screen = GetDC(NULL);
HBITMAP result = CreateDIBSection(screen, reinterpret_cast<BITMAPINFO*>(&bmpheader), DIB_RGB_COLORS, &converted, NULL, 0);
cout << "Error Final: " << GetLastError() << endl;
/* Copy the decoded image into the bitmap in the correct order */
for (unsigned int y1 = height - 1, y2 = 0; y2 < height; y1--, y2++)
for (unsigned int x = 0; x < width; x++)
{
*((char*)converted + 0 + 4 * x + 4 * width*y2) = raw[2 + 4 * x + 4 * width*y1]; // Blue
*((char*)converted + 1 + 4 * x + 4 * width*y2) = raw[1 + 4 * x + 4 * width*y1]; // Green
*((char*)converted + 2 + 4 * x + 4 * width*y2) = raw[0 + 4 * x + 4 * width*y1]; // Red
*((char*)converted + 3 + 4 * x + 4 * width*y2) = raw[3 + 4 * x + 4 * width*y1]; // Alpha
}
GetDIBits(screen, result, 0, height, src.data, (BITMAPINFO *)&bmpheader, DIB_RGB_COLORS);
cv::Mat Actual = src.clone();
ReleaseDC(NULL, screen);
/* Done! */
return Actual;
}
my .rc file looks like this:
and the resources.h entry looks like this
When running the code and hitting this line, I end up with a 2012 ( ERROR_TAG_NOT_FOUND ) error
HBITMAP result = CreateDIBSection(screen, reinterpret_cast<BITMAPINFO*>(&bmpheader), DIB_RGB_COLORS, &converted, NULL, 0);
Found it by calling GetLastError() before and after this line of code
And this is how I call this function in my int main() :
HINSTANCE BotModuleHandle = GetModuleHandle(NULL);
cout << "Attempting to load a resource: " << endl;
cv::Mat S = Resource2mat(BotModuleHandle, MAKEINTRESOURCE(103));
Thanks in advance.
Also any suggestions for a better approach for converting a PNG resource into a cv::Mat are highly appreciated

If all you really wish to achieve is to load the resource image into a cv::Mat, then you can do it with a much shorter function:
cv::Mat Resource2mat(const HMODULE hModule, const LPCSTR lpPNGName)
{
HRSRC found = FindResource(hModule, lpPNGName, "PNG");
unsigned int size = SizeofResource(hModule, found);
HGLOBAL loaded = LoadResource(hModule, found);
void* resource_data = LockResource(loaded);
return cv::imdecode(cv::_InputArray(static_cast<uchar*>(resource_data), size)
, cv::IMREAD_UNCHANGED);
}
LockResource gives you a pointer to a buffer (array of bytes) containing a PNG encoded image (as if you just read the contents of a PNG file into an array). SizeofResource gives you the size of this array in bytes.
OpenCV provides function cv::imdecode, which can decode PNG (and other formats) images from memory buffers. There's just a small issue -- we need to pass both the pointer as well as the size in just one parameter. To do this, we can explicitly construct a temporary cv::_InputArray.
Whole test program:
#include <windows.h>
#include "resource.h"
#include <opencv2/opencv.hpp>
cv::Mat Resource2mat(const HMODULE hModule, const LPCSTR lpPNGName)
{
HRSRC found = FindResource(hModule, lpPNGName, "PNG");
CV_Assert(found);
unsigned int size = SizeofResource(hModule, found);
CV_Assert(size);
HGLOBAL loaded = LoadResource(hModule, found);
CV_Assert(size);
void* resource_data = LockResource(loaded);
CV_Assert(resource_data);
return cv::imdecode(cv::_InputArray(static_cast<uchar*>(resource_data), size)
, cv::IMREAD_UNCHANGED);
}
int main()
{
HINSTANCE hModule = GetModuleHandle(NULL);
cv::Mat image(Resource2mat(hModule, MAKEINTRESOURCE(IDB_PNG1)));
cv::imshow("Resource image", image);
cv::waitKey();
return 0;
}
Resource header resource.h:
#define IDB_PNG1 101
Resource file pngres.rc:
#include "resource.h"
#include "winres.h"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDB_PNG1 PNG "resource.png"
Running this gives me a window with the image correctly displayed:

Related

Create Device Context with Icon and transparent background

I'm trying to get a image with HICON but the background is not transparent. How can I make it transparent? I need a winapi example because the code is in Dart, but it has all the windows calls/functions.
I've tried different version I've found on the internet but it didn't worked. I can access icon mask if that can help for a solution.
Current code:
var icon = SendMessage(hWnd, WM_GETICON, 2, 0); // ICON_SMALL2 - User Made Apps
if (icon == 0) icon = GetClassLongPtr(hWnd, -14); // GCLP_HICON - Microsoft Win Apps
final int hScreen = GetDC(hWnd);
final int hDC = CreateCompatibleDC(hScreen);
final int hBitmap = CreateCompatibleBitmap(hScreen, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
SelectObject(hDC, hBitmap);
// SetBkMode(hDC, TRANSPARENT); - Works for text only
// PatBlt(hDC, 0, 0, 545, 850, WHITENESS); - only white/black;
DrawIconEx(hDC, 0, 0, icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), NULL, NULL, 3);
The icon is transparent:
Even if I don't draw the icon, the output is a black square.
Can you suggest how to remove the background? In basic winapi calls. The code can be in cpp if it doesn't use special classes from libraries, I can use only dllCalls
Here is full working code:
// ignore_for_file: depend_on_referenced_packages, non_constant_identifier_names, avoid_print, unrelated_type_equality_checks
import 'dart:ffi';
import 'dart:io';
import 'package:win32/win32.dart';
import 'package:ffi/ffi.dart';
int enumWindowsProc(int hWnd, int lparam) {
if (IsWindowVisible(hWnd) == FALSE) return TRUE;
final length = GetWindowTextLength(hWnd);
if (length == 0) return TRUE;
var icon = SendMessage(hWnd, WM_GETICON, 2, 0); // ICON_SMALL2 - User Made Apps
if (icon == 0) icon = GetClassLongPtr(hWnd, -14); // GCLP_HICON - Microsoft Win Apps
if (icon == 0) {
icon = 0;
return 1;
}
final int hScreen = GetDC(hWnd);
final int hDC = CreateCompatibleDC(hScreen);
final int hBitmap = CreateCompatibleBitmap(hScreen, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
SelectObject(hDC, hBitmap);
SetBkMode(hDC, TRANSPARENT); //- Works for text only
PatBlt(hDC, 0, 0, GetSystemMetrics(SM_CXICON) ~/ 2, GetSystemMetrics(SM_CYICON), WHITENESS); // test, half white half black.
DrawIconEx(hDC, 0, 0, icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), NULL, NULL, 3);
//Turn to bytes
final bmpScreen = calloc<BITMAP>();
GetObject(hBitmap, sizeOf<BITMAP>(), bmpScreen);
final bitmapFileHeader = calloc<BITMAPFILEHEADER>();
final bitmapInfoHeader = calloc<BITMAPINFOHEADER>()
..ref.biSize = sizeOf<BITMAPINFOHEADER>()
..ref.biWidth = bmpScreen.ref.bmWidth
..ref.biHeight = bmpScreen.ref.bmHeight
..ref.biPlanes = 1
..ref.biBitCount = 32
..ref.biCompression = BI_RGB;
final dwBmpSize = ((bmpScreen.ref.bmWidth * bitmapInfoHeader.ref.biBitCount + 31) / 32 * 4 * bmpScreen.ref.bmHeight).toInt();
final lpBitmap = calloc<Uint8>(dwBmpSize);
GetDIBits(hDC, hBitmap, 0, bmpScreen.ref.bmHeight, lpBitmap, bitmapInfoHeader.cast(), DIB_RGB_COLORS);
final dwSizeOfDIB = dwBmpSize + sizeOf<BITMAPFILEHEADER>() + sizeOf<BITMAPINFOHEADER>();
bitmapFileHeader.ref.bfOffBits = sizeOf<BITMAPFILEHEADER>() + sizeOf<BITMAPINFOHEADER>();
bitmapFileHeader.ref.bfSize = dwSizeOfDIB;
bitmapFileHeader.ref.bfType = 0x4D42; // BM
var b = BytesBuilder();
b.add(Pointer<Uint8>.fromAddress(bitmapFileHeader.address).asTypedList(sizeOf<BITMAPFILEHEADER>()));
b.add(Pointer<Uint8>.fromAddress(bitmapInfoHeader.address).asTypedList(sizeOf<BITMAPINFOHEADER>()));
b.add(lpBitmap.asTypedList(dwBmpSize));
// I need the Bitmap in Bytes, I save it to file just for debugging.
//capture?.icon = b.takeBytes();
//
DeleteDC(hDC);
DeleteObject(hBitmap);
free(bmpScreen);
free(bitmapFileHeader);
free(bitmapInfoHeader);
free(lpBitmap);
Directory current = Directory.current;
File("${current.path}/imgs/i_${icon.toString()}.bmp").writeAsBytes(b.takeBytes());
return 1;
}
void main() {
final imgs = "${Directory.current.path}/imgs";
if (Directory(imgs).exists() == true) {
Directory(imgs).deleteSync(recursive: true);
}
final wndProc = Pointer.fromFunction<EnumWindowsProc>(enumWindowsProc, 0);
EnumWindows(wndProc, 0);
}
final _user32 = DynamicLibrary.open('user32.dll');
int DrawIconEx(int hdc, int xLeft, int yTop, int hIcon, int cxWidth, int cyWidth, int istepIfAniCur, int hbrFlickerFreeDraw, int diFlags) =>
_DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, hbrFlickerFreeDraw, diFlags);
final _DrawIconEx = _user32.lookupFunction<
Int32 Function(IntPtr hdc, Int32 xLeft, Int32 yTop, IntPtr hIcon, Int32 cxWidth, Int32 cyWidth, Uint32 istepIfAniCur, IntPtr hbrFlickerFreeDraw, Uint32 diFlags),
int Function(int hdc, int xLeft, int yTop, int hIcon, int cxWidth, int cyWidth, int istepIfAniCur, int hbrFlickerFreeDraw, int diFlags)>('DrawIconEx');
final _gdi32 = DynamicLibrary.open('gdi32.dll');
int PatBlt(int hdc, int x, int y, int w, int h, int rop) => _PatBlt(hdc, x, y, w, h, rop);
final _PatBlt =
_gdi32.lookupFunction<Int32 Function(IntPtr hdc, Int32 x, Int32 y, Int32 w, Int32 h, Uint32 rop), int Function(int hdc, int x, int y, int w, int h, int rop)>('PatBlt');
Found a even better solution, works with buffer and write to file, alpha channel and everything :)
https://github.com/pelayomendez/exe-icon-extractor/blob/master/src/module.cc
#include <tchar.h>
#include <iostream>
#include <windows.h>
#include <fstream>
#include <cassert>
using namespace std;
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
typedef struct
{
WORD idReserved; // must be 0
WORD idType; // 1 = ICON, 2 = CURSOR
WORD idCount; // number of images (and ICONDIRs)
// ICONDIR [1...n]
// ICONIMAGE [1...n]
} ICONHEADER;
//
// An array of ICONDIRs immediately follow the ICONHEADER
//
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes; // for cursors, this field = wXHotSpot
WORD wBitCount; // for cursors, this field = wYHotSpot
DWORD dwBytesInRes;
DWORD dwImageOffset; // file-offset to the start of ICONIMAGE
} ICONDIR;
//
// After the ICONDIRs follow the ICONIMAGE structures -
// consisting of a BITMAPINFOHEADER, (optional) RGBQUAD array, then
// the color and mask bitmap bits (all packed together
//
typedef struct
{
BITMAPINFOHEADER biHeader; // header for color bitmap (no mask header)
//RGBQUAD rgbColors[1...n];
//BYTE bXOR[1]; // DIB bits for color bitmap
//BYTE bAND[1]; // DIB bits for mask bitmap
} ICONIMAGE;
//
// Return the number of BYTES the bitmap will take ON DISK
//
static UINT NumBitmapBytes(BITMAP* pBitmap)
{
int nWidthBytes = pBitmap->bmWidthBytes;
// bitmap scanlines MUST be a multiple of 4 bytes when stored
// inside a bitmap resource, so round up if necessary
if (nWidthBytes & 3)
nWidthBytes = (nWidthBytes + 4) & ~3;
return nWidthBytes * pBitmap->bmHeight;
}
static BOOL GetIconBitmapInfo(HICON hIcon, ICONINFO* pIconInfo, BITMAP* pbmpColor, BITMAP* pbmpMask)
{
if (!GetIconInfo(hIcon, pIconInfo))
return FALSE;
if (!GetObject(pIconInfo->hbmColor, sizeof(BITMAP), pbmpColor))
return FALSE;
if (!GetObject(pIconInfo->hbmMask, sizeof(BITMAP), pbmpMask))
return FALSE;
return TRUE;
}
//
// Write one icon directory entry - specify the index of the image
//
static void WriteIconDirectoryEntry(BYTE* buffer, int* pBufferOffset, int nIdx, HICON hIcon, UINT nImageOffset)
{
ICONINFO iconInfo;
ICONDIR iconDir;
BITMAP bmpColor;
BITMAP bmpMask;
UINT nColorCount;
UINT nImageBytes;
GetIconBitmapInfo(hIcon, &iconInfo, &bmpColor, &bmpMask);
nImageBytes = NumBitmapBytes(&bmpColor) + NumBitmapBytes(&bmpMask);
if (bmpColor.bmBitsPixel >= 8)
nColorCount = 0;
else
nColorCount = 1 << (bmpColor.bmBitsPixel * bmpColor.bmPlanes);
// Create the ICONDIR structure
iconDir.bWidth = (BYTE)bmpColor.bmWidth;
iconDir.bHeight = (BYTE)bmpColor.bmHeight;
iconDir.bColorCount = nColorCount;
iconDir.bReserved = 0;
iconDir.wPlanes = bmpColor.bmPlanes;
iconDir.wBitCount = bmpColor.bmBitsPixel;
iconDir.dwBytesInRes = sizeof(BITMAPINFOHEADER) + nImageBytes;
iconDir.dwImageOffset = nImageOffset;
// Write to disk
memcpy(&buffer[*pBufferOffset], &iconDir, sizeof(iconDir));
(*pBufferOffset) += sizeof(iconDir);
// Free resources
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
}
static UINT WriteIconData(BYTE* buffer, int* pBufferOffset, HBITMAP hBitmap)
{
BITMAP bmp;
int i;
BYTE* pIconData;
UINT nBitmapBytes;
GetObject(hBitmap, sizeof(BITMAP), &bmp);
nBitmapBytes = NumBitmapBytes(&bmp);
pIconData = (BYTE*)malloc(nBitmapBytes);
GetBitmapBits(hBitmap, nBitmapBytes, pIconData);
// bitmaps are stored inverted (vertically) when on disk..
// so write out each line in turn, starting at the bottom + working
// towards the top of the bitmap. Also, the bitmaps are stored in packed
// in memory - scanlines are NOT 32bit aligned, just 1-after-the-other
for (i = bmp.bmHeight - 1; i >= 0; i--)
{
memcpy(&buffer[*pBufferOffset], pIconData + (i * bmp.bmWidthBytes), bmp.bmWidthBytes);
(*pBufferOffset) += bmp.bmWidthBytes;
// extend to a 32bit boundary (in the file) if necessary
if (bmp.bmWidthBytes & 3)
{
DWORD padding = 0;
memcpy(&buffer[*pBufferOffset], &padding, 4 - bmp.bmWidthBytes);
(*pBufferOffset) += 4 - bmp.bmWidthBytes;
}
}
free(pIconData);
return nBitmapBytes;
}
//
// Create a .ICO file, using the specified array of HICON images
//
BOOL SaveIcon3(HICON hIcon[], int nNumIcons, BYTE* buffer, int* pWritten)
{
int i;
int* pImageOffset = (int*)malloc(nNumIcons * sizeof(int));
int bufferOffset = 0;
if (hIcon == 0 || nNumIcons < 1)
return 0;
//
// Write the iconheader first of all
//
ICONHEADER iconheader;
// Setup the icon header
iconheader.idReserved = 0; // Must be 0
iconheader.idType = 1; // Type 1 = ICON (type 2 = CURSOR)
iconheader.idCount = nNumIcons; // number of ICONDIRs
// Write the header to disk
memcpy(&(buffer[bufferOffset]), &iconheader, sizeof(iconheader));
bufferOffset += sizeof(iconheader);
//
// Leave space for the IconDir entries
//
bufferOffset += sizeof(ICONDIR) * nNumIcons;
//
// Now write the actual icon images!
//
for (i = 0; i < nNumIcons; i++) {
ICONINFO iconInfo;
BITMAP bmpColor, bmpMask;
// GetIconBitmapInfo
GetIconBitmapInfo(hIcon[i], &iconInfo, &bmpColor, &bmpMask);
// record the file-offset of the icon image for when we write the icon directories
pImageOffset[i] = bufferOffset;
// WriteIconImageHeader
BITMAPINFOHEADER biHeader;
UINT nImageBytes;
// calculate how much space the COLOR and MASK bitmaps take
nImageBytes = NumBitmapBytes(&bmpColor) + NumBitmapBytes(&bmpMask);
// write the ICONIMAGE to disk (first the BITMAPINFOHEADER)
ZeroMemory(&biHeader, sizeof(biHeader));
// Fill in only those fields that are necessary
biHeader.biSize = sizeof(biHeader);
biHeader.biWidth = bmpColor.bmWidth;
biHeader.biHeight = bmpColor.bmHeight * 2; // height of color+mono
biHeader.biPlanes = bmpColor.bmPlanes;
biHeader.biBitCount = bmpColor.bmBitsPixel;
biHeader.biSizeImage = nImageBytes;
// write the BITMAPINFOHEADER
memcpy(&(buffer[bufferOffset]), &biHeader, sizeof(biHeader));
bufferOffset += sizeof(biHeader);
// color and mask bitmaps
WriteIconData(buffer, &bufferOffset, iconInfo.hbmColor);
WriteIconData(buffer, &bufferOffset, iconInfo.hbmMask);
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
}
*pWritten = bufferOffset;
//
// Lastly, skip back and write the icon directories.
//
bufferOffset = sizeof(ICONHEADER);
for (i = 0; i < nNumIcons; i++)
{
WriteIconDirectoryEntry(buffer, &bufferOffset, i, hIcon[i], pImageOffset[i]);
}
free(pImageOffset);
return 1;
}
void main()
{
HICON hIconLarge;
HICON hIconSmall;
int extractIcon = ExtractIconExW(L"E:\\Program Files\\Microsoft VS Code Insiders\\Code - Insiders.exe", 0, &hIconLarge, &hIconSmall, 1);
if (extractIcon <= 0) {
std::cout << "No icon";
return;
}
BYTE buffer[(256 * 256) * 4]; // (256x256) Max Windows Icon Size x 4 bytes (32 bits)
int written;
SaveIcon3(&hIconLarge, 1, buffer, &written);
std::ofstream file;
file.open("E:/t.ico", std::ios_base::binary);
assert(file.is_open());
for (int i = 0; i < sizeof(buffer) / sizeof(buffer[0]); ++i)
file.write((char*)(buffer + i * sizeof(buffer[0])), sizeof(buffer[0]));
file.close();
}
Found a solution.
static BITMAP_AND_BYTES createAlphaChannelBitmapFromIcon(HICON hIcon) {
// Get the icon info
ICONINFO iconInfo = {0};
GetIconInfo(hIcon, &iconInfo);
// Get the screen DC
HDC dc = GetDC(NULL);
// Get icon size info
BITMAP bm = {0};
GetObject( iconInfo.hbmColor, sizeof( BITMAP ), &bm );
// Set up BITMAPINFO
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = bm.bmWidth;
bmi.bmiHeader.biHeight = -bm.bmHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
// Extract the color bitmap
int nBits = bm.bmWidth * bm.bmHeight;
int32_t* colorBits = new int32_t[nBits];
GetDIBits(dc, iconInfo.hbmColor, 0, bm.bmHeight, colorBits, &bmi, DIB_RGB_COLORS);
// Check whether the color bitmap has an alpha channel.
// (On my Windows 7, all file icons I tried have an alpha channel.)
BOOL hasAlpha = FALSE;
for (int i = 0; i < nBits; i++) {
if ((colorBits[i] & 0xff000000) != 0) {
hasAlpha = TRUE;
break;
}
}
// If no alpha values available, apply the mask bitmap
if (!hasAlpha) {
// Extract the mask bitmap
int32_t* maskBits = new int32_t[nBits];
GetDIBits(dc, iconInfo.hbmMask, 0, bm.bmHeight, maskBits, &bmi, DIB_RGB_COLORS);
// Copy the mask alphas into the color bits
for (int i = 0; i < nBits; i++) {
if (maskBits[i] == 0) {
colorBits[i] |= 0xff000000;
}
}
delete[] maskBits;
}
// Release DC and GDI bitmaps
ReleaseDC(NULL, dc);
::DeleteObject(iconInfo.hbmColor);
::DeleteObject(iconInfo.hbmMask);
// Create GDI+ Bitmap
Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(bm.bmWidth, bm.bmHeight, bm.bmWidth*4, PixelFormat32bppARGB, (BYTE*)colorBits);
BITMAP_AND_BYTES ret = {bmp, colorBits};
return ret;
}
Original post: https://stackoverflow.com/a/22885412/1456151
And also from PowerToys source code:
HBITMAP CreateBitmapFromIcon(_In_ HICON hIcon, _In_opt_ UINT width, _In_opt_ UINT height)
{
HBITMAP hBitmapResult = NULL;
// Create compatible DC
HDC hDC = CreateCompatibleDC(NULL);
if (hDC != NULL)
{
// Get bitmap rectangle size
RECT rc = { 0 };
rc.left = 0;
rc.right = (width != 0) ? width : GetSystemMetrics(SM_CXSMICON);
rc.top = 0;
rc.bottom = (height != 0) ? height : GetSystemMetrics(SM_CYSMICON);
// Create bitmap compatible with DC
BITMAPINFO BitmapInfo;
ZeroMemory(&BitmapInfo, sizeof(BITMAPINFO));
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biWidth = rc.right;
BitmapInfo.bmiHeader.biHeight = rc.bottom;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
HDC hDCBitmap = GetDC(NULL);
HBITMAP hBitmap = CreateDIBSection(hDCBitmap, &BitmapInfo, DIB_RGB_COLORS, NULL, NULL, 0);
ReleaseDC(NULL, hDCBitmap);
if (hBitmap != NULL)
{
// Select bitmap into DC
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);
if (hBitmapOld != NULL)
{
// Draw icon into DC
if (DrawIconEx(hDC, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL))
{
// Restore original bitmap in DC
hBitmapResult = (HBITMAP)SelectObject(hDC, hBitmapOld);
hBitmapOld = NULL;
hBitmap = NULL;
}
if (hBitmapOld != NULL)
{
SelectObject(hDC, hBitmapOld);
}
}
if (hBitmap != NULL)
{
DeleteObject(hBitmap);
}
}
DeleteDC(hDC);
}
return hBitmapResult;
}

C++ - Problem with create bmp file and show it by createwindow()

I have a function that get data and create .BMP file as Qr Code.
int CreateBmpFile(std::wstring barcode)
{
const std::string data(barcode.begin(), barcode.end());
//const char* data;
char* szSourceSring = (char*)data.c_str();
unsigned int unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
unsigned char* pRGBData, * pSourceData, * pDestData;
QRcode* pQRC;
FILE* f;
// Compute QRCode
if (pQRC = QRcode_encodeString(szSourceSring, 0, QR_ECLEVEL_L, QR_MODE_8, 1))
//if(pQRC=QRcode_encodeString8bit(szSourceSring,0,QR_ECLEVEL_L))
{
unWidth = pQRC->width;
unWidthAdjusted = unWidth * OUT_FILE_PIXEL_PRESCALER * 3;
if (unWidthAdjusted % 4)
unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
unDataBytes = unWidthAdjusted * unWidth * OUT_FILE_PIXEL_PRESCALER;
// Allocate pixels buffer
if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
{
printf("Out of memory");
exit(-1);
}
// Preset to white
memset(pRGBData, 0xff, unDataBytes);
// Prepare bmp headers
BITMAPFILEHEADER kFileHeader;
kFileHeader.bfType = 0x4d42; // "BM"
kFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + unDataBytes;
kFileHeader.bfReserved1 = 0;
kFileHeader.bfReserved2 = 0;
kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER kInfoHeader;
kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
kInfoHeader.biWidth = unWidth * OUT_FILE_PIXEL_PRESCALER;
kInfoHeader.biHeight = -((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
kInfoHeader.biPlanes = 1;
kInfoHeader.biBitCount = 24;
kInfoHeader.biCompression = BI_RGB;
kInfoHeader.biSizeImage = 0;
kInfoHeader.biXPelsPerMeter = 0;
kInfoHeader.biYPelsPerMeter = 0;
kInfoHeader.biClrUsed = 0;
kInfoHeader.biClrImportant = 0;
// Convert QrCode bits to bmp pixels
pSourceData = pQRC->data;
for (y = 0; y < unWidth; y++)
{
pDestData = pRGBData + unWidthAdjusted * y * OUT_FILE_PIXEL_PRESCALER;
for (x = 0; x < unWidth; x++)
{
if (*pSourceData & 1)
{
for (l = 0; l < OUT_FILE_PIXEL_PRESCALER; l++)
{
for (n = 0; n < OUT_FILE_PIXEL_PRESCALER; n++)
{
*(pDestData + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_B;
*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_G;
*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_R;
}
}
}
pDestData += 3 * OUT_FILE_PIXEL_PRESCALER;
pSourceData++;
}
}
// Output the bmp file
if (!(fopen_s(&f, OUT_FILE, "wb")))
{
fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 1, f);
fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 1, f);
fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);
fclose(f);
}
else
{
printf("Unable to open file");
exit(-1);
}
// Free data
free(pRGBData);
QRcode_free(pQRC);
}
else
{
printf("NULL returned");
exit(-1);
}
return 0;
}
After call this function, my bmp file create and I can open it in windows to show.
If I want to load it and show in my win32 dialog by follow code:
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, L"samanqrcode.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_CREATEDIBSECTION | LR_SHARED);
DWORD err = GetLastError();
WCHAR szTest[10];
swprintf_s(szTest, 10, L"%d", err);
if(hBitmap == NULL)
::MessageBox(_hWnd, szTest, L"rrrrrrr", 0);
if (SUCCEEDED(hr))
{
_Image_Barcode = ::CreateWindow(_T("STATIC"), _T(""),
WS_CHILD | WS_VISIBLE | SS_BITMAP,
85, 70, 230, 230,
_hWnd,
(HMENU)IDI_BARCODE_IMAGE,
_hinst,
NULL);
if (_Image_Barcode == NULL)
hr = HRESULT_FROM_WIN32(::GetLastError());
}
::SendMessage(_Image_Barcode, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
LoadImage function return NULL and error code is 0.
If I use other file name (any bmp file for example created by paint application in windows or other...) in LoadImage function, bmp file show correctly.
Is my method to create bmp file incorrect?
Edit:
This question is like my problem.
LoadImage() with QRCode bitmap failing unless file is opened/saved with MS Paint first
That user in comment say: #AbhilashAruva
Hi, Thanks for the reply. I am pretty new to these images in c++. I have found a workaround to fix this issue. I am generating the image in JPEG format from my library and then converting this image into bmp format using gdi+. The loadImage function is now able to load the new bmp image. Thanks for all the help. – Abhilash Aruva Oct 8 '14 at 7:40
What is he mine? I can not implement his method.
I find solution. Using from gdi+ to convert bmp to jpg and convert jpg to bmp.

Copy HICON / HCURSOR in to Byte Array

Is any way can we convert HICON or HCURSOR in to Byte array, I googled in all the way I didnt found a single generic solution, below I tried to convert HICON color and mask BITMAP to byte array and sending this through socket and creating my icon using CreateIconIndirect API but instead of doing all this stuff if I can able to send a HICON directly that will be good.
int ProcessMouse()
{
BYTE m_hbmMaskBits[70000];
BYTE m_hbmColorBits[70000];
CURSORINFO CursorInfo;
CursorInfo.cbSize = sizeof(CursorInfo);
GetCursorInfo(&CursorInfo);
ICONINFO iconInfo;
if (!GetIconInfo(CursorInfo.hCursor, &iconInfo))
{
MessageBox(NULL, _T("CreateCursor Failed"),_T("message"),MB_OK|MB_SYSTEMMODAL);
}
bool isColorShape = (iconInfo.hbmColor != NULL);
bool isMaskShape = (iconInfo.hbmMask != NULL);
LONG cbSize = 0; int nWidth = 0; int nHeight = 0; int actualHeight = 0; int bmPlanes = 0;
int bmBitsPixel = 0; int xHotspot = 0; int yHotspot = 0; int widthBytes = 0;
// Return width,height,actualheight,bmplanes,bmbitspixel,hotsopt of cursor.
if(!CopyIconInfo( CursorInfo.hCursor,
nWidth,
nHeight,
actualHeight,
bmPlanes,
bmBitsPixel,
xHotspot,
yHotspot,
widthBytes ))
{
return 0;
}
std::vector<BYTE> bColor;
std::vector<BYTE> bMask;
int sz_hbmColor = 0;
int sz_hbmMask = 0;
_tempWidth = nWidth;
_tempHeight = nHeight;
//If HCURSOR have both color and mask go with regular approach.
if(isColorShape)
{
//Convert iconInfo.hbmColor HBITMAP to Byte array.
bColor = HBIMAPtoBYTE(iconInfo.hbmColor,sz_hbmColor);
//Convert iconInfo.hbmMask HBITMAP to Byte array.
bMask = HBIMAPtoBYTE(iconInfo.hbmMask,sz_hbmMask);
}
// If HCURSOR have only mask data go with new approach(split mask bitmap to color and mask).
else if(isMaskShape)
{
std::vector<BYTE> bSrcBitmap;
int sz_hbmBitmap = 0;
//Convert iconInfo.hbmMask HBITMAP to Byte array.
bSrcBitmap = HBIMAPtoBYTE(iconInfo.hbmMask,sz_hbmBitmap);
sz_hbmColor = sz_hbmBitmap/2;
sz_hbmMask = sz_hbmBitmap/2;
bMask.resize(bMask.size() + sz_hbmBitmap/2);
memcpy(&bMask[bSrcBitmap.size() - sz_hbmBitmap], &bSrcBitmap[0], sz_hbmBitmap/2 * sizeof(BYTE));
bColor.resize(bColor.size() + sz_hbmBitmap/2);
memcpy(&bColor[bSrcBitmap.size() - sz_hbmBitmap], &bSrcBitmap[sz_hbmBitmap/2], sz_hbmBitmap/2 * sizeof(BYTE));
//Clear at end.
bSrcBitmap.clear();
}
try{
err = memcpy_s((m_hbmMaskBits), sz_hbmMask, &(bMask[0]), sz_hbmMask );
err = memcpy_s((m_hbmColorBits),sz_hbmColor,&(bColor[0]),sz_hbmColor);
//Clear at end.
bMask.clear();
bColor.clear();
return 1;
}catch(...) {
if(err) {
MessageBox(NULL, _T("memcopy failed at mask or color copy"),_T("message"),MB_OK|MB_SYSTEMMODAL);
}
}
}
I tried in below way but it doesn't support for few monochrome cursors.
PICTDESC pd = {sizeof(pd), PICTYPE_ICON};
pd.icon.hicon = CursorInfo.hCursor;
CComPtr<IPicture> pPict = NULL;
CComPtr<IStream> pStrm = NULL;
BOOL res = FALSE;
res = SUCCEEDED( ::CreateStreamOnHGlobal(NULL, TRUE, &pStrm) );
res = SUCCEEDED( ::OleCreatePictureIndirect(&pd, IID_IPicture, TRUE, (void**)&pPict) );
res = SUCCEEDED( pPict->SaveAsFile( pStrm, TRUE, &cbSize ) );
if( res )
{
// rewind stream to the beginning
LARGE_INTEGER li = {0};
pStrm->Seek(li, STREAM_SEEK_SET, NULL);
// write to file
DWORD dwWritten = 0, dwRead = 0, dwDone = 0;
while( dwDone < cbSize )
{
if( SUCCEEDED(pStrm->Read(bCursorBuff, sizeof(bCursorBuff), &dwRead)) )
{
dwDone += dwRead;
}
}
_ASSERTE(dwDone == cbSize);
}
//End of Cursor image
pStrm.Release();
pPict.Release();
HICON and HCURSOR are system handles, so they work only on the current machine.
Over network only the actual data can be sent (bitmap bytes). Then that machine can create its own handles for it.
Using the HBITMAP bytes is the correct approach. You can find some details here:
How to convert HICON to HBITMAP in VC++?
You can get the raw HBITMAP bits using GetDIBits(). More information: C++/Win32: How to get the alpha channel from an HBITMAP?
Below Code works only for color cursor for monochrome cursor use to
convert 16bpp bitmap to 32bpp bitmap and use same code its works.
bool saveToMemory(HICON hIcon, BYTE* buffer, DWORD& nSize)
{
if (hIcon == 0)
return FALSE;
int * pImageOffset;
int nNumIcons = 1;
nSize = 0;
// copy iconheader first of all
ICONHEADER iconheader;
// Setup the icon header
iconheader.idReserved = 0; // Must be 0
iconheader.idType = 1; // Type 1 = ICON (type 2 = CURSOR)
iconheader.idCount = nNumIcons; // number of ICONDIRs
// save to memory
memcpy(buffer, &iconheader, sizeof(iconheader));
nSize += sizeof(iconheader); // update
//
// Leave space for the IconDir entries
//
nSize += sizeof(ICONDIR);
pImageOffset = (int *)malloc(nNumIcons * sizeof(int));
ICONINFO iconInfo;
BITMAP bmpColor, bmpMask;
GetIconBitmapInfo(hIcon, &iconInfo, &bmpColor, &bmpMask);
// record the file-offset of the icon image for when we write the icon directories
pImageOffset[0] = nSize;
// bitmapinfoheader + colortable
//WriteIconImageHeader(hFile, &bmpColor, &bmpMask);
BITMAPINFOHEADER biHeader;
UINT nImageBytes;
// calculate how much space the COLOR and MASK bitmaps take
nImageBytes = NumBitmapBytes(&bmpColor) + NumBitmapBytes(&bmpMask);
// write the ICONIMAGE to disk (first the BITMAPINFOHEADER)
ZeroMemory(&biHeader, sizeof(biHeader));
// Fill in only those fields that are necessary
biHeader.biSize = sizeof(biHeader);
biHeader.biWidth = bmpColor.bmWidth;
biHeader.biHeight = bmpColor.bmHeight * 2; // height of color+mono
biHeader.biPlanes = bmpColor.bmPlanes;
biHeader.biBitCount = bmpColor.bmBitsPixel;
biHeader.biSizeImage = nImageBytes;
// write the BITMAPINFOHEADER
//WriteFile(hFile, &biHeader, sizeof(biHeader), &nWritten, 0);
memcpy(&buffer[nSize], &biHeader, sizeof(biHeader));
nSize += sizeof(biHeader);
// save color and mask bitmaps
saveIconData(buffer, nSize, iconInfo.hbmColor);
saveIconData(buffer, nSize, iconInfo.hbmMask);
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
//
// Lastly, save the icon directories.
//
DWORD size = saveIconDirectoryEntry(buffer, sizeof(ICONHEADER), pImageOffset[0], hIcon);
free(pImageOffset);
return TRUE;
}
//
// Return the number of BYTES the bitmap will take ON DISK
//
static UINT NumBitmapBytes(BITMAP *pBitmap)
{
int nWidthBytes = pBitmap->bmWidthBytes;
// bitmap scanlines MUST be a multiple of 4 bytes when stored
// inside a bitmap resource, so round up if necessary
if (nWidthBytes & 3)
nWidthBytes = (nWidthBytes + 4) & ~3;
return nWidthBytes * pBitmap->bmHeight;
}
// same as WriteIconData but save to memory
static UINT saveIconData(BYTE* buffer, DWORD& nSize, HBITMAP hBitmap)
{
BITMAP bmp;
int i;
BYTE * pIconData;
UINT nBitmapBytes;
DWORD nWritten = 0;
GetObject(hBitmap, sizeof(BITMAP), &bmp);
nBitmapBytes = NumBitmapBytes(&bmp);
pIconData = (BYTE *)malloc(nBitmapBytes);
GetBitmapBits(hBitmap, nBitmapBytes, pIconData);
// bitmaps are stored inverted (vertically) when on disk..
// so write out each line in turn, starting at the bottom + working
// towards the top of the bitmap. Also, the bitmaps are stored in packed
// in memory - scanlines are NOT 32bit aligned, just 1-after-the-other
for (i = bmp.bmHeight - 1; i >= 0; i--)
{
// Write the bitmap scanline
// save to memory
memcpy(&buffer[nSize], pIconData + (i * bmp.bmWidthBytes), bmp.bmWidthBytes);
nSize += bmp.bmWidthBytes;
nWritten += bmp.bmWidthBytes;
}
free(pIconData);
return nWritten;
}
//
// same as WriteIconDirectoryEntry but save to memory
//
static UINT saveIconDirectoryEntry(BYTE* buffer, DWORD pos, int imageOffset, HICON hIcon)
{
ICONINFO iconInfo;
ICONDIR iconDir;
BITMAP bmpColor;
BITMAP bmpMask;
DWORD nWritten = 0;
UINT nColorCount;
UINT nImageBytes;
GetIconBitmapInfo(hIcon, &iconInfo, &bmpColor, &bmpMask);
nImageBytes = NumBitmapBytes(&bmpColor) + NumBitmapBytes(&bmpMask);
if (bmpColor.bmBitsPixel >= 8)
nColorCount = 0;
else
nColorCount = 1 << (bmpColor.bmBitsPixel * bmpColor.bmPlanes);
// Create the ICONDIR structure
iconDir.bWidth = (BYTE)bmpColor.bmWidth;
iconDir.bHeight = (BYTE)bmpColor.bmHeight;
iconDir.bColorCount = nColorCount;
iconDir.bReserved = 0;
iconDir.wPlanes = bmpColor.bmPlanes;
iconDir.wBitCount = bmpColor.bmBitsPixel;
iconDir.dwBytesInRes = sizeof(BITMAPINFOHEADER) + nImageBytes;
iconDir.dwImageOffset = imageOffset;
// save to memory
memcpy(&buffer[pos], &iconDir, sizeof(iconDir));
nWritten += sizeof(iconDir);
// Free resources
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
return nWritten;
}
I was able to do so by calling GetDIBits() twice, once to get the actual details of the cursor images and another time to get the pixels.
You can apply this code for the color and mask, just be aware that it only returns 32x32px cursors, also only the first frame, even if the size is configured for something else.
var windowDeviceContext = User32.GetWindowDC(IntPtr.Zero);
//Initialize the bitmap header and calculate its size.
var maskHeader = new BitmapInfoHeader();
maskHeader.Size = (uint) Marshal.SizeOf(maskHeader);
//Gets the image details.
Gdi32.GetDIBits(windowDeviceContext, iconInfo.Mask, 0, 0, null, ref maskHeader, DibColorModes.RgbColors);
//If there's any data, get it.
if (maskHeader.Height != 0)
{
//To prevent the cursor image from being inverted.
maskHeader.Height *= -1;
var maskBuffer = new byte[maskHeader.SizeImage];
Gdi32.GetDIBits(windowDeviceContext, iconInfo.Mask, 0, (uint) maskHeader.Height, maskBuffer, ref maskHeader, DibColorModes.RgbColors);
}
It's C#, but easily converted to your language of choice.

MFC casting Handle into pointer and DIB to DDB conversion

I am trying to create a bitmap by hardcoding an array of pixel values, converting this array of pixels into a DIB, and then turn this DIB into a DDB. I found two functions to convert CreateBitmapFromPixels and DIBToDDB on the internet. My problem is that the program would crash at line 244. I found that, at line 243, lpbi does not retrieve information from hDIB. Then I added the code at lines 229 and 230 to see if doing the same thing in the function that created the BITMAPINFO structure would help. Still, nothing was gotten from the HBITMAP. I am wondering if there is anything wrong with casting a handle into a pointer, what does it do, and are there other ways to get the HBITMAPINFOHEADER from a handle to a DIB so I can fix the problem.
HBITMAP ColorChange2Dlg::CreateBitmapFromPixels( HDC hDC,
UINT uWidth, UINT uHeight, UINT uBitsPerPixel, LPVOID pBits)
{
if(uBitsPerPixel < 8) // NOT IMPLEMENTED YET
return NULL;
if(uBitsPerPixel == 8)
return Create8bppBitmap(hDC, uWidth, uHeight, pBits);
HBITMAP hBitmap = 0;
if ( !uWidth || !uHeight || !uBitsPerPixel )
return hBitmap;
LONG lBmpSize = uWidth * uHeight * (uBitsPerPixel/8) ;
BITMAPINFO bmpInfo = { 0 };
bmpInfo.bmiHeader.biBitCount = uBitsPerPixel;
bmpInfo.bmiHeader.biHeight = uHeight;
bmpInfo.bmiHeader.biWidth = uWidth;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if(bmpInfo.bmiHeader.biBitCount==32) {
bmpInfo.bmiHeader.biCompression=BI_RGB;
//bmpInfo.bmiColors=NULL;
}
// Pointer to access the pixels of bitmap
UINT * pPixels = 0;
hBitmap = CreateDIBSection( hDC, (BITMAPINFO *)&
bmpInfo, DIB_RGB_COLORS, (void **)&
pPixels , NULL, 0);
if ( !hBitmap )
return hBitmap; // return if invalid bitmaps
//SetBitmapBits( hBitmap, lBmpSize, pBits);
// Directly Write
memcpy(pPixels, pBits, lBmpSize );
LPBITMAPINFOHEADER lpbi; //Line 229
lpbi = (LPBITMAPINFOHEADER)hBitmap; //Line 230
return hBitmap;
}
HBITMAP ColorChange2Dlg::DIBToDDB( HANDLE hDIB, CDC& dc )
{
LPBITMAPINFOHEADER lpbi;
HBITMAP hbm;
CPalette pal;
CPalette* pOldPal;
//CClientDC dc(NULL);
if (hDIB == NULL)
return NULL;
lpbi = (LPBITMAPINFOHEADER)hDIB; //Line 243
int nColors = lpbi->biClrUsed ? lpbi->biClrUsed : 1 << lpbi->biBitCount; //Line 244
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
LPVOID lpDIBBits;
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
bmInfo.bmiHeader.biClrUsed) +
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
// Create and select a logical palette if needed
if( nColors <= 256 && dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;
for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}
pal.CreatePalette( pLP );
delete[] pLP;
// Select and realize the palette
pOldPal = dc.SelectPalette( &pal, FALSE );
dc.RealizePalette();
}
hbm = CreateDIBitmap(dc.GetSafeHdc(), // handle to device context
(LPBITMAPINFOHEADER)lpbi, // pointer to bitmap info header
(LONG)CBM_INIT, // initialization flag
lpDIBBits, // pointer to initialization data
(LPBITMAPINFO)lpbi, // pointer to bitmap info
DIB_RGB_COLORS ); // color-data usage
if (pal.GetSafeHandle())
dc.SelectPalette(pOldPal,FALSE);
return hbm;
}
void ColorChange2Dlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
CClientDC dc(this);
COLORREF *pix = (COLORREF *)malloc(255*255*sizeof(COLORREF));
//int x = 1;
if(pix!=NULL){
for(int i=0;i<255;i++)
{
for(int j=0;j<255;j++)
{
pix[i*255+j] = RGB(i,j,0);
}
}
}
CDC tempDC;
tempDC.CreateCompatibleDC(&dc);
HBITMAP dib = CreateBitmapFromPixels(tempDC.m_hDC,255,255,8*sizeof(COLORREF),(BYTE*)pix);
HBITMAP finalMap = DIBToDDB(dib,tempDC);
HBITMAP oldMap = (HBITMAP)tempDC.SelectObject(finalMap);
dc.BitBlt(201,50,255,255,&tempDC,0,0,SRCCOPY);
tempDC.SelectObject(oldMap);
tempDC.DeleteDC();
}
To write compatible code, it's better not to access bits directly at all. You can use Gradient functions and GDI or GDI+ draw functions to do anything you want.
The code you have in mind pix[i*255+j] = RGB(i,j,0); is of a 32-bit image. Each pixel points to a color. It's not a palette image where each pixel points to an entry in the color table.
If display is 32 bit (most modern computers are, but check to make sure), you can do this with the following code
CBitmap m_bitmap;
void CMyWnd::make_bitmap()
{
if (m_bitmap.GetSafeHandle()) return;
int w = 255;
int h = 255;
int *pix = new int[w*h];
for (int i = 0; i < w; i++)
for (int j = 0; j < h; j++)
pix[i + j*w] = RGB(i, j, 0);
m_bitmap.CreateBitmap(w, h, 1, 32, pix);
delete[]pix;
}
And to draw the bitmap:
void CMyWnd::paint_bitmap(CDC &dc)
{
if (!m_bitmap.GetSafeHandle()) return;
CDC memdc;
memdc.CreateCompatibleDC(&dc);
HBITMAP oldbitmap = (HBITMAP)memdc.SelectObject(m_bitmap);
BITMAP bm;
m_bitmap.GetBitmap(&bm);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memdc, 0, 0, SRCCOPY);
memdc.SelectObject(oldbitmap);
}
void CMyWnd::OnPaint()
{
__super::OnPaint();
CClientDC dc(this);
paint_bitmap(dc);
}
Edit: For historical reasons the RGB value are saved backward as BGR. Use this function instead:
void CMyWnd::make_bitmap()
{
if (m_bitmap.GetSafeHandle()) return;
int w = 256;
int h = 256;
BYTE *pix = new BYTE[4*w*h];
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
int p = (i + j*w) * 4;
pix[p + 0] = 0;//blue
pix[p + 1] = i;//green
pix[p + 2] = j;//red
pix[p + 3] = 0;//not used in GDI functions
}
}
m_bitmap.CreateBitmap(w, h, 1, 32, pix);
delete[]pix;
}

Loading an image from resource and converting to bitmap in memory

I've searched around using google but I'm completely confused on how to load an image (PNG in my case) from resource and then converting it to a bitmap in memory for use in my splash screen. I've read about GDI+ and libpng but I don't really know how to do what I want. Could anyone help?
GDI+ supports PNG directly. See here and here.
EDIT: The GDI+ documentation offers some advice for how to use GDI+ in a DLL. In your case, the best solution is probably to define initialisation and teardown functions that the client code is required to call.
I ended up using PicoPNG to convert the PNG to a two dimensional vector which I then manually contructed a bitmap from. My final code looked like this:
HBITMAP LoadPNGasBMP(const HMODULE hModule, const LPCTSTR lpPNGName)
{
/* First we need to get an pointer to the PNG */
HRSRC found = FindResource(hModule, lpPNGName, "PNG");
unsigned int size = SizeofResource(hModule, found);
HGLOBAL loaded = LoadResource(hModule, found);
void* resource_data = LockResource(loaded);
/* Now we decode the PNG */
vector<unsigned char> raw;
unsigned long width, height;
int err = decodePNG(raw, width, height, (const unsigned char*)resource_data, size);
if (err != 0)
{
log_debug("Error while decoding png splash: %d", err);
return NULL;
}
/* Create the bitmap */
BITMAPV5HEADER bmpheader = {0};
bmpheader.bV5Size = sizeof(BITMAPV5HEADER);
bmpheader.bV5Width = width;
bmpheader.bV5Height = height;
bmpheader.bV5Planes = 1;
bmpheader.bV5BitCount = 32;
bmpheader.bV5Compression = BI_BITFIELDS;
bmpheader.bV5SizeImage = width*height*4;
bmpheader.bV5RedMask = 0x00FF0000;
bmpheader.bV5GreenMask = 0x0000FF00;
bmpheader.bV5BlueMask = 0x000000FF;
bmpheader.bV5AlphaMask = 0xFF000000;
bmpheader.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
bmpheader.bV5Intent = LCS_GM_BUSINESS;
void* converted = NULL;
HDC screen = GetDC(NULL);
HBITMAP result = CreateDIBSection(screen, reinterpret_cast<BITMAPINFO*>(&bmpheader), DIB_RGB_COLORS, &converted, NULL, 0);
ReleaseDC(NULL, screen);
/* Copy the decoded image into the bitmap in the correct order */
for (unsigned int y1 = height - 1, y2 = 0; y2 < height; y1--, y2++)
for (unsigned int x = 0; x < width; x++)
{
*((char*)converted+0+4*x+4*width*y2) = raw[2+4*x+4*width*y1]; // Blue
*((char*)converted+1+4*x+4*width*y2) = raw[1+4*x+4*width*y1]; // Green
*((char*)converted+2+4*x+4*width*y2) = raw[0+4*x+4*width*y1]; // Red
*((char*)converted+3+4*x+4*width*y2) = raw[3+4*x+4*width*y1]; // Alpha
}
/* Done! */
return result;
}