本人在开发三维视景类项目时遇到了这样的问题,需要在舰船模型上标明它的舷号,不同的船只有不同的号,而在加载模型时相同类型的船是按照同一方式加载的,于是笔者自然想到在舰艇舷号附近的纹理贴图上直接标上文本,这样舷号自然会显示出来。由于目前使用的是RGB格式的纹理,所以需要将它转成BMP格式,然后绘制文本,再转成RGB格式。
源代码如下:
EditImage.h
#include "dib.h"
/
class CEditImage : public CEdit
{
// Construction
public:
CEditImage();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CEditImage)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CEditImage();
// Generated message map functions
protected:
//{{AFX_MSG(CEditImage)
afx_msg void OnPaint();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
CDib* m_pDib;
CRect m_rect;
COLORREF m_clrText;
BOOL m_bShowImage;
BOOL SetImage(CString strName);
BOOL SaveBMPByDC(CString strFile);
private:
CDC* m_pDC;
CDC* m_pMemDC;
CBitmap* m_pBitmap;
void Convert(CString sFileName);
void RGBtoBMP(BYTE* pRGB,int nType,int nNum);
BYTE* m_pRGB;
CString m_sNote;
BOOL m_bBlend;
public:
BOOL WriteToRGB(CString sOriginName,CString sDestName,COLORREF clr,CRect rect,CString sNote);
};
EditImage.cpp
CEditImage::CEditImage()
{
m_bShowImage=false;
m_rect.left=100;
m_rect.top=10;
m_rect.right=200;
m_rect.bottom=200;
m_clrText=RGB(255,0,0);
m_pBitmap=NULL;
m_pDC=NULL;
m_pMemDC=NULL;
m_pRGB = NULL;
m_sNote="Hello";
m_pDib=NULL;
}
CEditImage::~CEditImage()
{
if(m_pMemDC)
{
delete m_pMemDC;
}
if(m_pDC)
delete m_pDC;
if(m_pBitmap)
{
m_pBitmap->DeleteObject();
delete m_pBitmap;
}
if(m_pRGB)
delete m_pRGB;
if(m_pDib)
delete m_pDib;
}
BEGIN_MESSAGE_MAP(CEditImage, CEdit)
//{{AFX_MSG_MAP(CEditImage)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_SIZE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CEditImage message handlers
void CEditImage::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
if(m_bShowImage)
{
m_pMemDC->SelectObject(m_pBitmap);
CSize cs;
cs.cx=m_pDib->bmSize.cx;
cs.cy=m_pDib->bmSize.cy;
m_pDib->Stretch(m_pMemDC,CPoint(0,0),cs);
m_pMemDC->SetTextColor(m_clrText);
CBrush* oldBrush=(CBrush*)m_pMemDC->SelectStockObject(NULL_BRUSH);
m_pMemDC->SetBkMode(TRANSPARENT);
LOGFONT lfFont;
CFont fontNew, *fontOld;
ZeroMemory(&lfFont, sizeof(lfFont));
lstrcpy(lfFont.lfFaceName, "Arial");
lfFont.lfHeight = m_rect.Height();
lfFont.lfWidth = m_rect.Width();
fontNew.CreateFontIndirect(&lfFont);
fontOld=m_pMemDC->SelectObject(&fontNew);
m_pMemDC->TextOut(m_rect.left,m_rect.top,m_sNote);
m_pDC->BitBlt(0,0,cs.cx,cs.cy,m_pMemDC,0,0,SRCCOPY);
m_pMemDC->SelectObject(oldBrush);
m_pMemDC->SelectObject(fontOld);
}
}
BOOL CEditImage::SetImage(CString strName)
{
if(m_pDib)
delete m_pDib;
m_pDib=new CDib();
m_bShowImage=false;
if(m_pDib->ReadFile(strName))
{
CSize cs;
cs.cx=m_pDib->bmSize.cx;
cs.cy=m_pDib->bmSize.cy;
MoveWindow(0,0,cs.cx,cs.cy,true);
m_bShowImage=true;
Invalidate(false);
}
else
m_bShowImage=false;
return m_bShowImage;
}
BOOL CEditImage::SaveBMPByDC(CString strFile)
{
BITMAP btm;
m_pBitmap->GetBitmap(&btm);
DWORD size=btm.bmWidthBytes*btm.bmHeight;
LPSTR lpData=(LPSTR)GlobalAllocPtr(GPTR,size);
/
BITMAPINFOHEADER bih;
bih.biBitCount=btm.bmBitsPixel;
bih.biClrImportant=0;
bih.biClrUsed=0;
bih.biCompression=0;
bih.biHeight=btm.bmHeight;
bih.biPlanes=1;
bih.biSize=sizeof(BITMAPINFOHEADER);
bih.biSizeImage=size;
bih.biWidth=btm.bmWidth;
bih.biXPelsPerMeter=0;
bih.biYPelsPerMeter=0;
///
HBITMAP bm;
bm=(HBITMAP)m_pBitmap->GetSafeHandle();
GetDIBits(m_pMemDC->GetSafeHdc(),bm,0,bih.biHeight,lpData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
// bm.GetBitmapBits(size,lpData); //此函数在处理5-5-5模式的16位色下会出现颜色混乱
//
if(bih.biBitCount<24)
return FALSE;
BITMAPFILEHEADER bfh;
bfh.bfReserved1=bfh.bfReserved2=0;
bfh.bfType=((WORD)('M'<< 8)|'B');
bfh.bfSize=54+size;
bfh.bfOffBits=54;
///rgb/
CFile bfr;
if(bfr.Open(strFile,CFile::modeCreate|CFile::modeWrite))
{
int nWidth=bih.biWidth;
int nHeight=bih.biHeight;
byte* tmpByte;
if(!m_bBlend)
{
tmpByte=new byte[nWidth*nHeight*3];
for(int i=0;i<nWidth*nHeight;i++)
{
tmpByte[i*3+0] = lpData[i*4+2];
tmpByte[i*3+1] = lpData[i*4+1];
tmpByte[i*3+2] = lpData[i*4+0];
}
}
else
{
tmpByte=new byte[nWidth*nHeight*4];
for(int i=0;i<nWidth*nHeight;i++)
{
tmpByte[i*4+0] = lpData[i*4+2];
tmpByte[i*4+1] = lpData[i*4+1];
tmpByte[i*4+2] = lpData[i*4+0];
if( tmpByte[i*4+0] == 0x00 && tmpByte[i*4+1] == 0x00 && tmpByte[i*4+2] == 0x00 )
tmpByte[i*4+3]=0;
else
tmpByte[i*4+3]=255;
}
}
bfr.Write(&nWidth,sizeof(int));
bfr.Write(&nHeight,sizeof(int));
bfr.Write(&m_bBlend,sizeof(BOOL));
if(m_bBlend)
bfr.Write(tmpByte,nWidth*nHeight*4);
else
bfr.Write(tmpByte,nWidth*nHeight*3);
bfr.Close();
delete tmpByte;
}
/
GlobalFreePtr(lpData);
return TRUE;
}
int CEditImage::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CEdit::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
return 0;
}
void CEditImage::OnSize(UINT nType, int cx, int cy)
{
CEdit::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
if(m_pDC)
delete m_pDC;
m_pDC=new CClientDC(this);
if(m_pMemDC)
delete m_pMemDC;
m_pMemDC=new CDC;
m_pMemDC->CreateCompatibleDC(m_pDC);
if(m_pBitmap)
{
m_pBitmap->DeleteObject();
delete m_pBitmap;
m_pBitmap=NULL;
}
m_pBitmap=new CBitmap;
m_pBitmap->CreateCompatibleBitmap(m_pDC,cx,cy);
}
BOOL CEditImage::WriteToRGB(CString sOriginName,CString sDestName,COLORREF clr,CRect rect,CString sNote)
{
m_clrText=clr;
m_rect.CopyRect(&rect);
m_sNote=sNote;
Convert(sOriginName);
return SaveBMPByDC(sDestName);
}
void CEditImage::Convert(CString sFileName)
{
CString strName = sFileName;
strName = strName.Left(strName.Find('.'));
//读RGB文件
CFile fl;
if(!fl.Open(strName+".RGB",CFile::modeRead))return;
int iWidth,iHeight;
fl.Read(&iWidth,sizeof(int));
fl.Read(&iHeight,sizeof(int));
fl.Read(&m_bBlend,sizeof(BOOL));
if(m_pRGB) delete m_pRGB;
if(m_bBlend)
{
m_pRGB = new BYTE[iWidth*iHeight*4];
fl.Read(m_pRGB,iWidth*iHeight*4);
RGBtoBMP(m_pRGB,4,iWidth*iHeight);
}
else
{
m_pRGB = new BYTE[iWidth*iHeight*3];
fl.Read(m_pRGB,iWidth*iHeight*3);
RGBtoBMP(m_pRGB,3,iWidth*iHeight);
}
fl.Close();
//写BMP文件
BITMAPFILEHEADER pFileHeader;
pFileHeader.bfType = 0x4d42;
pFileHeader.bfSize = sizeof(BITMAPFILEHEADER);
pFileHeader.bfReserved1 = 0;
pFileHeader.bfReserved2 = 0;
pFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//
BITMAPINFOHEADER bmi;
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = iWidth;
bmi.biHeight = iHeight;
bmi.biPlanes = 1;
bmi.biBitCount = 24;
bmi.biCompression = BI_RGB;
bmi.biSizeImage = 0;
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
fl.Open(strName+".BMP",CFile::modeCreate | CFile::modeWrite);
fl.Write(&pFileHeader,sizeof(BITMAPFILEHEADER));
fl.Write(&bmi,sizeof(BITMAPINFOHEADER));
fl.Write(m_pRGB,iWidth*iHeight*3);
fl.Close();
SetImage(strName+".BMP");
OnPaint();
}
void CEditImage::RGBtoBMP(BYTE* pRGB,int nType,int nNum)
{
BYTE* pBmp = new BYTE[nNum*3];
for(int i = 0;i < nNum;i++)
{
pBmp[i*3+2] = pRGB[i*nType+0];
pBmp[i*3+1] = pRGB[i*nType+1];
pBmp[i*3+0] = pRGB[i*nType+2];
}
memcpy(pRGB,pBmp,nNum*3*sizeof(BYTE));
delete pBmp;
}
说明:
此类的基类是一个CEdit,为的是利用它的窗口句柄生成位图并显示保存。
调用方法:
初始化RGB写编号/
m_pTexManage->m_ctrlEditImage->Create(WS_CHILD|WS_VISIBLE,CRect(0,0,10,10),this,ID_EDIT_WRITERGB);
m_pTexManage->m_ctrlEditImage->ShowWindow(SW_HIDE);
m_pTexManage->m_ctrlEditImage->WriteToRGB(Origin.RGB",sDest,RGB(r,g,b),CRect(0,0,100,50),”Hello”);
参数说明:源文件,目标文件,字体颜色,字体左上角位置,字体宽度,高度,文本