www.pudn.com > snatl.rar > Dib.cpp


// Dib.cpp: implementation of the CDib class. 
////////////////////////////////////////////////////////////////////// 
// 
//用途:IconSnap所需调用的类 
//功能:DIB设备无关位图基础操作类 
//作者:徐景周 
//日期:2001年9月 
// 
////////////////////////////////////////////////////////////////////// 
#include "stdafx.h" 
#include "IconSnap.h" 
#include "Dib.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CDib::CDib() 
{ 
 
} 
 
CDib::~CDib() 
{ 
 
} 
 
/**************************************************************************** 
* 
*     FUNCTION: FindDIBits 
* 
*     PURPOSE:  Locate the image bits in a CF_DIB format DIB. 
* 
*     PARAMS:   LPSTR lpbi - pointer to the CF_DIB memory block 
* 
*     RETURNS:  LPSTR - pointer to the image bits 
* 
* 
\****************************************************************************/ 
LPSTR CDib::FindDIBBits( LPSTR lpbi ) 
{ 
   return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) ); 
} 
/* End FindDIBits() *********************************************************/ 
 
/**************************************************************************** 
* 
*     FUNCTION: DIBNumColors 
* 
*     PURPOSE:  Calculates the number of entries in the color table. 
* 
*     PARAMS:   LPSTR lpbi - pointer to the CF_DIB memory block 
* 
*     RETURNS:  WORD - Number of entries in the color table. 
* 
* 
\****************************************************************************/ 
WORD CDib::DIBNumColors( LPSTR lpbi ) 
{ 
    WORD wBitCount; 
    DWORD dwClrUsed; 
 
    dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed; 
 
    if (dwClrUsed) 
        return (WORD) dwClrUsed; 
 
    wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount; 
 
    switch (wBitCount) 
    { 
        case 1: return 2; 
        case 4: return 16; 
        case 8:	return 256; 
        default:return 0; 
    } 
    return 0; 
} 
/* End DIBNumColors() ******************************************************/ 
 
/**************************************************************************** 
* 
*     FUNCTION: PaletteSize 
* 
*     PURPOSE:  Calculates the number of bytes in the color table. 
* 
*     PARAMS:   LPSTR lpbi - pointer to the CF_DIB memory block 
* 
*     RETURNS:  WORD - number of bytes in the color table 
* 
* 
\****************************************************************************/ 
WORD CDib::PaletteSize( LPSTR lpbi ) 
{ 
    return ( DIBNumColors( lpbi ) * sizeof( RGBQUAD ) ); 
} 
/* End PaletteSize() ********************************************************/ 
 
 
 
/**************************************************************************** 
* 
*     FUNCTION: BytesPerLine 
* 
*     PURPOSE:  Calculates the number of bytes in one scan line. 
* 
*     PARAMS:   LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER 
*                                           that begins the CF_DIB block 
* 
*     RETURNS:  DWORD - number of bytes in one scan line (DWORD aligned) 
* 
* 
\****************************************************************************/ 
DWORD CDib::BytesPerLine( LPBITMAPINFOHEADER lpBMIH ) 
{ 
    return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount); 
} 
/* End BytesPerLine() ********************************************************/ 
 
