PDFBox如何向PDF文档添加不同的行?

3

我正在研究生成PDF文档的方法。目前,我正在尝试不同的方法。我希望在PDF文档中获得多行内容。使用HelloWorld代码示例,我想出了...

package org.apache.pdfbox.examples.pdmodel;

import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;

import org.apache.pdfbox.pdmodel.PDPageContentStream;

import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

/**
 * Creates a "Hello World" PDF using the built-in Helvetica font.
 *
 * The example is taken from the PDF file format specification.
 */
public final class HelloWorld
{
    private HelloWorld()
    {
    }

    public static void main(String[] args) throws IOException
    {

        String filename = "line.pdf";
        String message = "line";

        PDDocument doc = new PDDocument();
        try
        {
            PDPage page = new PDPage();
            doc.addPage(page);

            PDFont font = PDType1Font.HELVETICA_BOLD;

            PDPageContentStream contents = new PDPageContentStream(doc, page);
            contents.beginText();
            contents.setFont(font, 12);
            // Loop to create 25 lines of text
            for (int y = 0; y< 25; y++) {
                int ty = 700 + y * 15;
                contents.newLineAtOffset(100, ty);
                //contents.newLineAtOffset(125, ty);
                //contents.showText(Integer.toString(i));
                contents.showText(message + " " + Integer.toString(i));
                System.out.println(message + " " + Integer.toString(i));
            }
            contents.endText();
            contents.close();

            doc.save(filename);
        }
        finally
        {
            doc.close();
            System.out.println("HelloWorld finished after 'doc.close()'.");
        }
    }
}

但是查看我的生成文档,我只看到 "line 0" 一次,而且没有其他行。我做错了什么?
3个回答

10

您的问题在于您认为 PDPageContentStream.newLineAtOffset 使用绝对坐标。事实并非如此,它使用相对坐标,参见 JavaDocs:

/**
 * The Td operator.
 * Move to the start of the next line, offset from the start of the current line by (tx, ty).
 *
 * @param tx The x translation.
 * @param ty The y translation.
 * @throws IOException If there is an error writing to the stream.
 * @throws IllegalStateException If the method was not allowed to be called at this time.
 */
public void newLineAtOffset(float tx, float ty) throws IOException

因此您的附加行远离可见页面区域。

因此,您可能希望这样做:

...
contents.beginText();
contents.setFont(font, 12);
contents.newLineAtOffset(100, 700);
// Loop to create 25 lines of text
for (int i = 0; i < 25; i++) {
    contents.showText(message + " " + Integer.toString(i));
    System.out.println(message + " " + Integer.toString(i));
    contents.newLineAtOffset(0, -15);
}
contents.endText();
...

在这里,您从100, 700开始,并且每行向下移动15个单位。


我猜测文档的(0,0)坐标在左下角,我的理解是你的contents.newLineAtOffset(0,-15);向上移动了? - De Macamba
2
0,0 是左下角,没错,但是 contents.newLineAtOffset(100, 700) 往上移了一点并且向右移动,然后每个 contents.newLineAtOffset(0, -15) 再次向下移动一行。 - mkl
感谢反馈。 - De Macamba
但是x和y的平移单位是什么?毫米?英寸?像素? - tmmls
1
它们是当前用户空间单位。如果您没有更改用户空间坐标系,则默认为1/72英寸的点。 - mkl

2
除了mkl的回答之外,您还可以为每行创建一个新的文本操作。这样做将使您能够使用绝对坐标。
...
contents.setFont(font, 12);
// Loop to create 25 lines of text
for (int i = 0; i < 25; i++) {
    int ty = 700 + y * 15;
    contents.beginText();
    contents.newLineAtOffset(100, ty);
    contents.showText(message + " " + Integer.toString(i));
    System.out.println(message + " " + Integer.toString(i))
    contents.endText();
}
...

是否需要使用这个取决于您的用例。
例如,我想要将一些文本右对齐。在这种情况下,使用绝对定位更容易,因此我创建了一个如下的帮助方法:

public static void showTextRightAligned(PDPageContentStream contentStream, PDType1Font font, int fontsize, float rightX, float topY, String text) throws IOException
{
    float textWidth = fontsize * font.getStringWidth(text) / 1000;
    float leftX = rightX - textWidth;
    contentStream.beginText();
    contentStream.newLineAtOffset(leftX, topY);
    contentStream.showText(text);
    contentStream.endText();
}

“int ty = 700 + y * 15;” --- 我猜你的意思是 “int ty = 700 - y * 15;”。除此之外,你说得对,结果基本相同。流可能会大一点,但只是一点点而已。 - mkl

-1
你可以这样做:
contentStream.beginText();
contentStream.newLineAtOffset(20,750);
//This begins the cursor at top right 
contentStream.setFont(PDType1Font.TIMES_ROMAN,8);
 
for (String readList : resultList) {
    contentStream.showText(readList);
    contentStream.newLineAtOffset(0,-12);
    //This will move cursor down by 12pts on every run of loop
}

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