三六、VC 对BMP位图的读写

VC++编程   2009-06-12 10:53   阅读155   评论0  
字号:    
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FG_DIB.h
class CFG_DIB : public CObject  
{
public:
    //默认构造函数
    CFG_DIB();
    //构造函数,根据图象宽和高,以及记录每个象素所需字节数来初始化
    CFG_DIB(int width, int height, int nBitCounts);
    virtual ~CFG_DIB();

public:
    HBITMAP m_hBitmap;
    LPBYTE m_lpDIBits;                //DIB位的起始位置
    LPBITMAPINFOHEADER m_lpBMPHdr;            //BITMAPINFOHEADER信息
    LPVOID m_lpvColorTable;                //颜色表信息
    HPALETTE m_hPalette;                //条调色板

private:
    DWORD m_dwImageSize;                //非BITMAPINFOHEADER或BITMAPFILEHEADER的位
    int m_nColorEntries;                //颜色表项的个数

//显示参数
public:
    CPoint m_Dest;                        //目的矩形域的左上角坐标
    CSize m_DestSize;                    //显示矩形的宽度和高度
    CPoint m_Src;                        //原矩形左下角坐标
    CSize m_SrcSize;                    //原矩形宽度和高度

public:
    void InitDestroy();                    //初始化变量
    void ComputePaletteSize(int nBitCounts);        //计算调色板大小
    void ComputeImage();                    //计算图象大小

    //从BMP文件中读入DIB信息
    BOOL ReadFile(CFile* pFile);
    //从BMP文件中读入DIB信息,与ReadFile不同的是使用CreateSection创建位图位
    BOOL ReadSection(CFile* pFile, CDC* pDC = NULL);
    //将DIB写入文件,保存成BMP图片格式
    BOOL WriteFile(CFile* pFile);
    //创建新的位图文件,根据参数width,height,nBitCounts分配内存空间
    BOOL NewFile(int width, int height, int nBitCounts);
    //关闭位图文件
    BOOL CloseFile();

    //显示位图
    BOOL Display(CDC* pDC);

    HBITMAP CreateBitmap(CDC* pDC);            //用DIB创建DDB
    HBITMAP CreateSection(CDC* pDC = NULL);        //创建位图位数据,即象素数据
    //如果DIB没有颜色表,可以用逻辑调色板
    BOOL SetLogPalette(CDC* pDC);
    //如果DIB有颜色表,可以创建系统调色板
    BOOL SetWinPalette();
    //把DIB对象的逻辑调色板选进设备环境里,然后实现调色板
    UINT UseLogPalette(CDC* pDC);

    //得到BitmapInfoHeader的大小,包含颜色表数据
    int GetHeaderSize()
    {
        return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries;
    }
    //得到图像的高度
    int GetHeight()
    {
        if(m_lpBMPHdr == NULL) return 0;
        return m_lpBMPHdr->biHeight;
    }
    //得到图像的宽度
    int GetWidth()
    {
        if(m_lpBMPHdr == NULL) return 0;
        return m_lpBMPHdr->biWidth;
    }
    //得到图像的大小
    int GetImageSize()
    {
        return m_dwImageSize;
    }
    long GetLineBit();        //得到一行的象素数
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FG_DIB.cpp
#include "FG_DIB.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CFG_DIB::CFG_DIB()
{
    m_hBitmap = NULL;
    m_hPalette = NULL;
    m_Dest.x = 0;
    m_Dest.y = 0;
    m_DestSize.cx = 0;
    m_DestSize.cy = 0;
    m_Src.x = 0;
    m_Src.y = 0;
    m_SrcSize.cx = 0;
    m_SrcSize.cy = 0;
    InitDestroy();
}

CFG_DIB::CFG_DIB(int width, int height, int nBitCounts)
{
    m_hBitmap = NULL;
    m_hPalette = NULL;
    m_Dest.x = 0;
    m_Dest.y = 0;
    m_DestSize.cx = 0;
    m_DestSize.cy = 0;
    m_Src.x = 0;
    m_Src.y = 0;
    m_SrcSize.cx = 0;
    m_SrcSize.cy = 0;
    InitDestroy();
    ComputePaletteSize(nBitCounts);                    //为BITMAPINFOHEADER结构申请空间。
    m_lpBMPHdr = (LPBITMAPINFOHEADER)new
        char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries];
    m_lpBMPHdr->biSize = sizeof(BITMAPINFOHEADER);    //以下是为BITMAPINFOHEADER结构赋值
    m_lpBMPHdr->biWidth = width;
    m_lpBMPHdr->biHeight = height;
    m_lpBMPHdr->biPlanes = 1;
    m_lpBMPHdr->biBitCount = nBitCounts;
    m_lpBMPHdr->biCompression = BI_RGB;
    m_lpBMPHdr->biSizeImage = 0;
    m_lpBMPHdr->biXPelsPerMeter = 0;
    m_lpBMPHdr->biYPelsPerMeter = 0;
    m_lpBMPHdr->biClrUsed = m_nColorEntries;
    m_lpBMPHdr->biClrImportant = m_nColorEntries;
    ComputeImage();
    memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorEntries);
    m_lpDIBits = NULL;      // 位图数据起始的位置
}