/**************************************************************************** 
* 
*     FUNCTION: ConvertDIBFormat 
* 
*     PURPOSE:  Creates a new DIB of the requested format, copies the source 
*               image to the new DIB. 
* 
*     PARAMS:   LPBITMAPINFO lpSrcDIB - the source CF_DIB 
*               UINT         nWidth   - width for new DIB 
*               UINT         nHeight  - height for new DIB 
*               UINT         nbpp     - bpp for new DIB 
*               BOOL         bStretch - TRUE to stretch source to dest 
*                                       FALSE to take upper left of image 
* 
*     RETURNS:  LPBYTE - pointer to new CF_DIB memory block with new image 
*               NULL on failure 
* 
* 
\****************************************************************************/ 
LPBYTE CDib::ConvertDIBFormat( LPBITMAPINFO lpSrcDIB, UINT nWidth, UINT nHeight, UINT nbpp, BOOL bStretch ) 
{ 
    LPBITMAPINFO    lpbmi = NULL; 
    LPBYTE        	lpSourceBits, lpTargetBits, lpResult; 
    HDC            	hDC = NULL, hSourceDC, hTargetDC; 
    HBITMAP        	hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap; 
    DWORD        	dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize; 
 
    // Allocate and fill out a BITMAPINFO struct for the new DIB 
    // Allow enough room for a 256-entry color table, just in case 
    dwTargetHeaderSize = sizeof( BITMAPINFO ) + ( 256 * sizeof( RGBQUAD ) ); 
    lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize ); 
    lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); 
    lpbmi->bmiHeader.biWidth = nWidth; 
    lpbmi->bmiHeader.biHeight = nHeight; 
    lpbmi->bmiHeader.biPlanes = 1; 
    lpbmi->bmiHeader.biBitCount = nbpp; 
    lpbmi->bmiHeader.biCompression = BI_RGB; 
    lpbmi->bmiHeader.biSizeImage = 0; 
    lpbmi->bmiHeader.biXPelsPerMeter = 0; 
    lpbmi->bmiHeader.biYPelsPerMeter = 0; 
    lpbmi->bmiHeader.biClrUsed = 0; 
    lpbmi->bmiHeader.biClrImportant = 0; 
    // Fill in the color table 
    if( ! CopyColorTable( lpbmi, (LPBITMAPINFO)lpSrcDIB ) ) 
    { 
        free( lpbmi ); 
        return NULL; 
    } 
 
    // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em 
    hDC = GetDC( NULL ); 
    hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (void ** )&lpTargetBits, NULL, 0 ); 
    hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS,(void ** ) &lpSourceBits, NULL, 0 ); 
    hSourceDC = CreateCompatibleDC( hDC ); 
    hTargetDC = CreateCompatibleDC( hDC ); 
 
    // Flip the bits on the source DIBSection to match the source DIB 
    dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine(&(lpSrcDIB->bmiHeader)); 
    dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine(&(lpbmi->bmiHeader)); 
    memcpy( lpSourceBits, FindDIBBits((LPSTR)lpSrcDIB), dwSourceBitsSize ); 
 
    // Select DIBSections into DCs 
    hOldSourceBitmap =(HBITMAP ) SelectObject( hSourceDC, hSourceBitmap ); 
    hOldTargetBitmap = (HBITMAP )SelectObject( hTargetDC, hTargetBitmap ); 
 
    // Set the color tables for the DIBSections 
    if( lpSrcDIB->bmiHeader.biBitCount <= 8 ) 
        SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors ); 
    if( lpbmi->bmiHeader.biBitCount <= 8 ) 
        SetDIBColorTable( hTargetDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors ); 
 
    // If we are asking for a straight copy, do it 
    if( (lpSrcDIB->bmiHeader.biWidth==lpbmi->bmiHeader.biWidth) && (lpSrcDIB->bmiHeader.biHeight==lpbmi->bmiHeader.biHeight) ) 
    { 
        BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY ); 
    } 
    else 
    { 
        // else, should we stretch it? 
        if( bStretch ) 
        { 
            SetStretchBltMode( hTargetDC, COLORONCOLOR ); 
            StretchBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, lpSrcDIB->bmiHeader.biWidth, lpSrcDIB->bmiHeader.biHeight, SRCCOPY ); 
        } 
        else 
        { 
            // or just take the upper left corner of the source 
            BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY ); 
        } 
    } 
 
    // Clean up and delete the DCs 
    SelectObject( hSourceDC, hOldSourceBitmap ); 
    SelectObject( hSourceDC, hOldTargetBitmap ); 
    DeleteDC( hSourceDC ); 
    DeleteDC( hTargetDC ); 
    ReleaseDC( NULL, hDC ); 
 
    // Flush the GDI batch, so we can play with the bits 
    GdiFlush(); 
 
    // Allocate enough memory for the new CF_DIB, and copy bits 
    lpResult =(LPBYTE ) malloc( dwTargetHeaderSize + dwTargetBitsSize ); 
    memcpy( lpResult, lpbmi, dwTargetHeaderSize ); 
    memcpy( FindDIBBits( (LPSTR)lpResult ), lpTargetBits, dwTargetBitsSize ); 
 
    // final cleanup 
    DeleteObject( hTargetBitmap ); 
    DeleteObject( hSourceBitmap ); 
    free( lpbmi ); 
 
    return lpResult; 
} 
/* End ConvertDIBFormat() ***************************************************/ 
 
