⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 handwritingview.cpp

📁 vc模仿手写字的源码,可以实现模仿手写字的功能
💻 CPP
📖 第 1 页 / 共 2 页
字号:
				x+=sx;
				if(e>=0)
				{
					y+=sy;
					e+=t2;
				}
				else
				{
					e+=t1;
				}
				dc->LineTo (x,y);

				//在象素的绘制之间进行延迟
				//
				Now=Upper/pStroke->Stroke.Speed ;
				for(Delay=0;Delay<Now;Delay++);
				dc->SelectStockObject(BLACK_PEN);
				Pen.DeleteObject();
			}
			dc->LineTo(x+1,y);
		}
		else
		{
			t1=2*dx;
			t2=2*(dx-dy);
			e=2*dx-dy;
			dWidth=dy?1.0*(Width2-Width1)/dy:Width2-Width1;
			for(i=0;i<dy;i++)
			{
				//创建相应宽度的笔
				//
				iWidth=Width1+dWidth*i;
				Pen.CreatePen (PS_SOLID,iWidth,RGB(0,0,0));//Style0
				dc->SelectObject(&Pen);
				y+=sy;
				if(e>=0)
				{
					x+=sx;
					e+=t2;
				}
				else
				{
					e+=t1;
				}
				dc->LineTo (x,y);

				//在象素的绘制之间进行延迟
				//
				Now=Upper/pStroke->Stroke.Speed;
				for(Delay=0;Delay<Now;Delay++);
				dc->SelectStockObject(BLACK_PEN);
				Pen.DeleteObject();
			}
			dc->LineTo(x+1,y);
		}
		
		pTemp=pStroke;
		pStroke=pStroke->pStroke ;
		
		//笔划书写间隔要进行一定延时,以模拟笔移动的效果
		//
		if(pStroke!=NULL)
		{
			if((pTemp->Stroke.x2-pStroke->Stroke.x1)*(pTemp->Stroke.x2-pStroke->Stroke.x1)+(pTemp->Stroke.y2-pStroke->Stroke.y1)*(pTemp->Stroke.y2-pStroke->Stroke.y1)>(Interval*Interval))
				for(Delay=0;Delay<Upper*Interval;Delay++);
		}
		
	}
}

//////////////////////////////////////////////
//位图文件打开按钮函数:启动打开并显示含有要录制的
//手写字符的位图文件的过程。
//
void CHandwritingView::OnbtnOpenBmp() 
{
	RECT rect;
	
	//打开字符位图文件并进行显示
	//
	sOperated=sOpenning;
	bErase=false;
	ReadBitmap();
	sOperated=sOpened;
	GetClientRect(&rect);
	InvalidateRect(&rect,TRUE);
}