CFG_DIB::~CFG_DIB()
{
    InitDestroy();
}

void CFG_DIB::InitDestroy()
{
    m_Dest.x = 0;
    m_Dest.y = 0;
    m_DestSize.cx = 0;
    m_DestSize.cy = 0;
    m_Src.x = 0;
    m_Src.y = 0;
    m_SrcSize.cx = 0;
    m_SrcSize.cy = 0;
    if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
    if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap);
    m_lpBMPHdr = NULL;
    m_lpDIBits = NULL;
    m_lpvColorTable = NULL;
    m_nColorEntries = 0;
    m_dwImageSize = 0;
    m_hBitmap = NULL;
    m_hPalette = NULL;
}

void CFG_DIB::ComputePaletteSize(int nBitCounts)
{
    if((m_lpBMPHdr == NULL) || (m_lpBMPHdr->biClrUsed == 0))
    {
        switch(nBitCounts)
        {
            case 1:
                m_nColorEntries = 2;
                break;
            case 4:
                m_nColorEntries = 16;
                break;
            case 8:
                m_nColorEntries = 256;
                break;
            case 16:
            case 24:
            case 32:
                m_nColorEntries = 0;
                break;
            default:
                ASSERT(FALSE);
        }
    }
    else
    {
        m_nColorEntries = m_lpBMPHdr->biClrUsed;
    }
    ASSERT((m_nColorEntries >= 0) && (m_nColorEntries <= 256));
}


void CFG_DIB::ComputeImage()
{
    if(m_lpBMPHdr->biSize != sizeof(BITMAPINFOHEADER))
    {
        TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n");
        throw new CException;
    }
    m_dwImageSize = m_lpBMPHdr->biSizeImage;
    if(m_dwImageSize == 0)
    {
        DWORD dwBytes = ((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) / 32;
        if(((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) % 32)     // 每个行必须满4个字节
        {
            dwBytes++;
        }
        dwBytes *= 4;
        //没被压缩
        m_dwImageSize = dwBytes * m_lpBMPHdr->biHeight;
    }
    // 得到颜色表的首地址
    m_lpvColorTable = (LPBYTE) m_lpBMPHdr + sizeof(BITMAPINFOHEADER);
}

HBITMAP CFG_DIB::CreateBitmap(CDC* pDC)
{
    if (m_dwImageSize == 0) return NULL;
    HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(),
        m_lpBMPHdr, CBM_INIT, m_lpDIBits,
        (LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS);
    ASSERT(hBitmap != NULL);
    return hBitmap;
}
HBITMAP CFG_DIB::CreateSection(CDC* pDC)
{
    if(m_lpBMPHdr == NULL) return NULL;
    if(m_lpDIBits != NULL) return NULL;                    //图像不存在
    m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
        (LPBITMAPINFO)m_lpBMPHdr, DIB_RGB_COLORS,
        (LPVOID*)&m_lpDIBits, NULL, 0);
    ASSERT(m_lpDIBits != NULL);
    return m_hBitmap;
}

BOOL CFG_DIB::SetWinPalette()
{
    if(m_nColorEntries == 0) return FALSE;
    if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
   
    TRACE("CDib::MakePalette --    m_nColorEntries = %d\n", m_nColorEntries);
    LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
        m_nColorEntries * sizeof(PALETTEENTRY)];
    pLogPal->palVersion = 0x300;
    pLogPal->palNumEntries = m_nColorEntries;
    LPRGBQUAD pDibRGBquad = (LPRGBQUAD) m_lpvColorTable;
    for(int i = 0; i < m_nColorEntries; i++)
    {
        pLogPal->palPalEntry[i].peRed = pDibRGBquad->rgbRed;
        pLogPal->palPalEntry[i].peGreen = pDibRGBquad->rgbGreen;
        pLogPal->palPalEntry[i].peBlue = pDibRGBquad->rgbBlue;
        pLogPal->palPalEntry[i].peFlags = 0;
        pDibRGBquad++;
    }
    m_hPalette = ::CreatePalette(pLogPal);
    delete pLogPal;
   
    return TRUE;
}

