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

    Re: getting RGB from a 16-bit bitmap

    dont worry about it now man, I got it all going and I'm more than happy about that
    thanks again for the function, it's just fine, I had a few x, y values swapped, is all, thats why the screen only had 3/4 of the pixels.

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

    Re: getting RGB from a 16-bit bitmap

    ok good to hear it worked out for you.
    anytime mate.

    Cheers

  3. #18
    Join Date
    Oct 2005
    Posts
    7

    Thumbs up Re: getting RGB from a 16-bit bitmap

    I know you solved your problem TiMBuS, but I thought I would post a solution/improvement for all the novices like me who need to see it so we can learn it!

    This is the entire OnClick() event for a button on my main form:

    Code:
    void __fastcall TFrmMain::Button3Click(TObject *Sender)
    {
    TPoint ptOrigin = FrmMain->GetClientOrigin(); //This ensures all drawing begins in the
    ptOrigin.x+=PaintBox->Left;                   //client area of MY form. my 'lpCapturedBits'
    ptOrigin.y+=PaintBox->Top;                    //was captured using user32.dll PrintWindow()
    					      //and represents ONLY an alien window, NOT the
    					      //whole screen! You can omit this, and set the
    					      //rcDrawArea TRect to the entire screen to
    					      //accomplish what TiMBuS was trying. I created
    					      //ptOrigin, rcDrawArea, BitsPerPixel, and
    					      //BitPosition for 3 reasons: To eliminate
    					      //redundancy, to make modifications easier, and
    					      //to make this code easier to read! NOTE: PaintBox
    					      //is a TPaintbox, and I am using C++ Builder 6.0
    					      //on Windows XP--->Thus the call to PrintWindow()...
    TRect rcDrawArea;
    rcDrawArea.left=ptOrigin.x;
    rcDrawArea.top=ptOrigin.y;
    rcDrawArea.right=ptOrigin.x+PaintBox->Width;
    rcDrawArea.bottom=ptOrigin.y+PaintBox->Height;
    
    int BitsPerPixel=4; //Add function here to determine screen color depth...Mine is 32 Bit
    		    //32 Bit Color Depth: BitsPerPixel=4
    		    //24 Bit Color Depth: BitsPerPixel=3
    		    //16 Bit Color Depth: BitsPerPixel=2
    		    //THIS IS WHERE TiMBuS had his problem! In fact, merely replacing 3
    		    //as a multiplier in his code might have been enough for him. I
    		    //think this code is more flexible, and should be faster, though!
    		    //PS: I tried it and it worked GREAT for me!
    
    int BitPosition=0;
    
    	for (int y = 0; y < rcDrawArea.Height(); ++y)
    	{
    		for (int x = 0; x < rcDrawArea.Width(); ++x)
    		{       //BitPosition avoids the same math being done 3x in a row, with the same values!
    			BitPosition=x*BitsPerPixel+(y*rcDrawArea.Width()*BitsPerPixel);
    			if (RGB(lpCapturedBits[BitPosition+2], lpCapturedBits[BitPosition+1], lpCapturedBits[BitPosition]) == RGB(255, 255, 255))
    				{
    					hdc = GetDC(NULL);
    					SetPixel(hdc, ptOrigin.x+x, ptOrigin.y+y, RGB(255, 0, 0));//You can Omit ptOrigin if using the WHOLE SCREEN
    					ReleaseDC(NULL, hdc);
    				}
    		}
    	}
    }
    My notes and explanations are in the code... My code, in particular, uses a capture of an alien window via User32.dll PrintWindow() to set the value of lpCapturedBits[]. I THINK you need to be running Windows XP to call that function... here is the breakdown on how to access lpCapturedBits, As I have seen it referenced MANY times in these posts, and never explained for those of use who still need the Dummy Books...

    Code:
        int BitsPerPixel=4;
        int captureSize = BitsPerPixel * captureWidth * captureHeight;
        lpCapturedBits = new char[captureSize];
    
        //'lpCapturedBits' is is my image data array, it is globally declared
    
        GetBitmapBits(memBM, captureSize, lpCapturedBits);
    'lpCapturedBits' is basically raw bitmap pixel bits stacked inside... For example, with bitPosition determined by desired pixel coords, and bits per pixel:

    Code:
    int bitPosition = (    (  y*captureWidth  )+x    )*BitsPerPixel; 
    //You may have to fudge your x,y values a bit... I had y=y+3 in this equation
    //to make my image line up, due to OTHER FACTORS
    
    lpCapturedBits[BitPosition]=blueBit;
    lpCapturedBits[BitPosition+1]=greenBit;
    lpCapturedBits[BitPosition+2]=redBit;
    lpCapturedBits[BitPosition+3]=alphaBit; //I don't use this, it is the transparency channel,
                                            //and the elusive "4th bit" that causes so many
                                            //beginners like me headaches!
    
    int PixelColor = RGB( redBit, greenBit, blueBit );
    I am just learning this stuff, so I figure as a novice, I can explain it to other novices!

    ~Maui
    Last edited by mauigb; October 23rd, 2005 at 10:59 PM.

  4. #19
    Join Date
    May 2004
    Posts
    28

    Re: getting RGB from a 16-bit bitmap

    Hi,

    sorry to bump the old thread, but just thought better to post here than start a new thread where I'll be told to do a forum search ... I've just did, plus google search

    Anyway, I just don't get it, it seems that all articles are missing some vital info which holds me off from continuing my work. What I'm trying to do is a simple thing (which became complicated) - get RGB values from a 16-bit 565 WORD value. Here's the problem. I have 3 variables (red, green, blue) of WORD type, which contain R, G and B values respectively. I pack these three values based on the algorythm found in MSDN (see source code). I get a 16-bit value containing all 3 RGB components. Then I'm trying to decode it back to separate R, G and B values, and I'm not getting those, even remotely.

    Initial RGB values are - 100 110 120 (dec)
    After decomposing I get 5 47 24 (dec)

    Below is the source code:

    Code:
    #include <iostream.h>
    #include <windows.h>
    
    int main ()
    {
    
    	WORD red = 100;
    	WORD green = 110;
    	WORD blue = 120;
    
    	WORD pixel565 = (red << 11) | (green << 5) | blue;	
    	
    	WORD red_mask = 0xF800;
    	WORD green_mask = 0x7E0;
    	WORD blue_mask = 0x1F;
    
    	BYTE red_value = (pixel565 & red_mask) >> 11;
    	BYTE green_value = (pixel565 & green_mask) >> 5;
    	BYTE blue_value = pixel565 & blue_mask;
    
    	cout << "R = " << (int)red_value << "\n";
    	cout << "G = " << (int)green_value << "\n";
    	cout << "B = " << (int)blue_value << "\n";
    
    	return 0;
    }
    Was is wrong with it? Something is obviously missing. But all the articles explain only that, so from their words this should be enough...well, maybe but it just doesn't work

    Any help is much appreciated,
    Oleg
    Last edited by Xatrix; January 3rd, 2006 at 09:23 AM.

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

    Re: getting RGB from a 16-bit bitmap

    Before "WORD pixel565 = (red << 11) | (green << 5) | blue;" you need to make sure the red, green and blue values are truncated to the appropriate size: red and blue are 5 bits, green is 6 bits.
    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 ]

  6. #21
    Join Date
    May 2004
    Posts
    28

    Re: getting RGB from a 16-bit bitmap

    ohh, that's it! Thank you, Marc!
    (wish it would have been mentioned in other sources cause that was the vital info which was omitted)

  7. #22
    Join Date
    Aug 2005
    Posts
    3

    Re: getting RGB from a 16-bit bitmap

    Sorry, for resurrecting this old topic, but it showed up as "HOT THREADS..." in my CodeGuru Newsletter which I was reading because I was bored.

    I have a question about golanshahar's method though. I always thought that if you create a compatible DC context it will be in the same color format as the source (i.e. Display). In your code you create a compatible device context which could be of any color depth (8, 16, 24, 32 bpp) and selecting a 24 bpp bitmap into it.

    What happens if you set your display to 256 colors and run this sample? Since you are delaing with device dependent bitmaps, wouldn't the colors be really distorted? Or am I missing something?

    Quote Originally Posted by golanshahar
    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  );
      ::DeleteObject  ( memDC1  );
      ::DeleteObject  ( memDC2  );
    }

    Cheers

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

    Re: getting RGB from a 16-bit bitmap

    Quote Originally Posted by Partizan
    Sorry, for resurrecting this old topic, but it showed up as "HOT THREADS..." in my CodeGuru Newsletter which I was reading because I was bored.
    dont you have something better to do when you are bored ?
    kidding.

    I have a question about golanshahar's method though. I always thought that if you create a compatible DC context it will be in the same color format as the source (i.e. Display). In your code you create a compatible device context which could be of any color depth (8, 16, 24, 32 bpp) and selecting a 24 bpp bitmap into it.

    What happens if you set your display to 256 colors and run this sample? Since you are delaing with device dependent bitmaps, wouldn't the colors be really distorted? Or am I missing something?
    well no you are not missing something. in fact you are right. however dont forget that this answer was given to a specific question

    if you seek for better solution that is not device depended the better/fast way is to work with the raw bits and simply turn each RGB24 to RGB16 , here look at this sample that i worte:

    Code:
    void ColorConversion24To16 ( BYTE *lpBits24, int Width, int Height, BYTE *lpBits16   )
    {
      int nPos16 = 0;
      int Size = Width*Height*3;
      for ( int nPos24 = 0 ; nPos24 < Size ; nPos24+=3 ,nPos16+=2)
      {
        BYTE Red24   = lpBits24[nPos24+2]; // 8-bit red
        BYTE Green24 = lpBits24[nPos24+1]; // 8-bit green
        BYTE Blue24  = lpBits24[nPos24+0]; // 8-bit blue
    
        BYTE Red16   = Red24   >> 3;  // 5-bit red
        BYTE Green16 = Green24 >> 2;  // 6-bit green
        BYTE Blue16  = Blue24  >> 3;  // 5-bit blue
    
        unsigned short RGB2Bytes = Blue16 + (Green16<<5) + (Red16<<(5+6));
    
        lpBits16[nPos16]  = LOBYTE(RGB2Bytes);
        lpBits16[nPos16+1]= HIBYTE(RGB2Bytes);
      }
    }
    
      // usage
      int Width  = 100;
      int Height = 100;
    
      BYTE *lpBits24 = new BYTE[Width*Height*3];
      BYTE *lpBits16 = new BYTE[Width*Height*2];
    
    
      ColorConversion24To16( lpBits24,Width,Height,lpBits16);
    
    
      delete [] lpBits24;
      delete [] lpBits16;
    it getting two raw bits (input as 24 and output as 16) and simply convert each 24 bit pixel to 16 bit.

    NOTE: i didnt test it much but it should work.

    /EDIT Opps i just realized that i coverted the other way around ( from 24 to 16 instead 16 to 24 ) i need to get some sleep. but anyway you got the idea.

    Cheers
    If a post helped you dont forget to "Rate This Post"

    My Article: Capturing Windows Regardless of Their Z-Order

    Cheers

  9. #24
    Join Date
    Aug 2005
    Posts
    3

    Re: getting RGB from a 16-bit bitmap

    Quote Originally Posted by golanshahar
    well no you are not missing something. in fact you are right. however dont forget that this answer was given to a specific question
    In that case you threw me off with one of your replies to philkr, saying that your method will work with ANY bitmap. You should note that it will work with "any" bitmap only if you are upconverting that "any" bitmap.

    Quote Originally Posted by golanshahar
    if you seek for better solution that is not device depended the better/fast way is to work with the raw bits and simply turn each RGB24 to RGB16 , here look at this sample that i worte:
    Thanks. I'm using similar in-memory manipulations on DIBs to change color depth. I find this method fast and accurate.

  10. #25
    Join Date
    May 2005
    Posts
    4,954

    Re: getting RGB from a 16-bit bitmap

    Quote Originally Posted by Partizan
    In that case you threw me off with one of your replies to philkr, saying that your method will work with ANY bitmap. You should note that it will work with "any" bitmap only if you are upconverting that "any" bitmap.
    i meant to every input format!
    ...while in my function it will work on every input format...
    which is true. (while your dc is compatible with 24 )

    Cheers
    If a post helped you dont forget to "Rate This Post"

    My Article: Capturing Windows Regardless of Their Z-Order

    Cheers

Page 2 of 2 FirstFirst 12

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