/**************************************************************************** 
* 
*     FUNCTION: CopyColorTable 
* 
*     PURPOSE:  Copies the color table from one CF_DIB to another. 
* 
*     PARAMS:   LPBITMAPINFO lpTarget - pointer to target DIB 
*               LPBITMAPINFO lpSource - pointer to source DIB 
* 
*     RETURNS:  BOOL - TRUE for success, FALSE for failure 
* 
* 
\****************************************************************************/ 
BOOL CDib::CopyColorTable( LPBITMAPINFO lpTarget, LPBITMAPINFO lpSource ) 
{ 
    // What we do depends on the target's color depth 
    switch( lpTarget->bmiHeader.biBitCount ) 
    { 
        // 8bpp - need 256 entry color table 
        case 8: 
            if( lpSource->bmiHeader.biBitCount == 8 ) 
            { // Source is 8bpp too, copy color table 
                memcpy( lpTarget->bmiColors, lpSource->bmiColors, 256*sizeof(RGBQUAD) ); 
                return TRUE; 
            } 
            else 
            { // Source is != 8bpp, use halftone palette                 
                HPALETTE        hPal; 
                HDC            	hDC = GetDC( NULL ); 
                PALETTEENTRY    pe[256]; 
                UINT            i; 
 
                hPal = CreateHalftonePalette( hDC ); 
                ReleaseDC( NULL, hDC ); 
                GetPaletteEntries( hPal, 0, 256, pe ); 
                DeleteObject( hPal ); 
                for(i=0;i<256;i++) 
                { 
                    lpTarget->bmiColors[i].rgbRed = pe[i].peRed; 
                    lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen; 
                    lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue; 
                    lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags; 
                } 
                return TRUE; 
            } 
        break; // end 8bpp 
 
        // 4bpp - need 16 entry color table 
        case 4: 
            if( lpSource->bmiHeader.biBitCount == 4 ) 
            { // Source is 4bpp too, copy color table 
                memcpy( lpTarget->bmiColors, lpSource->bmiColors, 16*sizeof(RGBQUAD) ); 
                return TRUE; 
            } 
            else 
            { // Source is != 4bpp, use system palette 
                HPALETTE        hPal; 
                PALETTEENTRY    pe[256]; 
                UINT            i; 
 
                hPal = (HPALETTE)GetStockObject( DEFAULT_PALETTE ); 
                GetPaletteEntries( hPal, 0, 16, pe ); 
                for(i=0;i<16;i++) 
                { 
                    lpTarget->bmiColors[i].rgbRed = pe[i].peRed; 
                    lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen; 
                    lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue; 
                    lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags; 
                } 
                return TRUE; 
            } 
        break; // end 4bpp 
 
        // 1bpp - need 2 entry mono color table 
        case 1: 
            lpTarget->bmiColors[0].rgbRed = 0; 
            lpTarget->bmiColors[0].rgbGreen = 0; 
            lpTarget->bmiColors[0].rgbBlue = 0; 
            lpTarget->bmiColors[0].rgbReserved = 0; 
            lpTarget->bmiColors[1].rgbRed = 255; 
            lpTarget->bmiColors[1].rgbGreen = 255; 
            lpTarget->bmiColors[1].rgbBlue = 255; 
            lpTarget->bmiColors[1].rgbReserved = 0; 
        break; // end 1bpp 
 
        // no color table for the > 8bpp modes 
        case 32: 
        case 24: 
        case 16: 
        default: 
            return TRUE; 
        break; 
    } 
    return TRUE; 
} 
/* End CopyColorTable() *****************************************************/ 
 
