WINCE/WIN32的第三方BMP操作类库----DIBSectionCE类

 

在文章  移动设备上使用openCV  中讲到

WINCE/WIN32的第三方BMP操作类库----DIBSectionCE类

现在对它具体来分析:

1、介绍

CDIBSectionCE是CDibCE的子类。

Device Independant Bitmaps(DIB)提供一个在你的电脑的当前显示器配置下的来操纵并显示bitmaps的途径,.

它们也是标准window  .BMP图的一种格式,这样有一种方法来加载、显示并修改DIBs是非常方便的。

Win32提供了许多不同的方法来处理DIB,包括标准的DIB功能,比如 SetBitsToDevice,GetDIBits、DrawDib函数等,

其中DrawDib是类似于DIBsections.

然而当工作在CE环境时,许多有用的函数被抛弃了,目的是为了减少OS的大小;

这样我们就只能用DDB(通过CBitmap)或DIBSections.它不是太方便的,即使因为DIBSections在DIBs是很强大的(因为我们有一个绑定的HBITMAP句柄),

因此能被GID函数操作,比如BitBlt和StrechBlt。此外这个DIBSection句柄也能被选择到一个内存DC中,并且用TextOut等直接画。

它是更容易地去访问DIB的bits,并一个一个地操作像素点.

DIBsections仅有的问题是DIBsection wrapper. 这是由于MFC版本的不断更新。

随着CE的到来,DIBSections显得重要。这里我们设计了CDIBSectionCE class - a DIBSection wrapper class.

此类提供了一个DIBSections的接口,包括加载、保存、显示DIBSections.

 

1、1、创建并显示DIBSections

创建DIBSections 的第一步是去填写BITMAPINFOHEADER结构体。它用于查询你支持的bitmap值。

不幸的是CE中没有这个功能,你必须自己去实现。虽然CE中有获得你提供的bitmap 的颜色表的功能。

但它它只解析DIBSections本身的颜色表信息。CDIBSections通过合成 half-tone 颜色表 获得此功能。

一旦你有BITMAPINFOHEADER结构体了,接下来就是简单调用CreateDIBSections.

这个函数将会返回一个HBITMAP句柄(指向真实的image bits)。

在CE中,有一些函数是丢失的,eg: GDIFlush和SetStretchBltMode,但是通过DIBSections创建的HBITMAP在用HBITMAP是没有困难的。

 

1、2  使用CDIBSectionsCE

它能通过SetBitmap() 或 Load()从disk中加载图像。

eg:

WINCE/WIN32的第三方BMP操作类库----DIBSectionCE类_第1张图片

 

1、3  CDIBsectionCE API

CDIBSection API包括了加载、显示图片;解析图片信息的方法,palette的获得。

WINCE/WIN32的第三方BMP操作类库----DIBSectionCE类_第2张图片

 

2、实现过程

把对应的.h .cpp与大家共享

#if !defined(AFX_CDIBSECTIONCE_H__35D9F3D4_B960_11D2_A981_2C4476000000__INCLUDED_)
#define AFX_CDIBSECTIONCE_H__35D9F3D4_B960_11D2_A981_2C4476000000__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// DIBSectionCE.h : header file
//

// Copyright ?Dundas Software Ltd. 1999, All Rights Reserved

// //////////////////////////////////////////////////////////////////////////

// Properties:
//	NO	Abstract class (does not have any objects)
//	NO	Derived from CWnd
//	NO	Is a CWnd.                     
//	NO	Two stage creation (constructor & Create())
//	NO	Has a message map
//	NO 	Needs a resource (template)
//	YES	Persistent objects (saveable on disk)      
//	YES	Uses exceptions

// //////////////////////////////////////////////////////////////////////////

// Desciption :         

// CDIBSectionCE is DIBSection wrapper class for win32 and WinCE platforms.
// This class provides a simple interface to DIBSections including loading,
// saving and displaying DIBsections.
//
// Full palette support is provided for Win32 and CE 2.11 and above. 

// Using CDIBSectionCE :

// This class is very simple to use. The bitmap can be set using either SetBitmap()
// (which accepts either a Device dependant or device independant bitmap, or a 
// resource ID) or by using Load(), which allows an image to be loaded from disk. 
// To display the bitmap simply use Draw or Stretch.
//
// eg. 
//
//      CDIBsection dibsection;
//      dibsection.Load(_T("image.bmp"));
//      dibsection.Draw(pDC, CPoint(0,0));  // pDC is of type CDC*
//
//      CDIBsection dibsection;
//      dibsection.SetBitmap(IDB_BITMAP); 
//      dibsection.Draw(pDC, CPoint(0,0));  // pDC is of type CDC*
//
// The CDIBsection API includes many methods to extract information about the
// image, as well as palette options for getting and setting the current palette.
//
// Author: Chris Maunder ([email protected])
// Date  : 12 April 1999


/////////////////////////////////////////////////////////////////////////////
// defines

// Only provide palette support for non-CE platforms, or for CE 2.11 and above
#if defined(_WIN32_WCE) && (_WIN32_WCE < 211)

#define DIBSECTION_NO_PALETTE 

// Dummy defn for CPalette if it is not available
#ifndef CPalette
#define CPalette void
#endif

#endif


#define DS_BITMAP_FILEMARKER  ((WORD) ('M' << 8) | 'B')    // is always "BM" = 0x4D42

/////////////////////////////////////////////////////////////////////////////
// BITMAPINFO wrapper

struct DIBINFO : public BITMAPINFO
{
	RGBQUAD	 arColors[255];    // Color table info - adds an extra 255 entries to palette

	operator LPBITMAPINFO()          { return (LPBITMAPINFO) this; }
	operator LPBITMAPINFOHEADER()    { return &bmiHeader;          }
	RGBQUAD* ColorTable()            { return bmiColors;           }
};

/////////////////////////////////////////////////////////////////////////////
// LOGPALETTE wrapper

#ifndef DIBSECTION_NO_PALETTE
struct PALETTEINFO : public LOGPALETTE
{
    PALETTEENTRY arPalEntries[255];               // Palette entries

    PALETTEINFO() { palVersion = (WORD) 0x300; }

    operator LPLOGPALETTE()   { return (LPLOGPALETTE) this;            }
    operator LPPALETTEENTRY() { return (LPPALETTEENTRY) (palPalEntry); }
};
#endif // DIBSECTION_NO_PALETTE


/////////////////////////////////////////////////////////////////////////////
// CDIBSectionCE object

class CDIBSectionCE : public CObject
{
// Construction
public:
	CDIBSectionCE();
	virtual ~CDIBSectionCE();
    void DeleteObject();

// static helpers
public:
    static int BytesPerLine(int nWidth, int nBitsPerPixel);
    static int NumColorEntries(int nBitsPerPixel);

