Is there a way I can determine if an HDC uses alpha channel? I read Question 333559 and Question 685684, but their questions are about BITMAP. Apparently, some HDC has alpha channel (though they may not use it. Call this "Type 1") while others do not ("Type 2"). I know this by doing the following:
Given a HDC,
Create a compatible DC, and create a DIB section. Select the created HBITMAP into the compatible DC.
BitBlt the source HDC to the compatible DC. Now examine the DIB section bits. For type 2 HDC, after every 3 bytes there is a byte always 0 (like 255 255 255 0); for type 1, these bytes are usualy 255 (like 250 240 230 255). To avoid false positive, I memset the bits to all 0x80 prior to the calls.
Use GetDIBits directly on the source HDC, specify the HBITMAP as GetCurrentObject(hdc, OBJ_BITMAP). For both types of HDC, the 4th bytes are always 0.
Change the DC bitmap by calling ExtTextOut. For type 2, ExtTextOut always set the 4th bytes to 0. For type 1, ExtTextOut always leave them untouched.
I also noticed that the source HDC that are created by APIs (CreateCompatibleDC(), BeginPaint() ...) are always type 2. Type 1 HDC are from standard controls (like menu text). Even the HDC I CreateCompatibleDC from a type 1 becomes a type 2.
So, on one hand, I'm frustrated that Microsoft does not provide equal information to developers (another example may be that you cannot know the direction of a HBITMAP after it is created), on the other hand, I'm still wondering is there a way to distinguish these HDC.
Thanks for help.
I just mimic GDI's behavior and everything works fine now.
Related
This question already has an answer here:
The result of CreateCompatibleDC only has two colors
(1 answer)
Closed 2 years ago.
Why would passing a compatible DC and the DC the compatible one is based on to CreateCompatibleBitmap() give different results?
This one creates a monochrome bitmap:
CDC dcMem;
dcMem.CreateCompatibleDC(mydc);
destBitmap->CreateCompatibleBitmap(&dcMem, rect.Width(), rect.Height());
CBitmap* pBmpOld = dcMem.SelectObject (destBitmap);
// ... Draw on to the DC ....
dcMem.SelectObject (pBmpOld);
This one creates the correct color bitmap:
CDC dcMem;
dcMem.CreateCompatibleDC(mydc);
destBitmap->CreateCompatibleBitmap (mydc, rect.Width(), rect.Height());
CBitmap* pBmpOld = dcMem.SelectObject (destBitmap);
// ... Draw on to the DC ....
dcMem.SelectObject (pBmpOld);
TIA!!
As per the comments, have a look at the CreateCompatibleBitmap documentation:
Note: When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it. If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap. To create a color bitmap, use the HDC that was used to create the memory device context, as shown in the following code ...
MSDN says that the bitmap used in GetDiBits should not be selected into a DC before calling this function. But from my experience(with BitBlt) I know that I cannot draw an a bitmap unless it is selected.
How does GetDiBits circumvents this? Can I just use an unselected, newly created bitmap as argument to this function?
GetDiBits as well CreateDibSection returns an array. But MSDN says about the first function:
"bits of the specified compatible bitmap"
I thought DI stands for DeviceIndependent. Why is there a contradiction? This means that, according to MSDN, GetDiBits can be used only with CreateCompatibleBitmap (which is DD)? Then I can't send this array to another machine to display it,right?
Both functions use a hDC. If CreateDibSection is truly DIndependent why does it need a hDC? All the needed info is provided through the bitmapinfoheader...
I cannot draw an a bitmap unless it is selected. How does GetDiBits circumvents this?
GetDIBits doesn't do any drawing. It reads pixel data from a bitmap and converts it into the desired color format. SetDIBits doesn't "draw" either, but it will set the pixel data in a bitmap.
Naming confusion.
The DI in GetDIBitmap refers to the fact that the pixel data is returned in a device-independent format (specifically, the one you ask for). The source bitmap can be a compatible bitmap or a device-independent bitmap.
Similarly SetDIBitmap takes device-independent pixel data and converts it to the type of the target bitmap.
These functions are confusingly named.
What's the DC for?
The DC is used to answer any questions about the pixel format on the device. For example, if the source format is a palette-based device-dependent bitmap, GetDIBits will assume the palette selected into the DC is the correct one. Note that the palette is not in the BITMAPINFOHEADER.
CreateDIBSection creates a hybrid bitmap that stashes data in a device-independent method, but may also keep a device-dependent copy in sync with it for performance. So it needs to know the DC of the intended device.
How can I get image bytes from hbitmap if I am given an HBITMAP pointer, and my application is console application.
I tryed using GetDIBits which require such parameter as HDC, which I can't get.
EDIT:
I load bitmap from file:
HBITMAP bm = 0;
BITMAP Bitmap;
bm = (HBITMAP)LoadImage (0, TEXT("C:\\img1.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
I pass the HBITMAP to the function and expect to get another HBITMAP of processed image:
HBITMAP out1 = func(bm);
Where func is:
HBITMAP func(HBITMAP im);
And the problem is how to get image bytes from HBITMAP.
The easiest way is not to use GetDIBits (nor GetBitmapBits). These functions suck because they copy the data.
If you want the data directly, just use (for a DDB bitmap)
BITMAP bitmap;
GetObject(hBitmap, sizeof(bitmap), (LPVOID)&bitmap);
For a DIB bitmap use
DIBSECTION dib;
GetObject(hBitmap, sizeof(dib), (LPVOID)&dib);
GetObject info, See:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144904%28v=vs.85%29.aspx
This will not involve any copying of data, thus avoids the complicated issues associated with GetDIBits, See:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144879%28v=vs.85%29.aspx
Esp. the comments at the bottom for an explanation of the difficulties with GetDIBits.
Note that you do not get the palette info, but since most bitmaps are 24 or 32 bits anyway this is hardly an issue most of the time.
Since you're using LoadImage to get the HBITMAP, then it is indeed a DIB (Device-Independent Bitmap) (they call it a DIBsection). However, you don't have the color information.
This MSDN HOWTO shows you how to select the DIBsection into a memory DC. They then go on to use GetDIBColorTable to get the palette. However, I believe from there, with that DC you can use GetDIBits to get the RGB bitmap information as you were trying to do.
Here's the general gist of it:
// Create a memory DC and select the DIBSection into it
hMemDC = CreateCompatibleDC( NULL );
(HBITMAP)SelectObject( hMemDC, hBitmap );
GetDIBits(hMemDC, hBitmap, ...);
You'll note in their code that SelectObject returns a handle to the what was in the DC. They then restore that before calling DeleteDC. I'm not sure its entirely necessary, but they do it. I left it out here for clarity.
What worked for us is this: call GetDIBits while the correct palette (if indexed colour) is still selected into the device context. (Without the palette selected, the colours got garbled.)
But in our use case, it turned out that DIB sections performed a lot better, so check those out as well and benchmark. However, there are some gotchas. Windows wouldn't use the palette, we had to call SetDIBColorTable before use. But the device context still needed a one entry (black only) dummy palette selected and realised into the device context otherwise Windows would also ignore the palette set by SetDIBColorTable. Both SetDIBColorTable and RealizePalette needed to be present otherwise the colours would be garbled.
See new answer since question was edited...
You cannot do this without a handle to the device context (HDC). This is because GetDIBits expects an HBITMAP which is
A handle to the bitmap. This must be a compatible bitmap (DDB).
A DDB is a Device-Dependent Bitmap, (as opposed to a DIB, or Device-Independent Bitmap). That means:
Note that a DDB does not contain color values; instead, the colors are in a device-dependent format.
Which is why GetDIBits requires an HDC. Otherwise it cannot get the color information.
Perhaps a good question is, where did you get an HBITMAP without an accompanying HDC?
If you're trying to create this bitmap in memory, first you can call CreateCompatibleDC to create an in-memory DC compatible with some device, then CreateCompatibleBitmap with that DC. Then you have an HBITMAP and HDC to work with as you please. Otherwise, if you don't know what your HBITMAP is pointing to, you can't expect to do anything useful with it.
You can try GetBitmapBits API even from console. More here:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144850%28v=vs.85%29.aspx
Just pass HBITMAP handle and you'll get your bytes
When I convert an Enhanced Metafile (constructed via GDI+ in C#) into an old-style Windows Metafile, the results are very rough, apparently because coordinates are being rounded to the nearest screen pixel. I see this if I convert either via
GetWinMetaFileBits(emfh, bits_l, bits, MM_ANISOTROPIC, GetDC(0));
or using GDI+'s Metafile::EmfToWmfBits. The culprit is presumably the screen DC being used. This posting suggests using a printer DC, which works for me, but obviously will not work if the user has no printers installed. Is there a better way? I have considered creating a high-resolution in-memory DC for the purpose, but I can find no proper documentation for doing so, and I also worry about the RAM used.
The normal way is to create a much higher resolution memory DC, render to that and then save it however you want. Note that font sizes can get screwed up by this.
HDC memDC = CreateCompatibleDC ( hDC );
HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
SelectObject ( memDC, memBM );
With nWidth , nHeight much larger.
The CreateCompatible bit should set all the dpi etc, but I have had problems where the fonts were drawn fixed pixel size rather than rescaled - so they ended up being only 10pixels high on a 10,000 pixel image
Ask Google for ENMETA.EXE
Description by Microsoft
Example in download included.
MSDN displays the following for CreatePatternBrush:
You can delete a pattern brush without
affecting the associated bitmap by
using the DeleteObject function.
Therefore, you can then use this
bitmap to create any number of pattern
brushes.
My question is the opposite. If the HBRUSH is long lived, can I delete the HBITMAP right after I create the brush? IE: does the HBRUSH store its own copy of the HBITMAP?
In this case, I'd like the HBRUSH to have object scope while the HBITMAP would have method scope (the method that creates the HBRUSH).
The HBRUSH and HBITMAP are entirely independent. The handles can be deleted entirely independent from each other, and, once created, no changes to either object will effect the other.
The brush does have its own copy of the bitmap. This is easily see by deleting the bitmap after creating the brush and then using the brush (works fine)
Using GetObject to fill a LOGBRUSH structure will return the original BITMAP handle in member lbhatch, though, and not the copy's handle, unfortunately. And using GetObject on the returned bitmap handle fails if the bitmap is deleted.
Anyone any idea how to get the original bitmap dimensions from the brush in this case? I wish to create a copy of the pattern brush even though the original bitmap is deleted. I can get a copy of the original bitmap simply by painting with the brush, but I don't know it's size. I tried using SetbrushorgEx (hdc, -1,-1), hoping the -1's would be reduced modulo its dimensions when brush selected into device context and get values when I retrieve with GetBrushOrgEx. Doesn't work.
I think the bitmap must outlive the brush: the brush just references the existing bitmap rather than copying it.
You could always try it and see what happened.
I doubt that the CreatePatternBrush() API copies the bitmap you give it, since an HBITMAP is:
a GDI handle, the maximum number of which is limited, and
potentially quite large.
Win32 and GDI tend to be conservative about creating internal copies of your data, if only because when most of their APIs were created (CreatePatternBrush() dates to Windows 95, and many functions are older still), memory and GDI handles were in much more limited supply than they are now. (For example, Windows 95 was required to run well on a system with only 4MB of RAM.)