PDFBOX是否可以实现文本两端对齐?

16

PDFBOX API中是否有任何功能可以使文本对齐,还是必须手动完成?如果必须手动完成,则如何使用Java进行文本对齐(其背后的逻辑是什么)


1
确切的问题是什么??不清楚你在问什么。 - Jhanvi
1个回答

33

这篇旧回答展示了如何将字符串拆分成适合给定width的子字符串。为了让那里的示例代码以一种填满整个行宽的方式绘制子字符串,请按以下方式替换(根据PDFBox版本):

PDFBox 1.8.x

替换最终循环

for (String line: lines)
{
    contentStream.drawString(line);
    contentStream.moveTextPositionByAmount(0, -leading);
}

使用这个更为详尽的版本:

for (String line: lines)
{
    float charSpacing = 0;
    if (line.length() > 1)
    {
        float size = fontSize * pdfFont.getStringWidth(line) / 1000;
        float free = width - size;
        if (free > 0)
        {
            charSpacing = free / (line.length() - 1);
        }
    }
    contentStream.appendRawCommands(String.format("%f Tc\n", charSpacing).replace(',', '.'));
            
    contentStream.drawString(line);
    contentStream.moveTextPositionByAmount(0, -leading);
}

(来自于PDFBox 1.8.x的BreakLongString.java测试中的testBreakStringJustified方法,链接:BreakLongString.java)

如果您对replace(',', '.')有疑问,请看下文。

contentStream.appendRawCommands(String.format("%f Tc\n", charSpacing).replace(',', '.'));

我的地区使用逗号作为小数分隔符,在第一次测试运行时,页面内容中出现了逗号,我有点懒,只是简单地添加了替换来修复问题...

PDFBox 2.0.x

替换最后一个循环

for (String line: lines)
{
    contentStream.showText(line);
    contentStream.newLineAtOffset(0, -leading);
}

用这个更加详细的:

for (String line: lines)
{
    float charSpacing = 0;
    if (line.length() > 1)
    {
        float size = fontSize * pdfFont.getStringWidth(line) / 1000;
        float free = width - size;
        if (free > 0)
        {
            charSpacing = free / (line.length() - 1);
        }
    }
    contentStream.setCharacterSpacing(charSpacing);
    
    contentStream.showText(line);
    contentStream.newLineAtOffset(0, -leading);
}

(来源于 PDFBox 2.0.x 的 BreakLongString.java 测试中的 testBreakStringJustified 方法, 可查看此链接)


该解决方案仅使用额外的字符间距(操作符 Tc)进行两端对齐。您也可以使用额外的单词间距(操作符Tw),它仅扩展空格字符,或两者的组合; 但请注意: 单词间距无法与所有字体编码一起使用。有关这些操作数的详细信息,请参见 PDF 规范的第 105 表“文本状态操作符”,第 9.3.2 节“字符间距”和第 9.3.3 节“单词间距”。可查看 ISO 32000-1

相较于原来的

non-justified

现在您将得到

enter image description here

如您所见,仍存在一个小缺陷,即段落的最后一行显然不应该两端对齐。因此,在最后一行中,使用 0 字符间距即可:

    contentStream.appendRawCommands("0 Tc\n"); // PDFBox 1.8.x

    contentStream.setCharacterSpacing(0); // PDFBox 2.0.x

PS 我刚刚发现 setCharacterSpacing 目前(2016年11月)只在 2.1.0-SNAPSHOT 开发版本中出现,而不是在 2.0.x 发行版本中。因此,在 2.0.x 中您可能需要改用 appendRawCommands,即使它已被标记为过时。


2
对于最后一行“不应该被调整”,我只在if(line.length() >= <something>)的情况下设置CharacterSpacing,并在其他情况下将其设置为0。这样,任何长度(以字符计)低于某个特定值的行都不会被调整。在我的情况下,我使用lines.get(0).length() / 1.5作为参考(假设存在lines.get(0))。 - Matteo A
2
太好了,非常感谢您的答案,它帮助我在我的Pdfbox-File中实现了我想要的对齐方式 :-)(PdfBox 2.0.21) - leole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接