Get bytes from HBITMAP
Asked Answered
V

5

6

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.

Vile answered 8/1, 2013 at 3:6 Comment(10)
Have you followed Microsoft's Image Store sample ?Inclined
@Inclined He stated that he tried GetDIBits but doesn't have a DC to pass to it (like the sample you linked to shows).Webby
@JonathonReinhart Forgive my failure to link using GetDIBits() to the OP trying (and failing) to following the prescribed method of doing this task from Microsoft's website. I didn't make the connection, and apparently I should have.Inclined
I guess the real question here, is "What are you planning on doing with the raw bytes?" If you want to write them to a PNG image, or something, you need to be getting device-independent data with GetDIBits.Webby
@Jonathon Reinhart I have to make some image processing and then output the result in a new HBITMAP pointer.Vile
@Vile The question at the end my answer stands -- "where did you get an HBITMAP without an accompanying HDC?"Webby
@Jonathon Reinhart This is the specification of the function that I have to implement. I don't know where it comes from...Vile
@Vile Well your question doesn't make any sense then. See my edit.Webby
@JonathonReinhart By the way, for testing purposes I am loading bitmap image using LoadImage function. And it comes without HDCVile
@Vile I think you need to show your code. I can help no further without seeing what you're doing / trying to do.Webby
W
0

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.

Webby answered 8/1, 2013 at 3:14 Comment(12)
Do you mean that anyway if using HBITMAP pointer I will have to deal with HDC?Vile
If you want to get color information, yes. Look at the link I included on DDBs.Webby
Only if you are dealing with a DDB, which is dependant on an HDC. If you are dealing with a DIB instead, then you do not need an HDC. So what does your HBITMAP actually point to - a DDB or a DIB?Ardelia
@RemyLebeau I thought an HBITMAP was always a DDB. HBITMAP on MSDN points you to this page, after which About Bitmaps states "A bitmap is one of the GDI objects that can be selected into a device context (DC)"Webby
@Jonathon Reinhart So it is not possible to connect existing HBITMAP with a newly created with HDC as you described in the Edit to your answer?Vile
Like I said, (unless I'm wrong, @RemyLebeau?) an HBITMAP is already tied to an HDC, in the extent that the HDC has the color information that the HBITMAP is referring to. You can certainly try, but I don't expect it to work. Again, your HBITMAP has to be coming from somewhere - and most likely, that place has its HDC.Webby
@Jonathon Reinhart if the HBITMAP was created using HDC, won't the GetDC function return the needed HDC if my function is called from DLL?Vile
@Vile Did you look at the documentation for GetDC? It takes an HWND to a window. The HBITMAP you're getting from LoadImage has nothing to do with your window (if you even have one).Webby
@Jonathon Reinhart I mean in case if HBITMAP was retrieved not using LoadImage. What if I pass NULL to getdc or GetCompatibleDC. Are you sure it is impossible to do something if HDC not provided?Vile
@Jonathon Reinhart OK I checked it, it is enough to call GetDC(NULL) and it works with it.Vile
Like I've said, it all depends where the HBITMAP is coming from, and if it's a DDB or DIB. I've given you everything I know and then some.Webby
If you load a bitmap from a resource, then you get an HBITMAP, but it's not tied to a particular DC. Like Remy has said, it is loading a DIB, not a DDB, so no DC is required.Gillette
F
14

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.

Frankfrankalmoign answered 31/10, 2014 at 11:49 Comment(1)
According to this msdn.microsoft.com/en-us/library/dd144904(v=vs.85).aspx if bitmap is not created by CreateDIBSection bitmap.bmBit pointer will be null.Lipsey
W
1

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.

Webby answered 8/1, 2013 at 5:33 Comment(0)
S
1

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.

Schottische answered 18/1, 2017 at 13:59 Comment(0)
W
0

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.

Webby answered 8/1, 2013 at 3:14 Comment(12)
Do you mean that anyway if using HBITMAP pointer I will have to deal with HDC?Vile
If you want to get color information, yes. Look at the link I included on DDBs.Webby
Only if you are dealing with a DDB, which is dependant on an HDC. If you are dealing with a DIB instead, then you do not need an HDC. So what does your HBITMAP actually point to - a DDB or a DIB?Ardelia
@RemyLebeau I thought an HBITMAP was always a DDB. HBITMAP on MSDN points you to this page, after which About Bitmaps states "A bitmap is one of the GDI objects that can be selected into a device context (DC)"Webby
@Jonathon Reinhart So it is not possible to connect existing HBITMAP with a newly created with HDC as you described in the Edit to your answer?Vile
Like I said, (unless I'm wrong, @RemyLebeau?) an HBITMAP is already tied to an HDC, in the extent that the HDC has the color information that the HBITMAP is referring to. You can certainly try, but I don't expect it to work. Again, your HBITMAP has to be coming from somewhere - and most likely, that place has its HDC.Webby
@Jonathon Reinhart if the HBITMAP was created using HDC, won't the GetDC function return the needed HDC if my function is called from DLL?Vile
@Vile Did you look at the documentation for GetDC? It takes an HWND to a window. The HBITMAP you're getting from LoadImage has nothing to do with your window (if you even have one).Webby
@Jonathon Reinhart I mean in case if HBITMAP was retrieved not using LoadImage. What if I pass NULL to getdc or GetCompatibleDC. Are you sure it is impossible to do something if HDC not provided?Vile
@Jonathon Reinhart OK I checked it, it is enough to call GetDC(NULL) and it works with it.Vile
Like I've said, it all depends where the HBITMAP is coming from, and if it's a DDB or DIB. I've given you everything I know and then some.Webby
If you load a bitmap from a resource, then you get an HBITMAP, but it's not tied to a particular DC. Like Remy has said, it is loading a DIB, not a DDB, so no DC is required.Gillette
G
0

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

Glazer answered 8/1, 2013 at 3:18 Comment(4)
From MSDN: "'Note This function is provided only for compatibility with 16-bit versions of Windows. Applications should use the GetDIBits function."Webby
Furthermore, this is getting the raw bits, but it is still a device-dependent bitmap, so you don't have correct color information.Webby
see my latest comment on the OP.Webby
@Vahid Farahmand GetBitmapBits is returning 0. Which means fail.Vile

© 2022 - 2024 — McMap. All rights reserved.