Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

screen capture: 24bit color Vs 256 color 1

Status
Not open for further replies.

tokool

Programmer
Nov 6, 2001
40
US
Hi all:
I have a piece of code which captures the screen and saves it as a bitmap file. When i use 32 and 24 bit color it works fine, however..when i set the display to 256 colors, it gives me a blank screen...why?????
Appriciate the help.
Thanks,
Preetham.
 
Almost certainly related to palettes. 32 and 24-bit desktops are easily captured because the code doesn't need to worry about palettes. 256 colors and less can, oddly, be a little more complex
 
Is there any piece of code that i could get that would help solve my problem.
And true, i am not handling any kinda paletts in my code.
 
please: would you post the piece of code for me? ive been searching for a while that functionality...

thanks anyway
 
The method GetScreenBitmap() is used to capture the screen.
There are some redundant operations performed in the method, which u can ignore or modify....



#define DibWidth(pDib) (((BITMAPINFOHEADER *)pDib)->biWidth)
#define DibHeight(pDib) (((BITMAPINFOHEADER *)pDib)->biHeight)
#define DibBitCount(pDib) (((BITMAPINFOHEADER *)pDib)->biBitCount)
#define DibClrUsed(pDib) (((BITMAPINFOHEADER *)pDib)->biClrUsed)
#define DibNumColors(pDib) (DibClrUsed(pDib) ? DibClrUsed (pDib) : (DibBitCount(pDib) <= 8 ? 1 << DibBitCount(pDib) : 0))

#define DibClrTablePtr(pDib) ((RGBQUAD *) (pDib + sizeof (BITMAPINFOHEADER)))

#define DibBitsPtr(pDib) (pDib + sizeof (BITMAPINFOHEADER) + sizeof (RGBQUAD) * DibNumColors(pDib))

#define DibRowLength(pDib) (((DibWidth(pDib) * DibBitCount(pDib) + 31) & ~31) >> 3)

#define DibRowPtr(pDib,iRow) (DibBitsPtr(pDib) + DibRowLength(pDib) * (DibHeight(pDib) - (iRow) - 1))

#define DibPixelPtr(pDib,iRow,iCol) (DibRowPtr(pDib,iRow) + (iCol) * DibBitCount(pDib) / 8)

#define DibBitsSize(pDib) (DibHeight(pDib) * DibRowLength(pDib))

#define DibTotalSize(pDib) (sizeof (BITMAPINFOHEADER) + sizeof (RGBQUAD) * DibNumColors(pDib) + DibBitsSize(pDib))
#define DibGetColor(pDib,i) (* (DibClrTablePtr(pDib) + (i)))
#define DibSetColor(pDib,i,rgb) (* (DibClrTablePtr(pDib) + (i)) = (rgb))

//Get the Screen Bitmap and return a global handle to the memory containing the bmp
BOOL GetScreenBitmap(HDC appDC);


HPALETTE GetCurrentPalette (HWND hwnd);

BYTE * ConvertDDBtoDIB (HWND hwnd, HBITMAP hBitmap, HPALETTE hPalette);

int Compare1 (const void * p1, const void * p2) ;
int Compare2 (const void * p1, const void * p2) ;

typedef struct
{
int indexOld ; // The original palette index
int indexNew ; // The new palette index
DWORD dwCount ; // The number of pixels of that color
RGBQUAD rgb ; // The RGB value for that index
}
COLORCOUNT ;
BYTE * DibSortColorTable (BYTE * pDib);

DWORD DibGetPixel (PBYTE pDib, int iRow, int iCol) ;
void DibSetPixel (PBYTE pDib, int iRow, int iCol, DWORD dwPixel) ;


