Given an HBITMAP, is there any way to find out, whether it contains an alpha channel? - winapi

In an attempt to improve this answer, I am looking for a way to determine, whether a bitmap referenced through an HBITMAP contains an alpha channel.
I understand, that I can call GetObject, and retrieve a BITMAP structure:
BITMAP bm = { 0 };
::GetObject(hbitmap, sizeof(bm), &bm);
But that only gets me the number of bits required to store the color of a pixel. It doesn't tell me, which bits are actually used, or how they relate to the individual channels. For example, a 16bpp bitmap could encode a 5-6-5 BGR image, or a 1-5-5-5 ABGR image. Likewise, a 32bpp bitmap could store ABGR or xBGR data.
I could take it a step further, and probe for a DIBSECTION instead (if available):
bool is_dib = false;
BITMAP bm = { 0 };
DIBSECTION ds = { 0 };
if ( sizeof(ds) == ::GetObject(hbitmap, sizeof(ds), &ds ) {
is_dib = true;
} else {
::GetObject(hbitmap, sizeof(bm), &bm );
}
While this can disambiguate the 16bpp case (using the dsBitfields member), it still fails to determine existence of an alpha channel in the case of a 32bpp image.
Is there any way to find out, whether a bitmap referenced through an HBITMAP contains an alpha channel (and which bit(s) are used for it), or is this information simply not available?

You cannot know definitively, but you can make a good educated guess if you're willing to iterate through the pixels..
(Ignoring the 16-bit color with 1-bit alpha channels, for now anyway.)
For there to be an alpha channel, it's necessary (but not sufficient) for the bitmap to be a DIB section and to have 32 bits per pixel. As noted in the question, you can check for those requirements.
We also know that Windows deals only with pre-multiplied alpha. That means, for every pixel A >= max(R, G, B). So, if you're willing to scan all the pixels, you can rule out a bunch of 24-bit images. If that condition holds for all pixels and if any of the A's are non-zero, you almost certainly have an alpha channel (or a corrupted image).
Basically, the only uncertainty left is the all-transparent image versus the all-black image, both of which consist of pixels with all channels set to zero. Perhaps it's sufficient to take an educated guess in that case. I would guess yes, since having a 32-bit DIB section is a pretty strong signal. If you had a 32-bit device-dependent bitmap, then it doesn't have alpha, and if you had a device-independent bitmap without alpha, you'd probably use 24 bits per pixel to save space.
Some of the more detailed bitmap info headers can tell you if bits are reserved for the alpha channel. For example, see BITMAPV5HEADER, which has a mask indicating which bits are the alpha channel (though the documentation says some contradictory things). Likewise for the BITMAPV4HEADER. Unfortunately, I don't think there's a way to get this version of the header from an HBITMAP. (And I'm certain there are alpha-enabled bitmap files out there that don't set these fields correctly.)
It's well-known that GDI doesn't handle alpha channels (with the exception of AlphaBlend, which doesn't take an HBITMAP but accesses one selected into a memory DC). There are user APIs, like UpdateLayeredWindow that work with images with alpha channels, but, like AlphaBlend, take the bitmap data from the information selected into a memory DC. LoadImage, if passed the correct flags, will preserve the alpha channel when loading a DIB to be accessed by HBITMAP.
ImageList_Add, which does take an HBITMAP, will preserve and alpha channel if the image list is created with the proper flags. In all these cases, however, the caller must know that the bitmap data contains proper alpha data and set the right flags for the API. This suggests that the information is not readily available from the bitmap handle.
If you have access to the bitmap resource or file that the image was loaded from, it is possible to see if the original header uses BI_BITFIELDS and has an alpha channel specified, but you can't get to that header from the HBITMAP in all cases. (And there's remains the concern that the header isn't filled out correctly.)

You can get it indirectly by using GetObject function. Tucked away in the documentation is a note:
If hgdiobj is a handle to a bitmap created by calling CreateDIBSection, and the specified buffer is large enough, the GetObject function returns a DIBSECTION structure. In addition, the bmBits member of the BITMAP structure contained within the DIBSECTION will contain a pointer to the bitmap's bit values.
If hgdiobj is a handle to a bitmap created by any other means, GetObject returns only the width, height, and color format information of the bitmap. You can obtain the bitmap's bit values by calling the GetDIBits or GetBitmapBits function.
(emphasis mine)
In other words: if you try to decode it is a DIBSECTION, but it's only a BITMAP, then
dibSection.BitmapInfoHeader
will not be updated. (e.g. left as zeros)
It's helpful to remember how a BITMAP and a DIBSECTION differ:
| BITMAP | DIBSECTION |
|------------------------|--------------------------|
| bmType: Longint | bmType: Longint |
| bmWidth: Longint | bmWidth: Longint |
| bmHeight: Longint | bmHeight: Longint |
| bmWidthBytes: Longint | bmWidthBytes: Longint |
| bmPlanes: Word | bmPlanes: Word |
| bmBitsPixel: Word | bmBitsPixel: Word |
| bmBits: Pointer | bmBits: Pointer |
| | |
| |BITMAPINFOHEADER | <-- will remain unchanged for BITMAPs
| | biSize: DWORD |
| | biWidth: Longint |
| | biHeight: Longint |
| | biPlanes: Word |
| | biBitCount: Word |
| | biCompression: DWORD |
| | biSizeImage: DWORD |
| | biXPelsPerMeter: Longint |
| | biYPelsPerMeter: Longint |
| | biClrUsed: DWORD |
| | biClrImportant: DWORD |
| | |
| | dsBitfields: DWORD[3] |
| | dshSection: HANDLE |
| | dsOffset: DWORD |
If you try to get a BITMAP as a DIBSECTION, the GetObject function will not fill in any fields of the BITMAPINFOHEADER.
So check if all those values are empty, and if so: you know it's not a DIBSECTION (and must be a BITMAP).
Sample
function IsDibSection(bmp: HBITMAP): Boolean
{
Result := True; //assume that it is a DIBSECTION.
var ds: DIBSECTION = Default(DIBSECTION); //initialize everything to zeros
var res: Integer;
//Try to decode hbitmap as a DIBSECTION
res := GetObject(bmp, sizeof(ds), ref ds);
if (res = 0)
ThrowLastWin32Error();
//If the bitmap actually was a BITMAP (and not a DIBSECTION),
//then BitmapInfoHeader values will remain zeros
if ((ds.Bmih.biSize = 0)
and (ds.Bmih.biWidth = 0)
and (ds.Bmih.biHeight= 0)
and (ds.Bmih.biPlanes= 0)
and (ds.Bmih.biBitCount= 0)
and (ds.Bmih.biCompression= 0)
and (ds.Bmih.biSizeImage= 0)
and (ds.Bmih.biXPelsPerMeter= 0)
and (ds.Bmih.biYPelsPerMeter= 0)
and (ds.Bmih.biClrUsed= 0)
and (ds.Bmih.biClrImportant= 0))
Result := False; //it's not a dibsection
}

Related

Shadows on windows with a bit depth of 32

In my reparenting window manager, I reparent windows to frames with the same bit depth:
let geom = self.conn.get_geometry(ev.window)?.reply()?;
let attr = self.conn.get_window_attributes(ev.window)?.reply()?;
let frame_win = self.conn.generate_id()?;
let win_aux = xproto::CreateWindowAux::new()
.event_mask(
xproto::EventMask::EXPOSURE
| xproto::EventMask::SUBSTRUCTURE_REDIRECT
| xproto::EventMask::SUBSTRUCTURE_NOTIFY
| xproto::EventMask::BUTTON_PRESS
| xproto::EventMask::BUTTON_RELEASE
| xproto::EventMask::POINTER_MOTION
| xproto::EventMask::ENTER_WINDOW
| xproto::EventMask::PROPERTY_CHANGE,
)
.background_pixel(self.config.background_pixel)
.border_pixel(self.config.border_pixel)
.colormap(attr.colormap);
self.conn.create_window(
geom.depth,
frame_win,
screen.root,
geom.x,
geom.y,
geom.width,
geom.height + self.config.title_height as u16,
self.config.border_width as u16,
xproto::WindowClass::INPUT_OUTPUT,
attr.visual,
&win_aux,
)?;
However, when the bit depth of the inside window and therefore the frame is 32, compositors do not draw shadows around the frame. If it has another depth like 24 they do. why would this happen?
It looks like xcompmgr just doesn't composite windows with a depth of 32. Picom and Compton work fine. Maybe there's some setting to change that; at any rate, there's nothing the wm can do about it.

How to read GetDeviceCaps() return values?

I am new to Windows API and I just can't seem to figure this out:
According to the documentation the function int GetDeviceCaps(HDC hdc,int index); returns integer values which correspond to the selected item I want to know about. However, how am I supposed to convert the integers to the values?
printf("Rastercaps: %d\n", GetDeviceCaps(hdc, RASTERCAPS));
// rastercaps: 32409
item RASTERCAPS:
values
RC_BANDING Requires banding support.
RC_BITBLT Capable of transferring bitmaps.
RC_BITMAP64 Capable of supporting bitmaps larger than 64 KB.
RC_DI_BITMAP Capable of supporting the SetDIBits and GetDIBits
functions.
RC_DIBTODEV Capable of supporting the SetDIBitsToDevice
function.
RC_FLOODFILL Capable of performing flood fills.
...
Does 32409 mean the device has RASTERCAP values (capabilities) 3,2,4,0 and 9, in the order as stated in their table?
Thank you.
They're bitmasks. In the relevant C header file (wingdi.h) there is
/* Raster Capabilities */
#define RC_NONE
#define RC_BITBLT 1 /* Can do standard BLT. */
#define RC_BANDING 2 /* Device requires banding support */
#define RC_SCALING 4 /* Device requires scaling support */
#define RC_BITMAP64 8 /* Device can support >64K bitmap */
...and many more.
The return value (32409) is made up of the bitwise-or of these values. So, for example, if you wanted to know if the device could support >64K bitmap you would do
int rc = GetDeviceCaps(hdc, RASTERCAPS);
if (rc & RC_BITMAP64) { /* it does support >64k */ }
So in this case, 32409 is 0111111010011001 in binary which means it has the capabilities RC_BITBLT | RC_BITMAP64 | RC_GDI20_OUTPUT | RC_DI_BITMAP |
RC_DIBTODEV | RC_BIGFONT | RC_STRETCHBLT | RC_FLOODFILL | RC_STRETCHDIB | RC_OP_DX_OUTPUT.
See "Bitwise operations in C"

How to add image in CTreeCtrl list in MFC

I am trying to add Image before the text in CTreeList control but it is not coming up, But what i observed is the the node name is started after some space , like it is leaving the space for bitmap , but image is not showing up.. here is the code snap:-
CImageList m_ImageList;
CBitmap m_Bitmap1;
m_ImageList.Create(16,16,ILC_COLOR32,1,1);
m_Bitmap1.LoadBitmap(IDB_BITMAP1);
m_ImageList.Add(&m_Bitmap1, RGB(0,0,0));
TreeSoft->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP |
TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT |
TVS_SINGLEEXPAND | TVS_SHOWSELALWAYS |
TVS_TRACKSELECT,
CRect(10, 10, 200, 240), this, 0x1221);
TreeSoft->SetImageList(&m_ImageList, TVSIL_NORMAL);
hTree = TreeSoft->InsertItem( L"Software Production",0,0, TVI_ROOT);
hCompany = TreeSoft->InsertItem(L"Microsoft",0,0, hTree);
Pls tell me what i am missing here...
Now you just need to set the image for the newly created branch:
TreeSoft->SetItemImage(hTree , 0, 0); // I think it starts from 0 (if it does not show try 1)
Just for testing purposes.
Create an icon with 16-bit color palette.
Instead of ILC_COLOR32 use ILC_COLOR.
And instead of RGB(0,0,0) use (COLORREF)0xFFFFFF
I have exact the same code except the smaller color palette and it works.
If this works you can try with the bigger palette.

What is the difference between creating a buffer object with clCreateBuffer + CL_MEM_COPY_HOST_PTR vs. clCreateBuffer + clEnqueueWriteBuffer?

I have seen both versions in tutorials, but I could not find out, what their advantages and disadvantages are. Which one is the proper one?
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);
vs.
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL);
Thanks.
[Update]
I added CL_MEM_COPY_HOST_PTR, to the second example to make it correct.
During my working with OpenCL I found a very important difference between
cl_mem CT = clCreateImage3DContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , Volume_format, X, Y, Z, rowPitch, slicePitch, sourceData, &error);
and
cl_mem CT = clCreateImage3D(Context, CL_MEM_READ_ONLY , Volume_format, X, Y, Z, 0, 0, 0, &error);
error = clEnqueueWriteImage(CommandQue, CT, CL_TRUE, origin, region, rowPitch, slicePitch, sourceData, 0, 0, 0);
For the first approach OpenCL will copy the host pointer not direct to the GPU. First it will allocate a second temporary buffer on the host which can cause problems if you load big stuff like a CT to the GPU. For a short time the needed memory is twice the CT size. Also the data is not copied during this function. It is copied during the argument setting to the kernel function which uses the 3D image object.
The second approach direct copies the data to the GPU. There are no additional allocations done by OpenCL. I think this is probably the same for normal buffer objects.
I assume that inputdata is not NULL.
In that case the second approach should not work at all, since the specifications says, that clCreateBuffer returns NULL and an error, if:
CL_INVALID_HOST_PTR if host_ptr is NULL and CL_MEM_USE_HOST_PTR or CL_MEM_COPY_HOST_PTR are set in flags or if host_ptr is not NULL but CL_MEM_COPY_HOST_PTR or CL_MEM_USE_HOST_PTR are not set in flags.
so you mean either
clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);
or
clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);
The first one should be more or less the same as the first approach you showed, while the second one won't actually copy the data, but instead use the supplied memory location for buffer storage (caching portions or all of it in device memory). Which of those two is better depends on the usage scenario obviously.
Personaly I prefer using the two step approach of first allocating the buffer and afterwards filling it with a writeToBuffer, since I find it easier to see what happens (of course one step might be faster (or it might not, thats just a guess))
The nice aspect of the first approach, is that "clEnqueueWriteBuffer" allows you to assign an event to the copy of a buffer. So, let's say you want to measure the time it takes to copy data to the GPU using the GPU_Profiling options, you will be able to do so with the first approach, but not with the second one.
The second approach is more compact, easier to read, and requires less lines to code.
One major difference that I've run into:
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);
This first set of commands will create an empty buffer and enqueue a command in your command queue to fill the buffer.
cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL)
This second command will create the buffer and fill it immediately. Note that there's no command queue in this argument list, so it uses the contents of input data as it is right now.
If you've already been running CL code and your source pointer is dependent upon a previous command in the command queue completing (e.g. an enqueued read of a prior output buffer), you definitely want to use the 1st method. If you try to create and fill the buffer in a single command, you'll end up with a race condition in which the buffer contents will not properly wait on the completion of your prior buffer read.
Well the main difference between these two is that the first one allocates memory on the device and then copies data to that memory. The second one only allocates.
Or did you mean clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);?

