#include "stdafx.h"    
#include "CCeXDib.h"    
   
#ifdef _DEBUG    
#undef THIS_FILE    
static char THIS_FILE[]=__FILE__;   
#define new DEBUG_NEW    
#endif    
   
CCeXDib::CCeXDib()   
{   
    m_hDib = NULL;   
    m_dwLineWidth = 0;   
    m_wColors = 0;   
   
    m_hMemDC = NULL;   
    m_hBitmap = NULL;   
    m_lpBits = NULL;   
   
    FreeResources();   
}   
   
CCeXDib::~CCeXDib()   
{   
    FreeResources();   
}   
   
void CCeXDib::FreeResources()   
{   
    if (m_hMemDC)   ::DeleteDC(m_hMemDC);   
    if (m_hBitmap)  ::DeleteObject(m_hBitmap);   
    if (m_hDib)     delete m_hDib;   
   
    m_hDib = NULL;   
    m_hMemDC = NULL;   
    m_hBitmap = NULL;   
    m_lpBits = NULL;   
    memset(&m_bi, 0, sizeof(m_bi));   
} // End of FreeResources    
   
HDIB CCeXDib::Create(DWORD dwWidth, DWORD dwHeight, WORD wBitCount)   
{   
    LPBITMAPINFOHEADER  lpbi = NULL;    // Pointer to BITMAPINFOHEADER    
    DWORD               dwLen = 0;      // Size of memory block    
   
    FreeResources();   
   
    // Following <SWITCH> is taken from    
    // CDIBSectionLite class by Chris Maunder    
    switch (wBitCount)    
    {   
        case 1:  m_wColors = 2;   break;   
#ifdef _WIN32_WCE    
        case 2:  m_wColors = 4;   break;   // winCE only           
#endif    
        case 4:  m_wColors = 16;  break;   
        case 8:  m_wColors = 256; break;   
        case 16:   
        case 24:   
        case 32: m_wColors = 0;   break;   // 16,24 or 32 bpp have no color table    
   
        default:   
           m_wColors = 0;   
    } // switch    
/*  
    // Make sure bits per pixel is valid  
    if (wBitCount <= 1)          wBitCount = 1;  
    else if (wBitCount <= 4) wBitCount = 4;  
    else if (wBitCount <= 8) wBitCount = 8;  
    else                        wBitCount = 24;  
  
    switch (wBitCount)  
    {  
        case 1:  
            m_wColors = 2;  
            break;  
        case 4:  
            m_wColors = 16;  
            break;  
        case 8:  
            m_wColors = 256;  
            break;  
        default:  
            m_wColors = 0;  
            break;  
    } // switch  
*/   
    m_dwLineWidth = WIDTHBYTES(wBitCount * dwWidth);   
   
    // Initialize BITMAPINFOHEADER    
    m_bi.biSize = sizeof(BITMAPINFOHEADER);   
    m_bi.biWidth = dwWidth;         // fill in width from parameter    
    m_bi.biHeight = dwHeight;       // fill in height from parameter    
    m_bi.biPlanes = 1;              // must be 1    
    m_bi.biBitCount = wBitCount;    // from parameter    
    m_bi.biCompression = BI_RGB;       
    m_bi.biSizeImage = m_dwLineWidth * dwHeight;   
    m_bi.biXPelsPerMeter = 0;   
    m_bi.biYPelsPerMeter = 0;   
    m_bi.biClrUsed = 0;   
    m_bi.biClrImportant = 0;   
   
    // Calculate size of memory block required to store the DIB.  This    
    // block should be big enough to hold the BITMAPINFOHEADER, the color    
    // table, and the bits.    
    dwLen = GetSize();   
   
    m_hDib = new HDIB[dwLen]; // Allocate memory block to store our bitmap    
    if (m_hDib == NULL) return NULL;   
   
    // Use our bitmap info structure to fill in first part of    
    // our DIB with the BITMAPINFOHEADER    
    lpbi = (LPBITMAPINFOHEADER)(m_hDib);   
    *lpbi = m_bi;   
   
    return m_hDib; // Return handle to the DIB    
} // End of Create    
   
DWORD CCeXDib::GetSize()   
{   
    return m_bi.biSize + m_bi.biSizeImage + GetPaletteSize();   
} // End of GetSize    
   
