CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 25
  1. #1
    Join Date
    Jul 2005
    Posts
    21

    getting RGB from a 16-bit bitmap

    Hey, you guys seem to be the best programmers around, so I've got a question to ask you.

    I'm writing a program that detects pixels off the screen, and reacts accordingly. I've designed it to be as fast as possible, so I've done the following:

    Made the program wait for printscr to be pressed, allowing windows to copy the data to the clipboard.
    Tested, Opened, and Read in the clipboard HANDLE (as a HBITMAP)
    called GetDIBits to read in the colour data (the only important part)

    Now, I copy the buffer to stdin and fill out a 2d array. its an 800x600 picture at 16-bit colour, so I have a 2d array at [800*2][600] size, 2 bytes (16 bits) per pixel. Ill say this method is VERY fast. it clocks in at about 70ms including my Sleep(50) that I put in to allow time for the screenshot to be copied.

    But now I can't read the colour. Thats my problem. With a 24-bit bitmap you can see the R, G, and B quite easily because they have their own bytes for each. All I know is that there is a colour table and this somehow relates to the 16-bits... not helpful eough for me, I'm afraid. How do I turn these 2 bytes into R, G, and B?
    Instead should I just 'rebuild' the bitmap into memory, and use GetPixel on it? Got any other ideas for fast pixel scanning?

    EDIT - maybe this should be in 'graphics programming' - can a mod move it there?
    Last edited by TiMBuS; July 15th, 2005 at 11:57 PM.

  2. #2
    Join Date
    May 2005
    Posts
    4,954

    Re: getting RGB from a 16-bit bitmap

    i have a function i once wrote that convert bitmap to 24 bit color, you can take a look and modify it for your purposes. it uses the ::CreateDIBSection(..) api.
    all you need to provide to the fuction is the:
    const int &nWidth // width of the image

    const int &nHeight// height of the image

    const HBITMAP // handle to the bitmap of the 16 bit you have ( you can have by ::CreateBitmap(..) api or from ::LoadImage(..) api

    BYTE *lpDesBits // out - pointer to 24 bit data bits that you sould alloc before calling the function in a size of witdh*height*3

    Code:
    void Get24BitImage ( const int &nWidth, const int &nHeight,const HBITMAP &hBitmap , BYTE *lpDesBits)
    {
      HDC hDC = ::GetDC( 0 );
    
      HDC  memDC1 = ::CreateCompatibleDC ( hDC );
      HDC memDC2 = ::CreateCompatibleDC ( hDC );
    
      BYTE *lpBits = NULL;
    
      BITMAPINFO bmi;
      ::ZeroMemory( &bmi, sizeof(BITMAPINFO) );
      bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
      bmi.bmiHeader.biWidth       = nWidth;
      bmi.bmiHeader.biHeight      = nHeight;
      bmi.bmiHeader.biPlanes      = 1;
      bmi.bmiHeader.biBitCount    = 24;
      bmi.bmiHeader.biCompression = BI_RGB;
    
      HBITMAP hDIBMemBM  = ::CreateDIBSection( 0, &bmi, DIB_RGB_COLORS, (void**)&lpBits, NULL, NULL );
      HBITMAP hOldBmp1  = (HBITMAP)::SelectObject(memDC1, hDIBMemBM );
        
      HBITMAP hOldBmp2  = (HBITMAP) ::SelectObject ( memDC2,hBitmap);
    
      ::BitBlt( memDC1, 0, 0, nWidth, nHeight, memDC2, 0, 0, SRCCOPY );
        
      for ( int i = 0 ; i < nHeight ; i++)
        ::CopyMemory(&lpDesBits[i*3*nWidth],&lpBits[nWidth*3*(nHeight-1-i)],nWidth*3);
    
      // clean up
      ::SelectObject  ( memDC1, hOldBmp1  );
      ::SelectObject  ( memDC2,hOldBmp2  );
      ::ReleaseDC    ( 0, hDC      );
      ::DeleteObject  ( hDIBMemBM  );
      ::DeleteObject  ( hOldBmp1  );
      ::DeleteObject  ( hOldBmp2  );
      ::DeleteDC  ( memDC1  );
      ::DeleteDC  ( memDC2  );
    }

    Cheers
    Last edited by golanshahar; January 4th, 2006 at 04:37 PM.

  3. #3
    Join Date
    Nov 2003
    Location
    Belgium
    Posts
    8,150

    Re: getting RGB from a 16-bit bitmap

    Why can't you just use an array with 24 or 32 bit values?
    Marc Gregoire - NuonSoft (http://www.nuonsoft.com)
    My Blog
    Wallpaper Cycler 3.5.0.97

    Author of Professional C++, 4th Edition by Wiley/Wrox (includes C++17 features)
    ISBN: 978-1-119-42130-6
    [ http://www.facebook.com/professionalcpp ]

  4. #4
    Join Date
    Jul 2005
    Posts
    21

    Re: getting RGB from a 16-bit bitmap

    because I'm reading in 16-bit colour from the screen.

    golanshahar: thanks a lot man, its helpful, I'll test it to see how fast it is, and if the solution is feasable, then ill rate ;p
    PS. Does it output the standard 'upside down' bitmap?
    Last edited by TiMBuS; July 16th, 2005 at 06:00 AM.

  5. #5
    Join Date
    Jul 2005
    Posts
    21

    Re: getting RGB from a 16-bit bitmap

    Omg. fast as ever. Props to you man, for making that function which is PERFECT for my needs. Its also **** useful.

    Seriously ask microsoft to package that in their GDI, lol.

  6. #6
    Join Date
    May 2005
    Posts
    4,954

    Re: getting RGB from a 16-bit bitmap

    your welcome mate.
    btw it will convert any image buffer to 24 bit not only 16bit.

    Cheers

  7. #7
    Join Date
    Nov 2003
    Location
    Belgium
    Posts
    8,150

    Re: getting RGB from a 16-bit bitmap

    Quote Originally Posted by TiMBuS
    because I'm reading in 16-bit colour from the screen.
    I see. In that case, there is already a function in the Windows GDI that does exactly that: GetDIBits. One of the parameters specify which color-depth you want. So if you call that function on a 16 bit bitmap and you request 24 bit, the conversion is done for you.
    Marc Gregoire - NuonSoft (http://www.nuonsoft.com)
    My Blog
    Wallpaper Cycler 3.5.0.97

    Author of Professional C++, 4th Edition by Wiley/Wrox (includes C++17 features)
    ISBN: 978-1-119-42130-6
    [ http://www.facebook.com/professionalcpp ]

  8. #8
    Join Date
    May 2005
    Posts
    4,954

    Re: getting RGB from a 16-bit bitmap

    Quote Originally Posted by Marc G
    I see. In that case, there is already a function in the Windows GDI that does exactly that: GetDIBits. One of the parameters specify which color-depth you want. So if you call that function on a 16 bit bitmap and you request 24 bit, the conversion is done for you.
    not quite true, AFAIK GetDIBits alone wont do the work you can use it in the end only after you call the CreateDIBSection and specifed the format in there, then the BitBlt does the convertion.
    i know that instead of BitBlt we one could use the SetDIBitsToDevice ( which can also convert )

    Cheers

  9. #9
    Join Date
    Jul 2005
    Location
    Germany
    Posts
    1,194

    Re: getting RGB from a 16-bit bitmap

    Although your problem is already solved, I wanted to add something, because you were talking about performance and the above solution is a bit like shooting birds with cannons, if you really only want to get the RGB components of a 16-bit bitmap.
    A 16-bit bitmap does not use a colortable (that is the case for 8-bit bitmaps). It also uses the bits to describe the red, green and blue value of the pixel directly. For 32-bit you had 8 bit for red, 8 bit for green, 8 bit for blue and 8 bit for alpha (transparency). For 24-bit you had the same without alpha. Now for 16-bit you have two possible formats, because you can't divide the 16 bits by 3.
    1) Format 555: 5 bits for each color, 1 bit is unused.
    2) Format 565: 5 bits red, 6 green, 5 blue
    I think windows uses the second format 565, because it provides a more exact color information for the green portion. But let's go practic:

    Given the information above you can easiliy calculate the color components of a 16 bit color value like this:
    Code:
    nRed = (nColor & 0xF800) >> 11;
    nGreen = (nColor & 0x07E0) >> 5;
    nBlue = nColor & 0x1F;

  10. #10
    Join Date
    Jul 2005
    Posts
    21

    Re: getting RGB from a 16-bit bitmap

    thanks philkr, thats a very handy alternative method, and its great to finally crack the 16-bit code =)

    ty.

  11. #11
    Join Date
    May 2005
    Posts
    4,954

    Re: getting RGB from a 16-bit bitmap

    Quote Originally Posted by philkr
    Although your problem is already solved, I wanted to add something, because you were talking about performance and the above solution is a bit like shooting birds with cannons, if you really only want to get the RGB components of a 16-bit bitmap.
    A 16-bit bitmap does not use a colortable (that is the case for 8-bit bitmaps). It also uses the bits to describe the red, green and blue value of the pixel directly. For 32-bit you had 8 bit for red, 8 bit for green, 8 bit for blue and 8 bit for alpha (transparency). For 24-bit you had the same without alpha. Now for 16-bit you have two possible formats, because you can't divide the 16 bits by 3.
    1) Format 555: 5 bits for each color, 1 bit is unused.
    2) Format 565: 5 bits red, 6 green, 5 blue
    I think windows uses the second format 565, because it provides a more exact color information for the green portion. But let's go practic:

    Given the information above you can easiliy calculate the color components of a 16 bit color value like this:

    Code:
    nRed = (nColor & 0xF800) >> 11;
    nGreen = (nColor & 0x07E0) >> 5;
    nBlue = nColor & 0x1F;
    its pretty obvious that working on raw bits is faster than bliting however:
    - as i mentioned above you can use ::SetDibBitsToDevice() which is faster then BitBlt.
    - although your idea is faster the probelm is that you have to use cases (for 8,16 bits etc) since you de-composing the bits by yourself and not letting DIB to do the convertion. while in my function it will work on every input format.

    btw yes windows is working on 565 bit format

    Cheers

  12. #12
    Join Date
    Jul 2005
    Location
    Germany
    Posts
    1,194

    Re: getting RGB from a 16-bit bitmap

    You are perfectly right, although using cases would not be a problem for most configurations. You would only have to call GetDeviceCaps(hdc, BITSPIXEL). If you care about the small number of users with 256 colors, your method would be more comfortable, I think.
    Please don't forget to rate users who helped you!

  13. #13
    Join Date
    Jul 2005
    Posts
    21

    Re: getting RGB from a 16-bit bitmap

    hey, philkr, you seem to forget that i'm pulling the bitmap off of the clipboard, so I need to copy the bitmap somehow anyway (because I don't think leaving the clipboard open is in any way a good idea).
    Also, golanshahar, why is my output... odd.
    I run your function, fill in a unsigned int struct called DIBits, then do the following:
    Code:
    for (int y = 0; y < 600; ++y)
    			{
    				for (int x = 0; x < 800; ++x)
    				{
    					if (RGB(DIBits[x*3+(y*800*3)+2], DIBits[x*3+(y*800*3)+1], DIBits[x*3+(y*800*3)]) == RGB(255, 255, 255))
    						{
    							hdc = GetDC(NULL);
    							SetPixel(hdc, x, y, RGB(255, 0, 0));
    							ReleaseDC(NULL, hdc);
    						}
    				}
    			}
    It should 'paint' every white pixel on screen red, yes? I'm sure that I'm pointing it to the correct position on the array, too.. But it's not working right. Is my test function wrong, or is the Get24BitImage function wrong?
    The general error is that the painted pixels are too high up. the image seems vertically compressed.

    also, the result seems to 'tile' so I get repeating patterns painted.
    Last edited by TiMBuS; July 18th, 2005 at 12:05 AM.

  14. #14
    Join Date
    Jul 2005
    Posts
    21

    Re: getting RGB from a 16-bit bitmap

    Well after a bit of testing with above code, I replaced the 'if' paramaters so it simply showed
    Code:
     if (DIBits)
    And I noticed that the screen only colours 450 pixels down, not 600. Quick calculation: 450/600 = 3/4, hence meaning that the output is missing one byte per pixel. Your function may return the three RGB colours but its missing the AA placeholders, and I'm not yet sure if your result skews the table by returning, say BBGGRR for pixel 1, then AABBGG for pixel 2, RRAABB for pixel 3, etc.

  15. #15
    Join Date
    May 2005
    Posts
    4,954

    Re: getting RGB from a 16-bit bitmap

    hi mate, the function should work i took out of project of mine i did couple of years ago and it work. i dont know how you use it exactly and if you passing corret params.

    send your project and i will look into it.

    Cheers

Page 1 of 2 12 LastLast

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