    static RGBQUAD ms_StdColours[];
#ifndef DIBSECTION_NO_PALETTE
    static BOOL UsesPalette(CDC* pDC) { return (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE); }
    static BOOL CreateHalftonePalette(CPalette& palette, int nNumColours);
#endif // DIBSECTION_NO_PALETTE

// Attributes
public:
    HBITMAP      GetSafeHandle() const       { return (this)? m_hBitmap : NULL;        }
    CSize        GetSize() const             { return CSize(GetWidth(), GetHeight());  }
    int          GetHeight() const           { return m_DIBinfo.bmiHeader.biHeight;    } 
    int          GetWidth() const            { return m_DIBinfo.bmiHeader.biWidth;     }
    int          GetPlanes() const           { return m_DIBinfo.bmiHeader.biPlanes;    }
    int          GetBitCount() const         { return m_DIBinfo.bmiHeader.biBitCount;  }
    LPVOID       GetDIBits()                 { return m_ppvBits;                       }
    LPBITMAPINFO GetBitmapInfo()             { return  (BITMAPINFO*) m_DIBinfo;        }
    DWORD        GetImageSize() const        { return m_DIBinfo.bmiHeader.biSizeImage; }
    LPBITMAPINFOHEADER GetBitmapInfoHeader() { return (BITMAPINFOHEADER*) m_DIBinfo;   }
    LPRGBQUAD    GetColorTable()             { return m_DIBinfo.ColorTable();          }

    BOOL SetBitmap(UINT nIDResource);
    BOOL SetBitmap(LPCTSTR lpszResourceName);
    BOOL SetBitmap(HBITMAP hBitmap, CPalette* pPalette = NULL);
    BOOL SetBitmap(LPBITMAPINFO lpBitmapInfo, LPVOID lpBits);   

#ifndef DIBSECTION_NO_PALETTE
    CPalette *GetPalette()  { return &m_Palette; }
    BOOL SetPalette(CPalette* pPalette);
    BOOL SetLogPalette(LOGPALETTE* pLogPalette);
#endif // DIBSECTION_NO_PALETTE

// Operations
public:
    BOOL Load(LPCTSTR lpszFileName);
    BOOL Save(LPCTSTR lpszFileName);

    BOOL Draw(CDC* pDC, CPoint ptDest, BOOL bForceBackground = FALSE);
    BOOL Stretch(CDC* pDC, CPoint ptDest, CSize size, BOOL bForceBackground = FALSE);

    CDC* GetMemoryDC(CDC* pDC = NULL, BOOL bSelectPalette = TRUE);
    BOOL ReleaseMemoryDC(BOOL bForceRelease = FALSE);

// Overrideables

// Implementation
public:
#ifdef _DEBUG
	virtual void AssertValid() const;
//	virtual void Dump(CDumpContext& dc) const;
#endif

// Implementation
protected:
    void _ShowLastError();
#ifndef DIBSECTION_NO_PALETTE
    BOOL CreatePalette();
    BOOL FillDIBColorTable(UINT nNumColours, RGBQUAD *pRGB);
#endif // DIBSECTION_NO_PALETTE
    UINT GetColorTableEntries(HDC hdc, HBITMAP hBitmap);

protected:
    HBITMAP m_hBitmap;          // Handle to DIBSECTION
    DIBINFO m_DIBinfo;          // Bitmap header & color table info
    VOID   *m_ppvBits;          // Pointer to bitmap bits
    UINT    m_iColorDataType;   // color data type (palette or RGB values)
    UINT    m_iColorTableSize;  // Size of color table

    CDC      m_MemDC;           // Memory DC for drawing on bitmap
    BOOL     m_bReuseMemDC;     // Reeuse the memory DC? (Quicker, but maybe unsafe)

#ifndef DIBSECTION_NO_PALETTE
    CPalette m_Palette;         // Color palette
    CPalette *m_pOldPalette;
#endif // DIBSECTION_NO_PALETTE

private:
    HBITMAP  m_hOldBitmap;      // Storage for previous bitmap in Memory DC
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CDIBSECTIONCE_H__35D9F3D4_B960_11D2_A981_2C4476000000__INCLUDED_)


 

// CDIBSectionCE.cpp : implementation file
//
// General purpose DIBsection wrapper class for Win9x, NT 4.0
// and WinCE.
//
// Author      : Chris Maunder ([email protected])
// Date        : 17 May 1999
//
// Copyright ?Dundas Software Ltd. 1999, All Rights Reserved                      
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. If 
// the source code in this file is used in any commercial application 
// then a simple email would be nice.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage, in any form, caused
// by this code. Use it at your own risk and as with all code expect bugs!
// It's been tested but I'm not perfect.
// 
// Please use and enjoy. Please let me know of any bugs/mods/improvements 
// that you have found/implemented and I will fix/incorporate them into this
// file.


#include "stdafx.h"
#include "DIBSectionCE.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// Use C++ exception handling instead of structured on non-CE platforms.
#ifndef _WIN32_WCE  
#undef TRY
#undef CATCH
#undef END_CATCH
#define TRY try
#define CATCH(ex_class, ex_object) catch(ex_class* ex_object)
#define END_CATCH
#endif  // _WIN32_WCE

// Standard colours
RGBQUAD CDIBSectionCE::ms_StdColours[] = {
    { 0x00, 0x00, 0x00, 0 },    // First 2 will be palette for monochrome bitmaps
    { 0xFF, 0xFF, 0xFF, 0 },

    { 0x00, 0x00, 0xFF, 0 },    // First 16 will be palette for 16 colour bitmaps
    { 0x00, 0xFF, 0x00, 0 },
    { 0x00, 0xFF, 0xFF, 0 },
    { 0xFF, 0x00, 0x00, 0 },
    { 0xFF, 0x00, 0xFF, 0 },
    { 0xFF, 0xFF, 0x00, 0 },

    { 0x00, 0x00, 0x80, 0 },
    { 0x00, 0x80, 0x00, 0 },
    { 0x00, 0x80, 0x80, 0 },
    { 0x80, 0x00, 0x00, 0 },
    { 0x80, 0x00, 0x80, 0 },
    { 0x80, 0x80, 0x00, 0 },
    { 0x80, 0x80, 0x80, 0 },

    { 0xC0, 0xC0, 0xC0, 0 },
};


/////////////////////////////////////////////////////////////////////////////
// CE DIBSection global functions

UINT CEGetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries, RGBQUAD *pColors);

/////////////////////////////////////////////////////////////////////////////
// CDIBSectionCE static functions