DWORD CCeXDib::GetPaletteSize()   
{   
    return (m_wColors * sizeof(RGBQUAD));   
} // End of GetPaletteSize    
   
LPBYTE CCeXDib::GetBits()   
{   
    if (m_hDib) return ((LPBYTE)m_hDib + *(LPDWORD)m_hDib + GetPaletteSize());    
   
    return NULL;   
} // End of GetBits    
   
DWORD CCeXDib::GetWidth()   
{   
    return m_bi.biWidth;   
} // End of GetWidth    
   
DWORD CCeXDib::GetHeight()   
{   
    return m_bi.biHeight;   
} // End of GetHeight    
   
DWORD CCeXDib::GetLineWidth()   
{   
    return m_dwLineWidth;   
} // End of GetLineWidth    
   
void CCeXDib::BlendPalette(COLORREF crColor, DWORD dwPerc)   
{   
    if (m_hDib == NULL || m_wColors == 0) return;   
   
    LPBYTE iDst = (LPBYTE)(m_hDib) + sizeof(BITMAPINFOHEADER);   
   
    long i,r,g,b;   
   
    RGBQUAD* pPal = (RGBQUAD*)iDst;   
   
    r = GetRValue(crColor);   
    g = GetGValue(crColor);   
    b = GetBValue(crColor);   
   
    if (dwPerc > 100) dwPerc = 100;   
   
    for (i = 0; i < m_wColors; i++)   
    {   
        pPal[i].rgbBlue = (BYTE)((pPal[i].rgbBlue * (100 - dwPerc) + b * dwPerc) / 100);   
        pPal[i].rgbGreen = (BYTE)((pPal[i].rgbGreen * (100 - dwPerc) + g * dwPerc) / 100);   
        pPal[i].rgbRed = (BYTE)((pPal[i].rgbRed * (100 - dwPerc) + r * dwPerc) / 100);   
    } // for    
} // End of BlendPalette    
   
void CCeXDib::Clear(BYTE byVal)   
{   
    if (m_hDib) memset(GetBits(), byVal, m_bi.biSizeImage);   
} // End of Clear    
   
void CCeXDib::SetPixelIndex(DWORD dwX, DWORD dwY, BYTE byI)   
{   
    if ((m_hDib == NULL) || (m_wColors == 0) ||   
        ((long)dwX < 0) || ((long)dwY < 0) || (dwX >= (DWORD)m_bi.biWidth) || (dwY >= (DWORD)m_bi.biHeight)) return;   
   
    LPBYTE iDst = GetBits();   
    iDst[(m_bi.biHeight - dwY - 1) * m_dwLineWidth + dwX] = byI;   
} // End of SetPixelIndex    
   
void CCeXDib::Clone(CCeXDib* src)   
{   
    Create(src->GetWidth(), src->GetHeight(), src->GetBitCount());   
    if (m_hDib) memcpy(m_hDib, src->m_hDib, GetSize());   
} // End of Clone    
   
WORD CCeXDib::GetBitCount()   
{   
    return m_bi.biBitCount;   
} // End of GetBitCount    
   
void CCeXDib::SetPaletteIndex(BYTE byIdx, BYTE byR, BYTE byG, BYTE byB)   
{   
    if (m_hDib && m_wColors)   
    {   
        LPBYTE iDst = (LPBYTE)(m_hDib) + sizeof(BITMAPINFOHEADER);   
        if ((byIdx >= 0) && (byIdx < m_wColors))   
        {      
            long ldx = byIdx * sizeof(RGBQUAD);   
            iDst[ldx++] = (BYTE)byB;   
            iDst[ldx++] = (BYTE)byG;   
            iDst[ldx++] = (BYTE)byR;   
            iDst[ldx] = (BYTE)0;   
        } // if    
    } // if    
} // End of SetPaletteIndex    
   