//Get the Screen Bitmap and return a global handle to the memory containing the bmp
BOOL
GetScreenBitmap(HDC hdcscr)
{
HPALETTE hPalette;
BYTE * pdib;
RECT appRectNew;
BITMAPFILEHEADER bmfh ;
DWORD dwTotalSize, dwBitsSize ;

GetClientRect(hWndApp, &appRectNew);
if(appRectNew.bottom + 48 != appRect.bottom ||
appRectNew.right + 8 != appRect.right ||
appRectNew.top != appRect.top ||
appRectNew.left != appRect.left)
{
appRect.bottom = appRectNew.bottom + 48;
appRect.right = appRectNew.right + 8;
appRect.top = appRectNew.top;
appRect.left = appRectNew.left;
//
hbitmap = CreateCompatibleBitmap(hdcscr,
int (appRect.right - appRect.left),
int (appRect.bottom - appRect.top));

SelectObject(hdcmem, hbitmap);
if(hbitmap == NULL)
{
//error
//err1 = GetLastError();
}
}


BitBlt(hdcmem, 0, 0,
abs(appRect.right - appRect.left),
abs(appRect.bottom - appRect.top),
hdcscr, appRect.left, appRect.top, SRCCOPY );

hPalette = GetCurrentPalette(hWndApp);
//if(hPalette == NULL)



if(hbitmap)
{
pdib = ConvertDDBtoDIB(hWndApp, hbitmap, hPalette);
if(pdib == NULL)
{
return 0;
}
pdib = DibSortColorTable(pdib);
}

// Get the size of the DIB and the bits
dwBitsSize = DibBitsSize (pdib) ;
dwTotalSize = DibTotalSize (pdib) ;

// Now we're ready to define the BITMAPFILEHEADER
bmfh.bfType = * (WORD *) &quot;BM&quot; ;
bmfh.bfSize = sizeof (BITMAPFILEHEADER) + dwTotalSize ;
bmfh.bfReserved1 = 0 ;
bmfh.bfReserved2 = 0 ;
bmfh.bfOffBits = bmfh.bfSize - dwBitsSize ;

//Allocate memory and move the bitmap data to the memory
if(prevMemScreenDataSize == 0 || prevMemScreenDataSize != bmfh.bfSize
|| memScreenData == 0)
memScreenData = (LPBYTE) GlobalAlloc(GMEM_FIXED, bmfh.bfSize);

memcpy((void *)memScreenData,(LPVOID)&bmfh, sizeof (bmfh));
memcpy((void *)(memScreenData + sizeof(bmfh)),(LPVOID)pdib, dwTotalSize);

//DeleteObject(hPalette);
//set the buffer size and the Buffer pointer
memScreenDataSize = bmfh.bfSize;
screenInfoCard->bufSize = bmfh.bfSize;
screenInfoCard->hSize = appRect.right - appRect.left;
screenInfoCard->vSize = appRect.bottom - appRect.top;
prevMemScreenDataSize = bmfh.bfSize;

// Open the output file
//write the bmp into the memory
DWORD dwTemp =0;
HANDLE hf = CreateFile(&quot;testCaptureBitmap.bmp&quot;,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
WriteFile(hf, memScreenData, bmfh.bfSize,
(LPDWORD) &dwTemp, NULL);
CloseHandle(hf);

free(pdib);

return true;
}







/*-------------------------------------------------------
GetCurrentPalette: Obtains the current system palette.
-------------------------------------------------------*/

HPALETTE GetCurrentPalette (HWND hwnd)
{
HDC hdc ;
HPALETTE hPalette ;
int iSize ;
LOGPALETTE * plogpal ;

// Get a video device context

hdc = GetDC (hwnd) ;

// If the video device supports palettes, get palette size
// (Betcha a hundred to one it'll be 256!)

if (RC_PALETTE & GetDeviceCaps (hdc, RASTERCAPS))
{
iSize = GetDeviceCaps (hdc, SIZEPALETTE) ;

// Allocate memory for the palette and get it.

plogpal = (LOGPALETTE*)malloc (sizeof (LOGPALETTE) +
sizeof (PALETTEENTRY) * (iSize - 1)) ;

plogpal->palVersion = 0x0300 ;
plogpal->palNumEntries = iSize ;

GetSystemPaletteEntries (hdc, 0, iSize, plogpal->palPalEntry) ;

// Now create a palette based on the system palette entries

hPalette = CreatePalette (plogpal) ;

// free the memory

free (plogpal) ;
}
// If the device doesn't support palettes, hPalette is NULL.

else
hPalette = NULL ;

// Release the DC
ReleaseDC (hwnd, hdc) ;

return hPalette ;
}



/*-------------------------------------------------------------------------
ConvertDDBtoDIB: Converts a GDI bitmap object to a DIB using a palette.
Function based on Knowledge Base article Q80080.
-------------------------------------------------------------------------*/

BYTE * ConvertDDBtoDIB (HWND hwnd, HBITMAP hBitmap, HPALETTE hPalette)
{
BITMAP bm ;
BITMAPINFO * pbmi ;
BYTE * pBits ;
HDC hdc ;
WORD wBitCount, wNumColor, wColorEntries, wRowLength ;

// Get information about the DDB & calculate bits per pixel

GetObject (hBitmap, sizeof (BITMAP), (PSTR) &bm) ;
wBitCount = bm.bmPlanes * bm.bmBitsPixel ;

// Figure out the DIB bit count and number of colors.
// (Probably more generalized than it needs to be)

if (wBitCount > 16)
{
wNumColor = 0 ;
wBitCount = 24 ;
}
else if (wBitCount > 8)
{
wNumColor = 0 ;
wBitCount = 16 ;
}
else if (wBitCount > 4)
{
wNumColor = 1 << wBitCount ;
wBitCount = 8 ;
}
else if (wBitCount > 2)
{
wNumColor = 1 << wBitCount ;
wBitCount = 4 ;
}
else if (wBitCount == 1)
{
wNumColor = 2 ;
}

// Determine the number of entries in the DIB color table

wColorEntries = wNumColor ;

if (wColorEntries == 0 && wBitCount <= 8)
wColorEntries = 1 << wBitCount ;

// DIB rows are always multiple of 4 bytes long.

wRowLength = ((bm.bmWidth * wBitCount + 31) & ~31) >> 3 ;

// Allocate memory for the entire DIB.

DWORD size = sizeof (BITMAPINFOHEADER) +
sizeof (RGBQUAD) * wColorEntries +
wRowLength * bm.bmHeight;
pbmi = (BITMAPINFO*)malloc (size) ;

if (pbmi == NULL)
{
cout << &quot;ERROR:&quot; << GetLastError() << endl;
return NULL ;
}

// Initialize the BITMAPINFOHEADER

pbmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER) ;
pbmi->bmiHeader.biWidth = bm.bmWidth ;
pbmi->bmiHeader.biHeight = bm.bmHeight ;
pbmi->bmiHeader.biPlanes = 1 ;
pbmi->bmiHeader.biBitCount = wBitCount ;
pbmi->bmiHeader.biCompression = BI_RGB ;
pbmi->bmiHeader.biSizeImage = 0 ;
pbmi->bmiHeader.biXPelsPerMeter = 0 ;
pbmi->bmiHeader.biYPelsPerMeter = 0 ;
pbmi->bmiHeader.biClrUsed = wNumColor ;
pbmi->bmiHeader.biClrImportant = 0 ;

// Determine the address of the pixel bits in the DIB

pBits = (BYTE *) pbmi + sizeof (BITMAPINFOHEADER) +
sizeof (RGBQUAD) * wColorEntries ;

// Get a video device context and select the palette into it

hdc = GetDC (hwnd) ;
SelectPalette (hdc, hPalette, FALSE) ;
RealizePalette (hdc) ;

// Here's the function we've all been waiting for.

GetDIBits (hdc, hBitmap, 0, bm.bmHeight, pBits, pbmi, DIB_RGB_COLORS) ;

// Clean up and get out.

ReleaseDC (hwnd, hdc) ;

return (BYTE *) pbmi ;
}