// 
// --- In?: nBitsPerPixel - bits per pixel
// --- Out : 
// --- Returns :The number of colours for this colour depth
// --- Effect : Returns the number of color table entries given the number
//              of bits per pixel of a bitmap
/*static*/ int CDIBSectionCE::NumColorEntries(int nBitsPerPixel) 
{
    int nColors = 0;

    switch (nBitsPerPixel) 
    {
	    case 1:  nColors = 2;   break;
#ifdef _WIN32_WCE
        case 2:  nColors = 4;   break;   // winCE only       
#endif
        case 4:  nColors = 16;  break;
        case 8:  nColors = 256; break;
        case 16:
        case 24:
        case 32: nColors = 0;   break;   // 16,24 or 32 bpp have no color table

        default:
           ASSERT(FALSE);
    }

    return nColors;
}

// 
// --- In?: nWidth - image width in pixels
//           nBitsPerPixel - bits per pixel
// --- Out :
// --- Returns : Returns the number of storage bytes needed for each scanline 
//               in the bitmap
// --- Effect : 
/*static*/ int CDIBSectionCE::BytesPerLine(int nWidth, int nBitsPerPixel)
{
    int nBytesPerLine = nWidth * nBitsPerPixel;
    nBytesPerLine = ( (nBytesPerLine + 31) & (~31) ) / 8;

    return nBytesPerLine;
}

#ifndef DIBSECTION_NO_PALETTE

// 
// --- In?: palette - reference to a palette object which will be filled
//           nNumColours - number of colour entries to fill
// --- Out :
// --- Returns : TRUE on success, false otherwise
// --- Effect : Creates a halftone color palette independant of screen color depth.
//              palette will be filled with the colors, and nNumColours is the No.
//              of colors to file. If nNumColoursis 0 or > 256, then 256 colors are used.
/*static*/ BOOL CDIBSectionCE::CreateHalftonePalette(CPalette& palette, int nNumColours)
{
    palette.DeleteObject();

    int nNumStandardColours = sizeof(ms_StdColours) / sizeof(ms_StdColours[0]);
    int nIndex = 0;
    int nNumEntries = nNumColours;
    if (nNumEntries <= 0 || nNumEntries > 256)
        nNumEntries = 256;

    PALETTEINFO PalInfo;                   
    PalInfo.palNumEntries = (WORD) nNumEntries;

    // The standard colours (16)
    for (int i = 0; i < nNumStandardColours; i++)
    {
        if (nIndex >= nNumEntries) 
            break;

        PalInfo.palPalEntry[nIndex].peRed   = ms_StdColours[i].rgbRed;
        PalInfo.palPalEntry[nIndex].peGreen = ms_StdColours[i].rgbGreen;
        PalInfo.palPalEntry[nIndex].peBlue  = ms_StdColours[i].rgbBlue;
        PalInfo.palPalEntry[nIndex].peFlags = 0;
        nIndex++;
    }

    // A colour cube (6 divisions = 216)
    for (int blue = 0; blue <= 5; blue++)
        for (int green = 0; green <= 5; green++)
            for (int red = 0; red <= 5; red++)
            {
                if (nIndex >= nNumEntries)
                    break;

                PalInfo.palPalEntry[nIndex].peRed   = (BYTE) ((red*255)/5);
                PalInfo.palPalEntry[nIndex].peGreen = (BYTE) ((green*255)/5);
                PalInfo.palPalEntry[nIndex].peBlue  = (BYTE) ((blue*255)/5);
                PalInfo.palPalEntry[nIndex].peFlags = 0;
                nIndex++;
            }

    // A grey scale (24 divisions)
    for (int grey = 0; grey <= 23; grey++)
    {
        if (nIndex >= nNumEntries) 
            break;

        PalInfo.palPalEntry[nIndex].peRed   = (BYTE) (grey*255/23);
        PalInfo.palPalEntry[nIndex].peGreen = (BYTE) (grey*255/23);
        PalInfo.palPalEntry[nIndex].peBlue  = (BYTE) (grey*255/23);
        PalInfo.palPalEntry[nIndex].peFlags = 0;
        nIndex++;
    }

    return palette.CreatePalette((LPLOGPALETTE) PalInfo);
}
#endif // DIBSECTION_NO_PALETTE


/////////////////////////////////////////////////////////////////////////////
// CDIBSectionCE

CDIBSectionCE::CDIBSectionCE()
{
    m_hBitmap     = NULL;
    m_hOldBitmap  = NULL;
    m_bReuseMemDC = FALSE;

    DeleteObject(); // This will initialise to a known state - ie. empty
}

CDIBSectionCE::~CDIBSectionCE()
{
    DeleteObject();
}

// --- In?:
// --- Out :
// --- Returns :
// --- Effect : Resets the object to an empty state, and frees all memory used.
void CDIBSectionCE::DeleteObject()
{
    // Unselect the bitmap out of the memory DC before deleting bitmap
    ReleaseMemoryDC(TRUE);

    if (m_hBitmap)
        ::DeleteObject(m_hBitmap);
    m_hBitmap = NULL;
    m_ppvBits = NULL;

#ifndef DIBSECTION_NO_PALETTE
    m_Palette.DeleteObject();
#endif

    memset(&m_DIBinfo, 0, sizeof(m_DIBinfo));

    m_iColorDataType = DIB_RGB_COLORS;
    m_iColorTableSize = 0;
}

/////////////////////////////////////////////////////////////////////////////
// CDIBSectionCE diagnostics

#ifdef _DEBUG
void CDIBSectionCE::AssertValid() const
{
    ASSERT(m_hBitmap);

    DIBSECTION ds;
    DWORD dwSize = GetObject( m_hBitmap, sizeof(DIBSECTION), &ds );
    ASSERT(dwSize == sizeof(DIBSECTION));

    ASSERT(0 <= m_iColorTableSize && m_iColorTableSize <= 256);

	CObject::AssertValid();
}
/*
void CDIBSectionCE::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc);
}
*/
#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////
// CDIBSectionCE operations

// --- In?: pDC - Pointer to a device context
//           ptDest - point at which the topleft corner of the image is drawn
// --- Out :
// --- Returns : TRUE on success
// --- Effect : Draws the image 1:1 on the device context
BOOL CDIBSectionCE::Draw(CDC* pDC, CPoint ptDest, BOOL bForceBackground /*=FALSE*/) 
{ 
    if (!m_hBitmap)
        return FALSE;

    CSize size = GetSize();
    CPoint ptOrigin = CPoint(0,0);

    // Create a memory DC compatible with the destination DC
    CDC* pMemDC = GetMemoryDC(pDC, FALSE);
    if (!pMemDC)
        return FALSE;
        
#ifndef DIBSECTION_NO_PALETTE
    // Select and realize the palette
    CPalette* pOldPalette = NULL;
    if (m_Palette.m_hObject && UsesPalette(pDC))
    {
        pOldPalette = pDC->SelectPalette(&m_Palette, bForceBackground);
        pDC->RealizePalette();
    }
#endif // DIBSECTION_NO_PALETTE

    BOOL bResult = pDC->BitBlt(ptDest.x, ptDest.y, size.cx, size.cy, pMemDC, 
                               ptOrigin.x, ptOrigin.y, SRCCOPY);

#ifndef DIBSECTION_NO_PALETTE
    if (pOldPalette)
        pDC->SelectPalette(pOldPalette, FALSE);
#endif // DIBSECTION_NO_PALETTE

    ReleaseMemoryDC();
    return bResult;
}

