DirectWrite文字排版——字符串去尾

DirectWrite是 DirectX 家族中专门用来做文本处理的部分,主要配合Direct2D进行渲染工作。

一、字符串去尾介绍
在文字渲染中,不免会遇到字符串去尾的需求。字符串去尾指的是:当字符串在指定的RECT中无法全部显示时,如何对文本进行截取,以适应目标区域大小;DirectWrite中的介绍是设置溢出布局宽度的文本的剪裁。我们把这种截取操作称为“字符串去尾”。
 
首先,给大家介绍一个DirectWrite中的类,IDWriteTextFormat类用于格式化文本的字体和段落属性,并且它还描述区域设置信息。
 
(1)IDWriteTextFormat::SetTrimming 方法

  设置溢出布局宽度的文本的剪裁选项。

  语法

  virtual HRESULT SetTrimming(
    [in]  const DWRITE_TRIMMING * trimmingOptions,
          IDWriteInlineObject * trimmingSign
  ) = 0;

  参数

  trimmingOptions [in]

  文本剪裁选项。

  trimmingSign

  应用程序定义的忽略符号。此参数可为 NULL。注意:我们想要用到省略号代替裁剪部分就需要用到这个参数。

  返回值

  如果该方法成功,则返回 S_OK。 否则,将返回错误代码。HRESULT.

 

(2)DWRITE_TRIMMING 结构 (SetTrimming函数的第一个参数)

  指定用于溢出布局框的文本的剪裁选项。

  语法

  struct DWRITE_TRIMMING { 
    DWRITE_TRIMMING_GRANULARITY granularity; 
    UINT32                      delimiter; 
    UINT32                      delimiterCount; 
  };

  成员

  granularity

  一个值,指定用于对溢出布局框的文本进行剪裁的文本粒度。

  enum DWRITE_TRIMMING_GRANULARITY { 
    DWRITE_TRIMMING_GRANULARITY_NONE,      //不进行任何剪裁。文本流超出布局宽度。
    DWRITE_TRIMMING_GRANULARITY_CHARACTER,   //在字符群集边界处进行剪裁
    DWRITE_TRIMMING_GRANULARITY_WORD      //在字边界处进行剪裁
  };

  delimiter

  一个字符代码,用作指示要保留的文本部分开头的分隔符。对路径省略号最有用,其中分隔符为斜杠。

  delimiterCount

  一个值,指示要后退的分隔符数量。

 

(3)DWriteFactory::CreateEllipsisTrimmingSign()方法

  此方法可以生成表示省略号的 IDWriteInlineObject(此方法得到的IDWriteInlineObject可以作为SetTrimming方法的第二个参数)。

二、实现字符串去尾效果

字符串裁剪效果完全可以通过配置IDWriteTextFormat对象来实现。下面来展示5种不同情况的字符串去尾效果的IDWriteTextFormat对象的创建及配置过程:
 
a)不使用去尾
 1     // 字体格式1:不使用去尾
 2     if (SUCCEEDED(hr))
 3     {
 4         DWRITE_TRIMMING trim1;
 5         IDWriteInlineObject* trim2 = NULL;
 6         hr = m_pDWriteFactory->CreateTextFormat( L"Arial Black", NULL, DWRITE_FONT_WEIGHT_NORMAL, 
 7             DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 20.0, L"en-us",&m_pTF1);
 8 
 9         if (SUCCEEDED(hr))
10         {                    // 换行模式(DWRITE_WORD_WRAPPING)设置为不换行
11             hr = m_pTF1->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
12         }
13 
14         if (SUCCEEDED(hr))
15         {
16             trim1.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
17             trim1.delimiter = 1;
18             trim1.delimiterCount = 10;
19             hr = m_pTF1->SetTrimming(&trim1,trim2);
20         }
21     }
b)以字符为单位去尾
 1     // 字体格式2:以字符为单位去尾
 2     if (SUCCEEDED(hr))
 3     {
 4         DWRITE_TRIMMING trim1;
 5         IDWriteInlineObject* trim2 = NULL;
 6         hr = m_pDWriteFactory->CreateTextFormat( L"Arial Black", NULL, DWRITE_FONT_WEIGHT_NORMAL, 
 7             DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 20.0, L"en-us",&m_pTF2);
 8 
 9         if (SUCCEEDED(hr))
10         {                        // 换行模式(DWRITE_WORD_WRAPPING)设置为不换行
11             hr = m_pTF2->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
12         }
13 
14         if (SUCCEEDED(hr))
15         {
16             trim1.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER;
17             trim1.delimiter = 1;
18             trim1.delimiterCount = 10;
19             hr = m_pTF2->SetTrimming(&trim1,trim2);
20         }
21     }
c)以单词为单位去尾
 1     // 字体格式3:以单词为单位去尾
 2     if (SUCCEEDED(hr))
 3     {
 4         DWRITE_TRIMMING trim1;
 5         IDWriteInlineObject* trim2 = NULL;
 6         hr = m_pDWriteFactory->CreateTextFormat( L"Arial Black", NULL, DWRITE_FONT_WEIGHT_NORMAL, 
 7             DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 20.0, L"en-us",&m_pTF3);
 8 
 9         if (SUCCEEDED(hr))
10         {                        // 换行模式(DWRITE_WORD_WRAPPING)设置为不换行
11             hr = m_pTF3->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
12         }
13 
14         if (SUCCEEDED(hr))
15         {
16             trim1.granularity = DWRITE_TRIMMING_GRANULARITY_WORD;
17             trim1.delimiter = 1;
18             trim1.delimiterCount = 10;
19             hr = m_pTF3->SetTrimming(&trim1,trim2);
20         }
21     }
d)以字符为单位去尾,用省略号代替略去部分
 1     // 字体格式4:以字符为单位去尾,用省略号代替略去部分
 2     if (SUCCEEDED(hr))
 3     {
 4         DWRITE_TRIMMING trim1;
 5         IDWriteInlineObject* trim2 = NULL;
 6         hr = m_pDWriteFactory->CreateTextFormat( L"Arial Black", NULL, DWRITE_FONT_WEIGHT_NORMAL, 
 7             DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 20.0, L"en-us",&m_pTF4);
 8 
 9         if (SUCCEEDED(hr))
10         {                        // 换行模式(DWRITE_WORD_WRAPPING)设置为不换行
11             hr = m_pTF4->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
12         }
13 
14         if (SUCCEEDED(hr))
15         {              // 
16             m_pDWriteFactory->CreateEllipsisTrimmingSign(m_pTF4,&trim2);
17         }
18 
19         if (SUCCEEDED(hr))
20         {
21             trim1.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER;
22             trim1.delimiter = 1;
23             trim1.delimiterCount = 10;
24             hr = m_pTF4->SetTrimming(&trim1,trim2);
25         }
26     }
e)以单词为单位去尾,用省略号代替略去部分
 1     // 字体格式4:以字符为单位去尾,用省略号代替略去部分
 2     if (SUCCEEDED(hr))
 3     {
 4         DWRITE_TRIMMING trim1;
 5         IDWriteInlineObject* trim2 = NULL;
 6         hr = m_pDWriteFactory->CreateTextFormat( L"Arial Black", NULL, DWRITE_FONT_WEIGHT_NORMAL, 
 7             DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 20.0, L"en-us",&m_pTF4);
 8 
 9         if (SUCCEEDED(hr))
10         {                        // 换行模式(DWRITE_WORD_WRAPPING)设置为不换行
11             hr = m_pTF4->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
12         }
13 
14         if (SUCCEEDED(hr))
15         {
16             m_pDWriteFactory->CreateEllipsisTrimmingSign(m_pTF4,&trim2);
17         }
18 
19         if (SUCCEEDED(hr))
20         {
21             trim1.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER;
22             trim1.delimiter = 1;
23             trim1.delimiterCount = 10;
24             hr = m_pTF4->SetTrimming(&trim1,trim2);
25         }
26     }
 
根据我们的实验发现,如果要实现“字符串去尾”的显示效果,必须先将换行模式(DWRITE_WORD_WRAPPING)设置为不换行;注意让显示的字符串长度超出目标矩形宽度,这样才能看出字符串去尾的效果。
 
在此Demo中,为了更好的展示出字符串去尾的视觉效果,我们将字符串绘制的目标矩形范围使用绿色画刷绘制出来,如下:

想看源码的朋友可以点击此处下载,Demo源码是Direct2DTests目录下的DWriteStringTrimming文件。

原文地址:https://www.cnblogs.com/Ray1024/p/5660490.html