CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Apr 2013
    Posts
    34

    GetDIBits question.

    sorry, I hate posting 2 questions about the same (or, at least, similar) topic, i thought i had my getpixel issue solved... but... I didn't

    so I'm trying to use GetDIBits, since I am capable of taking an image of the Minecraft window and copying it to a clipboard sucessfully.

    problem is, I don't have much of an Idea how to use GetDIBits, I have some working code written:

    Code:
    #include <Windows.h>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        HBITMAP hBitmap = (HBITMAP) LoadImage(0, L"C:/Foo.bmp" ,IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        // check hBitmap for error
    
    
        BITMAP bm;
        ::GetObject( hBitmap , sizeof(bm) , &bm );
    
    	 /* Omitting error checks for brevity */
        HDC dcBitmap = CreateCompatibleDC ( NULL );
        SelectObject( dcBitmap, hBitmap );
    
        BITMAPINFO bmpInfo;
        bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmpInfo.bmiHeader.biWidth = bm.bmWidth;
        bmpInfo.bmiHeader.biHeight = -bm.bmHeight;
        bmpInfo.bmiHeader.biPlanes = 1;
        bmpInfo.bmiHeader.biBitCount = 24;
        bmpInfo.bmiHeader.biCompression = BI_RGB;        
        bmpInfo.bmiHeader.biSizeImage = 0;        
    
        COLORREF* pixel = new COLORREF [ bm.bmWidth * bm.bmHeight ];
        GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
    	
        int r = GetRValue ( *pixel );
        int g = GetGValue ( *pixel );
        int b = GetBValue ( *pixel );
        cout << r << " " << g << " " << b << endl;
    
        bm.bmHeight = bm.bmHeight - 1;
        GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
        r = GetRValue ( *pixel );
        g = GetGValue ( *pixel );
        b = GetBValue ( *pixel );
        cout << r << " " << g << " " << b << endl;
        cin.get();
    
        return 0;
    }

    I just used a small image I made in ms pain as a test for now.

    problem is, I can retrieve the first pixel of every scan line by editing "bm.bmHeight" but I can't figure out how to
    grab the second (or third, or fourth) pixel in each scan line.

    any help?
    Last edited by peteandperry; June 13th, 2013 at 03:54 PM.

  2. #2
    Join Date
    Apr 1999
    Posts
    27,449

    Re: GetDIBits question.

    problem is, I can retrieve the first pixel of every scan line by editing "bm.bmHeight" but I can't figure out how to
    grab the second (or third, or fourth) pixel in each scan line.
    Your code doesn't show where you're trying to get any pixel except for the first one.
    Code:
        COLORREF* pixel = new COLORREF [ bm.bmWidth * bm.bmHeight ];
        GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
    	
        int r = GetRValue ( *pixel );
        int g = GetGValue ( *pixel );
        int b = GetBValue ( *pixel );
    
    So where is the code to get the RGB value for *(pixel+1), *(pixel+2), etc.?

    Also, you have a memory leak due to not calling delete[] on the data you allocated.

    Regards,

    Paul McKenzie

  3. #3
    Join Date
    Apr 2013
    Posts
    34

    Re: GetDIBits question.

    honestly? I don't know. I've tried reading through the msdn site, but couldn't make to much sense, so I edited some code I found somewhere online till I started to get the results I wanted to.

    so for each pixel I make another call to :
    Code:
    //Pixel 1
        GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
    	
        int r = GetRValue ( *pixel );
        int g = GetGValue ( *pixel );
        int b = GetBValue ( *pixel );
    
    //pixel 2
        bm.bmHeight = bm.bmHeight - 1;
        GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
    	
        int r = GetRValue ( *pixel );
        int g = GetGValue ( *pixel );
        int b = GetBValue ( *pixel );
    I figured "COLORREF* pixel = new COLORREF [ bm.bmWidth * bm.bmHeight ];" was where it was grabbing the location from, however,
    when I try to play around with that, It either crashes the program, or it changes nothing.

    ex: if I try this (one of the non-crashy solutions):

    Code:
    	while(true)
    	{
    	bm.bmHeight = bm.bmHeight - 1;
    	pixel = new COLORREF [ bm.bmWidth * bm.bmHeight ];
    	GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
    	r = GetRValue ( *pixel );
    	g = GetGValue ( *pixel );
    	b = GetBValue ( *pixel );
    	cout << r << " " << g << " " << b << endl;
    	cin.get();
    	}
    it gets the pixels on the left side of the bitmap, but it'll do the same even without the "pixel = new COLORREF [ bm.bmWidth * bm.bmHeight ];" there.

    and if I do this:


    Code:
    	while(true)
    	{
    	bm.bmWidth = bm.bmWidth - 1;
    	pixel = new COLORREF [ bm.bmWidth * bm.bmHeight ];
    	GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
    	r = GetRValue ( *pixel );
    	g = GetGValue ( *pixel );
    	b = GetBValue ( *pixel );
    	cout << r << " " << g << " " << b << endl;
    	cin.get();
    	}
    it just continuously grabs the pixel at x1, y1. (well.. not entirely true since the y axis seems to go from the bottom up... but whatever)

    *oh, and yes, I'll have the cleanup stuff included with my actual code, I probably should have it included in the sample code I gave in the first post. but thank you for pointing that out
    Last edited by peteandperry; June 13th, 2013 at 05:42 PM.

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449

    Re: GetDIBits question.

    Quote Originally Posted by peteandperry View Post
    honestly? I don't know. I've tried reading through the msdn site, but couldn't make to much sense, so I edited some code I found somewhere online till I started to get the results I wanted to.
    Your problem has nothing to do with pixels or GetDIBits. It has everything to do with not knowing how to use pointers and/or arrays properly.

    If you do this:
    Code:
    int num = 25;
    int* pNum = new int [num];  // a dynamic array of ints
    How do you get to the first int, second int, third int, etc. of the memory pointed to by pNum? Whatever that is, replace "int" with COLORREF. Now how do you get from the first COLORREF to the second COLORREF, etc.?

    Regards,

    Paul McKenzie

  5. #5
    Join Date
    Apr 2013
    Posts
    34

    Re: GetDIBits question.

    *sorry for the long reply, since your making me work I wanted to tell you what's going through my mind
    so hopefully you can help me better thank you*

    yes I am relatively new at pointers, and my knowledge of array's is rudimentary.
    eg. i know I can make/fill/call an array like this:

    Code:
    int holdstuff[3];
    holdstuff[0] = 1;
    holdstuff[1] = 2;
    holdstuff[2] = 3;
    
    cout << holdstuff[0] << holdstuff[1] << holdstuff[2] ;
    
    // which would give an output of "123"
    and as for pointers, I've only used them to return multiple variables across functions. and (to my knowledge) works like thus:

    Code:
    int numba = 1; // this is a normal variable
    
    int storagebin = &numba; // "storagebin" now holds the address of where "numba" stored the number 1.
    
    cout << *storagebin; // this tells the program to look up the address that "storagebin" is located, and display it's contents.
    now, using that knowledge, I'll attemp to figure out how your code snippet works:

    Code:
    int num = 25; // simple enough, you made a variable called num, and stored the number 25 in it.
    
    int* pNum = new int [num];  // now this one Does confuse me a bit, so I'll attempt to read it, here it goes:
    /*
    this makes "pNum" point to... what is now magicly an array that is the size of num (25) 
    which you would either call by... "pNum[x]" or.. "pNum = x" wich would call the corosponding int stored in num?
    
    that doesn't make sense to me :s
    to (hopefully) not sound like a complete dolt;
    I know that "pNum" is suppose to be a pointer to "num" but I don't see how the compiler is supposed to know that,
    and [num] is supposed to be an array.. but whats the name of the array? pNum?
    */
    like I said, I'm pretty darn sure I'm wrong, but I would greatly appreciate a nudge in the right direction

    edit: PS, I actually really appreciate you answering this with another question because that way I have to do the research myself, which helps me learn a lot more rather then just spoon feeding it to me thank you. ^.^

    and also, your question hits the nail right on the head of one of the main things i never understood while reading the "http://www.cplusplus.com/doc/tutorial/pointers/" page
    Last edited by peteandperry; June 13th, 2013 at 09:45 PM.

  6. #6
    Join Date
    Apr 2013
    Posts
    34

    Re: GetDIBits question.

    ** hopefully I can get this in before you post a reply **

    ok, reading the pointer page, for what feels like the hundredth time. if i understand correctly, the reason why you don't need to 'link' an array to a pointer is because it does it automatically when they're made in the right order.. let me explain.

    it seems, that when you make a variable, or an array of variables, it assigns some "slots" of memory (this much I knew)

    but, unlike when you make a normal variable which fills itself with a NULL value, when you make a pointer variable
    it takes on the address of the last assigned variable, and if that variable is an array, it takes on the address of the first value of the array, and every "1" you add to that value, opens up the following container, which happens to be where an array stores it's next value

    (made a little pic for visualization purposes)

    Name:  pointer.jpg