// --- In?: pDC - Pointer to a device context
//           ptDest - point at which the topleft corner of the image is drawn
//           size - size to stretch the image
// --- Out :
// --- Returns : TRUE on success
// --- Effect : Stretch draws the image to the desired size on the device context
BOOL CDIBSectionCE::Stretch(CDC* pDC, CPoint ptDest, CSize size,
                          BOOL bForceBackground /*=FALSE*/) 
{ 
    if (!m_hBitmap)
        return FALSE;

    CPoint ptOrigin = CPoint(0,0);
    CSize imagesize = GetSize();

    // Create a memory DC compatible with the destination DC
    CDC* pMemDC = GetMemoryDC(pDC, FALSE);
    if (!pMemDC)
        return FALSE;
        
#ifndef DIBSECTION_NO_PALETTE
    // Select and realize the palette
    CPalette* pOldPalette = NULL;
    if (m_Palette.m_hObject && UsesPalette(pDC))
    {
        pOldPalette = pDC->SelectPalette(&m_Palette, bForceBackground);
        pDC->RealizePalette();
    }
#endif // DIBSECTION_NO_PALETTE

#ifndef _WIN32_WCE
    pDC->SetStretchBltMode(COLORONCOLOR);
#endif // _WIN32_WCE

    BOOL bResult = pDC->StretchBlt(ptDest.x, ptDest.y, size.cx, size.cy, 
                                   pMemDC, 
                                   ptOrigin.x, ptOrigin.y, imagesize.cx, imagesize.cy, 
                                   SRCCOPY);

#ifndef DIBSECTION_NO_PALETTE
    if (pOldPalette)
        pDC->SelectPalette(pOldPalette, FALSE);
#endif // DIBSECTION_NO_PALETTE

    ReleaseMemoryDC();
    return bResult;
}

//////////////////////////////////////////////////////////////////////////////
// Setting the bitmap...

// --- In?: nIDResource - resource ID
// --- Out :
// --- Returns : Returns TRUE on success, FALSE otherwise
// --- Effect : Initialises the bitmap from a resource. If failure, then object is
//              initialised back to an empty bitmap.
BOOL CDIBSectionCE::SetBitmap(UINT nIDResource)
{
    return SetBitmap(MAKEINTRESOURCE(nIDResource));
}

// --- In?: lpszResourceName - resource name
// --- Out :
// --- Returns : Returns TRUE on success, FALSE otherwise
// --- Effect : Initialises the bitmap from a resource. If failure, then object is
//              initialised back to an empty bitmap.
BOOL CDIBSectionCE::SetBitmap(LPCTSTR lpszResourceName)
{
    HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(), 
                                        lpszResourceName,
                                        IMAGE_BITMAP, 
                                        0,0, 
#ifdef _WIN32_WCE
                                        0
#else
                                        LR_CREATEDIBSECTION
#endif
                                        );

    if (!hBmp) 
    {
        TRACE0("Unable to LoadImage");
        return FALSE;
    }

    BOOL bResult = SetBitmap(hBmp);
    ::DeleteObject(hBmp);
    return bResult;
}

// --- In?: lpBitmapInfo - pointer to a BITMAPINFO structure
//           lpBits - pointer to image bits
// --- Out :
// --- Returns : Returns TRUE on success, FALSE otherwise
// --- Effect : Initialises the bitmap using the information in lpBitmapInfo to determine
//              the dimensions and colours, and the then sets the bits from the bits in
//              lpBits. If failure, then object is initialised back to an empty bitmap.
BOOL CDIBSectionCE::SetBitmap(LPBITMAPINFO lpBitmapInfo, LPVOID lpBits)
{
    DeleteObject();

    if (!lpBitmapInfo || !lpBits)
        return FALSE;

    HDC hDC = NULL;
    TRY {
        BITMAPINFOHEADER& bmih = lpBitmapInfo->bmiHeader;

        // Compute the number of colours in the colour table
        m_iColorTableSize = NumColorEntries(bmih.biBitCount);

        DWORD dwBitmapInfoSize = sizeof(BITMAPINFO) + m_iColorTableSize*sizeof(RGBQUAD);

        // Copy over BITMAPINFO contents
        memcpy(&m_DIBinfo, lpBitmapInfo, dwBitmapInfoSize);

        // Should now have all the info we need to create the sucker.
        //TRACE(_T("Width %d, Height %d, Bits/pixel %d, Image Size %d\n"),
        //      bmih.biWidth, bmih.biHeight, bmih.biBitCount, bmih.biSizeImage);

        // Create a DC which will be used to get DIB, then create DIBsection
        hDC = ::GetDC(NULL);
        if (!hDC) 
        {
            TRACE0("Unable to get DC\n");
            AfxThrowResourceException();
        }

        m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*) m_DIBinfo,
                                     m_iColorDataType, &m_ppvBits, NULL, 0);
        ::ReleaseDC(NULL, hDC);
        if (!m_hBitmap)
        {
            TRACE0("CreateDIBSection failed\n");
            AfxThrowResourceException();
        }

        DWORD dwImageSize = m_DIBinfo.bmiHeader.biSizeImage;
        if (dwImageSize == 0)
        {
            int nBytesPerLine = BytesPerLine(lpBitmapInfo->bmiHeader.biWidth, 
                                             lpBitmapInfo->bmiHeader.biBitCount);
            dwImageSize = nBytesPerLine * lpBitmapInfo->bmiHeader.biHeight;
        }

#ifndef _WIN32_WCE
        // Flush the GDI batch queue 
        GdiFlush();
#endif

        memcpy(m_ppvBits, lpBits, dwImageSize);

#ifndef DIBSECTION_NO_PALETTE
        if (!CreatePalette())
        {
            TRACE0("Unable to create palette\n");
            AfxThrowResourceException();
        }
#endif // DIBSECTION_NO_PALETTE
    }
    CATCH (CException, e)
    {
        e->Delete();
        _ShowLastError();
        if (hDC) 
            ::ReleaseDC(NULL, hDC);
        DeleteObject();
        return FALSE;
    }
    END_CATCH

    return TRUE;
}