/**************************************************************************** 
* 
*     FUNCTION: SetMonoDIBPixel 
* 
*     PURPOSE:  Sets/Clears a pixel in a 1bpp DIB by directly poking the bits. 
* 
*     PARAMS:   LPBYTE pANDBits - pointer to the 1bpp image bits 
*               DWORD  dwWidth	- width of the DIB 
*               DWORD  dwHeight	- height of the DIB 
*               DWORD  x        - x location of pixel to set/clear 
*               DWORD  y        - y location of pixel to set/clear 
*               BOOL   bWhite	- TRUE to set pixel, FALSE to clear it 
* 
*     RETURNS:  void 
* 
* 
\****************************************************************************/ 
void CDib::SetMonoDIBPixel( LPBYTE pANDBits, DWORD dwWidth, DWORD dwHeight, DWORD x, DWORD y, BOOL bWhite ) 
{ 
    DWORD	ByteIndex; 
    BYTE    BitNumber; 
 
    // Find the byte on which this scanline begins 
    ByteIndex = (dwHeight - y - 1) * WIDTHBYTES(dwWidth); 
    // Find the byte containing this pixel 
    ByteIndex += (x >> 3); 
    // Which bit is it? 
    BitNumber = (BYTE)( 7 - (x % 8) ); 
 
    if( bWhite ) 
        // Turn it on 
        pANDBits[ByteIndex] |= (1<biSize != sizeof( BITMAPINFOHEADER ) ) 
    { 
        CloseHandle( hFile ); 
        free( lpDIB ); 
        MessageBox( NULL, "OS/2风格的位图不支持!", szFileName, MB_OK ); 
        return NULL; 
    } 
    // How big are the elements? 
    wPaletteSize = PaletteSize((LPSTR)lpDIB); 
    dwBitsSize = ((LPBITMAPINFOHEADER)lpDIB)->biHeight * BytesPerLine((LPBITMAPINFOHEADER)lpDIB); 
    // realloc to account for the total size of the DIB 
    if( (lpTemp = (LPBYTE)realloc( lpDIB, sizeof( BITMAPINFOHEADER ) + wPaletteSize + dwBitsSize )) == NULL ) 
    { 
        CloseHandle( hFile ); 
        MessageBox( NULL, "重新分配位图信息头所需内存失败!", szFileName, MB_OK ); 
        free( lpDIB ); 
        return NULL; 
    } 
    lpDIB = lpTemp; 
    // If there is a color table, read it 
    if( wPaletteSize != 0 ) 
    { 
        if( (!ReadFile( hFile, ((LPBITMAPINFO)lpDIB)->bmiColors, wPaletteSize, &dwBytes, NULL )) || (dwBytes!=wPaletteSize) ) 
        { 
            CloseHandle( hFile ); 
            free( lpDIB ); 
            MessageBox( NULL, "读位图颜色表出错!", szFileName, MB_OK ); 
            return NULL; 
        } 
    } 
    // Seek to the bits 
    // checking against 0 in case some bogus app didn't set this element 
    if( bfh.bfOffBits != 0 ) 
    { 
        if( SetFilePointer( hFile, bfh.bfOffBits, NULL, FILE_BEGIN ) == 0xffffffff ) 
        { 
            CloseHandle( hFile ); 
            free( lpDIB ); 
            MessageBox( NULL, "位图文件大小定位出错!", szFileName, MB_OK ); 
            return NULL; 
        } 
    } 
    // Read the image bits 
    if( (!ReadFile( hFile, FindDIBBits((LPSTR)lpDIB), dwBitsSize, &dwBytes, NULL )) || (dwBytes!=dwBitsSize) ) 
    { 
        CloseHandle( hFile ); 
        free( lpDIB ); 
        MessageBox( NULL, "读位图文件出错!", szFileName, MB_OK ); 
        return NULL; 
    } 
    // clean up 
    CloseHandle( hFile ); 
    return lpDIB; 
} 
/* End ReadBMPFile() ********************************************************/ 
 
/**************************************************************************** 
* 
*     FUNCTION: WriteBMPFile 
* 
*     PURPOSE:  Writes a BMP file from CF_DIB format 
* 
*     PARAMS:   LPCTSTR szFileName - the name of the file to read 
*               LPBYTE - pointer to the CF_DIB, NULL for failure 
* 
*     RETURNS:  BOOL - TRUE for success, FALSE for Failure 
* 
* 
\****************************************************************************/ 
BOOL CDib::WriteBMPFile( LPCTSTR szFileName, LPBYTE lpDIB ) 
{ 
    HANDLE            	hFile; 
    BITMAPFILEHEADER    bfh; 
    DWORD            	dwBytes, dwBytesToWrite; 
    LPBITMAPINFOHEADER	lpbmih; 
 
    // Open the file 
    if( (hFile=CreateFile( szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE ) 
    { 
        MessageBox( NULL, "位图文件建立失败!", szFileName, MB_OK ); 
        return FALSE; 
    } 
    bfh.bfType = 0x4d42; 
    bfh.bfReserved1 = 0; 
    bfh.bfReserved2 = 0; 
    bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + PaletteSize((LPSTR) lpDIB ); 
    bfh.bfSize = (bfh.bfOffBits + ((LPBITMAPINFOHEADER)lpDIB)->biHeight * BytesPerLine((LPBITMAPINFOHEADER)lpDIB))/4; 
    // Write the header 
    if( ( ! WriteFile( hFile, &bfh, sizeof(BITMAPFILEHEADER), &dwBytes, NULL ) ) || ( dwBytes != sizeof( BITMAPFILEHEADER ) ) ) 
    { 
        CloseHandle( hFile ); 
        MessageBox( NULL, "写位图文件头出错!", szFileName, MB_OK ); 
        return FALSE; 
    } 
    lpbmih = (LPBITMAPINFOHEADER)lpDIB; 
    lpbmih->biHeight /= 2; 
    dwBytesToWrite = bfh.bfOffBits + (lpbmih->biHeight * BytesPerLine(lpbmih)); 
    if( ( ! WriteFile( hFile, lpDIB, dwBytesToWrite, &dwBytes, NULL ) ) || ( dwBytes != dwBytesToWrite ) ) 
    { 
        CloseHandle( hFile ); 
        MessageBox( NULL, "写位图文件出错!", szFileName, MB_OK ); 
        return FALSE; 
    } 
    lpbmih->biHeight *= 2; 
    CloseHandle( hFile ); 
    return TRUE; 
} 
/* End WriteBMPFile() *******************************************************/