// Sorts the array of COLORCOUNT structures to put the highest
// counts at the beginning.

int Compare1 (const void * p1, const void * p2)
{
COLORCOUNT * pcc1 = (COLORCOUNT *) p1 ;
COLORCOUNT * pcc2 = (COLORCOUNT *) p2 ;

if (pcc1->dwCount > pcc2->dwCount)
return -1 ;

return (pcc1->dwCount < pcc2->dwCount) ;
}

// Sorts the array of COLORCOUNT structures to put the lowest
// old index at the beginning.

int Compare2 (const void * p1, const void * p2)
{
COLORCOUNT * pcc1 = (COLORCOUNT *) p1 ;
COLORCOUNT * pcc2 = (COLORCOUNT *) p2 ;

if (pcc1->indexOld < pcc2->indexOld)
return -1 ;

return (pcc1->indexOld > pcc2->indexOld) ;
}



/*----------------------------------------------------------------------
DibSortColorTable: Sorts a DIB color table to put most-used colors
at the beginning. Possibly reduces size of DIB
for unused colors, so returns pointer to new DIB.
----------------------------------------------------------------------*/
BYTE * DibSortColorTable (BYTE * pDib)
{
COLORCOUNT cc[256] ;
int cRows, cCols, cClrs, iRow, iCol, i, cClrsNew ;

// This function is only applicable for palette DIBs

if (DibBitCount(pDib) > 8)
return pDib ;

// Get some useful information about the DIB using macros
// defined in ScreenSeizeDib.h

cRows = DibHeight (pDib) ;
cCols = DibWidth (pDib) ;
cClrs = DibNumColors (pDib) ;

// Initialize the structure with DIB color table

for (i = 0 ; i < cClrs ; i++)
{
cc.indexOld = i ;
cc.indexNew = 0 ;
cc.dwCount = 0 ;
cc.rgb = DibGetColor (pDib, i) ;
}

// Now accumulate the pixel counts in the structure

for (iRow = 0 ; iRow < cRows ; iRow++)
for (iCol = 0 ; iCol < cCols ; iCol++)
cc[DibGetPixel (pDib, iRow, iCol)].dwCount ++ ;

// Sort the structure by the pixel counts

qsort (&cc, cClrs, sizeof (COLORCOUNT), Compare1) ;

// Transfer the sorted colors into the DIB, but
// don't transfer those that aren't used at all.

for (i = 0 ; i < cClrs && cc.dwCount ; i++)
DibSetColor (pDib, i, cc.rgb) ;

// The new number of colors is now available

cClrsNew = i ;

// Put the new color indices into the structure

for (i = 0 ; i < cClrs ; i++)
cc.indexNew = i ;

// Sort the structure by the old indices

qsort (&cc, cClrs, sizeof (COLORCOUNT), Compare2) ;

// Now we can easily change each color index

for (iRow = 0 ; iRow < cRows ; iRow++)
for (iCol = 0 ; iCol < cCols ; iCol++)
DibSetPixel (pDib, iRow, iCol,
cc[DibGetPixel (pDib, iRow, iCol)].indexNew) ;

// Now the file can be tightened up to get rid of unused colors

if (cClrsNew < cClrs)
{
BYTE * pBitsOld, * pBitsNew ;
int iBitsSize ;

pBitsOld = DibBitsPtr (pDib) ;
((BITMAPINFOHEADER *) pDib)->biClrUsed = cClrsNew ;
pBitsNew = DibBitsPtr (pDib) ;
iBitsSize = DibBitsSize (pDib) ;

for (i = 0 ; i < iBitsSize ; i++)
*pBitsNew++ = *pBitsOld++ ;

pDib = (BYTE*)realloc (pDib, DibTotalSize (pDib)) ;
}

return pDib ;
}