// --- In?: hBitmap - handle to image
//           pPalette - optional palette to use when setting image
// --- Out :
// --- Returns : Returns TRUE on success, FALSE otherwise
// --- Effect : Initialises the bitmap from the HBITMAP supplied. If failure, then
//              object is initialised back to an empty bitmap.
BOOL CDIBSectionCE::SetBitmap(HBITMAP hBitmap, CPalette* pPalette /*= NULL*/)
{
    DeleteObject();

    if (!hBitmap)
        return FALSE;

    // Get dimensions of bitmap
    BITMAP bm;
    if (!::GetObject(hBitmap, sizeof(bm),(LPVOID)&bm))
        return FALSE;
    bm.bmHeight = abs(bm.bmHeight);

    CWindowDC dc(NULL);
#ifndef DIBSECTION_NO_PALETTE
    CPalette* pOldPalette = NULL;
#endif // DIBSECTION_NO_PALETTE

    TRY {
        m_iColorTableSize = NumColorEntries(bm.bmBitsPixel);

        // Initialize the BITMAPINFOHEADER in m_DIBinfo
        BITMAPINFOHEADER& bih = m_DIBinfo.bmiHeader;
        bih.biSize          = sizeof(BITMAPINFOHEADER);
        bih.biWidth         = bm.bmWidth;
        bih.biHeight        = bm.bmHeight;
        bih.biPlanes        = 1;                // Must always be 1 according to docs
        bih.biBitCount      = bm.bmBitsPixel;
        bih.biCompression   = BI_RGB;
        bih.biSizeImage     = BytesPerLine(bm.bmWidth, bm.bmBitsPixel) * bm.bmHeight;
        bih.biXPelsPerMeter = 0;
        bih.biYPelsPerMeter = 0;
        bih.biClrUsed       = 0;
        bih.biClrImportant  = 0;

        GetColorTableEntries(dc.GetSafeHdc(), hBitmap);

#ifndef DIBSECTION_NO_PALETTE
        // If we have a palette supplied, then set the palette (and hance DIB color
        // table) using this palette
        if (pPalette)
            SetPalette(pPalette);

        if (m_Palette.GetSafeHandle())
        {
            pOldPalette = dc.SelectPalette(&m_Palette, FALSE);
            dc.RealizePalette();
        }
#endif // DIBSECTION_NO_PALETTE

        // Create it!
        m_hBitmap = CreateDIBSection(dc.m_hDC, 
                                     (const BITMAPINFO*) m_DIBinfo,
                                     m_iColorDataType,
                                     &m_ppvBits, 
                                     NULL, 0);
#ifndef DIBSECTION_NO_PALETTE
        if (pOldPalette)
            dc.SelectPalette(pOldPalette, FALSE);
        pOldPalette = NULL; 
#endif // DIBSECTION_NO_PALETTE

        if (!m_hBitmap)
        {
            TRACE0("Unable to CreateDIBSection\n");
            AfxThrowResourceException();
        }

#ifndef DIBSECTION_NO_PALETTE
        // If palette was supplied then create a palette using the entries in the DIB
        // color table.
        if (!pPalette)
            CreatePalette();
#endif // DIBSECTION_NO_PALETTE
   
        // Need to copy the supplied bitmap onto the newly created DIBsection
        CDC memDC, CopyDC;
        if (!CopyDC.CreateCompatibleDC(&dc) || !memDC.CreateCompatibleDC(&dc)) 
        {
            TRACE0("Unable to create compatible DC's\n");
            AfxThrowResourceException();
        }

#ifndef DIBSECTION_NO_PALETTE
        if (m_Palette.GetSafeHandle())
        {
            memDC.SelectPalette(&m_Palette, FALSE);  memDC.RealizePalette();
            CopyDC.SelectPalette(&m_Palette, FALSE); CopyDC.RealizePalette();
        }
#endif // DIBSECTION_NO_PALETTE

#ifndef _WIN32_WCE
        // Flush the GDI batch queue 
        GdiFlush();
#endif

        HBITMAP hOldMemBitmap  = (HBITMAP) SelectObject(memDC.m_hDC,  hBitmap);
        HBITMAP hOldCopyBitmap = (HBITMAP) SelectObject(CopyDC.m_hDC, m_hBitmap);

        CopyDC.BitBlt(0,0, bm.bmWidth, bm.bmHeight, &memDC, 0,0, SRCCOPY);

        SelectObject(memDC.m_hDC, hOldMemBitmap);
        SelectObject(CopyDC.m_hDC, hOldCopyBitmap);

#ifndef DIBSECTION_NO_PALETTE
        if (m_Palette.GetSafeHandle())
        {
            memDC.SelectStockObject(DEFAULT_PALETTE);
            CopyDC.SelectStockObject(DEFAULT_PALETTE);
        }
#endif // DIBSECTION_NO_PALETTE
    }
    CATCH (CException, e)
    {
        e->Delete();
        _ShowLastError();
#ifndef DIBSECTION_NO_PALETTE
        if (pOldPalette)
            dc.SelectPalette(pOldPalette, FALSE);
 #endif // DIBSECTION_NO_PALETTE
        DeleteObject();
        return FALSE;
    }
    END_CATCH

    return TRUE;
}


//////////////////////////////////////////////////////////////////////////////
// Persistance...