BOOL CFG_DIB::SetLogPalette(CDC* pDC)
{
    //如果DIB没有颜色表,可以用逻辑调色板
    if(m_nColorEntries != 0) return FALSE;
    m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc());
    return TRUE;
}

UINT CFG_DIB::UseLogPalette(CDC* pDC)
{
    if(m_hPalette == NULL) return 0;
    HDC hdc = pDC->GetSafeHdc();
    ::SelectPalette(hdc, m_hPalette, FALSE);        //Windows作为前台调色板来实现该调色板
    return ::RealizePalette(hdc);
}

BOOL CFG_DIB::NewFile(int width, int height, int nBitCounts)
{
    if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
    if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap);
    m_hBitmap = NULL;
    m_hPalette = NULL;
    m_Dest.x = 0;
    m_Dest.y = 0;
    m_DestSize.cx = 0;
    m_DestSize.cy = 0;
    m_Src.x = 0;
    m_Src.y = 0;
    m_SrcSize.cx = 0;
    m_SrcSize.cy = 0;
    InitDestroy();
    ComputePaletteSize(nBitCounts);                    //为BITMAPINFOHEADER结构申请空间。
    m_lpBMPHdr = (LPBITMAPINFOHEADER)new
        char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries];
    m_lpBMPHdr->biSize = sizeof(BITMAPINFOHEADER);    //以下是为BITMAPINFOHEADER结构赋值
    m_lpBMPHdr->biWidth = width;
    m_lpBMPHdr->biHeight = height;
    m_lpBMPHdr->biPlanes = 1;
    m_lpBMPHdr->biBitCount = nBitCounts;
    m_lpBMPHdr->biCompression = BI_RGB;
    m_lpBMPHdr->biSizeImage = 0;
    m_lpBMPHdr->biXPelsPerMeter = 0;
    m_lpBMPHdr->biYPelsPerMeter = 0;
    m_lpBMPHdr->biClrUsed = m_nColorEntries;
    m_lpBMPHdr->biClrImportant = m_nColorEntries;
    ComputeImage();
    memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorEntries);
    m_lpDIBits = (LPBYTE) new char[m_dwImageSize];

    memset(m_lpDIBits, 0, m_dwImageSize);

    return TRUE;
}

BOOL CFG_DIB::CloseFile()
{
    m_Dest.x = 0;
    m_Dest.y = 0;
    m_DestSize.cx = 0;
    m_DestSize.cy = 0;
    m_Src.x = 0;
    m_Src.y = 0;
    m_SrcSize.cx = 0;
    m_SrcSize.cy = 0;
    InitDestroy();
    return TRUE;
}