Storage location of yellow-blue shield icon

Where, in Windows, is this icon stored? I need to use it in a TaskDialog emulation for XP and am having a hard time tracking it down.
It's not in shell32.dll, explorer.exe, ieframe.dll or wmploc.dll (as these contain a lot of icons commonly used in Windows).
Edit:
For clarification, I am emulating a certain type of dialog in XP. The icon is (most likely) not present there. So I want to extract it from the library that holds it in Windows 7. I am extending an existing implementation of this emulation and want to provide a full feature set.
I wanted to point it out explicitly.
You are supposed to put a shield on UI elements that will trigger an elevation: MSDN: Step 4: Redesign Your UI for UAC Compatibility.
Of course, you don't have to go spelunking around DLLs to extract images (although it certainly does make it easier at design time when you can design your design with a design time interface).
Microsoft provides a couple of supported (and therefore guaranteed) ways that you can get ahold of the shield icon at runtime:
Add a shield icon to the user interface?:
Extract a small icon
SHSTOCKICONINFO sii;
sii.cbSize = sizeof(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &sii);
hiconShield = sii.hIcon;
Extract a large icon
SHSTOCKICONINFO sii;
sii.cbSize = sizeof(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICON | SHGSI_LARGEICON, &sii);
hiconShield = sii.hIcon;
Extract an icon of custom size
SHSTOCKICONINFO sii;
sii.cbSize = sizeof(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICONLOCATION, &sii);
hiconShield = ExtractIconEx(sii. ...);
Add a Shield Icon to a Button
Button_SetElevationRequiredState(hwndButton, TRUE);
The article forgot to mention LoadIcon:
hIconShield = LoadIcon(0, IDI_SHIELD);
Although LoadIcon has been "superseded" by LoadImage:
hIconShield = LoadImage(0, IDI_SHIELD, IMAGE_ICON, desiredWith, desiredHeight, LR_SHARED); //passing LR_SHARED causes size to be ignored. And you must pass LR_SHARED
Loading the size you want - by avoiding shared images
In order to avoid loading a "shared" version of the icon, you have to load the icon directly out of the file.
We all know that the shield exists in user32.dll as resource id 106:
| Icon | Standard Icon ID | Real Resource ID |
|------------------|-------------------|------------------|
| IDI_APPLICATION | 32512 | 100 |
| IDI_QUESTION | 32514 | 102 |
| IDI_WINLOGO | 32517 | 105 |
| IDI_WARNING | 32515 | 101 |
| IDI_ERROR | 32513 | 103 |
| IDI_INFORMATION | 32516 | 104 |
| IDI_SHIELD | 32518 | 106 |
That was undocumented spellunking.
SHGetStockIconInfo can give us the actual, current, guaranteed to change in the future, path and index:
TSHStockIconInfo sii;
ZeroMemory(#sii, SizeOf(sii));
sii.cbSize := SizeOf(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICONLOCATION, {var}sii);
resulting in:
sii.szPath: C:\WINDOWS\System32\imageres.dll
sii.iIcon: -78
You can load this image for the size you desire using LoadImage:
HMODULE hmod := LoadLibrary(sii.szPath);
Integer nIconIndex := Abs(sii.iIcon); //-78 --> 78
ico = LoadImage(hmod, MAKEINTRESOURCE(nIconIndex), IMAGE_ICON, 256, 256, 0);
Another slightly easier way is to use SHDefExtractIcon:
HICON GetStockIcon(DWORD StockIconID, Integer IconSize)
{
HRESULT hr;
TSHStockIconInfo sii;
ZeroMemory(#sii, SizeOf(sii));
sii.cbSize := SizeOf(sii);
hr = SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICONLOCATION, {var}sii);
OleCheck(hr);
HICON ico;
hr = SHDefExtractIcon(sii.szPath, sii.iIcon, 0, ref ico, null, IconSize);
OleCheck(hr);
return ico;
}
It does the loading for you, and it handles the negative icon index (and the secret meaning that has):
HICON shieldIcon = GetStockIcon(SIID_SHIELD, 256);
Personally, i then use WIC to wrap that into a IWICBitmap:
IWICBitmap GetStockWicBitmap(DWORD StockIconID, Integer IconSize)
{
HICON ico = GetStockIcon(StockIconID, IconSize);
IWICBitmap bitmap;
IWICImagingFactory factory = new WICImagingFactory();
HRESULT hr = factory.CreateBitmapFromHICON(ico, out bitmap);
OleCheck(hr);
return bitmap;
}
and so:
IWICBitmap bmp = GetStockWicBitmap(SIID_SHIELD, 256);
Now that you have the bitmap, at runtime, do with it what you want.
Small and Large
The problem with ExtractIconEx is that you're again stuck with the two shell sizes:
"small" (i.e. GetSystemMetrics(SM_CXSMICON))
"large" (i.e. GetSystemMetrics(SM_CXICON))
Loading icons is something that is quite a dark art in Windows:
LoadIcon
LoadImage
LoadImage(..., LR_SHARED)
ExtractIcon
ExtractIconEx
IExtractImage
SHDefExtractIcon
SHGetFileInfo(..., SHGFI_ICON, ...);
SHGetFileInfo(..., SHGFI_SYSICONINDEX, ...);
SHGetFileInfo(..., SHGFI_ICONLOCATION, ...);
IThumbnailProvider
Icons available through SHGetStockIconInfo
Microsoft gives a handy page that gives an example, and description, of all the stock icons.
SHSTOCKICONID (archive)
And the 256px shield icon (as of Windows 10):
The shield icon is located in the file C:\Windows\System32\imageres.dll (at least, in my copy of English 32-bit Windows 7). There are several versions of the shield icon there, including the blue and yellow version you have above (icon 78).
Icons extracted from Windows 7 x64 SP1 English:
16x16 shield icon:
24x24 shield icon:
32x32 shield icon:
You are asking the wrong question. It doesn't matter where this icon is stored on any version of windows. If Microsoft don't tell you then you should not use it - it might not be there in windows 8 (or whatever comes after 7).
If you want the icon so bad, there is a decent graphical representation of it above in this question. You could do alt-prt scrn then use your favourite graphics app to turn it into an icon and add it to your app. This may not be legal though (remember, IANAL)

Resources