From 2c171b6a9e63c924ed685f2702fc7d971786ac83 Mon Sep 17 00:00:00 2001 From: yhampe Date: Fri, 23 Feb 2024 13:55:11 +0100 Subject: [PATCH] RED-8481: Use visual layout parsing to detect signatures added a new layer for visual parsing results codestyle --- .../api/data/redaction/LayoutEngine.java | 3 +- .../processor/LayoutParsingPipeline.java | 17 +++-- .../processor/model/graph/nodes/Document.java | 13 +++- .../processor/model/graph/nodes/Image.java | 4 +- .../processor/model/graph/nodes/Section.java | 7 +- .../model/graph/nodes/SemanticNode.java | 15 +++- .../processor/model/graph/nodes/Table.java | 74 +++++++++++++------ .../adapter/VisualLayoutParsingAdapter.java | 13 +++- .../factory/DocumentGraphFactory.java | 6 +- .../service/viewerdoc/ContentStreams.java | 9 ++- 10 files changed, 113 insertions(+), 48 deletions(-) diff --git a/layoutparser-service/layoutparser-service-internal-api/src/main/java/com/knecon/fforesight/service/layoutparser/internal/api/data/redaction/LayoutEngine.java b/layoutparser-service/layoutparser-service-internal-api/src/main/java/com/knecon/fforesight/service/layoutparser/internal/api/data/redaction/LayoutEngine.java index c32cf52..d5f541e 100644 --- a/layoutparser-service/layoutparser-service-internal-api/src/main/java/com/knecon/fforesight/service/layoutparser/internal/api/data/redaction/LayoutEngine.java +++ b/layoutparser-service/layoutparser-service-internal-api/src/main/java/com/knecon/fforesight/service/layoutparser/internal/api/data/redaction/LayoutEngine.java @@ -1,5 +1,6 @@ package com.knecon.fforesight.service.layoutparser.internal.api.data.redaction; public enum LayoutEngine { - ALGORITHM, AI + ALGORITHM, + AI } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/LayoutParsingPipeline.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/LayoutParsingPipeline.java index 17800d1..772f2f4 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/LayoutParsingPipeline.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/LayoutParsingPipeline.java @@ -101,8 +101,10 @@ public class LayoutParsingPipeline { .orElse(originFile); VisualLayoutParsingResponse visualLayoutParsingResponse = new VisualLayoutParsingResponse(); - if (layoutParsingRequest.visualLayoutParsingFileId().isPresent()) { - visualLayoutParsingResponse = layoutParsingStorageService.getVisualLayoutParsingFile(layoutParsingRequest.visualLayoutParsingFileId().get()); + if (layoutParsingRequest.visualLayoutParsingFileId() + .isPresent()) { + visualLayoutParsingResponse = layoutParsingStorageService.getVisualLayoutParsingFile(layoutParsingRequest.visualLayoutParsingFileId() + .get()); } ImageServiceResponse imageServiceResponse = new ImageServiceResponse(); @@ -124,7 +126,7 @@ public class LayoutParsingPipeline { imageServiceResponse, tableServiceResponse, visualLayoutParsingResponse, - layoutParsingRequest.identifier().toString()); + layoutParsingRequest.identifier().toString()); log.info("Building document graph for {}", layoutParsingRequest.identifier()); @@ -134,7 +136,7 @@ public class LayoutParsingPipeline { layoutGridService.addLayoutGrid(viewerDocumentFile, documentGraph, viewerDocumentFile, false); - layoutGridService.addLayoutGrid(viewerDocumentFile,documentGraph,viewerDocumentFile,false,true); + layoutGridService.addLayoutGrid(viewerDocumentFile, documentGraph, viewerDocumentFile, false, true); log.info("Storing resulting files for {}", layoutParsingRequest.identifier()); @@ -281,11 +283,10 @@ public class LayoutParsingPipeline { imageServiceResponseAdapter.findOcr(classificationPage); } - if(signatures.containsKey(pageNumber)) { - if(classificationPage.getImages() == null ||classificationPage.getImages().size() == 0) { + if (signatures.containsKey(pageNumber)) { + if (classificationPage.getImages() == null || classificationPage.getImages().size() == 0) { classificationPage.setImages(signatures.get(pageNumber)); - } - else { + } else { classificationPage.getImages().addAll(signatures.get(pageNumber)); } } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Document.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Document.java index 8de25ca..23a3cd0 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Document.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Document.java @@ -60,13 +60,15 @@ public class Document implements GenericSemanticNode { public List
getMainSections() { - return streamChildrenOfType(NodeType.SECTION).map(node -> (Section) node).collect(Collectors.toList()); + return streamChildrenOfType(NodeType.SECTION).map(node -> (Section) node) + .collect(Collectors.toList()); } public Stream streamTerminalTextBlocksInOrder() { - return streamAllNodes().filter(SemanticNode::isLeaf).map(SemanticNode::getLeafTextBlock); + return streamAllNodes().filter(SemanticNode::isLeaf) + .map(SemanticNode::getLeafTextBlock); } @@ -87,13 +89,16 @@ public class Document implements GenericSemanticNode { @Override public Headline getHeadline() { - return streamAllSubNodesOfType(NodeType.HEADLINE).map(node -> (Headline) node).findFirst().orElse(Headline.builder().build()); + return streamAllSubNodesOfType(NodeType.HEADLINE).map(node -> (Headline) node) + .findFirst() + .orElse(Headline.builder().build()); } private Stream streamAllNodes() { - return documentTree.allEntriesInOrder().map(DocumentTree.Entry::getNode); + return documentTree.allEntriesInOrder() + .map(DocumentTree.Entry::getNode); } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Image.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Image.java index 0d9cc26..bcfb039 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Image.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Image.java @@ -70,7 +70,9 @@ public class Image implements GenericSemanticNode { @Override public TextBlock getTextBlock() { - return streamAllSubNodes().filter(SemanticNode::isLeaf).map(SemanticNode::getLeafTextBlock).collect(new TextBlockCollector()); + return streamAllSubNodes().filter(SemanticNode::isLeaf) + .map(SemanticNode::getLeafTextBlock) + .collect(new TextBlockCollector()); } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Section.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Section.java index ebc39c7..6680c01 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Section.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Section.java @@ -53,7 +53,8 @@ public class Section implements GenericSemanticNode { public boolean hasTables() { - return streamAllSubNodesOfType(NodeType.TABLE).findAny().isPresent(); + return streamAllSubNodesOfType(NodeType.TABLE).findAny() + .isPresent(); } @@ -61,7 +62,9 @@ public class Section implements GenericSemanticNode { public TextBlock getTextBlock() { if (textBlock == null) { - textBlock = streamAllSubNodes().filter(SemanticNode::isLeaf).map(SemanticNode::getLeafTextBlock).collect(new TextBlockCollector()); + textBlock = streamAllSubNodes().filter(SemanticNode::isLeaf) + .map(SemanticNode::getLeafTextBlock) + .collect(new TextBlockCollector()); } return textBlock; } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/SemanticNode.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/SemanticNode.java index 9afabb8..11a612c 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/SemanticNode.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/SemanticNode.java @@ -22,8 +22,6 @@ import com.knecon.fforesight.service.layoutparser.processor.model.graph.textbloc import com.knecon.fforesight.service.layoutparser.processor.model.graph.textblock.TextBlock; import com.knecon.fforesight.service.layoutparser.processor.utils.RectangleTransformations; -import ch.qos.logback.core.Layout; - public interface SemanticNode { /** @@ -337,12 +335,24 @@ public interface SemanticNode { } } + + /** + * returns the set of layoutengines + * + * @return set of layoutengines + */ Set getEngines(); + + /** + * adds a layoutengine to the set + */ default void addEngine(LayoutEngine engine) { + getEngines().add(engine); } + /** * Streams all children located directly underneath this node in the DocumentTree. * @@ -434,6 +444,7 @@ public interface SemanticNode { /** * TODO: this produces unwanted results for sections spanning multiple columns. * Computes the Union of the bounding boxes of all children recursively. + * * @return The union of the BoundingBoxes of all children */ private Map getBBoxFromChildren() { diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Table.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Table.java index f12ee8d..5bed37b 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Table.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/model/graph/nodes/Table.java @@ -48,6 +48,7 @@ public class Table implements SemanticNode { @EqualsAndHashCode.Exclude Map bBoxCache; + /** * Streams all entities in this table, that appear in a row, which contains any of the provided strings. * @@ -56,8 +57,7 @@ public class Table implements SemanticNode { */ public Stream streamEntitiesWhereRowContainsStringsIgnoreCase(List strings) { - return IntStream.range(0, numberOfRows) - .boxed() + return IntStream.range(0, numberOfRows).boxed() .filter(row -> rowContainsStringsIgnoreCase(row, strings)) .flatMap(this::streamRow) .map(TableCell::getEntities) @@ -74,8 +74,11 @@ public class Table implements SemanticNode { */ public boolean rowContainsStringsIgnoreCase(Integer row, List strings) { - String rowText = streamRow(row).map(TableCell::getTextBlock).collect(new TextBlockCollector()).getSearchText().toLowerCase(Locale.ROOT); - return strings.stream().map(String::toLowerCase).allMatch(rowText::contains); + String rowText = streamRow(row).map(TableCell::getTextBlock) + .collect(new TextBlockCollector()).getSearchText().toLowerCase(Locale.ROOT); + return strings.stream() + .map(String::toLowerCase) + .allMatch(rowText::contains); } @@ -88,9 +91,13 @@ public class Table implements SemanticNode { */ public Stream streamEntitiesWhereRowHasHeaderAndValue(String header, String value) { - List vertebrateStudyCols = streamHeaders().filter(headerNode -> headerNode.containsString(header)).map(TableCell::getCol).toList(); + List vertebrateStudyCols = streamHeaders().filter(headerNode -> headerNode.containsString(header)) + .map(TableCell::getCol) + .toList(); return streamTableCells().filter(tableCellNode -> vertebrateStudyCols.stream() - .anyMatch(vertebrateStudyCol -> getCell(tableCellNode.getRow(), vertebrateStudyCol).containsString(value))).map(TableCell::getEntities).flatMap(Collection::stream); + .anyMatch(vertebrateStudyCol -> getCell(tableCellNode.getRow(), vertebrateStudyCol).containsString(value))) + .map(TableCell::getEntities) + .flatMap(Collection::stream); } @@ -103,9 +110,13 @@ public class Table implements SemanticNode { */ public Stream streamEntitiesWhereRowHasHeaderAndAnyValue(String header, List values) { - List colsWithHeader = streamHeaders().filter(headerNode -> headerNode.containsString(header)).map(TableCell::getCol).toList(); + List colsWithHeader = streamHeaders().filter(headerNode -> headerNode.containsString(header)) + .map(TableCell::getCol) + .toList(); return streamTableCells().filter(tableCellNode -> colsWithHeader.stream() - .anyMatch(colWithHeader -> getCell(tableCellNode.getRow(), colWithHeader).containsAnyString(values))).map(TableCell::getEntities).flatMap(Collection::stream); + .anyMatch(colWithHeader -> getCell(tableCellNode.getRow(), colWithHeader).containsAnyString(values))) + .map(TableCell::getEntities) + .flatMap(Collection::stream); } @@ -117,12 +128,15 @@ public class Table implements SemanticNode { */ public Stream streamEntitiesWhereRowContainsEntitiesOfType(List types) { - List rowsWithEntityOfType = IntStream.range(0, numberOfRows) - .boxed() - .filter(rowNumber -> streamEntityTypesInRow(rowNumber).anyMatch(existingType -> types.stream().anyMatch(typeToCheck -> typeToCheck.equals(existingType)))) + List rowsWithEntityOfType = IntStream.range(0, numberOfRows).boxed() + .filter(rowNumber -> streamEntityTypesInRow(rowNumber).anyMatch(existingType -> types.stream() + .anyMatch(typeToCheck -> typeToCheck.equals(existingType)))) .toList(); - return rowsWithEntityOfType.stream().flatMap(this::streamRow).map(TableCell::getEntities).flatMap(Collection::stream); + return rowsWithEntityOfType.stream() + .flatMap(this::streamRow) + .map(TableCell::getEntities) + .flatMap(Collection::stream); } @@ -134,18 +148,24 @@ public class Table implements SemanticNode { */ public Stream streamEntitiesWhereRowContainsNoEntitiesOfType(List types) { - List rowsWithNoEntityOfType = IntStream.range(0, numberOfRows) - .boxed() - .filter(rowNumber -> streamEntityTypesInRow(rowNumber).noneMatch(existingType -> types.stream().anyMatch(typeToCheck -> typeToCheck.equals(existingType)))) + List rowsWithNoEntityOfType = IntStream.range(0, numberOfRows).boxed() + .filter(rowNumber -> streamEntityTypesInRow(rowNumber).noneMatch(existingType -> types.stream() + .anyMatch(typeToCheck -> typeToCheck.equals(existingType)))) .toList(); - return rowsWithNoEntityOfType.stream().flatMap(this::streamRow).map(TableCell::getEntities).flatMap(Collection::stream); + return rowsWithNoEntityOfType.stream() + .flatMap(this::streamRow) + .map(TableCell::getEntities) + .flatMap(Collection::stream); } private Stream streamEntityTypesInRow(Integer rowNumber) { - return streamRow(rowNumber).map(TableCell::getEntities).flatMap(Collection::stream).map(RedactionEntity::getType).distinct(); + return streamRow(rowNumber).map(TableCell::getEntities) + .flatMap(Collection::stream) + .map(RedactionEntity::getType) + .distinct(); } @@ -162,7 +182,8 @@ public class Table implements SemanticNode { throw new IllegalArgumentException(format("row %d, col %d is out of bounds for number of rows of %d and number of cols %d", row, col, numberOfRows, numberOfCols)); } int idx = row * numberOfCols + col; - return (TableCell) documentTree.getEntryById(treeId).getChildren().get(idx).getNode(); + return (TableCell) documentTree.getEntryById(treeId).getChildren() + .get(idx).getNode(); } @@ -199,7 +220,8 @@ public class Table implements SemanticNode { */ public Stream streamCol(int col) { - return IntStream.range(0, numberOfRows).boxed().map(row -> getCell(row, col)); + return IntStream.range(0, numberOfRows).boxed() + .map(row -> getCell(row, col)); } @@ -211,9 +233,11 @@ public class Table implements SemanticNode { */ public Stream streamRow(int row) { - return IntStream.range(0, numberOfCols).boxed().map(col -> getCell(row, col)); + return IntStream.range(0, numberOfCols).boxed() + .map(col -> getCell(row, col)); } + /** * Streams all TableCells row-wise and filters them with header == true. * @@ -234,7 +258,8 @@ public class Table implements SemanticNode { */ public Stream streamHeadersForCell(int row, int col) { - return Stream.concat(streamRow(row), streamCol(col)).filter(TableCell::isHeader); + return Stream.concat(streamRow(row), streamCol(col)) + .filter(TableCell::isHeader); } @@ -307,7 +332,9 @@ public class Table implements SemanticNode { public TextBlock getTextBlock() { if (textBlock == null) { - textBlock = streamAllSubNodes().filter(SemanticNode::isLeaf).map(SemanticNode::getLeafTextBlock).collect(new TextBlockCollector()); + textBlock = streamAllSubNodes().filter(SemanticNode::isLeaf) + .map(SemanticNode::getLeafTextBlock) + .collect(new TextBlockCollector()); } return textBlock; } @@ -318,6 +345,8 @@ public class Table implements SemanticNode { return treeId.toString() + ": " + NodeType.TABLE + ": #cols: " + numberOfCols + ", #rows: " + numberOfRows + ", " + this.getTextBlock().buildSummary(); } + + @Override public Map getBBox() { @@ -326,4 +355,5 @@ public class Table implements SemanticNode { } return bBoxCache; } + } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/python_api/adapter/VisualLayoutParsingAdapter.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/python_api/adapter/VisualLayoutParsingAdapter.java index 398d5de..6fe668b 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/python_api/adapter/VisualLayoutParsingAdapter.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/python_api/adapter/VisualLayoutParsingAdapter.java @@ -24,6 +24,7 @@ public class VisualLayoutParsingAdapter { private static String SIGNATURES = "signature"; + public Map> buildExtractedTablesPerPage(VisualLayoutParsingResponse visualLayoutParsingResponse) { Map> tableCells = new HashMap<>(); @@ -34,10 +35,11 @@ public class VisualLayoutParsingAdapter { } + public Map> buildExtractedSignaturesPerPage(VisualLayoutParsingResponse visualLayoutParsingResponse) { Map> signatures = new HashMap<>(); - if(visualLayoutParsingResponse.getData() != null) { + if (visualLayoutParsingResponse.getData() != null) { visualLayoutParsingResponse.getData() .forEach(tableData -> signatures.computeIfAbsent(tableData.getPage_idx() + 1, tableCell -> new ArrayList<>()) .addAll(convertSignatures(tableData.getPage_idx(), tableData.getBoxes()))); @@ -67,14 +69,17 @@ public class VisualLayoutParsingAdapter { } + public List convertSignatures(int pageNumber, List tableObjects) { List signatures = new ArrayList<>(); tableObjects.stream().forEach(t -> { - if(t.getLabel().equals(SIGNATURES)) { - ClassifiedImage signature = new ClassifiedImage(new Rectangle2D.Float(t.getBox().getX1(),t.getBox().getY1(),t.getBox().getX2() - t.getBox().getX1(),t.getBox().getY2() - t.getBox().getY1()), - ImageType.SIGNATURE,true,false,false,pageNumber); + if (t.getLabel().equals(SIGNATURES)) { + ClassifiedImage signature = new ClassifiedImage(new Rectangle2D.Float(t.getBox().getX1(), + t.getBox().getY1(), + t.getBox().getX2() - t.getBox().getX1(), + t.getBox().getY2() - t.getBox().getY1()), ImageType.SIGNATURE, true, false, false, pageNumber); signatures.add(signature); } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/factory/DocumentGraphFactory.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/factory/DocumentGraphFactory.java index 3ec26ef..778ad91 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/factory/DocumentGraphFactory.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/factory/DocumentGraphFactory.java @@ -20,8 +20,6 @@ import com.knecon.fforesight.service.layoutparser.processor.model.Classification import com.knecon.fforesight.service.layoutparser.processor.model.ClassificationFooter; import com.knecon.fforesight.service.layoutparser.processor.model.ClassificationHeader; import com.knecon.fforesight.service.layoutparser.processor.model.ClassificationPage; -import com.knecon.fforesight.service.layoutparser.processor.model.image.ClassifiedImage; -import com.knecon.fforesight.service.layoutparser.processor.model.text.TextPageBlock; import com.knecon.fforesight.service.layoutparser.processor.model.graph.DocumentTree; import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Document; import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Footer; @@ -33,6 +31,8 @@ import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Pa import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Paragraph; import com.knecon.fforesight.service.layoutparser.processor.model.graph.nodes.Section; import com.knecon.fforesight.service.layoutparser.processor.model.graph.textblock.AtomicTextBlock; +import com.knecon.fforesight.service.layoutparser.processor.model.image.ClassifiedImage; +import com.knecon.fforesight.service.layoutparser.processor.model.text.TextPageBlock; import com.knecon.fforesight.service.layoutparser.processor.utils.IdBuilder; import com.knecon.fforesight.service.layoutparser.processor.utils.TextPositionOperations; @@ -104,7 +104,7 @@ public class DocumentGraphFactory { .transparent(image.isHasTransparency()) .page(page) .documentTree(context.getDocumentTree()); - if(image.isSourceByAi()) { + if (image.isSourceByAi()) { imageBuilder.engines(new HashSet<>(Set.of(LayoutEngine.AI))); } Image imageNode = imageBuilder.build(); diff --git a/layoutparser-service/viewer-doc-processor/src/main/java/com/knecon/fforesight/service/viewerdoc/ContentStreams.java b/layoutparser-service/viewer-doc-processor/src/main/java/com/knecon/fforesight/service/viewerdoc/ContentStreams.java index 31d6fca..937f75d 100644 --- a/layoutparser-service/viewer-doc-processor/src/main/java/com/knecon/fforesight/service/viewerdoc/ContentStreams.java +++ b/layoutparser-service/viewer-doc-processor/src/main/java/com/knecon/fforesight/service/viewerdoc/ContentStreams.java @@ -26,7 +26,14 @@ public class ContentStreams { public static Identifier ESCAPE_END = new Identifier("escape start", COSName.getPDFName("ESCAPE_END"), false); - public static List allContentStreams = List.of(KNECON_LAYOUT, KNECON_VISUAL_PARSING,KNECON_OCR, KNECON_OCR_BBOX_DEBUG, KNECON_OCR_TEXT_DEBUG, OTHER, ESCAPE_START, ESCAPE_END); + public static List allContentStreams = List.of(KNECON_LAYOUT, + KNECON_VISUAL_PARSING, + KNECON_OCR, + KNECON_OCR_BBOX_DEBUG, + KNECON_OCR_TEXT_DEBUG, + OTHER, + ESCAPE_START, + ESCAPE_END); public record Identifier(String name, COSName cosName, boolean optionalContent) {