I want to know how can I query for metada of an image that I loaded with LoadImage. For example, how do I go about querying its demensions?
You can use GetObject with BITMAP.
I create a sample with LoadImage:
HWND background = CreateWindow("STATIC", "background", SS_BITMAP | WS_CHILD | WS_VISIBLE, 200, 200, 300, 300, hwnd, NULL, NULL, NULL);
HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 100, 100, LR_LOADFROMFILE);
SendMessage(background, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp);
This sample shows an image:
Then I get the image information through GetObject:
BITMAP bitmapInfo;
GetObject(hBmp, sizeof bitmapInfo, &bitmapInfo);
Then you can view the specific information of the image through the returned BITMAPstructure.
It works for me:
Related
I'm working on a Win32 app with layered windows. The window contents are drawn using Cairo. The transparency is very unpredictable however. Sometimes everything is correct; opaque parts are opaque, transparent parts transparent. Other times what should be opaque becomes transparent or vanishes completely.
This is the most minimal example I could reduce the problem to (based on this answer). It should draw a square in the upper left corner of the screen, with the left half transparent grey and the right half opaque black.
import core.sys.windows.windows;
import std.utf;
import std.stdio;
import cairo;
import cairo_win32;
const UINT WIDTH = 500;
const UINT HEIGHT = 500;
extern(Windows)
LRESULT WndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam) nothrow {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void main(string[] args) {
WNDCLASS wndclass;
wndclass.lpszClassName = "Test".toUTF16z;
wndclass.lpfnWndProc = &WndProc;
RegisterClass(&wndclass);
HINSTANCE hInstance = GetModuleHandle(NULL);
HWND hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TOOLWINDOW, wndclass.lpszClassName, "Test".toUTF16z, WS_POPUP, 50, 50, WIDTH, HEIGHT, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_SHOWNA);
HDC hdcScreen = GetDC(NULL);
// Offscreen hdc for painting
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmMem = CreateCompatibleBitmap(hdcScreen, WIDTH, HEIGHT);
auto hOld = SelectObject(hdcMem, hbmMem);
// Draw using offscreen hdc
auto surface = cairo_win32_surface_create(hdcMem);
auto cr = cairo_create(surface);
// Transparent grey
cairo_rectangle(cr, 0, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 0.4, 0.4, 0.4, 0.8);
cairo_fill(cr);
// Black
cairo_rectangle(cr, 250, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 0, 0, 0, 1);
cairo_fill(cr);
cairo_destroy(cr);
cairo_surface_destroy(surface);
// Show on screen
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
RECT win_rect;
GetWindowRect(hwnd, &win_rect);
POINT ptZero = POINT(0, 0);
POINT win_pos = POINT(win_rect.left, win_rect.top);
SIZE win_dims = SIZE(WIDTH, HEIGHT);
UpdateLayeredWindow(hwnd, hdcScreen, &win_pos, &win_dims, hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA);
// Reset offscreen hdc to default bitmap
SelectObject(hdcMem, hOld);
// Cleanup
DeleteObject(hbmMem);
DeleteDC (hdcMem);
ReleaseDC(NULL, hdcScreen);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
This works, as you can see here.
However, when I now switch the order of the two Cairo draw calls like this:
// Opaque black
cairo_rectangle(cr, 250, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 0.01, 0.01, 0.01, 1.0);
cairo_fill(cr);
// Transparent grey
cairo_rectangle(cr, 0, 0, 250, HEIGHT);
cairo_set_source_rgba(cr, 0.4, 0.4, 0.4, 0.8);
cairo_fill(cr);
Then the opaque right half becomes completely transparent.
What's going on here? I assume I must be doing something more fundamentally wrong, probably with the whole HDC and UpdateLayeredWindow business.
Update: I tried to create an image surface with CAIRO_FORMAT_ARGB32, used the exact same drawing operations and wrote it to a PNG file. In that case both images look correct and identical.
It seems like the first operation can't have an alpha of exactly 1.0. If I set the first rectangle's alpha to 1.0, the second (black opaque) rectangle vanishes. If I set the first rectangle's alpha to 0.99 instead, the second rectangle is drawn correctly.
I'm trying to write a WinAPI wrapper using C++11 but I've encountered a problem.
My tracksbars seem to go invisible whenever I resize the main window ( this problem does not occur with buttons/labels/progressbars/comboboxes/etc)
void Trackbar::Create(Window* parent)
{
this->handle = CreateWindowEx(
0,
TRACKBAR_CLASS
nullptr,
WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE | TBS_TRANSPARENTBKGND,
170,
150,
100,
50,
parent->GetHandle(),
0,
GetModuleHandle(0),
nullptr);
if(!this->handle)
ERRORMB();
SendMessage(this->handle, TBM_SETRANGE, true, (LPARAM)MAKELONG(0, 100));
SendMessage(this->handle, TBM_SETPAGESIZE, 0, 4);
SendMessage(this->handle, TBM_SETSEL, false, (LPARAM)MAKELONG(0, 100));
SendMessage(this->handle, TBM_SETPOS, true, 0);
}
Why is this happening and how can I fix it?
I use SetLayeredWindowAttributes with LWA_COLORKEY to replace a color (#ff00ff) with transparency, in order to achieve transparent background in the CEF1 example.
It works well on 7/Vista.
On Windows XP, the function succeeds, but the color remains opaque.
My code to create the main window:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
HWND hWnd;
hInst = hInstance;
hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_COMPOSITED, szWindowClass, szTitle,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE, CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
WndProc for the main window:
switch (message) {
case WM_CREATE: {
...
info.SetTransparentPainting(TRUE);
info.SetAsChild(hWnd, rect);
// Create the new child browser window
CefBrowser::CreateBrowser(info,
static_cast<CefRefPtr<CefClient> >(g_handler),
url_to_pageWithMagentaBackground, settings);
SetLayeredWindowAttributes(hWnd, RGB(0xff, 0x00, 0xff), 0xff, LWA_COLORKEY);
Html displayed:
<style type="text/css">html { background: #ff00ff; }</style>
Note these points:
It does work on XP with LWA_ALPHA (makes whole window semi-transparent),
but not with LWA_COLORKEY
When I connect to the XP through Remote Desktop, I do see the transparency as expected!
Can someone explain this please?
I'm trying to create a launcher window with 5 "invisible" buttons that have a smaller partially transparent image centered inside them. The image inside changes depending on whether the user is hovering over the button. In this example the images are resources IDB_Website1 and IDB_Website2.
The images are in .png format. I'm using GDI+ and loading PNG files from resources with http://www.codeproject.com/Articles/3537/Loading-JPG-PNG-resources-using-GDI.
I've used BS_OWNERDRAW to handle the graphics of the button. The problem is that I don't know how to link the "PNG from resources" code to the parent's WM_DRAWITEM. With the current way I've done the code, I lose the transparency of the .png by going through HBITMAP.
Global variable:
HBITMAP globalpic;
Main wndproc:
case WM_CREATE:
{
HWND hwndButton = CreateWindow(TEXT("button"), NULL,
WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
190, 230, 260, 50, // <- the larger rect size
hWnd, (HMENU) HT_BUTTON1, hInst, NULL);
HTButton = (WNDPROC) SetWindowLong(hwndButton, GWL_WNDPROC, (LONG) ButtonProc);
}
case WM_DRAWITEM:
{
DRAWITEMSTRUCT* lpDrawItem = (DRAWITEMSTRUCT*)lParam;
HBITMAP hBmp;
HDC hdc = CreateCompatibleDC(NULL);
if (hovering) // <- mousehover detection, not included
{
gdi.CreateBM(IDB_Website2, _T("PNG"), hInst, hdc, 62, 100, 200, 40);
} else {
gdi.CreateBM(IDB_Website1, _T("PNG"), hInst, hdc, 62, 100, 200, 40);
}
hBmp = globalpic; // get the global var gdi.CreateBM created
DeleteDC(hdc);
BITMAP bm;
GetObject(hBmp, sizeof(bm), &bm);
HDC hMemDC = CreateCompatibleDC(NULL);
HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, hBmp);
StretchBlt (lpDrawItem->hDC,
lpDrawItem->rcItem.left + 30,
lpDrawItem->rcItem.top + 5,
200, <- the width of image
40, <- the height of image
hMemDC,
0, 0,
bm.bmWidth,
bm.bmHeight,
SRCCOPY);
SelectObject(hMemDC, hOldBmp);
DeleteDC(hMemDC);
DeleteObject(hBmp);
break;
}
class GDI's method CreateBM.
Currently, since I don't know of a better way, it sends the HBITMAP to the global variable globalpic. The problem is that by doing this, I lose transparency.
void CreateBM(UINT menuid, LPCTSTR pType, HMODULE hInst, HDC hdc, int x, int y, int w, int h)
{
CGdiPlusBitmapResource m_pBitmap;
m_pBitmap.Load(menuid, pType, hInst);
m_pBitmap.m_pBitmap->GetHBITMAP(RGB(255, 255, 0), &globalpic);
//m_pBitmap.m_pBitmap->GetHBITMAP(GetBkColor(hdc), &globalpic); // <- no-go either
}
Any way I could do this more directly? I feel that going through the HBITMAP route is completely unnecessary but I couldn't for the life of me figure out how I should do it.
Then again, if using the HBITMAP way is fine, any pointers on how I could make the color (I guess (RGB(255, 255, 0) ...?) transparent with the current implementation?
Answering to Hans:
I also have a GDI method like this, but it's unused at the moment because I couldn't get the image removed after drawing it (as is needed when hovering changes the image):
void Create(UINT menuid, LPCTSTR pType, HMODULE hInst, HDC hdc, int x, int y, int w, int h)
{
Graphics grpx(hdc);
ht_img = new CGdiPlusBitmapResource();
ht_img -> Load(menuid, pType, hInst);
grpx.DrawImage(*ht_img, x, y, w, h);
delete ht_img;
}
I attampted to draw a irregular window with the UpdateLayeredWindow(), in msvc2008, xp sp3.
Here is part of my code:
//Add something(CreateWindowEx()):
hwndCyauWnd = CreateWindowEx(
/*WS_EX_TOOLWINDOW |*/ WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_LAYERED,
lpwsCyauClassName,
lpwsCyauWndName,
WS_CLIPSIBLINGS | WS_POPUP,
GetSystemMetrics(SM_CXSCREEN)-320,
GetSystemMetrics(SM_CYSCREEN)-232,
320, 200,
NULL,
NULL,
hInstance,
NULL);
//Skip Lines
HDC hdcCyauWnd = GetDC(hwndCyauWnd);
HDC hdcBuffer = CreateCompatibleDC(hdcCyauWnd);
//HBITMAP hbmCyau = CreateCompatibleBitmap(hdcBuffer,120, 93);
//SelectObject(hdcBuffer, hbmCyau);
POINT ptZero = {0, 0};
POINT ptDrawPos = {0, 0};
RECT rctCyauWnd;
GetWindowRect(hwndCyauWnd, &rctCyauWnd);
SIZE szCyauWnd={rctCyauWnd.right - rctCyauWnd.left, rctCyauWnd.bottom - rctCyauWnd.top};
BLENDFUNCTION blendPixelFunction = { AC_SRC_OVER, 0, 100, AC_SRC_ALPHA};
Graphics gphCyauWnd(hdcBuffer);
Image imgCyau(L"surface0000.png");
gphCyauWnd.DrawImage(&imgCyau, 0, 0, 125, 93);
UpdateLayeredWindow(hwndCyauWnd,
hdcCyauWnd, &ptZero,
&szCyauWnd,
hdcBuffer, &ptZero,
0, //RGB(255, 255, 255),
&blendPixelFunction,
ULW_ALPHA);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
I have tried several method to use this function, but all failed, NOTHING APPEAR on the screen.
Could anybody tell me what happens and how to slove it?
Add:
Whole source file have been upload to my skydrive, anyone can edit, much appreciation! (I have become a poor underdog now...)
You mixed up GDI and GDI+, which is not a good idea. Here is a working example:
hWnd = CreateWindowEx(WS_EX_LAYERED, szWindowClass, szTitle, 0,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
// Load PNG
CImage img;
img.Load("BACKGR.png");
// Get image sizes
int nWidth = img.GetWidth();
int nHeight = img.GetHeight();
// Create memory DC
HDC hdcScreen = GetDC(NULL);
HDC hDC = CreateCompatibleDC(hdcScreen);
// Create memory bitmap
HBITMAP hBmp = CreateCompatibleBitmap(hdcScreen, nWidth, nHeight);
HBITMAP hBmpOld = (HBITMAP)SelectObject(hDC, hBmp);
// Draw image to memory bitmap (currently selected in memory DC)
img.Draw(hDC, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight);
// Call UpdateLayeredWindow
BLENDFUNCTION blend = {0};
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 128;// half transparent
blend.AlphaFormat = AC_SRC_ALPHA;
POINT ptLocation = {0, 0};
SIZE szWnd = {nWidth, nHeight};
POINT ptSrc = {0, 0};
UpdateLayeredWindow(hWnd, hdcScreen, &ptLocation, &szWnd, hDC, &ptSrc, 0, &blend, ULW_ALPHA);
ShowWindow(hWnd, SW_SHOW);
SelectObject(hDC, hBmpOld);
DeleteObject(hBmp);
DeleteDC(hDC);
ReleaseDC(NULL, hdcScreen);
If you want GDI+ to draw to an image with an alpha channel, you have to draw to a Bitmap, not an HDC, and you have to specify that the Bitmap's format has alpha. To do that with an HBITMAP, you have to also point GDI+ to the bitmap bits.
Something like this:
BITMAPINFOHEADER bih;
HBITMAP hbmp;
HDC hdc;
void *bits;
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;
hdc = CreateCompatibleDC(NULL);
hbmp = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, &bits, NULL, 0);
Bitmap bitmap(width, height, 0, PixelFormat32bppPARGB, bits);
Graphics graphics(bitmap);
graphics->DrawWhatever(...);
graphics->Flush();
SelectObject(hdc, hbitmap);
UpdateLayeredWindow(hwnd, hdc, ...