//////////////////////////////////////////////
//位图文件读取函数:打开、构造与缓冲含有手写字
//符的位图文件。
//
void CHandwritingView::ReadBitmap()
{
	#define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B') //"BM"

	CFile f;
	CFileException e;
	BITMAPFILEHEADER bmfHead;
	BITMAPINFOHEADER bmHead;
	DWORD rdBytes,svBytes,nPixel;
	UINT nEntries;
	UINT nScan,tmp;
	BYTE *pTemp=NULL,*pRGBQUARD=NULL;
	int i,j;
	DWORD index;
	BYTE iRGB,OneByte;
	LONG lOffset;
	CString pFileName;
	
	//通过文件对话框获取有效的文件名
	//
	pFileName=CString("");
	CFileDialog fDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, "bitmap Files (*.bmp)||",NULL );
	if((fDlg.DoModal())!=IDOK)
	{
		return;
	}

	pFileName=fDlg.GetPathName ();
	if(!pFileName)
	{
		return;
	}
	
	//打开位图文件
	//
	if(!f.Open(pFileName, CFile::modeRead, &e ))
	{
		MessageBox("Hi,file.","File operating.",MB_OK);
		exit(0);
	}
    
	//读取位图文件并构造显示数据:关于解压算法可参见位图文件
	//的有关存储格式介绍
	//
	f.Read (&bmfHead,sizeof(BITMAPFILEHEADER));
	if(bmfHead.bfType!=DIB_HEADER_MARKER)
	{
		MessageBox("File is not BMP!",NULL,MB_OK);
		return;
	}
	f.Seek(14,CFile::begin);
	f.Read (&bmHead,sizeof(BITMAPINFOHEADER));
	if(bmHead.biCompression)
	{
		MessageBox("cannot open this compressed file!",NULL,MB_OK);
		exit(1);
	}

	//从堆中分配逐象素缓冲所需要容量的内存
	//
	tmp=bmHead.biWidth*bmHead.biBitCount;
	nScan=tmp%32?(tmp/32*4+(tmp%32+32)/32*4):tmp/8;
	rdBytes=nScan*bmHead.biHeight ;	
	svBytes=bmHead.biWidth*bmHead.biHeight;
	pTemp=new BYTE[rdBytes];
	if(pBuff)
		delete pBuff;
	pBuff=new _MYBITMAP[svBytes];
	if(!pBuff||!pTemp)
	{
		MessageBox("Cannot allocate memory","Memory allocate",MB_OK);
		exit(0);
	}
	
	//读取数据
	//
	lOffset=bmfHead.bfOffBits;
	f.Seek (lOffset,CFile::begin);
	f.Read (pTemp,rdBytes);

	if(bmHead.biBitCount<24)
	{
		nEntries=Pow2(bmHead.biBitCount); 
		pRGBQUARD=new BYTE[nEntries*4];
		f.Seek (54l,CFile::begin);
		f.Read (pRGBQUARD,nEntries*4);
	}
	f.Close();

	//进行数据构造
	//
	switch(bmHead.biBitCount)
	{
	case 1:nPixel=0;
		for(i=bmHead.biHeight-1;i>=0;i--)
			for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
				{
					OneByte=pTemp[index+j/8];
					iRGB=(OneByte&Pow2(7-j%8))?1:0;
					pBuff[nPixel++].clrRGBA =RGB(pRGBQUARD[iRGB*4+2],pRGBQUARD[iRGB*4+1],pRGBQUARD[iRGB*4]);
				}
			break;
		case 4:nPixel=0;
			for(i=bmHead.biHeight-1;i>=0;i--)
				for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
				{
					OneByte=pTemp[index+j*4/8];
					iRGB=j%2?OneByte&0x0f:OneByte>>4;
					pBuff[nPixel++].clrRGBA =RGB(pRGBQUARD[iRGB*4+2],pRGBQUARD[iRGB*4+1],pRGBQUARD[iRGB*4]);
				}
			break;
		case 8:nPixel=0;
			for(i=bmHead.biHeight-1;i>=0;i--)
				for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
				{
					OneByte=pTemp[index+j];
					iRGB=OneByte;
					pBuff[nPixel++].clrRGBA =RGB(pRGBQUARD[iRGB*4+2],pRGBQUARD[iRGB*4+1],pRGBQUARD[iRGB*4]);
				}
				break;
		case 24:nPixel=0;
			for(i=bmHead.biHeight-1;i>=0;i--)
				for(index=i*nScan,j=0;j<bmHead.biWidth;j++)
				{
					pBuff[nPixel++].clrRGBA =RGB(pTemp[index+2],pTemp[index+1],pTemp[index]);
					index+=3;
				}
				break;
		default:
			MessageBox("File not supported.",NULL,MB_OK);
			exit(1);
	}

	//保存变量状态及释放临时资源
	//
	biWidth=bmHead.biWidth;
	biHeight=bmHead.biHeight;
	bmp=true;

	if(pTemp)
		delete pTemp;
	if(pRGBQUARD)
		delete pRGBQUARD;
}

////////////////////////////////////////////////////////////////////////////////
//位图显示函数:在屏幕上某位置将缓冲的位图显示出来
//
void CHandwritingView::DrawBitmap(MYBITMAP *pBmp, int x0, int y0, CClientDC *dc)
{
	int x,y;
	UINT i,j;
	DWORD index;
	
	//逐象素显示位图
	//
	y=y0;
	dc->SetROP2 (R2_COPYPEN);
	if(pBmp)
		for(i=0;i<biHeight;i++,y++)
			for(x=x0,index=i*biWidth,j=0;j<biWidth;j++,x++)
				dc->SetPixel (x,y,pBmp[index++].clrRGBA);
}

////////////////////////////////////////
//幂函数:计算2的x次幂
//
DWORD CHandwritingView::Pow2(UINT x)
{
	DWORD dwProduct;
	UINT i;

	for(dwProduct=1,i=1;i<=x;i++)
		dwProduct*=2;
	return dwProduct;
}

