如何给显示文字加一层黑色边框

      在工作中遇到这样一个问题,在实时监视的视频显示中需要在视频中显示当前时间,通道名等额外信息,无论信息内容在视频画面上采用何种颜色显示,当信息显示区域背景的视频画面的颜色正好与显示信息内容的颜色一致或差不多相似时,这个时候,很难看清显示的内容,尽管这种情况出现的概率并不大,但可能性仍然存在,解决这个问题最好的方法是在信息文字的外围加上一层和文字颜色不一样的外边。下面我们以文字为白色,外围加黑边为例来分析这个问题。

      以下分析基于在windows操作系统的PC机上实现。

      如何在白色文字的外围加裹一层黑边,目前我知道的有两种方式。

1.通过获得windows显示设备句柄,利用windows的textout()函数可以直接裹上黑边。具体代码如下:

bool drawText(CDC *pDC,
         LPCTSTR lpszText,
         const CRect& rctDraw,
         UINT nFormat,
         COLORREF clrText,
         COLORREF clrBack)
{
 ASSERT(pDC != NULL);
 if (pDC->GetSafeHdc() == NULL) return false;

 COLORREF oldColor = pDC->GetTextColor();
 int      oldBkMod = pDC->SetBkMode(TRANSPARENT);

 CRect rect = rctDraw;
 pDC->SetTextColor(clrBack);
 rect.OffsetRect(-1, -1); pDC->DrawText(lpszText, rect, nFormat);
 rect.OffsetRect( 1,  0); pDC->DrawText(lpszText, rect, nFormat);
 rect.OffsetRect( 1,  0); pDC->DrawText(lpszText, rect, nFormat);
 rect.OffsetRect( 0,  1); pDC->DrawText(lpszText, rect, nFormat);
 rect.OffsetRect( 0,  1); pDC->DrawText(lpszText, rect, nFormat);
 rect.OffsetRect(-1,  0); pDC->DrawText(lpszText, rect, nFormat);
 rect.OffsetRect(-1,  0); pDC->DrawText(lpszText, rect, nFormat);
 rect.OffsetRect( 0, -1); pDC->DrawText(lpszText, rect, nFormat);

 pDC->SetTextColor(clrText);
 rect.OffsetRect( 1,  0); pDC->DrawText(lpszText, rect, nFormat);

 pDC->SetBkMode(oldBkMod);
 pDC->SetTextColor(oldColor);

 return true;
}

 

2.通过已获取的点阵字符库,然后构建一个新的包含黑边的字符库结构,显示时,对这个新的字符库结构显示。

以16*16的点阵字符库为例,一个汉字需要16*16位即32个字节来表示,如下图

 

在32个字节里存取的都是字模显示的位信息,2个字节表示一行,按位从左到右显示,0表示无色,1表示文字色,一共16行。

      为了在字的外围加一层黑边,需要定义一个新的数据结构,用两个位来保存点阵信息,00表示无色,11表示文字色,01表示边框色,这样考虑到为了在字的边缘处也可能有黑边,新的字符矩阵应为18*18,其中两个位表示一个点阵信息,这样每一行需要18*2位,为了方便存取,每一行用5个字节表示,从左到右按位填充信息,多余位补0。

具体算法思路:

     将含单色信息的字符模数据展开到内存,然后第一次逐行扫描点,凡是扫到某点位文字色,那么在加黑边后,新的数据结构中,其周围8个点,只有两种情况,一种是黑边色点,一种是文字色点,暂时不去理会它是否文字色点,将其周围8个点一律设为黑边色点,其自身设为文字色点,这样一次扫描完所有点后,显然在新的数据结构中,有很多文字点被设为了黑边色点,这样需要再对单色信息的字符模数据再扫描一遍,如扫到点为文字色,将新的数据结构中对应的点调为文字色,这样就将上一次扫描中本是文字色点却设为黑边色点的所有点信息全部调整过来了。

具体源码如下:

void AddShadowToZM(BYTE *pZM,int nWidth,int nHeight,BYTE **ppShadowZM)
{
if(pZM == NULL)
 {
  return;
 }
 if(*ppShadowZM != NULL)
 {
  delete []*ppShadowZM;
 }

 //由于需要加上黑边,考虑用两个比特位来表示一位象素,00表示无象素显示,01表示该象素为黑边象素,11表示该象素为文字象素
 //同时考虑到外围需要加一层,在宽度上需要增加4个比特位,和位图对应从左至右,最前两个比特位对应位图左上角原点
 //在高度上增加两行
 *ppShadowZM = new BYTE[(nWidth*2+1)*(nHeight+2)];
 memset(*ppShadowZM,0,(nWidth*2+1)*(nHeight+2));
    int i,j,k;
 //SHADOW
 for(i = 0;i < nHeight;i++)
 {
  for(j = 0;j < nWidth;j++)
  {
   for(k = 0;k < 8;k++)
   {
    if((pZM[i*nWidth+j] >> (7-k))&0x01)
    {
     //TRACE("0");
     //如果某一位为1,将其四周象素全部置为01,表示为加黑边
     for(int m = 0;m < 3;m++)
     {
      for(int n = 0;n < 3;n++)
      {
       (*ppShadowZM)[(i+m)*(nWidth*2+1)+(j*8+k+n)*2/8] |= 1<<((3-(k+n)%4))*2;
       //TRACE("2");
      }
     }
                }
    else
    {
     //TRACE(" ");
    }
   }
        }
  //TRACE("/n");
 }

    for(i = 0;i < nHeight;i++)
 {
  for(j = 0;j < nWidth;j++)
  {
   for(k = 0;k < 8;k++)
   {
                if((pZM[i*nWidth+j] >> (7-k))&0x01)
    {
                   (*ppShadowZM)[(i+1)*(nWidth*2+1)+(j*8+k+1)*2/8] |= 3<<((3-(k+1)%4))*2;
       //TRACE("0");
    }
    else
    {
     //TRACE("*");
    }
   }
  }
 }

}

 

在获取了新的点阵数据结构后,可以根据显示的要求将其显示在视频画面上。

 

上述的第二种方法,虽然比较麻烦,但在获取了点阵字符模数据文件后,这种方法更具普遍性。关于点阵字符模数据的获取将另行讨论。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
可以通过在 QWidget 或 QPushButton 的子类中重写 paintEvent 方法来实现此功能。具体实现步骤如下: 1. 在 paintEvent 方法中调用父类的 paintEvent 方法,以保证按钮的原有样式被绘制出来。 2. 创建一个 QLinearGradient 对象,并设置渐变色的起止位置、起止颜色。 3. 创建一个 QPainter 对象,并将其设置为按钮的画布。 4. 使用 QPainter 对象的 fillRect 方法,绘制一个矩形,其左上角坐标为 (0, 0),右下角坐标为按钮宽度和高度的一半,即 (width() / 2, height() / 2)。该矩形即为按钮正上方区域。 5. 将该矩形填充为之前创建的渐变色。 6. 在矩形上方绘制按钮的文字,保证不会被蒙层遮挡。 下面给出一个 QPushButton 的子类的代码示例: ```python class GradientButton(QPushButton): def paintEvent(self, event): # 调用父类的 paintEvent 方法 QPushButton.paintEvent(self, event) # 创建渐变色对象 gradient = QLinearGradient(0, 0, 0, self.height() / 2) gradient.setColorAt(0, QColor(0, 0, 0, 0)) # 渐变起始颜色为透明 gradient.setColorAt(1, QColor(0, 0, 0, 100)) # 渐变终止颜色为半透明黑色 # 创建 QPainter 对象 painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿 painter.setBrush(QBrush(gradient)) # 设置画刷为渐变色 painter.setPen(Qt.NoPen) # 不需要边框 # 绘制矩形 rect = QRectF(0, 0, self.width() / 2, self.height() / 2) painter.drawRect(rect) # 绘制文字 painter.setPen(QColor(255, 255, 255)) painter.setFont(self.font()) painter.drawText(self.rect(), Qt.AlignCenter, self.text()) ``` 在该子类中,我们重写了 QPushButton 的 paintEvent 方法,并添了一个渐变色的矩形蒙层。同时保证了按钮的文字不会被覆盖。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值