我如何协调这些文本位置和行位置与 PDFBox?
How do I reconcile these text positions and line positions with PDFBox?
我为 table 中的行返回的 y 坐标似乎超出了文本的坐标。似乎有一些转变正在进行,但我找不到它。如果可能的话,我想在下面扩展的 PDFGraphicsStreamEngine 范围内解决这个问题,而不必回到 PDFBox 中可用的其他输入流的绘图板。
我已经扩展 PDFTextStripper
以获取页面上每个文本字形的位置:
public class MyPDFTextStripper extends PDFTextStripper {
private List<TextPosition> tps;
public MyPDFTextStripper() throws IOException {
tps = new ArrayList<>();
}
@Override
protected void writeString
(String text,
List<TextPosition> textPositions)
throws IOException {
tps.addAll(textPositions);
}
List<TextPosition> getTps() {
return tps;
}
}
并且我扩展了 PDFGraphicsStreamEngine
以将页面上的每一行提取为 Line2D
:
public class LineCatcher extends PDFGraphicsStreamEngine
{
private final GeneralPath linePath = new GeneralPath();
private List<Line2D> lines;
LineCatcher(PDPage page)
{
super(page);
lines = new ArrayList<>();
}
List<Line2D> getLines() {
return lines;
}
@Override
public void strokePath() throws IOException
{
Rectangle2D rect = linePath.getBounds2D();
Line2D line = new Line2D.Double(rect.getX(), rect.getY(),
rect.getX() + rect.getWidth(),
rect.getY() + rect.getHeight());
lines.add(line);
linePath.reset();
}
@Override
public void moveTo(float x, float y) throws IOException
{linePath.moveTo(x, y);}
@Override
public void lineTo(float x, float y) throws IOException
{linePath.lineTo(x, y);}
@Override
public Point2D getCurrentPoint() throws IOException
{return linePath.getCurrentPoint();}
//all other overridden methods can be left empty for the purposes of this problem.
}
我写了一个简单的程序来演示这个问题:
public class PageAnalysis {
public static void main(String[] args) {
try (PDDocument doc = PDDocument.load(new File("onePage.pdf"))) {
PDPage page = doc.getPage(0);
MyPDFTextStripper ts = new MyPDFTextStripper();
ts.getText(doc);
List<TextPosition> tps = ts.getTps();
System.out.println("Y coordinates in text:");
Set<Integer> ySet = new HashSet<>();
for (TextPosition tp: tps) {
ySet.add((int)tp.getY());
}
List<Integer> yList = new ArrayList<>(ySet);
Collections.sort(yList);
for (int y: yList){
System.out.print(y + "\t");
}
System.out.println();
System.out.println("Y coordinates in lines:");
LineCatcher lineCatcher = new LineCatcher(page);
lineCatcher.processPage(page);
List<Line2D> lines = lineCatcher.getLines();
ySet = new HashSet<>();
for (Line2D line: lines) {
ySet.add((int)line.getY2());
}
yList = new ArrayList<>(ySet);
Collections.sort(yList);
for (int y: yList){
System.out.print(y + "\t");
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这个输出是:
Y coordinates in text:
66 79 106 118 141 153 171 189 207 225 243 261 279 297 315 333 351 370 388 406 424 442 460 478 496 514 780
Y coordinates in lines:
322 340 358 376 394 412 430 448 466 484 502 520 538 556 574 593 611 629 647 665 683 713
文本列表中的最后一个数字对应于底部页码的 y 坐标。我找不到线条的 y 坐标发生了什么,尽管它似乎是那些已经被转换的(媒体框在这里与文本相同,并且适合文本位置) .当前变换矩阵的 yScaling 也为 1.0。
的确,PDFTextStripper
有一个坏习惯,就是将坐标转换成一个非常非 PDF 风格的坐标系,原点在页面的左上角,y 坐标向下增加。
对于TextPosition tp
,因此,您应该不使用
tp.getY()
但是而不是
tp.getTextMatrix().getTranslateY()
不幸的是,即使这些坐标更接近实际的 PDF 默认坐标系,但它们仍可能会被平移,请参见。 : 这些坐标仍然被转换为原点在裁剪框的左下角。
因此,你真的需要这样的东西:
tp.getTextMatrix().getTranslateY() + cropBox.getLowerLeftY()
其中 cropBox
是检索为
的 PDRectangle
PDRectangle cropBox = doc.getPage(n).getCropBox();
其中 n
是包含该内容的页码。
我为 table 中的行返回的 y 坐标似乎超出了文本的坐标。似乎有一些转变正在进行,但我找不到它。如果可能的话,我想在下面扩展的 PDFGraphicsStreamEngine 范围内解决这个问题,而不必回到 PDFBox 中可用的其他输入流的绘图板。
我已经扩展 PDFTextStripper
以获取页面上每个文本字形的位置:
public class MyPDFTextStripper extends PDFTextStripper {
private List<TextPosition> tps;
public MyPDFTextStripper() throws IOException {
tps = new ArrayList<>();
}
@Override
protected void writeString
(String text,
List<TextPosition> textPositions)
throws IOException {
tps.addAll(textPositions);
}
List<TextPosition> getTps() {
return tps;
}
}
并且我扩展了 PDFGraphicsStreamEngine
以将页面上的每一行提取为 Line2D
:
public class LineCatcher extends PDFGraphicsStreamEngine
{
private final GeneralPath linePath = new GeneralPath();
private List<Line2D> lines;
LineCatcher(PDPage page)
{
super(page);
lines = new ArrayList<>();
}
List<Line2D> getLines() {
return lines;
}
@Override
public void strokePath() throws IOException
{
Rectangle2D rect = linePath.getBounds2D();
Line2D line = new Line2D.Double(rect.getX(), rect.getY(),
rect.getX() + rect.getWidth(),
rect.getY() + rect.getHeight());
lines.add(line);
linePath.reset();
}
@Override
public void moveTo(float x, float y) throws IOException
{linePath.moveTo(x, y);}
@Override
public void lineTo(float x, float y) throws IOException
{linePath.lineTo(x, y);}
@Override
public Point2D getCurrentPoint() throws IOException
{return linePath.getCurrentPoint();}
//all other overridden methods can be left empty for the purposes of this problem.
}
我写了一个简单的程序来演示这个问题:
public class PageAnalysis {
public static void main(String[] args) {
try (PDDocument doc = PDDocument.load(new File("onePage.pdf"))) {
PDPage page = doc.getPage(0);
MyPDFTextStripper ts = new MyPDFTextStripper();
ts.getText(doc);
List<TextPosition> tps = ts.getTps();
System.out.println("Y coordinates in text:");
Set<Integer> ySet = new HashSet<>();
for (TextPosition tp: tps) {
ySet.add((int)tp.getY());
}
List<Integer> yList = new ArrayList<>(ySet);
Collections.sort(yList);
for (int y: yList){
System.out.print(y + "\t");
}
System.out.println();
System.out.println("Y coordinates in lines:");
LineCatcher lineCatcher = new LineCatcher(page);
lineCatcher.processPage(page);
List<Line2D> lines = lineCatcher.getLines();
ySet = new HashSet<>();
for (Line2D line: lines) {
ySet.add((int)line.getY2());
}
yList = new ArrayList<>(ySet);
Collections.sort(yList);
for (int y: yList){
System.out.print(y + "\t");
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这个输出是:
Y coordinates in text:
66 79 106 118 141 153 171 189 207 225 243 261 279 297 315 333 351 370 388 406 424 442 460 478 496 514 780
Y coordinates in lines:
322 340 358 376 394 412 430 448 466 484 502 520 538 556 574 593 611 629 647 665 683 713
文本列表中的最后一个数字对应于底部页码的 y 坐标。我找不到线条的 y 坐标发生了什么,尽管它似乎是那些已经被转换的(媒体框在这里与文本相同,并且适合文本位置) .当前变换矩阵的 yScaling 也为 1.0。
的确,PDFTextStripper
有一个坏习惯,就是将坐标转换成一个非常非 PDF 风格的坐标系,原点在页面的左上角,y 坐标向下增加。
对于TextPosition tp
,因此,您应该不使用
tp.getY()
但是而不是
tp.getTextMatrix().getTranslateY()
不幸的是,即使这些坐标更接近实际的 PDF 默认坐标系,但它们仍可能会被平移,请参见。
因此,你真的需要这样的东西:
tp.getTextMatrix().getTranslateY() + cropBox.getLowerLeftY()
其中 cropBox
是检索为
PDRectangle
PDRectangle cropBox = doc.getPage(n).getCropBox();
其中 n
是包含该内容的页码。