Вы можете использовать класс PDFBox PDFTextStripperByArea
для извлечения текста из определенной области документа. Вы можете опираться на это, указав регион каждой ячейки таблицы. Это не предусмотрено из коробки, но пример класса DrawPrintTextLocations
демонстрирует, как вы можете анализировать ограничивающие блоки отдельных символов в документе (было бы здорово проанализировать ограничивающие блоки строк или абзацев , но я не видел поддержки в PDFBox для этого - см. этот вопрос ). Вы можете использовать этот подход, чтобы сгруппировать все соприкасающиеся ограничивающие рамки, чтобы идентифицировать отдельные ячейки таблицы. Один из способов сделать это - сохранить набор boxes
из Rectangle2D
областей, а затем для каждого анализируемого символа найти ограничивающую рамку символа, как в DrawPrintTextLocations.writeString(String string, List<TextPosition> textPositions)
, и объединить ее с существующим содержимым.
Rectangle2D bounds = s.getBounds2D();
// Pad sides to detect almost touching boxes
Rectangle2D hitbox = bounds.getBounds2D();
final double dx = 1.0; // This value works for me, feel free to tweak (or add setter)
final double dy = 0.000; // Rows of text tend to overlap, so no need to extend
hitbox.add(bounds.getMinX() - dx , bounds.getMinY() - dy);
hitbox.add(bounds.getMaxX() + dx , bounds.getMaxY() + dy);
// Find all overlapping boxes
List<Rectangle2D> intersectList = new ArrayList<Rectangle2D>();
for(Rectangle2D box: boxes) {
if(box.intersects(hitbox)) {
intersectList.add(box);
}
}
// Combine all touching boxes and update
for(Rectangle2D box: intersectList) {
bounds.add(box);
boxes.remove(box);
}
boxes.add(bounds);
Затем вы можете передать эти регионы PDFTextStripperByArea
.
Вы также можете пойти еще дальше и отделить горизонтальные и вертикальные компоненты этих областей, и таким образом вывести области всех ячеек таблицы, независимо от того, удерживаете ли они какое-либо содержимое.
У меня была причина выполнить эти шаги, и в конце концов я написал свой собственный класс PDFTableStripper
, используя PDFBox . Я поделился своим кодом в виде gist на GitHub . Метод main
дает пример использования класса:
try (PDDocument document = PDDocument.load(new File(args[0])))
{
final double res = 72; // PDF units are at 72 DPI
PDFTableStripper stripper = new PDFTableStripper();
stripper.setSortByPosition(true);
// Choose a region in which to extract a table (here a 6"wide, 9" high rectangle offset 1" from top left of page)
stripper.setRegion(new Rectangle(
(int) Math.round(1.0*res),
(int) Math.round(1*res),
(int) Math.round(6*res),
(int) Math.round(9.0*res)));
// Repeat for each page of PDF
for (int page = 0; page < document.getNumberOfPages(); ++page)
{
System.out.println("Page " + page);
PDPage pdPage = document.getPage(page);
stripper.extractTable(pdPage);
for(int c=0; c<stripper.getColumns(); ++c) {
System.out.println("Column " + c);
for(int r=0; r<stripper.getRows(); ++r) {
System.out.println("Row " + r);
System.out.println(stripper.getText(r, c));
}
}
}
}