Views: 2036
Size:  4.3 KB


    so... to answer your question (I think...) you would call the values in the array.... like this?

    Code:
    int num = 25;
    int* pNum = new int [num];  // a dynamic array of ints
    
    int holder;
    int X = 0;
    while(X <= num)
    {
        pNum = pNum + X;
        holder = *pNum;
        cout << holder << endl;
        X++;
    }
    though this still doesn't make full sense to me, but makes more sense then before.
    also i assume this wouldn't work since there is nothing stored in the array yet.

  7. #7
    Join Date
    Apr 1999
    Posts
    27,449

    Re: GetDIBits question.

    Quote Originally Posted by peteandperry View Post
    so... to answer your question (I think...) you would call the values in the array.... like this?

    Code:
    int num = 25;
    int* pNum = new int [num];  // a dynamic array of ints
    
    int holder;
    int X = 0;
    while(X <= num)
    {
        pNum = pNum + X;
        holder = *pNum;
        cout << holder << endl;
        X++;
    }
    though this still doesn't make full sense to me, but makes more sense then before.
    also i assume this wouldn't work since there is nothing stored in the array yet.
    You're making it much more difficult than it should be.

    Please look below:
    Code:
    int main()
    {
        int num = 25;
        int* pNum = new int [num];  // a dynamic array of ints
        pNum[0] = 1;  // sets the first element to 1
        pNum[1] = 20; // sets the second element to 20
        *(pNum + 1) = 45; // an alternate way to set the second element to 45
        //...
        int theNum = pNum[0]; // gets the first item pointed to by pNum
        theNum = pNum[1];  // gets the second item pointed to by pNum
        theNum = *(pNum + 1) // alternate way to get the second element
        delete [] pNum;
    }
    That is how simple it is. When you add a value to a pointer, you are accessing the n'th element from where the pointer points to.

    Knowing how to manipulate a pointer is a fundamental you must have if you want to write programs in a language such as C++ program.

    However, you must also realize that pointers shouldn't be overused. For example, your original sample didn't need to use any explicit pointer usage, as you have containers that relieve you of needing to use new[] and delete[] to create a dynamic array (CArray and std::vector, for example), making the code safer and (more) bug-free.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; June 14th, 2013 at 05:55 AM.

  8. #8
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: GetDIBits question.

    Quote Originally Posted by peteandperry View Post
    so... to answer your question (I think...) you would call the values in the array.... like this?

    Code:
    int num = 25;
    int* pNum = new int [num];  // a dynamic array of ints
    
    int holder;
    int X = 0;
    while(X <= num)
    {
        pNum = pNum + X;
        holder = *pNum;
        cout << holder << endl;
        X++;
    }
    though this still doesn't make full sense to me, but makes more sense then before.
    also i assume this wouldn't work since there is nothing stored in the array yet.
    Not withstanding Paul's post #7, the bounds of an array start at 0 and stop 1 before the maximum number of elements. So in your example, the bounds would be 0 to num - 1. So this

    Code:
    while(X <= num)
    should be
    Code:
    while(X < num)
    also, you would normally write this code like this

    Code:
    int const num = 25;
    int *const pNum = new int [num];  // a dynamic array of ints
    
    int *holder = pNum;
    for (int x = 0; x < num; x++, holder++) {
        cout << *holder << endl;
    }
    or even
    Code:
    int const num = 25;
    int *const pNum = new int [num];  // a dynamic array of ints
    
    for (int x = 0; x < num; x++)  {
        cout << pNum[x] << endl;
    }
    In your code you are changing pNum so that you no longer know the address of the start of the allocated memory - so can't use it or free it later!
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  9. #9
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: GetDIBits question.

    nononono a DIB doesn't store COLORREF's. don't use COLORREF in this case.

    for 24bit RGB it's an RGBTRIPLE structure
    for 32bit RGB it's an RGBQUAD structure where the rgbReserved member may or may not hold to the alpha value.

    the OP seems to want a 24Bit DIB, so it's RGBTRIPLE you want to use in that case. if you use COLORREF in this case, you'll get wonky results.



    while you could (ab)use a COLORREF in lieu of a RGBQUAD to some extent at this particular moment in time, it's a bad idea for several reasons. Since with a DIB you typically want to access color values, the RGB structures are more efficient in that anyway.

    COLORREF is currently typedefed to a DWORD, but from a pure theoretical POV MS could decide tomorrow that on the next windows platform a 64bit COLORREF with 16bits per color value might make more sence and change all their API's that way. And all well written code should correctly recompile. assuming a bitmap is made of colorrefs in that way would fail.

  10. #10
    Join Date
    Apr 2013
    Posts
    34

    Re: GetDIBits question.

    ** Sorry for this uber long response, you guys have given me a lot of input, and I feel like each one of you deserve
    and individual reply


    Paul McKenzie:

    I guess in my head I was getting confused because I was trying to figure out how the compiler thinks

    because in my head:

    Code:
    int num = 25;
    int* pNum = new int [num];  // a dynamic array of ints
    should be called like this

    Code:
    int num = 25;
    int * pNum[num];
    but having tested that, I found out that doesn't work.

    and the reason I was over thinking it was because in my code just doing "pixel[x]" led to a lot of problems.
    so I experimented with the alternative ( *(pixel+x) ) but, now (thanks to you) I found what I was doing wrong
    (I was using the pointers wrong) and pixel[x] does work

    and yes. in fact, I try to use as few pointers as possible (though, I admit, that's because I'm still uncomfortable
    using them because they get hard to follow very quickly trying to remember where what pointer is pointing to, then remembering that
    the pointer is just a pointer to the location of the container, not the contents itself, ect ect ect)
    which hurts my brain pretty fast, so yeah, I try to avoid using them if I can.

    I just used that example to show the extent of the knowledge I had of them at that point (more knowledgeable now though thanks to you ^>^ )

    and that last sentence of yours helped me understand why int * pNum[num] doesn't work, and helped me get a bit more understanding what needs to be cleaned up at the end of the program


    2kaud:

    thank you! though I actually did know that, I must have had a brain fart

    as for me using a while loop rather then a for loop, I guess that's just a bad habit I picked up
    from being self thought and the programming path I took (started learning with q-basic ages ago, more recently to mql4, ect which, for some reason
    even though In the back of my head I hear a voice saying "just use a for loop you dolt" I still end up using while loops.

    does it make any difference to performance? or is it purely a convenience?

    yes, that is correct I have now done away with changing the original pointer (don't know why I did it like that in the first place...)

    thank you!


    OReubens:

    Hmm... that could be the reason why I'm having the new Issue I'm having (see below).
    though I tried implementing it and since it seems to work by filling a struct rather then just being a normal
    data type, I started to get different problems that I'm sure I can figure out eventually but seem to require a fair bit more code.. though I'm sure
    once I figure it out it probably won't require nearly as much code as I'm thinking right now..

    I will be looking into this however, since I do want to make some of my software future proof. but if I have any questions about that I might start a new thread since it seems
    to be drifting from the original question.. unless my gut feeling is correct and it would solve this current problem:


    NEW PROBLEM!
    yay!... lol

    ok, here's my code now:

    Code:
    #include <Windows.h>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        HBITMAP hBitmap = (HBITMAP) LoadImage(0, L"C:/Foo.bmp" ,IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    
        BITMAP bm;
        ::GetObject( hBitmap , sizeof(bm) , &bm );
    
        HDC dcBitmap = CreateCompatibleDC ( NULL );
        SelectObject( dcBitmap, hBitmap );
    
        BITMAPINFO bmpInfo;
        bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmpInfo.bmiHeader.biWidth = bm.bmWidth;
        bmpInfo.bmiHeader.biHeight = -bm.bmHeight;
        bmpInfo.bmiHeader.biPlanes = 1;
        bmpInfo.bmiHeader.biBitCount = 24;
        bmpInfo.bmiHeader.biCompression = BI_RGB;        
        bmpInfo.bmiHeader.biSizeImage = 0;        
    
    	
    	COLORREF* pixel = new COLORREF [ bm.bmWidth * bm.bmHeight ];
        GetDIBits( dcBitmap , hBitmap , 0 , bm.bmHeight , pixel , &bmpInfo , DIB_RGB_COLORS );
    	int r,g,b;  
    	
    	//  vvvvvvvvvvvvv  ------ THIS IS THE NEW STUFF ------- vvvvvvvvvv //
    
    
    
    	cout << bm.bmWidth << " " << bm.bmHeight << endl; // just checking if the dimentions mach up with the actual bmp, they do.
    	int y = 0;
    	while(y < (bm.bmWidth * bm.bmHeight)) // again.. I probably should just use a for loop here >.< " for (int y = 0; x < (bm.bmWidth * bm.bmHeight); y++)
    	{
    		r = GetRValue ( pixel[y] );
    		g = GetGValue ( *(pixel+y) );
    		b = GetBValue ( *(pixel+y) );
    
    		cout << r << " " << g << " " << b << endl;
    		cin.get();
    		y=y+1; // y++ would work aswell
    	}
    
    	delete[] pixel; // i hope that's all I need to clean up..
    	return 0; // i'll worry about sending proper error codes later, to save clutter
    
    }

    ok, now, it's definitely getting closer to working perfectly, it (kinda) goes from pixel to pixel, and automatically goes to the next scan line at the end of each line.

    however.

    it seems to skip one color bite every time, like this:


    Name:  error.jpg
Views: 2066
Size:  13.5 KB
    (I can upload a picture of the output console as well if you want, but I think you know what I mean)

    you guys have been amazing so far! and I have really, truly appreciate it, and I've learned much
    (more then I've shown in this code, I've also learned stuff I can use for future code)

    but, I hate to ask.. but.. any Idea why it's doing this?

  11. #11
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: GetDIBits question.

    The answer is the type you iterate by:
    Code:
    C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include>grep -n COLORREF *.h | grep typedef
    windef.h:314:typedef DWORD   COLORREF;
    windef.h:315:typedef DWORD   *LPCOLORREF;
    wtypes.h:241:typedef DWORD COLORREF;
    wtypes.h:246:typedef DWORD *LPCOLORREF;
    Best regards,
    Igor

  12. #12
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: GetDIBits question.

    Quote Originally Posted by peteandperry View Post
    as for me using a while loop rather then a for loop, I guess that's just a bad habit I picked up
    from being self thought and the programming path I took (started learning with q-basic ages ago, more recently to mql4, ect which, for some reason
    even though In the back of my head I hear a voice saying "just use a for loop you dolt" I still end up using while loops.

    does it make any difference to performance? or is it purely a convenience?
    With todays optimising c++ compilers, no it doesn't make any difference to performance. It's just a style thing.

    You might also like to look at
    http://www.learncpp.com/
    Last edited by 2kaud; June 16th, 2013 at 07:04 AM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured