(1) CDib类的声明
// DIB.h:类CDib声明头文件
#ifndef __DIB_H__
#define __DIB_H__
#include <wingdi.h>
class CDib
{
public:
CDib();
~CDib();
BOOL Load( const char * );
BOOL Save( const char * );
BOOL Draw( CDC *, int nX = 0, int nY = 0, int nWidth = -1, int nHeight = -1, int mode = SRCCOPY);
BOOL SetPalette( CDC * );
private:
CPalette m_Palette;
unsigned char *m_pDib, *m_pDibBits;
DWORD m_dwDibSize;
BITMAPINFOHEADER *m_pBIH;
RGBQUAD *m_pPalette;
int m_nPaletteEntries;
};
#endif
(2) CDib类的实现
// DIB.cpp:类CDib实现文件
#include "stdafx.h"
#include "DIB.h"
CDib::CDib()
{
m_pDib = NULL;
}
CDib::~CDib()
{
// 如果位图已经被加载,释放内存
if (m_pDib != NULL)
delete []m_pDib;
}
下面这个函数非常重要,其功能为加载位图,类似于CBitmap类的LoadBitmap函数:
BOOL CDib::Load(const char *pszFilename)
{
CFile cf;
// 打开位图文件
if (!cf.Open(pszFilename, CFile::modeRead))
return (FALSE);
// 获得位图文件大小,并减去BITMAPFILEHEADER的长度
DWORD dwDibSize;
dwDibSize = cf.GetLength() - sizeof(BITMAPFILEHEADER);
// 为DIB位图分配内存
unsigned char *pDib;
pDib = new unsigned char[dwDibSize];
if (pDib == NULL)
return (FALSE);
BITMAPFILEHEADER BFH;
// 读取位图文件数据
try
{
// 文件格式是否正确有效
if ( cf.Read(&BFH, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) ||
BFH.bfType != ’MB’ || cf.Read(pDib, dwDibSize) != dwDibSize)
{
delete []pDib;
return (FALSE);
}
}
catch (CFileException *e)
{
e->Delete();
delete []pDib;
return (FALSE);
}
// delete先前加载的位图
if (m_pDib != NULL)
delete m_pDib;
// 将临时Dib数据指针和Dib大小变量赋给类成员变量
m_pDib = pDib;
m_dwDibSize = dwDibSize;
// 为相应类成员变量赋BITMAPINFOHEADER和调色板指针
m_pBIH = (BITMAPINFOHEADER*)m_pDib;
m_pPalette = (RGBQUAD*) &m_pDib[sizeof(BITMAPINFOHEADER)];
// 计算调色板中实际颜色数量
m_nPaletteEntries = 1 << m_pBIH->biBitCount;
if (m_pBIH->biBitCount > 8)
m_nPaletteEntries = 0;
else if (m_pBIH->biClrUsed != 0)
m_nPaletteEntries = m_pBIH->biClrUsed;
// 为相应类成员变量赋image data指针
m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof (RGBQUAD)];
// delete先前的调色板
if (m_Palette.GetSafeHandle() != NULL)
m_Palette.DeleteObject();
// 如果位图中存在调色板,创建LOGPALETTE 及CPalette
if (m_nPaletteEntries != 0)
{
LOGPALETTE *pLogPal = (LOGPALETTE*)new char[sizeof(LOGPALETTE) + m_nPaletteEntries *sizeof(PALETTEENTRY)];
if (pLogPal != NULL)
{
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = m_nPaletteEntries;
for (int i = 0; i < m_nPaletteEntries; i++)
{
pLogPal->palPalEntry[i].peRed = m_pPalette[i].rgbRed;
pLogPal->palPalEntry[i].peGreen = m_pPalette[i].rgbGreen;
pLogPal->palPalEntry[i].peBlue = m_pPalette[i].rgbBlue;
}
//创建CPalette并释放LOGPALETTE的内存
m_Palette.CreatePalette(pLogPal);
delete []pLogPal;
}
}
return (TRUE);
}
//函数功能:保存位图入BMP文件
BOOL CDib::Save(const char *pszFilename)
{
if (m_pDib == NULL)
return (FALSE);
CFile cf;
if (!cf.Open(pszFilename, CFile::modeCreate | CFile::modeWrite))
return (FALSE);
try
{
BITMAPFILEHEADER BFH;
memset(&BFH, 0, sizeof(BITMAPFILEHEADER));
BFH.bfType = ’MB’;
BFH.bfSize = sizeof(BITMAPFILEHEADER) + m_dwDibSize;
BFH.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) + m_nPaletteEntries *sizeof(RGBQUAD);
cf.Write(&BFH, sizeof(BITMAPFILEHEADER));
cf.Write(m_pDib, m_dwDibSize);
}
catch (CFileException *e)
{
e->Delete();
return (FALSE);
}
return (TRUE);
}
下面这个函数也非常重要,其功能为在pDC指向的CDC中绘制位图,起点坐标为(nX,nY),绘制宽度和高度为nWidth、nHeight,最后一个参数是光栅模式:
BOOL CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)
{
if (m_pDib == NULL)
return (FALSE);
// 获取位图宽度和高度赋值
if (nWidth == - 1)
nWidth = m_pBIH->biWidth;
if (nHeight == - 1)
nHeight = m_pBIH->biHeight;
// 绘制位图
StretchDIBits(pDC->m_hDC, nX, nY, nWidth, nHeight, 0, 0, m_pBIH->biWidth, m_pBIH->biHeight, m_pDibBits, (BITMAPINFO*)m_pBIH, BI_RGB, mode);
return (TRUE);
}
//函数功能:设置调色板
BOOL CDib::SetPalette(CDC *pDC)
{
if (m_pDib == NULL)
return (FALSE);
// 检查当前是否有一个调色板句柄,对于大于256色的位图,为NULL
if (m_Palette.GetSafeHandle() == NULL)
return (TRUE);
// 选择调色板,接着实施之,最后恢复老的调色板
CPalette *pOldPalette;
pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
pDC->RealizePalette();
pDC->SelectPalette(pOldPalette, FALSE);
return (TRUE);
}
从整个CDib类的代码中我们可以看出,DIB位图的显示需遵循如下步骤:
(1)读取位图,本类中使用pDib = new unsigned char[dwDibSize]为位图中的信息分配内存,另一种方法是调用API函数CreateDIBSection,譬如:
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
(LPVOID*) &m_lpDIBits, NULL, 0);
m_hBitmap定义为:
HBITMAP m_hBitmap;
(2)根据读取的位图信息,计算出调色板大小,然后创建调色板;
(3)调用CDib::SetPalette( CDC *pDC )设置调色板,需要用到CDC::SelectPalette及CDC::RealizePalette两个函数;
(4)调用CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)函数绘制位图。在此函数中,真正发挥显示位图作用的是对StretchDIBits API函数的调用。StretchDIBits函数具有缩放功能,其最后一个参数也是光栅操作的模式。
下面给出DIB位图的打开及显示并在其中加入天极网logo的函数源代码。"DIB位图"父菜单下"打开"子菜单的单击事件消息处理函数为(其功能为打开位图并显示之):
void CBitMapExampleDlg::OnOpendibpic()
{
// 弹出文件对话框,让用户选择位图文件
CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL,"位图文件(*.BMP)|*.bmp;*.BMP|");
if (IDOK == fileDialog.DoModal())
{
// 加载位图并显示之
CDib dib;
if (dib.Load(fileDialog.GetPathName()))
{
CClientDC dc(this);
dib.SetPalette(&dc);
dib.Draw(&dc);
}
}
}
"DIB位图"父菜单下"标记"子菜单的单击事件消息处理函数为(其功能为给位图加上天极网logo):
void CBitMapExampleDlg::OnMarkDibpic()
{
// 弹出文件对话框,让用户选择标记logo
CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL, "标记位图文件(*.BMP)|*.bmp;*.BMP|");
if (IDOK == fileDialog.DoModal())
{
// 加载标记logo位图并与目标位图相与
CDib dib;
if (dib.Load(fileDialog.GetPathName()))
{
CClientDC dc(this);
dib.SetPalette(&dc);
dib.Draw(&dc, 0, 0, - 1, - 1, SRCAND);
}
}
///
我在网上没找到,所以在这里把它贴了出来,其实一句一句的敲,也很快的,一个月就敲完了,当然了,是一边玩一边敲的,注:源代码来自向世明著的《Visual C++ 数字图像与图形处理》
// dib.h: interface for the Cdib class.
//
//
#if !defined(AFX_DIB_H__98D8CBB1_E122_4397_890B_257BFA0AD5BF__INCLUDED_)
#define AFX_DIB_H__98D8CBB1_E122_4397_890B_257BFA0AD5BF__INCLUDED_
#define _CDIB_H
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class Cdib : public CObject
{
DECLARE_DYNAMIC(Cdib)
public:
Cdib();
Cdib(const char *pszDibFileName);
virtual ~Cdib();
void ClearMemory();
void Init();
void LoadFile(const char*pszDibFileName);
#ifdef _DEBUG
virtual void Dump(CDumpContext &dc)const;
virtual void AssertValid() const;
#endif
DWORD GetDdbData32(LPBYTE lpbyDdb32);
DWORD GetDdbData24(LPBYTE lpbyDdb24); //将1、4、8或者24位的DIB图象数据转化为DDB格式的24位位图数据,并存放在lpbyDdb24所指示的内存区域中
DWORD GetDibWidthBytes(int nWidth,BYTE byBitCount); //计算每行的扫描存储宽度字节数
BYTE GetBitCount() const; //获得颜色位数
DWORD GetSize(); //获得被压缩位图的字节数
LONG GetWidth() const;
LONG GetHeight() const;
UINT GetColorNumber() const; //获得颜色总数
char *GetFileName() const;
BOOL IsValid() const;
RGBQUAD *GetRGBQuad() const;
BYTE *GetDibData() const; //获得指向图象位疏忽局的指针
BITMAPINFO *GetBmpInfo() const;
INT Draw(HDC hdc,int Xdest,int Ydest,int nDestWidth,int nDestHeight,
int Xsrc,int Ysrc,int nSrcWidth,int nSrcHeight,UINT iUsage,DWORD dwRop);
protected:
bool m_bValid; //标志装载位图图象的操作过程是否成功
RGBQUAD * m_pRGBQuad; //颜色表项的指针
BYTE * m_pDibData; //指向位数据的指针
LONG m_nWidth,m_nHeight; //图象的宽度和高度,以象素为单位
byte m_nBitCount; //颜色位数,可能取值为1、4、8或者24
UINT m_nTotalColors; //颜色总数,可能取值为2、16、256等
char *m_pszFileName; //文件名(包括路径)的指针
BITMAPFILEHEADER * m_pBitmapFileHeader; //指向位图文件的文件头的指针
BITMAPINFOHEADER * m_pBitmapInfoHeader; //指向位图文件的信息头的指针
BITMAPINFO * m_pBitmapInfo; //指向位图文件的信息头和颜色表项(总称BITMAPINFO)的指针
HGLOBAL m_hDIB; //内存管理句柄
HPALETTE CreateBitmapPalette(); //简单的用颜色表项中的颜色来设置逻辑调色盘中的项,其中的逻辑调色盘是用CreatPalette函数来创建的
private:
};
#endif // !defined(AFX_DIB_H__98D8CBB1_E122_4397_890B_257BFA0AD5BF__INCLUDED_)
dib.cpp文件的全部代码及注释:
// dib.cpp: implementation of the Cdib class.
//
//
#include "stdafx.h"
#include "ImageBasic.h"
#include "dib.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#ifdef _DEBUG
//
// Construction/Destruction
//
IMPLEMENT_DYNAMIC(Cdib,CObject)
Cdib::Cdib()
{
Init();
}
Cdib::Cdib(const char *pszDibFileName)
{
Init();
LoadFile(pszDibFileName);
}
Cdib::~Cdib()
{
ClearMemory();
}
void Cdib::ClearMemory()
{
if(m_hDIB!=NULL)
::GlobalFree(m_hDIB);
m_hDIB=0;
m_pDibData=NULL;
m_pszFileName=NULL;
m_pBitmapFileHeader=NULL;
m_pBitmapInfoHeader=NULL;
m_pBitmapInfo=NULL;
m_pRGBQuad=NULL;
}
void Cdib::Init()
{
m_pRGBQuad=NULL;
m_pDibData=NULL;
m_nWidth=0;
m_nHeight=0;
m_nBitCount=0;
m_nTotalColors=0;
m_pBitmapFileHeader=NULL;
m_pBitmapInfoHeader=NULL;
m_pBitmapInfo=NULL;
m_hDIB=0;
m_pszFileName=NULL;
}
void Cdib::LoadFile(const char*pszDibFileName)
{
ASSERT(pszDibFileName);
if(m_pBitmapInfo) ::GlobalFree(m_hDIB);
Init();
m_pszFileName =(char*) pszDibFileName;
BITMAPFILEHEADER bitmapFileHeader;
CFile dibFile(pszDibFileName,CFile::modeRead);
try
{
UINT nBFHsize=dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER));
if(nBFHsize!=sizeof(BITMAPFILEHEADER)) //如果打开文件出错,则弹出出现异常窗口
{
m_bValid=FALSE;
return;
}
}
catch(CFileException *e)
{
e->Delete();
}
if(bitmapFileHeader.bfType==0x4d42)
{
AfxGetApp()->BeginWaitCursor();
DWORD dwFileLength=dibFile.GetLength();
DWORD dwSize=dwFileLength-sizeof(BITMAPFILEHEADER);
m_hDIB=(HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE,dwSize); //为DIB信息和图像数据分配可移动的内存给句柄m_hDIB
if(m_hDIB==0)
m_bValid=FALSE;
BYTE *pbyDib=(BYTE *)::GlobalLock(m_hDIB); //定义指向BMP文件的指针,锁定内存并从文件中读取数据
if(pbyDib==NULL)
m_bValid=FALSE;
try
{
DWORD dwReadSize=dibFile.Read((void*)pbyDib,dwSize);
dibFile.Close();
if(dwReadSize!=dwSize)
{
m_bValid=FALSE;
::GlobalUnlock(m_hDIB);
::GlobalFree(m_hDIB);
Init();
return;
}
}
catch(CFileException *e)
{
e->Delete();
}
m_pBitmapInfo=(BITMAPINFO *)pbyDib;
m_pBitmapInfoHeader=(BITMAPINFOHEADER *)pbyDib;
m_nWidth=m_pBitmapInfoHeader->biWidth;
m_nHeight=m_pBitmapInfoHeader->biHeight;
m_nBitCount=(BYTE)m_pBitmapInfoHeader->biBitCount; //获得位图的每个象素所占用的位数
m_nTotalColors=GetColorNumber();
if(m_pBitmapInfoHeader->biClrUsed==0) //如果位图实际使用的颜色数为0,说明位图为1、4或者8位位图
m_pBitmapInfoHeader->biClrUsed= m_nTotalColors; //此时,把位图实际使用的颜色数赋值给biClrUsed
m_pRGBQuad=(RGBQUAD*)(pbyDib+m_pBitmapInfoHeader->biSize);
DWORD dwColorTableSize=m_nTotalColors*sizeof(RGBQUAD);
m_pDibData=pbyDib+m_pBitmapInfoHeader->biSize+dwColorTableSize;
if(m_pRGBQuad==(RGBQUAD*)m_pDibData)
m_pRGBQuad=NULL;
m_pBitmapInfoHeader->biSizeImage=GetSize();
::GlobalUnlock(m_hDIB);
AfxGetApp()->EndWaitCursor;
m_bValid=true;
}
else
{
AfxMessageBox("This is not a bitmap file!");
m_bValid=false;
}
}
#ifdef _DEBUG
void Cdib::Dump(CDumpContext &dc)const
{
CObject::Dump(dc);
}
void Cdib::AssertValid() const
{
CObject::AssertValid();
ASSERT(m_pszFileName!=NULL);
ASSERT(m_hDIB!=0);
}
#endif
long Cdib::GetWidth() const
{
return m_nWidth;
}
LONG Cdib::GetHeight() const
{
return m_nHeight;
}
DWORD Cdib::GetSize()
{
if(m_pBitmapInfoHeader->biSizeImage!=0)
return (m_pBitmapInfoHeader->biSizeImage);
else
return (DWORD) GetDibWidthBytes(m_nWidth,24)*(DWORD)m_nHeight;
}
BYTE Cdib::GetBitCount() const
{
return m_nBitCount;
}
UINT Cdib::GetColorNumber() const
{
UINT nColors=0;
if((m_pBitmapInfoHeader->biSizeImage==0) && (m_pBitmapInfoHeader->biSizeImage<9))
{
switch (m_pBitmapInfoHeader->biBitCount)
{
case 1: nColors=2;break;
case 4: nColors=16;break;
case 8: nColors=256;break;
}
}
else
nColors=(UINT)m_pBitmapInfoHeader->biClrUsed;
return nColors;
}
BYTE * Cdib::GetDibData() const
{
return m_pDibData;
}
RGBQUAD *Cdib::GetRGBQuad() const
{
return m_pRGBQuad;
}
BITMAPINFO *Cdib::GetBmpInfo() const
{
return m_pBitmapInfo;
}
char *Cdib::GetFileName() const
{
return m_pszFileName;
}
BOOL Cdib::IsValid() const
{
return m_bValid;
}
DWORD Cdib::GetDibWidthBytes(int nWidth,BYTE byBitCount)
{
DWORD dwWidthBytes=(DWORD)nWidth; //如果位图的每个象素的位数是8,那么整个位图的字节数就等于象素数
if(byBitCount==1) //如果位图的每个象素的位数是1,那么一个字节就包含了8个象素
dwWidthBytes=(nWidth+7)/8;
if(byBitCount==4)
dwWidthBytes=(nWidth+1)/2; //如果位图的每个象素的位数是4,那么一个字节就包含了2个象素
if(byBitCount==24)
dwWidthBytes=3*nWidth; //如果位图的每个象素的位数是24,那么一个象素就需要3个字节来存储
while((dwWidthBytes&3)!=0)
dwWidthBytes++;
return dwWidthBytes;
}
//将1、4、8或者24位的DIB图象数据转换为DDB格式的24位位图,并存放在lpbyDdb24指示的内存区域中
DWORD Cdib::GetDdbData24(LPBYTE lpbyDdb24)
{
ASSERT(lpbyDdb24);
DWORD dwDibWidthBytes=GetDibWidthBytes(m_nWidth,m_nBitCount);
DWORD dwDdbWidthBytes=((m_nWidth*24+15)/16)*2; //????????
if(m_nBitCount==1)
{
LONG nLineBytes=(m_nWidth+7)/8;
BYTE abyBitMask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
DWORD dwDibBaseIndex=(m_nHeight-1)*dwDibWidthBytes;
DWORD dwDdbBaseIndex=0;
for(LONG i=0;i<m_nHeight;i++)
{
BYTE *pbyDibRaw=m_pDibData+dwDibBaseIndex;
BYTE *pbyDdbRaw=lpbyDdb24+dwDdbBaseIndex;
for(LONG j=0;j<nLineBytes;j++)
{
BYTE byBit8=*(pbyDibRaw++);
for(int n=0;n<8;n++)
{
BYTE byBitSingle=(byBit8 & abyBitMask[n])>>(7-n);
*(pbyDdbRaw++)=m_pRGBQuad[byBitSingle].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byBitSingle].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byBitSingle].rgbRed;
}
} //end j
dwDibBaseIndex-=dwDibWidthBytes;
dwDdbBaseIndex+=dwDdbWidthBytes;
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==1)
else
if (m_nBitCount==4)
{
LONG nLineBytes=(m_nWidth+1)/2;
DWORD dwDibBaseIndex=(m_nHeight-1)*dwDibWidthBytes;
DWORD dwDdbBaseIndex=0;
for(LONG i=0;i<m_nHeight;i++)
{
BYTE *pbyDibRaw=m_pDibData+dwDibBaseIndex;
BYTE *pbyDdbRaw=lpbyDdb24+dwDdbBaseIndex;
for(LONG j=0;j<nLineBytes;j++)
{
BYTE byBit8=*(pbyDibRaw++); //对于4位位图,一个字节里面含有两个象素。前4位代表一个象素的颜色表项指针,后4位同样。
BYTE byBitHigh=(byBit8 & 0xF0)>>4; //因此这里要右移4位,再与F0取与,先得到第一个象素
BYTE byBitLow=(byBit8 & 0x0F);
*(pbyDdbRaw++)=m_pRGBQuad[byBitHigh].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byBitHigh].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byBitHigh].rgbRed;
*(pbyDdbRaw++)=m_pRGBQuad[byBitLow].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byBitLow].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byBitLow].rgbRed;
} //end j
dwDibBaseIndex-=dwDibWidthBytes;
dwDdbBaseIndex+=dwDdbWidthBytes;
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==4)
else
if (m_nBitCount==8)
{
DWORD dwDibBaseIndex=(m_nHeight-1)*dwDibWidthBytes;
DWORD dwDdbBaseIndex=0;
for(LONG i=0;i<m_nHeight;i++)
{
BYTE *pbyDibRaw=m_pDibData+dwDibBaseIndex;
BYTE *pbyDdbRaw=lpbyDdb24+dwDdbBaseIndex;
for(LONG j=0;j<m_nWidth;j++)
{
BYTE byIndex=*(pbyDibRaw++);
*(pbyDdbRaw++)=m_pRGBQuad[byIndex].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byIndex].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byIndex].rgbRed;
} // end j
dwDibBaseIndex-=dwDibWidthBytes;
dwDdbBaseIndex+=dwDdbWidthBytes;
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==8)
else
if (m_nBitCount==24)
{
DWORD dwLength=m_nWidth*3;
BYTE *pbyDibRaw=m_pDibData+(m_nHeight-1)*dwDibWidthBytes;
BYTE *pbyDdbRaw=lpbyDdb24;
for(LONG i=0;i<m_nHeight;i++)
{
::CopyMemory(pbyDdbRaw,pbyDibRaw,dwLength);
pbyDibRaw-=dwDibWidthBytes; //from
pbyDdbRaw-=dwDdbWidthBytes; //to
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==24)
return (m_nWidth*m_nHeight);
}
//将所有格式的颜色数据转换为32位颜色,按字节顺序依次为绿色、蓝色、红色和8位Alpha(说明256级透明性)
DWORD Cdib::GetDdbData32(LPBYTE lpbyDdb32)
{
ASSERT(lpbyDdb32);
DWORD dwDibWidthBytes=GetDibWidthBytes(m_nWidth,m_nBitCount);
DWORD dwDdbWidthBytes=m_nWidth*4;
if(m_nBitCount==1)
{
LONG nLineBytes=(m_nWidth+7)/8;
BYTE abyBitMask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
DWORD dwDibBaseIndex=(m_nHeight-1)*dwDibWidthBytes;
DWORD dwDdbBaseIndex=0;
for(LONG i=0;i<m_nHeight;i++)
{
BYTE *pbyDibRaw=m_pDibData+dwDibBaseIndex;
BYTE *pbyDdbRaw=lpbyDdb32+dwDdbBaseIndex;
for(LONG j=0;j<nLineBytes;j++)
{
BYTE byBit8=*(pbyDibRaw++);
for(int n=0;n<8;n++)
{
BYTE byBitSingle=(byBit8 & abyBitMask[n])>>(7-n);
*(pbyDdbRaw++)=m_pRGBQuad[byBitSingle].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byBitSingle].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byBitSingle].rgbRed;
pbyDdbRaw++;
}
} //end j
dwDibBaseIndex-=dwDibWidthBytes;
dwDdbBaseIndex+=dwDdbWidthBytes;
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==1)
else
if (m_nBitCount==4)
{
LONG nLineBytes=(m_nWidth+1)/2;
DWORD dwDibBaseIndex=(m_nHeight-1)*dwDibWidthBytes;
DWORD dwDdbBaseIndex=0;
for(LONG i=0;i<m_nHeight;i++)
{
BYTE *pbyDibRaw=m_pDibData+dwDibBaseIndex;
BYTE *pbyDdbRaw=lpbyDdb32+dwDdbBaseIndex;
for(LONG j=0;j<nLineBytes;j++)
{
BYTE byBit8=*(pbyDibRaw++); //对于4位位图,一个字节里面含有两个象素。前4位代表一个象素的颜色表项指针,后4位同样。
BYTE byBitHigh=(byBit8 & 0xF0)>>4; //因此这里要右移4位,再与F0取与,先得到第一个象素
BYTE byBitLow=(byBit8 & 0x0F);
*(pbyDdbRaw++)=m_pRGBQuad[byBitHigh].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byBitHigh].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byBitHigh].rgbRed;
pbyDdbRaw++;
*(pbyDdbRaw++)=m_pRGBQuad[byBitLow].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byBitLow].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byBitLow].rgbRed;
pbyDdbRaw++;
} //end j
dwDibBaseIndex-=dwDibWidthBytes;
dwDdbBaseIndex+=dwDdbWidthBytes;
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==4)
else
if (m_nBitCount==8)
{
DWORD dwDibBaseIndex=(m_nHeight-1)*dwDibWidthBytes;
DWORD dwDdbBaseIndex=0;
for(LONG i=0;i<m_nHeight;i++)
{
BYTE *pbyDibRaw=m_pDibData+dwDibBaseIndex;
BYTE *pbyDdbRaw=lpbyDdb32+dwDdbBaseIndex;
for(LONG j=0;j<m_nWidth;j++)
{
BYTE byIndex=*(pbyDibRaw++);
*(pbyDdbRaw++)=m_pRGBQuad[byIndex].rgbBlue;
*(pbyDdbRaw++)=m_pRGBQuad[byIndex].rgbGreen;
*(pbyDdbRaw++)=m_pRGBQuad[byIndex].rgbRed;
pbyDdbRaw++;
} // end j
dwDibBaseIndex-=dwDibWidthBytes;
dwDdbBaseIndex+=dwDdbWidthBytes;
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==8)
else
if (m_nBitCount==24)
{
DWORD dwDibBaseIndex=(m_nHeight-1)*dwDibWidthBytes;
DWORD dwDdbBaseIndex=0;
for(LONG i=0;i<m_nHeight;i++)
{
BYTE *pbyDibRaw=m_pDibData+dwDibBaseIndex;
BYTE *pbyDdbRaw=lpbyDdb32+dwDdbBaseIndex;
for(LONG j=0;j<m_nWidth;j++)
{
*(pbyDdbRaw++)=*(pbyDibRaw++); //blue
*(pbyDdbRaw++)=*(pbyDibRaw++); //qree
*(pbyDdbRaw++)=*(pbyDibRaw++); //red
pbyDdbRaw++;
} // end j
dwDibBaseIndex-=dwDibWidthBytes;
dwDdbBaseIndex+=dwDdbWidthBytes;
} //end i
return (dwDdbWidthBytes*m_nHeight);
} //end if(m_nBitCount==24)
return (m_nWidth*m_nHeight);
}
//用颜色表项中的颜色来设置逻辑调色板中的项,并通过CreatePalette函数来创建一个逻辑调色板
HPALETTE Cdib::CreateBitmapPalette()
{
if((m_pRGBQuad==NULL)||!IsValid()) //如果不存在颜色表或者BMP文件不合法
return NULL;
struct
{
WORD palVersion;
WORD palNumEntries;
PALETTEENTRY palPalEntry[256];
}palette={0x300,256};
LPRGBQUAD pRGBTable=m_pRGBQuad;
for(UINT i=0;i<m_nTotalColors;++i)
{
palette.palPalEntry[i].peRed=pRGBTable[i].rgbRed;
palette.palPalEntry[i].peGreen=pRGBTable[i].rgbGreen;
palette.palPalEntry[i].peBlue=pRGBTable[i].rgbBlue;
palette.palPalEntry[i].peFlags=0;
}
HPALETTE hPalette=::CreatePalette((LPLOGPALETTE)&palette);
return hPalette;
}
//通过调用系统的StretchDIBits()来绘制位图,它能够方便的确定位图输出的位置,并决定是否拉伸图象
int Cdib::Draw(HDC hdc,int Xdest,int Ydest,int nDestWidth,int nDestHeight,
int Xsrc,int Ysrc,int nSrcWidth,int nSrcHeight,UINT iUsage,DWORD dwRop)
{
if(m_pRGBQuad) //如果存在颜色表
{
HPALETTE hPalette=CreateBitmapPalette();
HPALETTE hOldPalette=::SelectPalette(hdc,hPalette,FALSE);
::RealizePalette(hdc);
int nScanLines=::StretchDIBits(hdc,Xdest,Ydest,nDestWidth,nDestHeight,
Xsrc,Ysrc,nSrcWidth,nSrcHeight,
m_pDibData,m_pBitmapInfo,iUsage,dwRop);
::SelectPalette(hdc,hOldPalette,FALSE);
::DeleteObject(hPalette);
return nScanLines;
}
else
return StretchDIBits(hdc,Xdest,Ydest,nDestWidth,nDestHeight,
Xsrc,Ysrc,nSrcWidth,nSrcHeight,
m_pDibData,m_pBitmapInfo,iUsage,dwRop);
}
#endif