Pdf iTextSharp-文本位置不正确
提取本例中单词的位置时: 使用iTextSharp 5.5.8 有些单词的坐标不正确。例如,第一段第17行:“gehen oder im Widerspruch zur Reiseaus-” 单词左上方的x值为118217296350524587。只有第一个值看起来是正确的(118208277320487540)。“gehen”和“order”之间空格字符右底点的x值为208,这似乎是正确的,而且似乎也是单词“order”的正确x位置。也许这与段落的填充模式有关,但我不确定应该执行哪些操作来获得正确的坐标 我正在使用LocationTextExtractionsStrategy并计算单词在300 dpi坐标系下的位置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位置。也许这与段落的填充模式有关,但我不确定应该执行哪些操作来获得
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
处,即使已映射到空格字符,也不能应用单词间距,因为
通常这在文本提取期间不是问题,通常使用多字节编码对空格字符进行编码的PDF生成器知道单词间距不适用于这些字符,因此不会将单词间距从默认的0值更改为0,因此此处的iText错误不会造成伤害。字间距指令的使用通常表明使用的字体将单字节代码32映射到空格字符 另一方面,您的PDF文件似乎并没有考虑到这一事实,它看起来像是首先设置了单词间距(
0.2861 Tw
),并且在认识到它没有任何区别后,添加了明确的间距(-286
在TJ
指令中)。(或者这是PDF生成器开发历史的一部分。)
请注意,TJ参数中的正值表示向左移动,因此负值(如上文-286
所述)确实会扩大或增加间隙:
数组TJ显示一个或多个文本字符串,允许单个字形定位。数组的每个元素应为字符串或数字。如果元素是字符串,则该运算符应显示该字符串。如果是一个数字,操作员应按该数值调整文本位置;也就是说,它应翻译文本矩阵Tm。数字应以文本空间单位的千分之一表示(见9.4.4,“文本空间详细信息”)。根据书写模式,应从当前水平或垂直坐标中减去该量。在默认坐标系中,正调整的效果是将绘制的下一个图示符向左或向下移动给定的量。图46显示了将偏移传递到TJ的效果示例
(表109–显示中运算符的文本)
你误解了负值:它们确实扩大了间距。如上所述,单词间距根本不适用于任何地方,因为我们有严格的两字节编码,所以没有单字节32编码一个空格。