/*
描述:保存位图到文件
*/
BOOL CFG_DIB::WriteFile(CFile* pFile)
{
    BITMAPFILEHEADER bmfh;
    bmfh.bfType = 0x4d42;  // 'BM'
    int sizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries;
    bmfh.bfSize = 0;
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
    bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
        sizeof(RGBQUAD) * m_nColorEntries;   
    try
    {
        pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
        pFile->Write((LPVOID) m_lpBMPHdr,  sizeHdr);
        pFile->Write((LPVOID) m_lpDIBits, m_dwImageSize);
    }
    catch(CException* pe)
    {
        pe->Delete();
        AfxMessageBox("write error");
        return FALSE;
    }
   
    return TRUE;
}

/*
描述:向位图中读取数据,读位图
*/
BOOL CFG_DIB::ReadFile(CFile* pFile)
{
    InitDestroy();
    int counts, size;
    BITMAPFILEHEADER bmfh;
    try
    {
        counts = pFile->Read((LPVOID) &bmfh,
                    sizeof(BITMAPFILEHEADER));
        if(counts != sizeof(BITMAPFILEHEADER))
        {
            throw new CException;
        }
        if(bmfh.bfType != 0x4d42)
        {
            throw new CException;
        }
        size = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
        m_lpBMPHdr = (LPBITMAPINFOHEADER) new char[size];
        // BITMAPINFOHEADER和颜色表
        counts = pFile->Read(m_lpBMPHdr, size);
        ComputeImage();
        ComputePaletteSize(m_lpBMPHdr->biBitCount);
        SetWinPalette();
        m_lpDIBits = (LPBYTE) new char[m_dwImageSize];
        counts = pFile->Read(m_lpDIBits, m_dwImageSize);
    }
    catch(CException* pe)
    {
        AfxMessageBox("Read error");
        pe->Delete();
        return FALSE;
    }
   
    return TRUE;
}

BOOL CFG_DIB::ReadSection(CFile* pFile, CDC* pDC)
{
    InitDestroy();
    int counts, size;
    BITMAPFILEHEADER bmfh;
    try
    {
        counts = pFile->Read((LPVOID) &bmfh,
                    sizeof(BITMAPFILEHEADER));
        if(counts != sizeof(BITMAPFILEHEADER)) {
            throw new CException;
        }
        if(bmfh.bfType != 0x4d42) {
            throw new CException;
        }
        size = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
        m_lpBMPHdr = (LPBITMAPINFOHEADER) new char[size];
        //BITMAPINFOHEADER和颜色表
        counts = pFile->Read(m_lpBMPHdr, size);
        if(m_lpBMPHdr->biCompression != BI_RGB)
        {
            throw new CException;
        }
        ComputeImage();
        ComputePaletteSize(m_lpBMPHdr->biBitCount);
        SetWinPalette();
        UseLogPalette(pDC);
        m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
            (LPVOID*) &m_lpDIBits, NULL, 0);
        ASSERT(m_lpDIBits != NULL);
        counts = pFile->Read(m_lpDIBits, m_dwImageSize); // 图像
    }
    catch(CException* pe)
    {
        AfxMessageBox("ReadSection error");
        pe->Delete();
        return FALSE;
    }
   
    return TRUE;
}

/*
描述: 将位图中数据在屏幕上显示
*/
BOOL CFG_DIB::Display(CDC* pDC)
{
    if(m_lpBMPHdr == NULL) return FALSE;
    if(m_hPalette != NULL)
    {
        ::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
    }

    ::StretchDIBits(pDC->GetSafeHdc(), m_Dest.x, m_Dest.y,
                                m_DestSize.cx, m_DestSize.cy,
                                m_Src.x, m_Src.y,
                                m_SrcSize.cx, m_SrcSize.cy,
                                m_lpDIBits, (LPBITMAPINFO) m_lpBMPHdr,
                                DIB_RGB_COLORS, SRCCOPY);
    return TRUE;
}

/*
描述:得到位图中一行的字节个数
*/
long CFG_DIB::GetLineBit()
{
    long dwBytes = ((long)m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) / 32;
    if(((long)m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) % 32)
    {
        dwBytes++;
    }
    dwBytes *= 4;

    return dwBytes;
}

评论(?)
阅读(?)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
网易公司版权所有 ©1997-2009