在背景上输出和擦除文字

在背景上输出文字,并且可以不留痕迹的擦除。
微软提供的 CDC 函数, TextOut 和 DrawText 不支持界面像素的异或运算操作,所以无法从背景中擦除输出的文字。要达到这种目的,只好使用支持像素的异或运算的图形函数了。
有两种方式可以选择:
1.    输出轮廓路径,然后指定画刷填充封闭的路径区域。
2.    得到文字的点阵图,使用向屏幕花点的方式输出文字。
 
下面给出第二种方式的实现代码。
调用两次下面的函数可以擦除输出的文字, 还可以显示按任意角度旋转的文字。
注意:传入的设备上下文变量 pDC ,其中的 ROP2 属性应该指定为 R2_XORPEN 或 R2_NOTXORPEN 

void CDicfexView :: DrawVectorText ( CDC * pDC , CString & strText , CPoint pntPosition , int nAngle )
{
     if ( strText . IsEmpty ())
        return ;
 
     CClientDC dc ( this );
 
     // 确认要按文本输出的坐标映射模式
     if ( pDC -> GetMapMode () != MM_TEXT )
     {
         // 转换到原坐标映射
         dc . SetROP2 ( pDC -> GetROP2 () );
 
         pDC -> LPtoDP ( & pntPosition );
         pDC = & dc ;
     }
 
     DWORD dwSize ;
       
     MAT2 stM2 ;
     GLYPHMETRICS stGM ;        
     TEXTMETRIC stTM ;
 
     // 创建字体
    CFont font ;
     LOGFONT stFont ;
     memset (& stFont ,0, sizeof ( stFont ));
     // 设置字体结构的属性;
     stFont . lfHeight =12;
     stFont . lfWeight = FW_NORMAL ;
     stFont . lfClipPrecision = CLIP_LH_ANGLES ;
     strcpy (( char *) stFont . lfFaceName , "Courier New" );
     stFont . lfEscapement =  nAngle * 10;
     stFont . lfOrientation =  nAngle * 10;
 
     font . CreateFontIndirect ( & stFont );
 
     CFont * pOldFont = pDC -> SelectObject (& font );
    pDC -> SelectObject (& font );
     pDC -> GetTextMetrics (& stTM );
 
     // 坐标变换矩阵 , 但这种转换时 , 由于精度舍入的原因 , 取得的字体点阵的质量很差 ,
     // 给 stFont.lfEscapement 变量赋值 , 似乎微软做过优化 , 取得字体点阵勉强能说的过去 ,
     /*double nEscapement = nAngle * 3.1415926 / 180.0;
    stM2.eM11 = FloatToFixed(cos(nEscapement));
     stM2.eM12 = FloatToFixed(sin(nEscapement));
     stM2.eM21 = FloatToFixed(-sin(nEscapement));
     stM2.eM22 = FloatToFixed(cos(nEscapement));*/
 
     stM2 . eM11 = FloatToFixed (1.0);
     stM2 . eM12 = FloatToFixed (0.0);
     stM2 . eM21 = FloatToFixed (0.0);
     stM2 . eM22 = FloatToFixed (1.0);
 
     int nChar = 0; 
    int nSx = pntPosition . x ;
    int nSy = pntPosition . y ;
 
     int nFontSpace = 0;
 
     int nCx = 0;
    int nCy = 0;
 
    for ( int i = 0; i < strText . GetLength (); i ++)
    {
        if ( strText . GetAt ( i ) >= 0)
            nChar = strText . GetAt ( i );
        else
        {
              // 宽字节
            int th = strText . GetAt ( i );
            int tl = strText . GetAt ( i + 1);
            nChar = (( th & 0x00ff)<<8) + ( tl & 0x00ff);
            i ++;
        }
  
         // 得到字体轮廓信息的尺寸
         dwSize = pDC -> GetGlyphOutline ( nChar , GGO_BITMAP ,& stGM , 0L , NULL ,& stM2 );
         // 定义缓冲区
         BYTE * pBuffer = new BYTE [ dwSize ];
         memset ( pBuffer , 0, dwSize );
         // 取得字体轮廓
         pDC -> GetGlyphOutline ( nChar , GGO_BITMAP , & stGM , dwSize , pBuffer , & stM2 );
    
         int nStride = dwSize / stGM . gmBlackBoxY ;
 
         // 轮廓数据
         OUTLINETEXTMETRIC    stOtm ; 
         memset ( & stOtm , 0, sizeof ( stOtm ) ); 
         stOtm . otmSize = sizeof ( stOtm ); 
         pDC -> GetOutlineTextMetrics ( sizeof ( stOtm ), & stOtm );
 
         //x 的偏移量
         int nXOffset = stGM . gmptGlyphOrigin . x ;    
         //y 的偏移量    字的顶部        - y 方向原点  都是相对于 baseline 
         int nYOffset = stOtm . otmAscent - stGM . gmptGlyphOrigin . y ;   
        
         for ( int y =0; y < stGM . gmBlackBoxY ; ++ y )
         {
              for ( int x =0; x < nStride ; ++ x )
              {
                   for ( int k =0; k < 8; ++ k )
                   {
                       if ( ( pBuffer [ y * nStride + x ] >> (7- k ) ) & 1 )
                       {
                            int nX = nCx + 8 * x + k + nXOffset ;
                            int nY = nCy + y + nYOffset ;
 
                            pDC -> SetPixel ( nSx + nX , nSy + nY , RGB (255,200,200) );
                       }
                   }
              }
         }
 
         // 设置下一个字符的位置
         nCx += stGM . gmCellIncX ;
        nCx += nFontSpace ;
        nCy += stGM . gmCellIncY ;
 
         delete [] pBuffer ;
    }
 
    pDC -> SelectObject ( pOldFont );
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值