/////////////////////////////////////////////////////
//字符笔划删除函数:将字符笔划链表中的笔划节点删除并
//释放相应资源。
//
void CHandwritingView::DeleteStrokes()
{
	STROKES *pTemp;
	
	//删除一个字符的所有笔划节点
	//
	while(Strokes)
	{
		pTemp=Strokes;
		Strokes=Strokes->pStroke ;
		pTemp->pStroke =NULL;
		if (pTemp)
		delete pTemp;
	}
}

///////////////////////////////////////////////////////////
//实例按钮函数:根据给定的笔划数据,动态地展示实例
//字符的手写过程
void CHandwritingView::OnbtnSample() 
{
	UINT i;
	STROKES *pTmp;
	
	//示例字符“龙飞凤舞”的笔划数据
	//
	static _STROKE lffw[]={{34,13,39,18,3,10,1},{39,18,45,24,12,9,1},{45,16,45,27,1,6,1},{20,33,28,32,1,10,1},{29,31,48,29,10,7,1},{51,28,70,30,5,6,1},{37,31,40,52,7,6,1},{52,35,51,42,2,7,1},
							{52,41,44,50,3,7,1},{9,71,15,66,2,9,1},{19,64,27,58,13,7,1},{29,56,58,54,5,5,1},{41,53,41,66,5,8,1},{41,68,26,89,7,7,1},{26,88,23,137,7,5,2},{41,65,48,76,3,4,1},
							{46,73,46,132,6,7,3},{48,118,35,101,8,4,3},{34,99,31,69,3,7,3},{36,70,73,71,5,9,3},{73,68,90,64,5,7,2},{90,61,83,54,2,5,1},{83,54,75,58,3,5,1},{76,56,70,103,5,5,3},
							{71,94,83,85,8,7,2},{82,86,97,85,8,7,1},{97,86,81,102,7,7,1},{82,101,82,121,6,7,2},{84,119,120,121,6,9,3},{119,119,130,110,7,9,1},{130,110,130,100,6,5,1},{131,100,124,98,5,7,1},
							{124,95,113,97,5,6,1},{108,96,109,90,6,6,1},{110,88,119,80,6,8,1},{118,79,119,71,5,6,1},{119,72,113,73,2,6,1},{116,72,106,63,5,5,1},{107,61,106,53,7,5,1},{107,53,102,47,7,7,1},
							{103,48,83,44,5,5,1},{82,42,112,37,10,9,1},{113,37,118,33,9,1,1},
							{132,25,164,24,8,7,1},{162,22,162,49,6,5,1},{164,49,196,50,6,8,3},{198,50,198,23,6,3,3},{198,21,196,17,3,7,1},{194,17,189,18,5,4,1},{188,17,180,26,4,6,1},{180,25,186,31,4,3,1},
							{188,30,201,31,3,3,1},{204,30,213,39,7,7,1},{210,36,210,53,8,9,1},{212,51,177,89,10,6,3},{176,88,176,109,4,6,2},{176,107,189,117,5,6,1},{188,113,230,114,6,5,2},{229,113,215,101,8,8,2},
							{217,101,204,102,5,8,1},{205,98,189,111,8,6,2},{187,110,187,91,3,3,2},{186,89,176,85,4,4,1},{117,84,162,73,5,5,2},{162,73,142,74,6,5,1},{143,73,140,71,4,6,1},{140,69,136,55,8,8,1},
							{135,54,143,51,7,8,1},{143,50,155,59,7,7,1},{153,58,153,91,7,6,2},{152,89,144,129,7,12,1},{144,122,127,143,10,7,2},{130,139,127,143,6,1,1},{236,28,237,40,2,5,1},{237,38,241,52,6,7,1},
							{241,50,243,80,6,5,1},{253,35,277,37,6,7,2},{275,37,276,48,7,5,1},{276,47,277,87,6,5,1},{277,87,292,91,5,7,1},{290,89,312,91,5,6,3},{311,89,313,85,8,6,1},{312,83,312,71,6,6,2},
							{312,72,295,42,5,6,2},{294,40,290,14,5,5,3},{290,12,279,14,6,5,1},{280,14,261,32,5,7,3},{261,31,260,47,6,6,2},{256,45,259,86,6,9,3},{259,83,268,96,6,10,3},{266,93,254,102,5,8,2},
							{254,101,254,117,12,7,2},{253,116,266,129,6,7,1},{267,126,275,131,5,3,1},
							{308,27,315,43,7,4,1},{313,39,326,22,9,5,1},{326,20,340,22,7,5,1},{339,21,345,31,5,4,1},{344,28,352,28,6,6,1},{350,26,371,24,10,5,1},{371,24,379,36,7,6,1},{377,32,389,31,4,9,1},
							{387,28,401,24,9,5,1},{402,24,422,16,9,8,1},{333,43,344,69,7,6,1},{360,43,361,74,11,8,1},{382,43,380,54,5,5,1},{407,42,392,57,5,7,1},{392,56,384,78,10,5,1},{384,77,378,80,3,6,1},
							{377,79,375,77,5,4,1},{325,63,406,57,10,7,1},{350,78,335,99,7,7,3},{343,90,355,108,7,7,2},{353,105,352,126,4,8,2},{351,123,336,129,9,8,2},{338,127,328,128,6,8,1},{331,127,320,121,7,8,2},
							{314,120,334,118,8,7,3},{333,115,413,93,8,5,3},{414,91,414,73,4,4,2},{415,74,406,70,5,5,2},{405,67,399,95,7,10,2},{399,87,399,153,11,8,3},{377,104,377,122,8,6,2},{376,118,407,121,8,8,3},
							{406,121,414,117,7,4,3},{-1,0,0,0,0,0,0}};
	
	//根据事先录制得到的示例字符“龙飞凤舞”的数据构造其
	//链表结构并显示之
	//
	i=0;
	if(Strokes)
		DeleteStrokes();
	while(lffw[i].x1>-1)
	{
		pTmp= new _STROKES;
		if(pTmp==NULL)
		{
			MessageBox( "不能获取所需要的内存", _T(""),MB_OK );
			exit(0);
		}
		pTmp->Stroke.x1=lffw[i].x1 ;
		pTmp->Stroke.y1=lffw[i].y1 ;
		pTmp->Stroke.x2=lffw[i].x2 ;
		pTmp->Stroke.y2=lffw[i].y2 ;
		pTmp->Stroke.x1=lffw[i].x1 ;
		pTmp->Stroke.Width1=lffw[i].Width1;
		pTmp->Stroke.Width2=lffw[i].Width2;
		pTmp->Stroke.Speed=lffw[i].Speed;
		pTmp->pStroke =NULL;
		
		if(pCurrentStroke)
		{
			pCurrentStroke->pStroke=pTmp;
			pCurrentStroke=pTmp;
		}
		if(Strokes==NULL)
		{
			Strokes=pTmp;
			pCurrentStroke=pTmp;
		}
		i++;
	}

	sOperated=sPlaying;
	Writing(Strokes,1,5,false,1,10,10,m_pDC,false);
	sOperated=sPlayed;
	bmp=false;
	bErase=false;
}

