Pdf iTextSharp-文本位置不正确

Pdf iTextSharp-文本位置不正确,pdf,character-encoding,itextsharp,itext,text-extraction,Pdf,Character Encoding,Itextsharp,Itext,Text Extraction,提取本例中单词的位置时: 使用iTextSharp 5.5.8 有些单词的坐标不正确。例如,第一段第17行:“gehen oder im Widerspruch zur Reiseaus-” 单词左上方的x值为118217296350524587。只有第一个值看起来是正确的(118208277320487540)。“gehen”和“order”之间空格字符右底点的x值为208,这似乎是正确的,而且似乎也是单词“order”的正确x位置。也许这与段落的填充模式有关,但我不确定应该执行哪些操作来获得

提取本例中单词的位置时: 使用iTextSharp 5.5.8

有些单词的坐标不正确。例如,第一段第17行:“gehen oder im Widerspruch zur Reiseaus-” 单词左上方的x值为118217296350524587。只有第一个值看起来是正确的(118208277320487540)。“gehen”和“order”之间空格字符右底点的x值为208,这似乎是正确的,而且似乎也是单词“order”的正确x位置。也许这与段落的填充模式有关,但我不确定应该执行哪些操作来获得正确的坐标

我正在使用LocationTextExtractionsStrategy并计算单词在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);
           }
     }
public覆盖void RenderText(TextRenderInfo renderInfo)
{
//对于提供的示例
//uUnit=1
//originX=33.862
//原始值=33.555
//dpi=300
//上述值(使用代码计算时):
//pdfnumberuserunit=pageDict.GetAsNumber(PdfName.userUnit);
//if(userUnit!=null)
// {
//uUnit=userUnit.FloatValue;
// }
//矩形尺寸=读卡器.GetPageSize(i);
//浮动原点=尺寸左侧;
//浮动原点=暗底;
//计算坐标:
renderInfo.GetText();
LineSegment段=renderInfo.GetBaseline();
List charInfo=renderInfo.GetCharacterRenderInfos().ToList();
foreach(charInfo中的TextRenderInfo项)
{
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]-原始)*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]-原始)*dpi*uUnit/72.0f);
}
}

这确实是iText&iTextSharp中的一个bug:

x坐标极不准确的行是那些设置了较大字间距值的行,例如,您的行:

0.2861 Tw T*
[<0047004500480045004E0000>-286<004F0044004500520000>-286<0049004D0000>-231<003700490044004500520053005000520055004300480000>-286<005A005500520000>-286<00320045004900530045004100550053000D>]TJ 
0.2861太瓦*
[-286-286-231-286-286]TJ
(Tw的
0.2861
参数很大。)

根据所讨论字体的ToUnicode映射,每个单词末尾的
0000
映射到空格字符。因此,iText在计算x坐标时添加单词间距值,因为根据PDF规范:

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

(第9.3.3节单词间距的第一句)

不幸的是,它没有考虑到

使用时,应将字间距应用于字符串中出现的每个单字节字符代码32 将代码32定义为单字节代码的简单字体或复合字体。本条不适用于以下情况: 多字节代码中的字节值32

(第9.3.3节单词间距的最后一句)

因此,在上面的
0000
处,即使已映射到空格字符,也不能应用单词间距
,因为

  • 讨论中的字体编码纯粹是多字节和
  • 即使是单字节编码的空格字符,单词间距也仅适用于单字节代码32,而不适用于仅使用ASCII代码32映射到空格字符的代码

  • 通常这在文本提取期间不是问题,通常使用多字节编码对空格字符进行编码的PDF生成器知道单词间距不适用于这些字符,因此不会将单词间距从默认的0值更改为0,因此此处的iText错误不会造成伤害。字间距指令的使用通常表明使用的字体将单字节代码32映射到空格字符

    另一方面,您的PDF文件似乎并没有考虑到这一事实,它看起来像是首先设置了单词间距(
    0.2861 Tw
    ),并且在认识到它没有任何区别后,添加了明确的间距(
    -286
    TJ
    指令中)。(或者这是PDF生成器开发历史的一部分。)

    请注意,TJ参数中的正值表示向左移动,因此负值(如上文
    -286
    所述)确实会扩大或增加间隙:

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

    (表109–显示中运算符的文本)


    你误解了负值:它们确实扩大了间距。如上所述,单词间距根本不适用于任何地方,因为我们有严格的两字节编码,所以没有单字节32编码一个空格。