diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/classification/parsing/PDFAreaTextStripper.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/classification/parsing/PDFAreaTextStripper.java deleted file mode 100644 index 22aab9b9..00000000 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/classification/parsing/PDFAreaTextStripper.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.iqser.red.service.redaction.v1.server.layoutparsing.classification.parsing; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.apache.pdfbox.text.PDFTextStripperByArea; -import org.apache.pdfbox.text.TextPosition; - -import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.text.TextPositionSequence; - -import lombok.Getter; -import lombok.Setter; - -public class PDFAreaTextStripper extends PDFTextStripperByArea { - - @Getter - private List textPositionSequences = new ArrayList<>(); - - @Setter - private int pageNumber; - - - public PDFAreaTextStripper() throws IOException { - - } - - - @Override - public void writeString(String text, List textPositions) throws IOException { - - int startIndex = 0; - for (int i = 0; i <= textPositions.size() - 1; i++) { - - if (i == 0 && (textPositions.get(i).getUnicode().equals(" ") || textPositions.get(i).getUnicode().equals("\u00A0"))) { - startIndex++; - continue; - } - - // Strange but sometimes this is happening, for example: Metolachlor2.pdf - if (i > 0 && textPositions.get(i).getX() < textPositions.get(i - 1).getX()) { - List sublist = textPositions.subList(startIndex, i); - if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0).getUnicode().equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) { - textPositionSequences.add(new TextPositionSequence(sublist, pageNumber)); - } - startIndex = i; - } - - if (textPositions.get(i).getRotation() == 0 && i > 0 && textPositions.get(i).getX() > textPositions.get(i - 1).getEndX() + 1) { - List sublist = textPositions.subList(startIndex, i); - if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0).getUnicode().equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) { - textPositionSequences.add(new TextPositionSequence(sublist, pageNumber)); - } - startIndex = i; - } - - if (i > 0 && (textPositions.get(i).getUnicode().equals(" ") || textPositions.get(i).getUnicode().equals("\u00A0")) && i <= textPositions.size() - 2) { - List sublist = textPositions.subList(startIndex, i); - if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0).getUnicode().equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) { - textPositionSequences.add(new TextPositionSequence(sublist, pageNumber)); - } - startIndex = i + 1; - } - } - - List sublist = textPositions.subList(startIndex, textPositions.size()); - if (!sublist.isEmpty() && (sublist.get(sublist.size() - 1).getUnicode().equals(" ") || sublist.get(sublist.size() - 1).getUnicode().equals("\u00A0"))) { - sublist = sublist.subList(0, sublist.size() - 1); - } - if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0).getUnicode().equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) { - textPositionSequences.add(new TextPositionSequence(sublist, pageNumber)); - } - super.writeString(text); - } - - - public void clearPositions() { - - textPositionSequences = new ArrayList<>(); - } - -} diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicPositionBlockData.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicPositionBlockData.java index 1008e12f..71a1bdd4 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicPositionBlockData.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicPositionBlockData.java @@ -1,5 +1,10 @@ package com.iqser.red.service.redaction.v1.server.layoutparsing.document.data; +import java.awt.geom.Rectangle2D; +import java.util.List; + +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.textblock.AtomicTextBlock; + import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -16,4 +21,40 @@ public class AtomicPositionBlockData { int[] stringIdxToPositionIdx; float[][] positions; + + public static AtomicPositionBlockData fromAtomicTextBlock(AtomicTextBlock atomicTextBlock) { + + return AtomicPositionBlockData.builder() + .id(atomicTextBlock.getId()) + .positions(toPrimitiveFloatMatrix(atomicTextBlock.getPositions())) + .stringIdxToPositionIdx(toPrimitiveIntArray(atomicTextBlock.getStringIdxToPositionIdx())) + .build(); + } + + + private static int[] toPrimitiveIntArray(List list) { + + int[] array = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + array[i] = list.get(i); + } + return array; + } + + + private static float[][] toPrimitiveFloatMatrix(List positions) { + + float[][] positionMatrix = new float[positions.size()][]; + for (int i = 0; i < positions.size(); i++) { + positionMatrix[i] = toArray(positions.get(i)); + } + return positionMatrix; + } + + + private static float[] toArray(Rectangle2D positions) { + + return new float[]{(float) positions.getMinX(), (float) positions.getMinY(), (float) positions.getWidth(), (float) positions.getHeight()}; + } + } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicTextBlockData.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicTextBlockData.java index 24903a3c..804a7f5f 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicTextBlockData.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/AtomicTextBlockData.java @@ -1,5 +1,9 @@ package com.iqser.red.service.redaction.v1.server.layoutparsing.document.data; +import java.util.List; + +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.textblock.AtomicTextBlock; + import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -20,4 +24,28 @@ public class AtomicTextBlockData { int end; int[] lineBreaks; + + public static AtomicTextBlockData fromAtomicTextBlock(AtomicTextBlock atomicTextBlock) { + + return AtomicTextBlockData.builder() + .id(atomicTextBlock.getId()) + .page(atomicTextBlock.getPage().getNumber().longValue()) + .searchText(atomicTextBlock.getSearchText()) + .numberOnPage(atomicTextBlock.getNumberOnPage()) + .start(atomicTextBlock.getBoundary().start()) + .end(atomicTextBlock.getBoundary().end()) + .lineBreaks(toPrimitiveIntArray(atomicTextBlock.getLineBreaks())) + .build(); + } + + + private static int[] toPrimitiveIntArray(List list) { + + int[] array = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + array[i] = list.get(i); + } + return array; + } + } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentDataMapper.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentDataMapper.java index e1d5f0ca..4ba1e33c 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentDataMapper.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentDataMapper.java @@ -1,6 +1,5 @@ package com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.mapper; -import java.awt.geom.Rectangle2D; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,13 +29,13 @@ public class DocumentDataMapper { List atomicTextBlockData = document.streamTerminalTextBlocksInOrder() .flatMap(textBlock -> textBlock.getAtomicTextBlocks().stream()) .distinct() - .map(DocumentDataMapper::toAtomicTextBlockData) + .map(AtomicTextBlockData::fromAtomicTextBlock) .toList(); List atomicPositionBlockData = document.streamTerminalTextBlocksInOrder() .flatMap(textBlock -> textBlock.getAtomicTextBlocks().stream()) .distinct() - .map(DocumentDataMapper::toAtomicPositionBlockData) + .map(AtomicPositionBlockData::fromAtomicTextBlock) .toList(); List pageData = document.getPages().stream().map(DocumentDataMapper::toPageData).toList(); @@ -75,7 +74,7 @@ public class DocumentDataMapper { }; return DocumentTreeData.EntryData.builder() - .treeId(toPrimitiveIntArray(entry.getTocId())) + .treeId(toPrimitiveIntArray(entry.getTreeId())) .subEntries(entry.getChildren().stream().map(DocumentDataMapper::toEntryData).toList()) .type(entry.getType()) .atomicBlocks(atomicTextBlocks) @@ -97,46 +96,7 @@ public class DocumentDataMapper { } - private AtomicTextBlockData toAtomicTextBlockData(AtomicTextBlock atomicTextBlock) { - - return AtomicTextBlockData.builder() - .id(atomicTextBlock.getId()) - .page(atomicTextBlock.getPage().getNumber().longValue()) - .searchText(atomicTextBlock.getSearchText()) - .numberOnPage(atomicTextBlock.getNumberOnPage()) - .start(atomicTextBlock.getBoundary().start()) - .end(atomicTextBlock.getBoundary().end()) - .lineBreaks(toPrimitiveIntArray(atomicTextBlock.getLineBreaks())) - .build(); - } - - - private AtomicPositionBlockData toAtomicPositionBlockData(AtomicTextBlock atomicTextBlock) { - - return AtomicPositionBlockData.builder() - .id(atomicTextBlock.getId()) - .positions(toPrimitiveFloatMatrix(atomicTextBlock.getPositions())) - .stringIdxToPositionIdx(toPrimitiveIntArray(atomicTextBlock.getStringIdxToPositionIdx())) - .build(); - } - - - private float[][] toPrimitiveFloatMatrix(List positions) { - - float[][] positionMatrix = new float[positions.size()][]; - for (int i = 0; i < positions.size(); i++) { - float[] singlePositions = new float[4]; - singlePositions[0] = (float) positions.get(i).getMinX(); - singlePositions[1] = (float) positions.get(i).getMinY(); - singlePositions[2] = (float) positions.get(i).getWidth(); - singlePositions[3] = (float) positions.get(i).getHeight(); - positionMatrix[i] = singlePositions; - } - return positionMatrix; - } - - - private int[] toPrimitiveIntArray(List list) { + private static int[] toPrimitiveIntArray(List list) { int[] array = new int[list.size()]; for (int i = 0; i < list.size(); i++) { diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentGraphMapper.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentGraphMapper.java index d4449929..6abb7e4f 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentGraphMapper.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/data/mapper/DocumentGraphMapper.java @@ -3,7 +3,6 @@ package com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.ma import static com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.NodeType.FOOTER; import static com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.NodeType.HEADER; -import java.awt.geom.Rectangle2D; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; @@ -11,13 +10,11 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; -import com.google.common.primitives.Ints; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.AtomicPositionBlockData; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.AtomicTextBlockData; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.DocumentData; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.DocumentTreeData; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.PageData; -import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.Boundary; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.DocumentTree; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Document; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Footer; @@ -86,8 +83,8 @@ public class DocumentGraphMapper { TextBlock textBlock = toTextBlock(entryData.getAtomicBlocks(), context, node); node.setLeafTextBlock(textBlock); } - List tocId = Arrays.stream(entryData.getTreeId()).boxed().toList(); - node.setTreeId(tocId); + List treeId = Arrays.stream(entryData.getTreeId()).boxed().toList(); + node.setTreeId(treeId); if (entryData.getType() == HEADER) { pages.forEach(page -> page.setHeader((Header) node)); @@ -96,7 +93,7 @@ public class DocumentGraphMapper { } else { pages.forEach(page -> page.getMainBody().add(node)); } - newEntries.add(DocumentTree.Entry.builder().tocId(tocId).type(entryData.getType()).children(buildEntries(entryData.getSubEntries(), context)).node(node).build()); + newEntries.add(DocumentTree.Entry.builder().treeId(treeId).type(entryData.getType()).children(buildEntries(entryData.getSubEntries(), context)).node(node).build()); } return newEntries; } @@ -168,12 +165,16 @@ public class DocumentGraphMapper { private TextBlock toTextBlock(Long[] atomicTextBlockIds, Context context, SemanticNode parent) { - return Arrays.stream(atomicTextBlockIds) - .map(atomicTextBlockId -> toAtomicTextBlock(context.atomicTextBlockData.get(Math.toIntExact(atomicTextBlockId)), - context.atomicPositionBlockData.get(Math.toIntExact(atomicTextBlockId)), - parent, - context)) - .collect(new TextBlockCollector()); + return Arrays.stream(atomicTextBlockIds).map(atomicTextBlockId -> getAtomicTextBlock(context, parent, atomicTextBlockId)).collect(new TextBlockCollector()); + } + + + private static AtomicTextBlock getAtomicTextBlock(Context context, SemanticNode parent, Long atomicTextBlockId) { + + return AtomicTextBlock.fromAtomicTextBlockData(context.atomicTextBlockData.get(Math.toIntExact(atomicTextBlockId)), + context.atomicPositionBlockData.get(Math.toIntExact(atomicTextBlockId)), + parent, + getPage(context.atomicTextBlockData.get(Math.toIntExact(atomicTextBlockId)).getPage(), context)); } @@ -183,28 +184,6 @@ public class DocumentGraphMapper { } - private AtomicTextBlock toAtomicTextBlock(AtomicTextBlockData atomicTextBlockData, AtomicPositionBlockData atomicPositionBlockData, SemanticNode parent, Context context) { - - return AtomicTextBlock.builder() - .id(atomicTextBlockData.getId()) - .numberOnPage(atomicTextBlockData.getNumberOnPage()) - .page(getPage(atomicTextBlockData.getPage(), context)) - .boundary(new Boundary(atomicTextBlockData.getStart(), atomicTextBlockData.getEnd())) - .searchText(atomicTextBlockData.getSearchText()) - .lineBreaks(Ints.asList(atomicTextBlockData.getLineBreaks())) - .stringIdxToPositionIdx(Ints.asList(atomicPositionBlockData.getStringIdxToPositionIdx())) - .positions(toRectangle2DList(atomicPositionBlockData.getPositions())) - .parent(parent) - .build(); - } - - - private static List toRectangle2DList(float[][] positions) { - - return Arrays.stream(positions).map(floatArr -> (Rectangle2D) new Rectangle2D.Float(floatArr[0], floatArr[1], floatArr[2], floatArr[3])).toList(); - } - - private Page getPage(Long pageIndex, Context context) { return context.pages.stream() diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/DocumentGraphFactory.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/DocumentGraphFactory.java index b7341163..93226e60 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/DocumentGraphFactory.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/DocumentGraphFactory.java @@ -23,6 +23,7 @@ import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.mo import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.DocumentTree; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Document; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Footer; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.GenericSemanticNode; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Header; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Headline; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Image; @@ -30,7 +31,6 @@ import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.no import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Page; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Paragraph; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Section; -import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.textblock.AtomicTextBlock; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.utils.TextPositionOperations; import com.iqser.red.service.redaction.v1.server.redaction.utils.IdBuilder; @@ -75,11 +75,14 @@ public class DocumentGraphFactory { } - public void addParagraphOrHeadline(SemanticNode parentNode, ClassificationTextBlock originalTextBlock, Context context, List textBlocksToMerge) { + public void addParagraphOrHeadline(GenericSemanticNode parentNode, + ClassificationTextBlock originalTextBlock, + Context context, + List textBlocksToMerge) { Page page = context.getPage(originalTextBlock.getPage()); - SemanticNode node; + GenericSemanticNode node; if (pageBlockIsHeadline(originalTextBlock)) { node = Headline.builder().documentTree(context.getDocumentTree()).build(); } else { @@ -93,12 +96,12 @@ public class DocumentGraphFactory { AtomicTextBlock textBlock = context.textBlockFactory.buildAtomicTextBlock(TextPositionOperations.mergeAndSortTextPositionSequenceByYThenX(textBlocks), node, context, page); if (node instanceof Headline headline) { - List tocId = context.documentTree.createNewChildEntryAndReturnId(parentNode.getTreeId(), NodeType.HEADLINE, node); + List tocId = context.documentTree.createNewChildEntryAndReturnId(parentNode, NodeType.HEADLINE, node); headline.setLeafTextBlock(textBlock); headline.setTreeId(tocId); } if (node instanceof Paragraph paragraph) { - List tocId = context.documentTree.createNewChildEntryAndReturnId(parentNode.getTreeId(), NodeType.PARAGRAPH, node); + List tocId = context.documentTree.createNewChildEntryAndReturnId(parentNode, NodeType.PARAGRAPH, node); paragraph.setLeafTextBlock(textBlock); paragraph.setTreeId(tocId); } @@ -119,7 +122,7 @@ public class DocumentGraphFactory { .build(); page.getMainBody().add(imageNode); - List tocId = context.getDocumentTree().createNewChildEntryAndReturnId(section.getTreeId(), NodeType.IMAGE, imageNode); + List tocId = context.getDocumentTree().createNewChildEntryAndReturnId(section, NodeType.IMAGE, imageNode); imageNode.setTreeId(tocId); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/SectionNodeFactory.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/SectionNodeFactory.java index 7e308dc7..4188dbfc 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/SectionNodeFactory.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/SectionNodeFactory.java @@ -14,10 +14,10 @@ import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.mo import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.image.ClassifiedImage; import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.table.TablePageBlock; import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.text.ClassificationTextBlock; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.GenericSemanticNode; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.NodeType; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Page; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Section; -import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.utils.TableMergingUtility; import lombok.experimental.UtilityClass; @@ -25,7 +25,7 @@ import lombok.experimental.UtilityClass; @UtilityClass public class SectionNodeFactory { - public void addSection(SemanticNode parentNode, List pageBlocks, List images, DocumentGraphFactory.Context context) { + public void addSection(GenericSemanticNode parentNode, List pageBlocks, List images, DocumentGraphFactory.Context context) { if (pageBlocks.isEmpty()) { return; @@ -40,7 +40,7 @@ public class SectionNodeFactory { if (parentNode == null) { tocId = context.getDocumentTree().createNewMainEntryAndReturnId(NodeType.SECTION, section); } else { - tocId = context.getDocumentTree().createNewChildEntryAndReturnId(parentNode.getTreeId(), NodeType.SECTION, section); + tocId = context.getDocumentTree().createNewChildEntryAndReturnId(parentNode, NodeType.SECTION, section); } section.setTreeId(tocId); diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/TableNodeFactory.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/TableNodeFactory.java index 11563c79..9b692fc3 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/TableNodeFactory.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/factory/TableNodeFactory.java @@ -11,11 +11,13 @@ import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.mo import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.table.Cell; import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.table.TablePageBlock; import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.text.TextPositionSequence; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.GenericSemanticNode; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.NodeType; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Page; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.SemanticNode; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Table; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.TableCell; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.textblock.TextBlock; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.utils.TextPositionOperations; import lombok.experimental.UtilityClass; @@ -26,7 +28,7 @@ public class TableNodeFactory { public static final double TABLE_CELL_MERGE_CONTENTS_SIZE_THRESHOLD = 0.05; - public void addTable(SemanticNode parentNode, List tablesToMerge, DocumentGraphFactory.Context context) { + public void addTable(GenericSemanticNode parentNode, List tablesToMerge, DocumentGraphFactory.Context context) { setPageNumberInCellTextBlocks(tablesToMerge); Set pages = tablesToMerge.stream().map(AbstractPageBlock::getPage).map(context::getPage).collect(Collectors.toSet()); @@ -35,7 +37,7 @@ public class TableNodeFactory { pages.forEach(page -> addTableToPage(page, parentNode, table)); - List tocId = context.getDocumentTree().createNewChildEntryAndReturnId(parentNode.getTreeId(), NodeType.TABLE, table); + List tocId = context.getDocumentTree().createNewChildEntryAndReturnId(parentNode, NodeType.TABLE, table); table.setTreeId(tocId); addTableCells(mergedRows, table, context); @@ -82,20 +84,20 @@ public class TableNodeFactory { @SuppressWarnings("PMD.UnusedPrivateMethod") // PMD actually flags this wrong - private void addTableCell(Cell cell, int rowIndex, int colIndex, SemanticNode parentNode, DocumentGraphFactory.Context context) { + private void addTableCell(Cell cell, int rowIndex, int colIndex, Table tableNode, DocumentGraphFactory.Context context) { Page page = context.getPage(cell.getPageNumber()); TableCell tableCell = TableCell.builder().documentTree(context.getDocumentTree()).row(rowIndex).col(colIndex).header(cell.isHeaderCell()).bBox(cell.getBounds2D()).build(); page.getMainBody().add(tableCell); - com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.textblock.TextBlock textBlock; + TextBlock textBlock; - List tocId = context.getDocumentTree().createNewChildEntryAndReturnId(parentNode.getTreeId(), NodeType.TABLE_CELL, tableCell); + List tocId = context.getDocumentTree().createNewTableChildEntryAndReturnId(tableNode, NodeType.TABLE_CELL, tableCell); tableCell.setTreeId(tocId); if (cell.getTextBlocks().isEmpty()) { - tableCell.setLeafTextBlock(context.getTextBlockFactory().emptyTextBlock(parentNode, context, page)); + tableCell.setLeafTextBlock(context.getTextBlockFactory().emptyTextBlock(tableNode, context, page)); tableCell.setLeaf(true); } else if (cell.getTextBlocks().size() == 1) { diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/DocumentTree.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/DocumentTree.java index 6fd8a1e5..e4649aed 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/DocumentTree.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/DocumentTree.java @@ -10,8 +10,11 @@ import java.util.stream.Stream; import com.google.common.hash.Hashing; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Document; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.GenericSemanticNode; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.NodeType; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.SemanticNode; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Table; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.TableCell; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.textblock.TextBlock; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.textblock.TextBlockCollector; @@ -30,7 +33,7 @@ public class DocumentTree { public DocumentTree(Document document) { - root = Entry.builder().tocId(Collections.emptyList()).type(NodeType.DOCUMENT).children(new LinkedList<>()).node(document).build(); + root = Entry.builder().treeId(Collections.emptyList()).type(NodeType.DOCUMENT).children(new LinkedList<>()).node(document).build(); } @@ -40,13 +43,31 @@ public class DocumentTree { } - public List createNewMainEntryAndReturnId(NodeType nodeType, SemanticNode node) { + public List createNewMainEntryAndReturnId(NodeType nodeType, GenericSemanticNode node) { - return createNewChildEntryAndReturnId(Collections.emptyList(), nodeType, node); + return createNewChildEntryAndReturnIdImpl(Collections.emptyList(), nodeType, node); } - public List createNewChildEntryAndReturnId(List parentId, NodeType nodeType, SemanticNode node) { + public List createNewChildEntryAndReturnId(GenericSemanticNode parentNode, NodeType nodeType, GenericSemanticNode node) { + + return createNewChildEntryAndReturnIdImpl(parentNode.getTreeId(), nodeType, node); + } + + + public List createNewChildEntryAndReturnId(GenericSemanticNode parentNode, NodeType nodeType, Table node) { + + return createNewChildEntryAndReturnIdImpl(parentNode.getTreeId(), nodeType, node); + } + + + public List createNewTableChildEntryAndReturnId(Table parentTable, NodeType nodeType, TableCell tableCell) { + + return createNewChildEntryAndReturnIdImpl(parentTable.getTreeId(), nodeType, tableCell); + } + + + private List createNewChildEntryAndReturnIdImpl(List parentId, NodeType nodeType, SemanticNode node) { if (!entryExists(parentId)) { throw new UnsupportedOperationException(format("parentId %s does not exist!", parentId)); @@ -55,19 +76,19 @@ public class DocumentTree { Entry parent = getEntryById(parentId); List newId = new LinkedList<>(parentId); newId.add(parent.children.size()); - parent.children.add(Entry.builder().tocId(newId).node(node).type(nodeType).children(new LinkedList<>()).build()); + parent.children.add(Entry.builder().treeId(newId).node(node).type(nodeType).children(new LinkedList<>()).build()); return newId; } - private boolean entryExists(List tocId) { + private boolean entryExists(List treeId) { - if (tocId.isEmpty()) { + if (treeId.isEmpty()) { return root != null; } - Entry entry = root.children.get(tocId.get(0)); - for (int id : tocId.subList(1, tocId.size())) { + Entry entry = root.children.get(treeId.get(0)); + for (int id : treeId.subList(1, treeId.size())) { if (id >= entry.children.size() || 0 > id) { return false; } @@ -77,43 +98,49 @@ public class DocumentTree { } - public Entry getParentEntryById(List tocId) { + public Entry getParentEntryById(List treeId) { - return getEntryById(getParentId(tocId)); + return getEntryById(getParentId(treeId)); } - public boolean hasParentById(List tocId) { + public boolean hasParentById(List treeId) { - return !tocId.isEmpty(); + return !treeId.isEmpty(); } - public Stream streamChildrenNodes(List tocId) { + public Stream streamChildNodes(List treeId) { - return getEntryById(tocId).children.stream().map(Entry::getNode); + return getEntryById(treeId).children.stream().map(Entry::getNode); } - private static List getParentId(List tocId) { + public Stream streamChildNodesOfType(List treeId, NodeType nodeType) { - if (tocId.isEmpty()) { + return getEntryById(treeId).children.stream().filter(entry -> entry.type.equals(nodeType)).map(Entry::getNode); + } + + + private static List getParentId(List treeId) { + + if (treeId.isEmpty()) { throw new UnsupportedOperationException("Root has no parent!"); } - if (tocId.size() < 2) { + if (treeId.size() < 2) { return Collections.emptyList(); } - return tocId.subList(0, tocId.size() - 1); + return treeId.subList(0, treeId.size() - 1); } - public Entry getEntryById(List tocId) { + public Entry getEntryById(List treeId) { - if (tocId.isEmpty()) { + if (treeId.isEmpty()) { return root; } - Entry entry = root.children.get(tocId.get(0)); - for (int id : tocId.subList(1, tocId.size())) { + Entry entry = root.children.get(treeId.get(0)); + for (int id : treeId.subList(1, treeId.size())) { entry = entry.children.get(id); } return entry; @@ -151,12 +178,12 @@ public class DocumentTree { } - public SemanticNode getHighestParentById(List tocId) { + public SemanticNode getHighestParentById(List treeId) { - if (tocId.isEmpty()) { + if (treeId.isEmpty()) { return root.node; } - return root.children.get(tocId.get(0)).node; + return root.children.get(treeId.get(0)).node; } @@ -166,7 +193,7 @@ public class DocumentTree { @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public static class Entry { - List tocId; + List treeId; NodeType type; SemanticNode node; List children; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Document.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Document.java index df6ab4d6..b56c0e59 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Document.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Document.java @@ -28,7 +28,7 @@ import lombok.experimental.FieldDefaults; @AllArgsConstructor @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class Document implements SemanticNode { +public class Document implements GenericSemanticNode { Set pages; DocumentTree documentTree; @@ -46,7 +46,7 @@ public class Document implements SemanticNode { public List
getMainSections() { - return streamChildren().filter(node -> node instanceof Section).map(node -> (Section) node).collect(Collectors.toList()); + return streamChildrenOfType(NodeType.SECTION).map(node -> (Section) node).collect(Collectors.toList()); } @@ -73,10 +73,7 @@ public class Document implements SemanticNode { @Override public Headline getHeadline() { - return streamAllSubNodes().filter(node -> node instanceof Headline) - .map(node -> (Headline) node) - .findFirst() - .orElseThrow(() -> new NotFoundException("No Headlines found in this document!")); + return streamChildrenOfType(NodeType.HEADLINE).map(node -> (Headline) node).findFirst().orElseThrow(() -> new NotFoundException("No Headlines found in this document!")); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Footer.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Footer.java index b38fa09e..fe2b6d47 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Footer.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Footer.java @@ -21,7 +21,7 @@ import lombok.experimental.FieldDefaults; @AllArgsConstructor @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class Footer implements SemanticNode { +public class Footer implements GenericSemanticNode { List treeId; TextBlock leafTextBlock; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/GenericSemanticNode.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/GenericSemanticNode.java new file mode 100644 index 00000000..e5505d6f --- /dev/null +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/GenericSemanticNode.java @@ -0,0 +1,5 @@ +package com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes; + +public interface GenericSemanticNode extends SemanticNode { + +} diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Header.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Header.java index 8419ec06..dd04c09b 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Header.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Header.java @@ -21,7 +21,7 @@ import lombok.experimental.FieldDefaults; @AllArgsConstructor @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class Header implements SemanticNode { +public class Header implements GenericSemanticNode { List treeId; TextBlock leafTextBlock; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Headline.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Headline.java index 1c23a98e..d56c6ad6 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Headline.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Headline.java @@ -21,13 +21,13 @@ import lombok.experimental.FieldDefaults; @AllArgsConstructor @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class Headline implements SemanticNode { +public class Headline implements GenericSemanticNode { List treeId; TextBlock leafTextBlock; @Builder.Default - boolean leaf = true; + final boolean leaf = true; @EqualsAndHashCode.Exclude DocumentTree documentTree; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Image.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Image.java index 4e56a5d9..ae737b5b 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Image.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Image.java @@ -26,7 +26,7 @@ import lombok.experimental.FieldDefaults; @AllArgsConstructor @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class Image implements SemanticNode { +public class Image implements GenericSemanticNode { List treeId; String id; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Paragraph.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Paragraph.java index 327150f7..4452aef8 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Paragraph.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Paragraph.java @@ -19,7 +19,7 @@ import lombok.experimental.FieldDefaults; @Builder @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class Paragraph implements SemanticNode { +public class Paragraph implements GenericSemanticNode { List treeId; TextBlock leafTextBlock; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Section.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Section.java index 24a2f270..9fa15727 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Section.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Section.java @@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j; @Builder @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class Section implements SemanticNode { +public class Section implements GenericSemanticNode { List treeId; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/SemanticNode.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/SemanticNode.java index 8a11620f..10ee10be 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/SemanticNode.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/SemanticNode.java @@ -57,7 +57,7 @@ public interface SemanticNode { default Set getPages(Boundary boundary) { if (!getBoundary().contains(boundary)) { - throw new IllegalArgumentException(format("%s which was used to query foir pages is not contained in the %s of this node!", getBoundary(), boundary)); + throw new IllegalArgumentException(format("%s which was used to query for pages is not contained in the %s of this node!", boundary, getBoundary())); } return buildTextBlock().getPages(boundary); } @@ -211,7 +211,7 @@ public interface SemanticNode { default Integer getNumberOnPage() { TextBlock textBlock = buildTextBlock(); - if (textBlock.getAtomicTextBlocks().size() > 0) { + if (!textBlock.getAtomicTextBlocks().isEmpty()) { return buildTextBlock().getAtomicTextBlocks().get(0).getNumberOnPage(); } else { return -1; @@ -226,7 +226,7 @@ public interface SemanticNode { */ default boolean hasText() { - return buildTextBlock().length() > 0; + return !buildTextBlock().isEmpty(); } @@ -318,7 +318,18 @@ public interface SemanticNode { */ default Stream streamChildren() { - return getDocumentTree().streamChildrenNodes(getTreeId()); + return getDocumentTree().streamChildNodes(getTreeId()); + } + + + /** + * Streams all children located directly underneath this node in the DocumentTree. + * + * @return Stream of all children + */ + default Stream streamChildrenOfType(NodeType nodeType) { + + return getDocumentTree().streamChildNodesOfType(getTreeId(), nodeType); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Table.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Table.java index 3e00e7a3..0000ca59 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Table.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/Table.java @@ -147,7 +147,7 @@ public class Table implements SemanticNode { */ public Stream streamTableCells() { - return streamChildren().map(node -> (TableCell) node); + return streamChildrenOfType(NodeType.TABLE_CELL).map(node -> (TableCell) node); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/TableCell.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/TableCell.java index 61399350..9b3ca02b 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/TableCell.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/nodes/TableCell.java @@ -23,7 +23,7 @@ import lombok.experimental.FieldDefaults; @Builder @AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class TableCell implements SemanticNode { +public class TableCell implements GenericSemanticNode { List treeId; int row; diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/textblock/AtomicTextBlock.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/textblock/AtomicTextBlock.java index ffeb62f6..f340abcd 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/textblock/AtomicTextBlock.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/graph/textblock/AtomicTextBlock.java @@ -3,12 +3,16 @@ package com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.t import static java.lang.String.format; import java.awt.geom.Rectangle2D; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import com.google.common.primitives.Ints; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.AtomicPositionBlockData; +import com.iqser.red.service.redaction.v1.server.layoutparsing.document.data.AtomicTextBlockData; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.Boundary; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.Page; import com.iqser.red.service.redaction.v1.server.layoutparsing.document.graph.nodes.SemanticNode; @@ -51,6 +55,31 @@ public class AtomicTextBlock implements TextBlock { } + public static AtomicTextBlock fromAtomicTextBlockData(AtomicTextBlockData atomicTextBlockData, + AtomicPositionBlockData atomicPositionBlockData, + SemanticNode parent, + Page page) { + + return AtomicTextBlock.builder() + .id(atomicTextBlockData.getId()) + .numberOnPage(atomicTextBlockData.getNumberOnPage()) + .page(page) + .boundary(new Boundary(atomicTextBlockData.getStart(), atomicTextBlockData.getEnd())) + .searchText(atomicTextBlockData.getSearchText()) + .lineBreaks(Ints.asList(atomicTextBlockData.getLineBreaks())) + .stringIdxToPositionIdx(Ints.asList(atomicPositionBlockData.getStringIdxToPositionIdx())) + .positions(toRectangle2DList(atomicPositionBlockData.getPositions())) + .parent(parent) + .build(); + } + + + private static List toRectangle2DList(float[][] positions) { + + return Arrays.stream(positions).map(floatArr -> (Rectangle2D) new Rectangle2D.Float(floatArr[0], floatArr[1], floatArr[2], floatArr[3])).toList(); + } + + public CharSequence getLine(int lineNumber) { if (lineNumber >= numberOfLines() || lineNumber < 0) { diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/services/EntityCreationService.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/services/EntityCreationService.java index 0d9c58c6..45ef4803 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/services/EntityCreationService.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/services/EntityCreationService.java @@ -247,7 +247,7 @@ public class EntityCreationService { public void addEntityToGraph(RedactionEntity entity, DocumentTree documentTree) { - SemanticNode containingNode = documentTree.streamChildrenNodes(Collections.emptyList()) + SemanticNode containingNode = documentTree.streamChildNodes(Collections.emptyList()) .filter(node -> node.buildTextBlock().containsBoundary(entity.getBoundary())) .findFirst() .orElseThrow(() -> new NoSuchElementException("No containing Node found!")); diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/PdfVisualisationUtility.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/PdfVisualisationUtility.java index 1e1845b9..07f2e9f1 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/PdfVisualisationUtility.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/PdfVisualisationUtility.java @@ -139,7 +139,7 @@ public class PdfVisualisationUtility { private String buildString(DocumentTree.Entry entry) { - return entry.getNode().getNumberOnPage() + ": " + entry.getTocId() + ": " + entry.getType().toString(); + return entry.getNode().getNumberOnPage() + ": " + entry.getTreeId() + ": " + entry.getType().toString(); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleMapper.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleMapper.java index abd5c492..43aa842d 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleMapper.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleMapper.java @@ -8,14 +8,9 @@ import java.util.List; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Point; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Rectangle; -import com.iqser.red.service.redaction.v1.server.layoutparsing.classification.model.AbstractPageBlock; public class RectangleMapper { - - public static Rectangle2D toRectangle2D(AbstractPageBlock abstractPageBlock) { - - return new Rectangle2D.Float(abstractPageBlock.getMinX(), abstractPageBlock.getMinY(), abstractPageBlock.getWidth(), abstractPageBlock.getHeight()); - } + //TODO: Move functions into using services public static Rectangle2D toRectangle2D(Rectangle redactionLogRectangle) { diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleTransformations.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleTransformations.java index e9bf9c59..1e3ddc2a 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleTransformations.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/layoutparsing/document/utils/RectangleTransformations.java @@ -29,7 +29,13 @@ public class RectangleTransformations { public static Rectangle2D bBoxUnionAbstractTextContainer(List abstractPageBlocks) { - return abstractPageBlocks.stream().map(RectangleMapper::toRectangle2D).collect(new Rectangle2DUnion()); + return abstractPageBlocks.stream().map(RectangleTransformations::toRectangle2D).collect(new Rectangle2DUnion()); + } + + + public static Rectangle2D toRectangle2D(AbstractPageBlock abstractPageBlock) { + + return new Rectangle2D.Float(abstractPageBlock.getMinX(), abstractPageBlock.getMinY(), abstractPageBlock.getWidth(), abstractPageBlock.getHeight()); }