//////////////////////////////////////////
//屏幕重画函数:在窗口显示区改变时重新显示
//先前的内容
//
void CHandwritingView::Draw()
{   
	if(!bErase)
	{
		if(bmp)
			DrawBitmap(pBuff,0,0,m_pDC);
		else
			Writing(Strokes,1,5,false,1,10,10,m_pDC,true);
	}

}

////////////////////////////////////////////////////////
//数据按钮更新消息函数:系统自动更新数据按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnCoordinate(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable (Strokes!=NULL);
}

////////////////////////////////////////////////////////
//录制结束按钮函数:结束本次字符的笔划录制过程。
//
void CHandwritingView::OnbtnEnd() 
{
	sOperated=sRecorded;
}

////////////////////////////////////////////////////////
//结束按钮更新消息函数:系统自动更新结束按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnEnd(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable (sOperated==sRecording);
}

////////////////////////////////////////////////////////
//字符按钮更新消息函数:系统自动更新字符按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnOpenBmp(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable ((sOperated!=sRecording)&&(sOperated!=sPlaying));
}

////////////////////////////////////////////////////////
//播放按钮更新消息函数:系统自动更新播放按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnPlay(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable (Strokes!=NULL&&sOperated!=sPlayed&&sOperated!=sRecording);	
}

////////////////////////////////////////////////////////
//录制按钮更新消息函数:系统自动更新录制按钮的显示状态。
//
void CHandwritingView::OnUpdatebtnRecord(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable (bmp);	
}

////////////////////////////////////////////////////////
//示例按钮更新消息函数:系统自动更新示例按钮的状态。
//
void CHandwritingView::OnUpdatebtnSample(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable ((sOperated!=sRecording)&&(sOperated!=sPlaying))	;
}

/////////////////////////////////////////////
//显示刷新按钮函数:启动对屏幕显示内容的刷新。
//
void CHandwritingView::OnbtnRefresh() 
{
	bErase=true;
	Invalidate(TRUE);	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -