iTextSharp - 文本位置不正确

时间:2016-02-19 14:19:15

标签: pdf character-encoding itextsharp itext text-extraction

在此示例中提取单词的位置时: http://www.dertour.de/static/agb/2015/sommer/DER_Deutschland_So15.pdf 使用iTextSharp 5.5.8

我得到的错误'某些单词的坐标。例如,在第一段的第17行:' gehen oder im Widerspruch zur Reiseaus - ' 单词的左侧,顶部位置的x值是118,217,296,350,524,587。只有第一个值似乎是正确的(118,208,277,320,487,540)。 'gehen'之间空格字符的右下角的x值。而且' oder'是208,这似乎是正确的,也似乎是“oder”这个词的正确x-pos。也许它与段落的fillmode有关,但我不确定我应该采取哪些操作来获得正确的坐标。

我使用LocationTextExtractionStrategy并将字位置计算为300 dpi坐标系。

      public override void RenderText(TextRenderInfo renderInfo)
      {
           // for the provided example
           // uUnit = 1
           // originX = 33.862
           // originY = 33.555 
           // dpi = 300

           // above values where calculated with code:
           // PdfNumber userUnit = pageDict.GetAsNumber(PdfName.USERUNIT);
           // if (userUnit != null)
           // {
           //    uUnit = userUnit.FloatValue;
           // }
           // Rectangle dim = reader.GetPageSize(i);
           // float originX = dim.Left;
           // float originY = dim.Bottom;


           // calculate coordinates:
           renderInfo.GetText();
           LineSegment segment = renderInfo.GetBaseline();
           List<TextRenderInfo> charInfo = renderInfo.GetCharacterRenderInfos().ToList();

           foreach (TextRenderInfo item in charInfo)
           {
              LineSegment char_segment = item.GetBaseline();

              int char_left = (int)Math.Round((char_segment.GetStartPoint()[0] - originX) * dpi * uUnit / 72.0f);
              int char_top = (int)Math.Round((item.GetAscentLine().GetEndPoint()[1] - originY) * dpi * uUnit / 72.0f);
              int char_right = (int)Math.Round((char_segment.GetEndPoint()[0] - originX) * dpi * uUnit / 72.0f);
              int char_bottom = (int)Math.Round((item.GetDescentLine().GetStartPoint()[1] - originY) * dpi * uUnit / 72.0f);
           }
     }

1 个答案:

答案 0 :(得分:1)

这确实是iText&amp; iTextSharp的:

具有极不准确的x坐标的行是设置了大字数间隔值的行,例如,你的行:

0.2861 Tw T*
[<0047004500480045004E0000>-286<004F0044004500520000>-286<0049004D0000>-231<003700490044004500520053005000520055004300480000>-286<005A005500520000>-286<00320045004900530045004100550053000D>]TJ 

0.2861的{​​{1}}参数很大。)

根据相关字体的 ToUnicode 地图,每个单词末尾的Tw映射到空格字符。因此,iText在计算 x 坐标时会添加单词间距值,因为根据PDF规范ISO 32000-1

  

字间距与字符间距的工作方式相同,但仅适用于ASCII空格字符

     

(第9.3.3节“Word间距”的第一句)

不幸的是,它没有考虑到

  

在使用时,字间距应适用于字符串中每次出现的单字节字符代码32   简单字体或复合字体,将代码32定义为单字节代码。它不适用于。的出现   多字节代码中的字节值32。

     

(第9.3.3节“Word间距”的最后一句)

因此,在0000以上,不得应用字间距,即使它已映射到空格字符,因为

  1. 有问题的字体编码纯粹是多字节和
  2. 即使在单字节编码空格字符的情况下,字间距仅应用于单字节代码 32,而不应用于仅用ASCII代码32映射到空格字符的代码。
  3. 通常这在文本提取过程中不是问题,通常使用多字节编码对空格字符进行编码的PDF生成器会发现字间距不适用于它们,因此不会改变字间距。默认值为0,因此这里的iText错误没有任何危害。字间距指令的使用通常表示使用的字体将单字节代码32映射到空格字符。

    另一方面,你的PDF似乎并没有在脑海中创造出这样的事实,看起来首先设置了单词间距(0000),并且在认识到它没有区别之后,已添加显式间隙​​(0.2861 Tw指令中的-286。 (或者这是PDF生成器开发历史的一部分。)

    请注意 TJ 参数中的正值表示向左移位,因此负值(如上文TJ所述)确实扩大或增加差距:

      

    array TJ 显示一个或多个文本字符串,允许单独的字形定位。数组的每个元素应该是字符串或数字。如果元素是字符串,则此运算符应显示字符串。如果是数字,运营商应按该数量调整文本位置;也就是说,它应翻译文本矩阵 T m 。数字应以文本空间为单位的千分之一表示(见9.4.4,&#34;文本空间详细信息&#34;)。根据写入模式,该量应从当前水平或垂直坐标中减去。在默认坐标系中,正调整具有将下一个字形向左或向下移动给定量的效果。图46显示了将偏移量传递给 TJ 的效果示例。

         

    (表109 - ISO 32000-1中的文字显示运算符)