/*--------------------------------------------------------------------------
DibGetPixel: Gets a pixel value for a particular row and column address.
NOTE: No bounds check on row and column!
--------------------------------------------------------------------------*/

DWORD DibGetPixel (PBYTE pDib, int iRow, int iCol)
{
// Handy macro in ScreenSeizeDib.h

BYTE * pPixel = DibPixelPtr (pDib, iRow, iCol) ;

// Another macro and gritty bit work

switch (DibBitCount (pDib))
{
case 1: return 0x01 & (* pPixel >> (7 - (iCol & 7))) ;
case 4: return 0x0F & (* pPixel >> (iCol & 1 ? 0 : 4)) ;
case 8: return * pPixel ;
case 16: return * (WORD *) pPixel ;
case 24: return 0x00FFFFFF & * (DWORD *) pPixel ;
case 32: return * (DWORD *) pPixel ;
}
return 0 ;
}

/*--------------------------------------------------------------------------
DibSetPixel: Sets a pixel value for a particular row and column address.
NOTE: No bounds check on row and column!
--------------------------------------------------------------------------*/

void DibSetPixel (PBYTE pDib, int iRow, int iCol, DWORD dwPixel)
{
// Ditto

BYTE * pPixel = DibPixelPtr (pDib, iRow, iCol) ;

switch (DibBitCount (pDib))
{
case 1: * pPixel &= ~(1 << (7 - (iCol & 7))) ;
* pPixel |= dwPixel << (7 - (iCol & 7)) ;
break ;

case 4: * pPixel &= 0x0F << (iCol & 1 ? 4 : 0) ;
* pPixel |= dwPixel << (iCol & 1 ? 0 : 4) ;
break ;

case 8: * pPixel = (BYTE) dwPixel ;
break ;

case 16: * (WORD *) pPixel = (WORD) dwPixel ;
break ;

case 24: * (RGBTRIPLE *) pPixel = * (RGBTRIPLE *) &dwPixel ;
break ;

case 32: * (DWORD *) pPixel = dwPixel ;
break ;
}
}

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top