void CCeXDib::Draw(HDC hDC, DWORD dwX, DWORD dwY)   
{   
    HBITMAP hBitmap = NULL;   
    HBITMAP hOldBitmap = NULL;   
    HDC     hMemDC = NULL;   
   
    if (m_hBitmap == NULL)   
    {   
        m_hBitmap = CreateDIBSection(hDC, (BITMAPINFO*)m_hDib, DIB_RGB_COLORS, &m_lpBits, NULL, 0);   
        if (m_hBitmap == NULL)  return;   
        if (m_lpBits == NULL)   
        {   
            ::DeleteObject(m_hBitmap);   
            m_hBitmap = NULL;   
            return;   
        } // if    
    } // if    
   
    memcpy(m_lpBits, GetBits(), m_bi.biSizeImage);   
   
    if (m_hMemDC == NULL)   
    {   
        m_hMemDC = CreateCompatibleDC(hDC);   
        if (m_hMemDC == NULL)   return;   
    } // if    
   
    hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap);   
   
    BitBlt(hDC, dwX, dwY, m_bi.biWidth, m_bi.biHeight, m_hMemDC, 0, 0, SRCCOPY);   
   
    SelectObject(m_hMemDC, hOldBitmap);   
} // End of Draw    
   
void CCeXDib::SetGrayPalette()   
{   
    RGBQUAD     pal[256];   
    RGBQUAD*    ppal;   
    LPBYTE      iDst;   
    int         ni;   
   
    if (m_hDib == NULL || m_wColors == 0) return;   
   
    ppal = (RGBQUAD*)&pal[0];   
    iDst = (LPBYTE)(m_hDib) + sizeof(BITMAPINFOHEADER);   
    for (ni = 0; ni < m_wColors; ni++)   
    {   
        pal[ni] = RGB2RGBQUAD(RGB(ni,ni,ni));   
    } // for    
   
    pal[0] = RGB2RGBQUAD(RGB(0,0,0));   
    pal[m_wColors-1] = RGB2RGBQUAD(RGB(255,255,255));   
   
    memcpy(iDst, ppal, GetPaletteSize());   
} // End of SetGrayPalette    
   
RGBQUAD CCeXDib::RGB2RGBQUAD(COLORREF cr)   
{   
    RGBQUAD c;   
    c.rgbRed = GetRValue(cr);   /* get R, G, and B out of DWORD */   
    c.rgbGreen = GetGValue(cr);   
    c.rgbBlue = GetBValue(cr);   
    c.rgbReserved=0;   
    return c;   
} // End of RGB2RGBQUAD    
   
WORD CCeXDib::GetNumColors()   
{   
    return m_wColors;   
} // End of GetNumColors    
   
BOOL CCeXDib::WriteBMP(LPCTSTR bmpFileName)   
{   
    BITMAPFILEHEADER    hdr;   
    HANDLE  hFile;   
    DWORD   nByteWrite;   
   
    if (*bmpFileName == _T('\0') || m_hDib == 0) return 0;   
   
    hFile=CreateFile(           // open if exist ini file    
        bmpFileName,            // pointer to name of the file     
        GENERIC_WRITE,          // access mode     
        0,                      // share mode     
        NULL,                   // pointer to security descriptor     
        CREATE_ALWAYS,          // how to create     
        FILE_ATTRIBUTE_NORMAL,  // file attributes     
        NULL                    // handle to file with attributes to copy      
        );   
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;   
   
    // Fill in the fields of the file header    
    hdr.bfType = BFT_BITMAP;   
    hdr.bfSize = GetSize() + sizeof(BITMAPFILEHEADER);   
    hdr.bfReserved1 = hdr.bfReserved2 = 0;   
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER)+   
                    m_bi.biSize + GetPaletteSize();   
   
    // Write the file header    
    WriteFile(                      // write ini (sync mode <-> no overlapped)    
        hFile,                      // handle of file to write     
        (LPSTR) &hdr,               // address of buffer that contains data      
        sizeof(BITMAPFILEHEADER),   // number of bytes to write     
        &nByteWrite,                // address of number of bytes written     
        NULL                        // address of structure for data     
        );   
   
    // Write the DIB header and the bits    
    WriteFile(                      // write ini (sync mode <-> no overlapped)    
        hFile,                      // handle of file to write     
        (LPSTR) m_hDib,             // address of buffer that contains data      
        GetSize(),                  // number of bytes to write     
        &nByteWrite,                // address of number of bytes written     
        NULL                        // address of structure for data     
        );   
   
    CloseHandle(hFile);             // free file handle    
   
    return TRUE;   
} // End of WriteBMP   