// --- In?: lpszFileName - image filename
// --- Out :
// --- Returns : Returns TRUE on success, FALSE otherwise
// --- Effect : Loads the bitmap from a bitmap file with the name lpszFileName. 
//              If failure, then object is initialised back to an empty bitmap.
BOOL CDIBSectionCE::Load(LPCTSTR lpszFileName)
{
    CFile file;
    if (!file.Open(lpszFileName, CFile::modeRead))
        return FALSE;

    // 获得当前的文件位置.  
    DWORD dwFileStart = file.GetPosition();

    // 文件的第一部分包含文件头.
	// 这个将告诉我们是不是它是一个bitmap,头有多大,并且文件多大。
	// 文件头中的头的大小包含了颜色表.
	BITMAPFILEHEADER BmpFileHdr;
    int nBytes;
    nBytes = file.Read(&BmpFileHdr, sizeof(BmpFileHdr));
    if (nBytes != sizeof(BmpFileHdr)) 
    {
        TRACE0("Failed to read file header\n");
        return FALSE;
    }

    // 检查在开始地址是不是含有 'BM'.
    if (BmpFileHdr.bfType != DS_BITMAP_FILEMARKER)
    {
        TRACE0("Not a bitmap file\n");
        return FALSE;
    }

    // 读头 (assuming it's a DIB). 
	DIBINFO	BmpInfo;
    nBytes = file.Read(&BmpInfo, sizeof(BITMAPINFOHEADER)); 
    if (nBytes != sizeof(BITMAPINFOHEADER)) 
    {
        TRACE0("Failed to read BITMAPINFOHEADER\n");
        return FALSE;
    }

    // 检查我们有一个真实的window DIB 文件.
    if (BmpInfo.bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
    {
        TRACE0(" File is not a Windows DIB\n");
        return FALSE;
    }

    // 看颜色表有多大   (if there is one).  
    int nColors = NumColorEntries(BmpInfo.bmiHeader.biBitCount);
	if (nColors > 0) 
    {
        // 读颜色表.
        int nColorTableSize = nColors * sizeof(RGBQUAD);
		nBytes = file.Read(BmpInfo.ColorTable(), nColorTableSize);
		if (nBytes != nColorTableSize) 
        {
			TRACE0("Failed to read color table\n");
			return FALSE;
        }
	}

	// bitmap surface有多大.
    int nBitsSize = BmpFileHdr.bfSize - BmpFileHdr.bfOffBits;

    // 为bits分配内存,并从文件中读bits.
    BYTE* pBits = (BYTE*) malloc(nBitsSize);
    if (!pBits) 
    {
        TRACE0("Out of memory for DIB bits\n");
        return FALSE;
    }

    // 在文件中跳到所要的位置.
    file.Seek(dwFileStart + BmpFileHdr.bfOffBits, CFile::begin);

    // read the bits
    nBytes = file.Read(pBits, nBitsSize);
    if (nBytes != nBitsSize) 
    {
        TRACE0("Failed to read bits\n");
        free(pBits);
		return FALSE;
    }

	// Everything went OK.
	BmpInfo.bmiHeader.biSizeImage = nBitsSize;

    if (!SetBitmap((LPBITMAPINFO) BmpInfo, pBits))
    {
        TRACE0("Failed to set bitmap info\n");
        free(pBits);
		return FALSE;
    }

    free(pBits);

    return TRUE;
}

// --- In?: lpszFileName - image filename
// --- Out :
// --- Returns : Returns TRUE on success, FALSE otherwise
// --- Effect : Saves the image to file.
BOOL CDIBSectionCE::Save(LPCTSTR lpszFileName)
{
    BITMAPFILEHEADER   hdr;
    LPBITMAPINFOHEADER lpbi = GetBitmapInfoHeader();

    if (!lpbi || !lpszFileName)
        return FALSE;

    CFile file;
    if (!file.Open(lpszFileName, CFile::modeWrite|CFile::modeCreate))
        return FALSE;

    DWORD dwBitmapInfoSize = sizeof(BITMAPINFO) + m_iColorTableSize*sizeof(RGBQUAD);
    DWORD dwFileHeaderSize = dwBitmapInfoSize + sizeof(hdr);

    // Fill in the fields of the file header 
    hdr.bfType       = DS_BITMAP_FILEMARKER;
    hdr.bfSize       = dwFileHeaderSize + lpbi->biSizeImage;
    hdr.bfReserved1  = 0;
    hdr.bfReserved2  = 0;
    hdr.bfOffBits    = dwFileHeaderSize;

    // Write the file header 
    file.Write(&hdr, sizeof(hdr));

    // Write the DIB header
    file.Write(lpbi, dwBitmapInfoSize);
    
    // Write DIB bits
    file.Write(GetDIBits(), lpbi->biSizeImage);

    return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CDIBSectionCE palette stuff

#ifndef DIBSECTION_NO_PALETTE

// --- In?:
// --- Out :
// --- Returns : TRUE on success
// --- Effect : Creates the palette from the DIBSection's color table. Assumes 
//              m_iColorTableSize has been set and the DIBsection m_hBitmap created
BOOL CDIBSectionCE::CreatePalette()
{
    m_Palette.DeleteObject();

    if (!m_hBitmap)
        return FALSE;

    // Create a 256 color halftone palette if there is no color table in the DIBSection
    if (m_iColorTableSize == 0)
        return CreateHalftonePalette(m_Palette, 256);

    // Get space for the colour entries
    RGBQUAD *pRGB = new RGBQUAD[m_iColorTableSize];
    if (!pRGB)
        return CreateHalftonePalette(m_Palette, m_iColorTableSize);

    HDC hDC = ::GetDC(NULL);
    if (!hDC)
    {
        delete [] pRGB;
        return FALSE;
    }

    // Create a memory DC compatible with the current DC
    CDC MemDC;
    MemDC.CreateCompatibleDC(CDC::FromHandle(hDC));
    if (!MemDC.GetSafeHdc())
    {
        delete [] pRGB;
        ::ReleaseDC(NULL, hDC);
        return CreateHalftonePalette(m_Palette, m_iColorTableSize);
    }
    ::ReleaseDC(NULL, hDC);
    
    HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(MemDC.GetSafeHdc(), m_hBitmap);
    if (!hOldBitmap)
    {
        delete [] pRGB;
        return CreateHalftonePalette(m_Palette, m_iColorTableSize);
    }

    // Get the colours used. WinCE does not support GetDIBColorTable so if you
    // are using this on a CE device with palettes, then you need to replace
    // the call with code that manually gets the color table from the m_DIBinfo structure.
#ifdef _WIN32_WCE
    int nColours = ::CEGetDIBColorTable(MemDC.GetSafeHdc(), 0, m_iColorTableSize, pRGB);
#else
    int nColours = ::GetDIBColorTable(MemDC.GetSafeHdc(), 0, m_iColorTableSize, pRGB);
#endif

    // Clean up
    ::SelectObject(MemDC.GetSafeHdc(), hOldBitmap);

    if (!nColours)   // No colours retrieved => the bitmap in the DC is not a DIB section
    {
        delete [] pRGB;
        return CreateHalftonePalette(m_Palette, m_iColorTableSize);
    }   
    
    // Create and fill a LOGPALETTE structure with the colours used.
    PALETTEINFO PaletteInfo;
    PaletteInfo.palNumEntries = (WORD) m_iColorTableSize;
                 
	int i=0;
    for (i = 0; i < nColours; i++)
    {
        PaletteInfo.palPalEntry[i].peRed   = pRGB[i].rgbRed;
        PaletteInfo.palPalEntry[i].peGreen = pRGB[i].rgbGreen;
        PaletteInfo.palPalEntry[i].peBlue  = pRGB[i].rgbBlue;
        PaletteInfo.palPalEntry[i].peFlags = 0;
    }
    for (; i < (int) m_iColorTableSize; i++)
    {
        PaletteInfo.palPalEntry[i].peRed   = 0;
        PaletteInfo.palPalEntry[i].peGreen = 0;
        PaletteInfo.palPalEntry[i].peBlue  = 0;
        PaletteInfo.palPalEntry[i].peFlags = 0;
    }

    delete [] pRGB;

    // Create Palette!
    return m_Palette.CreatePalette(&PaletteInfo);
}

// --- In?: pPalette - new palette to use
// --- Out :
// --- Returns : TRUE on success
// --- Effect : Sets the current palette used by the image from the supplied CPalette,
//              and sets the color table in the DIBSection
BOOL CDIBSectionCE::SetPalette(CPalette* pPalette)
{
    m_Palette.DeleteObject();

    if (!pPalette)
        return FALSE;

    UINT nColours = pPalette->GetEntryCount();
    if (nColours <= 0 || nColours > 256)
        return FALSE;

    // Get palette entries
    PALETTEINFO pi;
    pi.palNumEntries = (WORD) pPalette->GetPaletteEntries(0, nColours, (LPPALETTEENTRY) pi);
                          
    // TODO: If pi.palNumEntries < m_iColorTableSize, then fill in blanks with 0's

    return SetLogPalette(&pi);
}

// --- In?: pLogPalette - new palette to use
// --- Out :
// --- Returns : TRUE on success
// --- Effect : Sets the current palette used by the image from the supplied LOGPALETTE
BOOL CDIBSectionCE::SetLogPalette(LOGPALETTE* pLogPalette)
{
    ASSERT(pLogPalette->palVersion == (WORD) 0x300);
    UINT nColours = pLogPalette->palNumEntries;
    if (nColours <= 0 || nColours > 256)
    {
        CreatePalette();
        return FALSE;
    }

    // Create new palette
    m_Palette.DeleteObject();
    if (!m_Palette.CreatePalette(pLogPalette))
    {
        CreatePalette();
        return FALSE;
    }

    if (m_iColorTableSize == 0)
        return TRUE;

    // Set the DIB colours
    RGBQUAD RGBquads[256]; 
    for (UINT i = 0; i < nColours; i++)
    {
        RGBquads[i].rgbRed   = pLogPalette->palPalEntry[i].peRed;
        RGBquads[i].rgbGreen = pLogPalette->palPalEntry[i].peGreen;
        RGBquads[i].rgbBlue  = pLogPalette->palPalEntry[i].peBlue;
        RGBquads[i].rgbReserved = 0;
    }
    
    return FillDIBColorTable(nColours, RGBquads);
}

// --- In?: nNumColours - number of colours to set
//           pRGB - colours to fill
// --- Out :
// --- Returns : Returns TRUE on success
// --- Effect : Sets the colours used by the image. Only works if # colours <= 256
BOOL CDIBSectionCE::FillDIBColorTable(UINT nNumColours, RGBQUAD *pRGB)
{
    if (!pRGB || !nNumColours || !m_iColorTableSize || nNumColours > 256)
        return FALSE;

    // get the number of colors to return per BITMAPINFOHEADER docs
    UINT nColors;
    LPBITMAPINFOHEADER pBmih = GetBitmapInfoHeader();
    if (pBmih->biClrUsed)
        nColors = pBmih->biClrUsed;
    else
        nColors = 1 << (pBmih->biBitCount*pBmih->biPlanes);

    // Initialize the loop variables
    nColors = min(nNumColours, nColors);

    LPRGBQUAD pColorTable = GetColorTable();
    for (UINT iColor = 0; iColor < nColors; iColor++)
    {
        pColorTable[iColor].rgbReserved = 0;
        pColorTable[iColor].rgbBlue     = pRGB[iColor].rgbBlue;
        pColorTable[iColor].rgbRed      = pRGB[iColor].rgbRed;
        pColorTable[iColor].rgbGreen    = pRGB[iColor].rgbGreen;
    }

    return TRUE;
}

#endif // DIBSECTION_NO_PALETTE


// --- In?: hdc     - the Device Context in which the DIBSection is selected
//           hBitmap - the bitmap whose solor entries are to be queried
//           lpbi    - a pointer to a BITMAPINFO structure that will have it's
//                     color table filled.
// --- Out :
// --- Returns : the number of colors placed in the color table
// --- Effect : This function is a replacement for GetDIBits, in that it retrieves 
//              (or synthesizes) the color table from the given bitmap, and stores 
//              the values in the BITMAPINFO structure supplied.
UINT CDIBSectionCE::GetColorTableEntries(HDC hdc, HBITMAP hBitmap)
{
    UINT nColorTableSize = m_iColorTableSize;
    if (!nColorTableSize)
        return 0;
    
    // Fill the color table with the colours from the bitmap's color table
    LPRGBQUAD pColorTable = GetColorTable();
    
    // Get the color table from the HBITMAP and copy them over.
    UINT nCount;
    RGBQUAD* pRGB = new RGBQUAD[nColorTableSize];
    if (pRGB)
    {
        HBITMAP hOldBitmap = (HBITMAP) SelectObject(hdc, hBitmap);
        nCount = CEGetDIBColorTable(hdc, 0, nColorTableSize, pRGB);
        SelectObject(hdc, hOldBitmap);
        if (nCount)
        {
            nColorTableSize = nCount;
            memcpy(pColorTable, pRGB, nCount*sizeof(RGBQUAD));
        }
    }
    delete [] pRGB;

    // Didn't work - so synthesize one.
    if (!nCount)
    {       
        int nNumStandardColours = sizeof(ms_StdColours) / sizeof(ms_StdColours[0]);
        UINT nIndex = 0;
        
		int i = 0;
        // The standard colours (16)
        for (i = 0; i < nNumStandardColours; i++)
        {
            if (nIndex >= nColorTableSize) 
                break;

            memcpy( &(pColorTable[i]), &(ms_StdColours[i]), sizeof(RGBQUAD) );         
            
            nIndex++;
        }
        
        // A colour cube (6 divisions = 216)
        for (int blue = 0; blue <= 5; blue++)
            for (int green = 0; green <= 5; green++)
                for (int red = 0; red <= 5; red++)
                {
                    if (nIndex >= nColorTableSize)
                        break;
                    
                    pColorTable[i].rgbRed   = (BYTE) ((red*255)/5);
                    pColorTable[i].rgbGreen = (BYTE) ((green*255)/5);
                    pColorTable[i].rgbBlue  = (BYTE) ((blue*255)/5);
                    pColorTable[i].rgbReserved = 0;
                    nIndex++;
                }
                
        // A grey scale (24 divisions)
        for (int grey = 0; grey <= 23; grey++)
        {
            if (nIndex >= nColorTableSize) 
                break;
            
            pColorTable[i].rgbRed   = (BYTE) (grey*255/23);
            pColorTable[i].rgbGreen = (BYTE) (grey*255/23);
            pColorTable[i].rgbBlue  = (BYTE) (grey*255/23);
            pColorTable[i].rgbReserved = 0;
            nIndex++;
        }
    }

    return nColorTableSize;
}

/**********************************************************************
This function is from the MS KB article "HOWTO: Get the Color Table of 
a DIBSection in Windows CE".

PARAMETERS:
HDC - the Device Context in which the DIBSection is selected
UINT - the index of the first color table entry to retrieve
UINT - the number of color table entries to retrieve
RGBQUAD - a buffer large enough to hold the number of RGBQUAD
entries requested

RETURNS:
UINT - the number of colors placed in the buffer

***********************************************************************/
UINT CEGetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries,
                        RGBQUAD *pColors)
{   
    if (pColors == NULL)
        return 0;                       // No place to put them, fail
    
    // Get a description of the DIB Section
    HBITMAP hDIBSection = (HBITMAP) GetCurrentObject( hdc, OBJ_BITMAP );

    DIBSECTION ds;
    DWORD dwSize = GetObject( hDIBSection, sizeof(DIBSECTION), &ds );
    
    if (dwSize != sizeof(DIBSECTION))
        return 0;                      // Must not be a DIBSection, fail
    
    if (ds.dsBmih.biBitCount > 8)
        return 0;                      // Not Palettized, fail
    
    // get the number of colors to return per BITMAPINFOHEADER docs
    UINT cColors;
    if (ds.dsBmih.biClrUsed)
        cColors = ds.dsBmih.biClrUsed;
    else
        cColors = 1 << (ds.dsBmih.biBitCount*ds.dsBmih.biPlanes);
    
    // Create a mask for the palette index bits for 1, 2, 4, and 8 bpp
    WORD wIndexMask = (0xFF << (8 - ds.dsBmih.biBitCount)) & 0x00FF;
    
    // Get the pointer to the image bits
    LPBYTE pBits = (LPBYTE) ds.dsBm.bmBits;
    
    // Initialize the loop variables
    cColors = min( cColors, cEntries );
    BYTE OldPalIndex = *pBits;
 
    UINT TestPixelY;
    if (ds.dsBmih.biHeight > 0 )
        // If button up DIB, pBits points to last row
        TestPixelY = ds.dsBm.bmHeight-1;
    else
        // If top down DIB, pBits points to first row
        TestPixelY = 0;
    
    for (UINT iColor = uStartIndex; iColor < cColors; iColor++)
    {
        COLORREF    rgbColor;
        
        // Set the palette index for the test pixel,
        // modifying only the bits for one pixel
        *pBits = (iColor << (8 - ds.dsBmih.biBitCount)) |
            (*pBits & ~wIndexMask);
        
        // now get the resulting color
        rgbColor = GetPixel( hdc, 0, TestPixelY );
        
        pColors[iColor - uStartIndex].rgbReserved = 0;
        pColors[iColor - uStartIndex].rgbBlue = GetBValue(rgbColor);
        pColors[iColor - uStartIndex].rgbRed = GetRValue(rgbColor);
        pColors[iColor - uStartIndex].rgbGreen = GetGValue(rgbColor);
    }
    
    // Restore the test pixel
    *pBits = OldPalIndex;
    
    return cColors;
}


// --- In?: pDC - device context to use when calling CreateCompatibleDC
//           bSelectPalette - if TRUE, the current palette will be preselected
// --- Out :
// --- Returns : A pointer to a memory DC
// --- Effect : Creates a memory DC and selects in the current bitmap so it can be
//              modified using the GDI functions. Only one memDC can be created for
//              a given CDIBSectionCE object. If you have a memDC but wish to recreate it
//              as compatible with a different DC, then call ReleaseMemoryDC first.
//              If the memory DC has already been created then it will be recycled.
//              Note that if using this in an environment where the colour depth of
//              the screen may change, then you will need to set "m_bReuseMemDC" to FALSE
CDC* CDIBSectionCE::GetMemoryDC(CDC* pDC /*=NULL*/, BOOL bSelectPalette /*=TRUE*/)
{
    if (!m_bReuseMemDC)
        ReleaseMemoryDC(TRUE);
    else if (m_MemDC.GetSafeHdc())   // Already created?
    {
#ifndef _WIN32_WCE
        // Flush the GDI batch queue 
        GdiFlush();
#endif
        return &m_MemDC;
    }

    // Create a memory DC compatible with the given DC
    if (pDC)
        m_MemDC.CreateCompatibleDC(pDC);
    else
    {
        HDC hDC = ::GetDC(NULL);    // screen DC
        if (!hDC) return FALSE;
        m_MemDC.CreateCompatibleDC(CDC::FromHandle(hDC));
        ::ReleaseDC(NULL, hDC);
    }
    if (!m_MemDC.GetSafeHdc())
        return NULL;

    // Select in the bitmap
    m_hOldBitmap = (HBITMAP) ::SelectObject(m_MemDC.GetSafeHdc(), m_hBitmap);
    if (!m_hOldBitmap)
    {
        m_MemDC.DeleteDC();
        return NULL;
    }

#ifndef DIBSECTION_NO_PALETTE
    // Select in the palette
    if (bSelectPalette && UsesPalette(&m_MemDC))
    {
        // Palette should already have been created - but just in case...
        if (!m_Palette.GetSafeHandle())
            CreatePalette();

        m_pOldPalette = m_MemDC.SelectPalette(&m_Palette, FALSE);
        m_MemDC.RealizePalette();
    }
    else
        m_pOldPalette = NULL;
#endif // DIBSECTION_NO_PALETTE

#ifndef _WIN32_WCE
    // Flush the GDI batch queue 
    GdiFlush();
#endif // _WIN32_WCE

    return &m_MemDC;
}

// --- In?: bForceRelease - if TRUE, then the memory DC is forcibly released
// --- Out :
// --- Returns : TRUE on success
// --- Effect : Selects out the current bitmap and deletes the mem dc. If bForceRelease 
//              is FALSE, then the DC release will not actually occur. This is provided 
//              so you can have
//
//                 GetMemoryDC(...)
//                 ... do something
//                 ReleaseMemoryDC()
//
//               bracketed calls. If m_bReuseMemDC is subsequently set to FALSE, then 
//               the same code fragment will still work.
BOOL CDIBSectionCE::ReleaseMemoryDC(BOOL bForceRelease /*=FALSE*/)
{
    if ( !m_MemDC.GetSafeHdc() || (m_bReuseMemDC && !bForceRelease) )
        return TRUE; // Nothing to do

#ifndef _WIN32_WCE
    // Flush the GDI batch queue 
    GdiFlush();
#endif // _WIN32_WCE

    // Select out the current bitmap
    if (m_hOldBitmap)
        ::SelectObject(m_MemDC.GetSafeHdc(), m_hOldBitmap);
    m_hOldBitmap = NULL;

#ifndef DIBSECTION_NO_PALETTE
    // Select out the current palette
    if (m_pOldPalette)
        m_MemDC.SelectPalette(m_pOldPalette, FALSE);
    m_pOldPalette = NULL;
#endif // DIBSECTION_NO_PALETTE

    // Delete the memory DC
    return m_MemDC.DeleteDC();
}


#ifdef _DEBUG
// Makes trace windows a little bit more informative...
void CDIBSectionCE::_ShowLastError()
{
    LPVOID lpMsgBuf;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,    
                  NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
                  (LPTSTR) &lpMsgBuf, 0, NULL);
    TRACE1("Last error: %s\n", lpMsgBuf);
    LocalFree(lpMsgBuf);
}
#else
void CDIBSectionCE::_ShowLastError() {}
#endif



 

你可能感兴趣的:(WINCE/WIN32的第三方BMP操作类库----DIBSectionCE类)