Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e5ff31810 | ||
|
|
8b1574845c | ||
|
|
e1adcfb02c | ||
|
|
11164219c5 | ||
|
|
c9516205fe | ||
|
|
f5790bccab | ||
|
|
74e63ca292 | ||
|
|
6638f0cf9e | ||
|
|
5448153096 | ||
|
|
03274ba1ab | ||
|
|
664b9b4206 | ||
|
|
564d74e39d | ||
|
|
cfb7554c61 | ||
|
|
ee40064b32 | ||
|
|
f2fafc3db2 | ||
|
|
d5b0638f11 |
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.atlassian.bamboo</groupId>
|
||||
<artifactId>bamboo-specs-parent</artifactId>
|
||||
<version>7.0.4</version>
|
||||
<version>7.1.2</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
@@ -34,4 +34,4 @@
|
||||
|
||||
<!-- run 'mvn test' to perform offline validation of the plan -->
|
||||
<!-- run 'mvn -Ppublish-specs' to upload the plan to your Bamboo server -->
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM gin5/platform-base:5.2.0
|
||||
FROM red/base-image:1.0.0
|
||||
|
||||
ARG PLATFORM_JAR
|
||||
|
||||
@@ -6,4 +6,4 @@ ENV PLATFORM_JAR ${PLATFORM_JAR}
|
||||
|
||||
ENV USES_ELASTICSEARCH false
|
||||
|
||||
COPY ["${PLATFORM_JAR}", "/"]
|
||||
COPY ["${PLATFORM_JAR}", "/"]
|
||||
|
||||
+14
-6
@@ -44,10 +44,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
|
||||
@Getter
|
||||
private float minCharWidth = Float.MAX_VALUE;
|
||||
private int maxCharWidths;
|
||||
|
||||
@Getter
|
||||
private float minCharHeight = Float.MAX_VALUE;
|
||||
private int maxCharHeight;
|
||||
|
||||
@Getter
|
||||
private final List<TextPositionSequence> textPositionSequences = new ArrayList<>();
|
||||
@@ -201,8 +201,16 @@ public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
|
||||
int startIndex = 0;
|
||||
for (int i = 0; i <= textPositions.size() - 1; i++) {
|
||||
minCharWidth = Math.min(minCharWidth, textPositions.get(i).getWidthDirAdj());
|
||||
minCharHeight = Math.min(minCharHeight, textPositions.get(i).getHeightDir());
|
||||
|
||||
int charHeight = (int) textPositions.get(i).getHeightDir();
|
||||
if(charHeight > maxCharHeight){
|
||||
maxCharHeight = charHeight;
|
||||
}
|
||||
|
||||
int charWidth = (int) textPositions.get(i).getWidthDirAdj();
|
||||
if(charWidth > maxCharWidths){
|
||||
maxCharWidths = charWidth;
|
||||
}
|
||||
|
||||
if (i == 0 && textPositions.get(i).getUnicode().equals(" ")) {
|
||||
startIndex++;
|
||||
@@ -241,8 +249,8 @@ public class PDFLinesTextStripper extends PDFTextStripper {
|
||||
@Override
|
||||
public String getText(PDDocument doc) throws IOException {
|
||||
|
||||
minCharWidth = Float.MAX_VALUE;
|
||||
minCharHeight = Float.MAX_VALUE;
|
||||
maxCharWidths = 0;
|
||||
maxCharWidths = 0;
|
||||
textPositionSequences.clear();
|
||||
rulings.clear();
|
||||
graphicsPath.clear();
|
||||
|
||||
+2
-2
@@ -17,6 +17,6 @@ public class ParsedElements {
|
||||
private boolean landscape;
|
||||
private boolean rotated;
|
||||
|
||||
private float minCharWidth;
|
||||
private float minCharHeight;
|
||||
private float maxCharWidth;
|
||||
private float maxCharHeight;
|
||||
}
|
||||
|
||||
+4
-13
@@ -9,9 +9,7 @@ import com.iqser.red.service.redaction.v1.model.Point;
|
||||
import com.iqser.red.service.redaction.v1.model.Rectangle;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@@ -19,10 +17,6 @@ public class TextPositionSequence implements CharSequence {
|
||||
|
||||
private List<TextPosition> textPositions = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private float[] annotationColor;
|
||||
|
||||
private final int page;
|
||||
|
||||
|
||||
@@ -194,22 +188,18 @@ public class TextPositionSequence implements CharSequence {
|
||||
|
||||
public Rectangle getRectangle() {
|
||||
|
||||
float height = textPositions.get(0).getHeightDir() + 2;
|
||||
float height = getTextHeight();
|
||||
|
||||
float posXInit;
|
||||
float posXInit = getX1();
|
||||
float posXEnd;
|
||||
float posYInit;
|
||||
float posYEnd;
|
||||
|
||||
if (textPositions.get(0).getRotation() == 90) {
|
||||
|
||||
posXEnd = textPositions.get(0).getYDirAdj() + 2;
|
||||
posXInit = textPositions.get(0).getYDirAdj() - height;
|
||||
posYInit = textPositions.get(0).getXDirAdj();
|
||||
posYInit = getY1();
|
||||
posYEnd = textPositions.get(textPositions.size() - 1).getXDirAdj() - height + 4;
|
||||
} else {
|
||||
|
||||
posXInit = textPositions.get(0).getXDirAdj();
|
||||
posXEnd = textPositions.get(textPositions.size() - 1)
|
||||
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidth() + 1;
|
||||
posYInit = textPositions.get(0).getPageHeight() - textPositions.get(0).getYDirAdj() - 2;
|
||||
@@ -220,4 +210,5 @@ public class TextPositionSequence implements CharSequence {
|
||||
return new Rectangle(new Point(posXInit, posYInit), posXEnd - posXInit, posYEnd - posYInit + height, page);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+27
@@ -1,6 +1,8 @@
|
||||
package com.iqser.red.service.redaction.v1.server.redaction.model;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
|
||||
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.utils.TextNormalizationUtilities;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
@@ -13,4 +15,29 @@ public class CellValue {
|
||||
|
||||
int rowSpanStart;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
|
||||
TextPositionSequence previous = null;
|
||||
for (TextPositionSequence word : textBlock.getSequences()) {
|
||||
|
||||
if (previous != null) {
|
||||
if (Math.abs(previous.getY1() - word.getY1()) > word.getTextHeight()) {
|
||||
sb.append('\n');
|
||||
} else {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
sb.append(word.toString());
|
||||
previous = word;
|
||||
}
|
||||
|
||||
return TextNormalizationUtilities.removeHyphenLineBreaks(sb.toString())
|
||||
.replaceAll("\n", " ")
|
||||
.replaceAll(" {2}", " ");
|
||||
}
|
||||
|
||||
}
|
||||
+39
-17
@@ -33,13 +33,14 @@ public class Section {
|
||||
private Map<String, CellValue> tabularData;
|
||||
|
||||
|
||||
public boolean rowEquals(String headerName, String value){
|
||||
String cleanHeaderName = headerName.replaceAll("\n", "")
|
||||
.replaceAll(" ", "")
|
||||
.replaceAll("-", "");
|
||||
public boolean rowEquals(String headerName, String value) {
|
||||
|
||||
return tabularData != null && tabularData.containsKey(cleanHeaderName)
|
||||
&& tabularData.get(cleanHeaderName).getTextBlock().getText().equals(value);
|
||||
String cleanHeaderName = headerName.replaceAll("\n", "").replaceAll(" ", "").replaceAll("-", "");
|
||||
|
||||
return tabularData != null && tabularData.containsKey(cleanHeaderName) && tabularData.get(cleanHeaderName)
|
||||
.getTextBlock()
|
||||
.getText()
|
||||
.equals(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -172,25 +173,46 @@ public class Section {
|
||||
|
||||
public void highlightCell(String cellHeader, int ruleNumber, String type) {
|
||||
|
||||
String cleanHeaderName = cellHeader.replaceAll("\n", "")
|
||||
.replaceAll(" ", "")
|
||||
.replaceAll("-", "");
|
||||
annotateCell(cellHeader, ruleNumber, type, false, null);
|
||||
}
|
||||
|
||||
|
||||
public void redactCell(String cellHeader, int ruleNumber, String type, String reason) {
|
||||
|
||||
annotateCell(cellHeader, ruleNumber, type, true, reason);
|
||||
}
|
||||
|
||||
|
||||
public void redactNotCell(String cellHeader, int ruleNumber, String type, String reason) {
|
||||
|
||||
annotateCell(cellHeader, ruleNumber, type, false, reason);
|
||||
}
|
||||
|
||||
|
||||
private void annotateCell(String cellHeader, int ruleNumber, String type, boolean redact, String reason) {
|
||||
|
||||
String cleanHeaderName = cellHeader.replaceAll("\n", "").replaceAll(" ", "").replaceAll("-", "");
|
||||
|
||||
CellValue value = tabularData.get(cleanHeaderName);
|
||||
if (value == null) {
|
||||
log.warn("Could not find any data for {}.", cellHeader);
|
||||
} else {
|
||||
Entity entity = new Entity(value.getTextBlock()
|
||||
.getText(), type, value.getRowSpanStart(), value.getRowSpanStart() + value.getTextBlock()
|
||||
.getText()
|
||||
Entity entity = new Entity(value.toString(), type, value.getRowSpanStart(), value.getRowSpanStart() + value.toString()
|
||||
.length(), headline, sectionNumber);
|
||||
entity.setRedaction(false);
|
||||
entity.setRedaction(redact);
|
||||
entity.setMatchedRule(ruleNumber);
|
||||
entity.setRedactionReason(cellHeader);
|
||||
entity.setTargetSequences(value.getTextBlock().getSequences()); // Make sure no other cells with same content are highlighted
|
||||
entities.add(entity);
|
||||
}
|
||||
entity.setRedactionReason(reason);
|
||||
entity.setTargetSequences(value.getTextBlock()
|
||||
.getSequences()); // Make sure no other cells with same content are highlighted
|
||||
|
||||
// HashSet keeps the older value, but we want the new only.
|
||||
if(entities.contains(entity)){
|
||||
entities.remove(entity);
|
||||
}
|
||||
entities.add(entity);
|
||||
|
||||
entities = removeEntitiesContainedInLarger(entities);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-3
@@ -27,9 +27,7 @@ import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EntityRedactionService {
|
||||
@@ -72,7 +70,7 @@ public class EntityRedactionService {
|
||||
.replaceAll("-", "");
|
||||
tabularData.put(headerName, new CellValue(cell.getTextBlocks().get(0), cellStart));
|
||||
});
|
||||
start = start + cell.getTextBlocks().get(0).toString().length();
|
||||
start = start + cell.toString().length();
|
||||
for (TextBlock textBlock : cell.getTextBlocks()) {
|
||||
searchableRow.addAll(textBlock.getSequences());
|
||||
}
|
||||
|
||||
+13
-7
@@ -21,7 +21,6 @@ import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractT
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.CleanRulings;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.service.RulingCleaningService;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.service.TableExtractionService;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.utils.Utils;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -37,6 +36,7 @@ public class PdfSegmentationService {
|
||||
private final ClassificationService classificationService;
|
||||
private final SectionsBuilderService sectionsBuilderService;
|
||||
|
||||
|
||||
public Document parseDocument(PDDocument pdDocument) throws IOException {
|
||||
|
||||
Document document = new Document();
|
||||
@@ -56,19 +56,21 @@ public class PdfSegmentationService {
|
||||
int rotation = pdPage.getRotation();
|
||||
boolean isRotated = rotation != 0 && rotation != 360;
|
||||
|
||||
ParsedElements parsedElements = ParsedElements
|
||||
.builder()
|
||||
|
||||
ParsedElements parsedElements = ParsedElements.builder()
|
||||
.rulings(stripper.getRulings())
|
||||
.sequences(stripper.getTextPositionSequences())
|
||||
.minCharWidth(Utils.round(stripper.getMinCharWidth(), 2))
|
||||
.minCharHeight(Utils.round(stripper.getMinCharHeight(), 2))
|
||||
.maxCharWidth(stripper.getMaxCharWidths())
|
||||
.maxCharHeight(stripper.getMaxCharWidths())
|
||||
.landscape(isLandscape)
|
||||
.rotated(isRotated)
|
||||
.build();
|
||||
|
||||
CleanRulings cleanRulings = rulingCleaningService.getCleanRulings(parsedElements.getRulings(), parsedElements.getMinCharWidth(), parsedElements.getMinCharHeight());
|
||||
CleanRulings cleanRulings = rulingCleaningService.getCleanRulings(parsedElements.getRulings(), parsedElements
|
||||
.getMaxCharWidth(), parsedElements.getMaxCharHeight());
|
||||
|
||||
Page page = blockificationService.blockify(parsedElements.getSequences(), cleanRulings.getHorizontal(), cleanRulings.getVertical());
|
||||
Page page = blockificationService.blockify(parsedElements.getSequences(), cleanRulings.getHorizontal(), cleanRulings
|
||||
.getVertical());
|
||||
page.setRotation(rotation);
|
||||
|
||||
tableExtractionService.extractTables(cleanRulings, page);
|
||||
@@ -91,7 +93,10 @@ public class PdfSegmentationService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void increaseDocumentStatistics(Page page, Document document) {
|
||||
|
||||
if (!page.isLandscape()) {
|
||||
document.getFontSizeCounter().addAll(page.getFontSizeCounter().getCountPerValue());
|
||||
}
|
||||
@@ -100,6 +105,7 @@ public class PdfSegmentationService {
|
||||
document.getFontStyleCounter().addAll(page.getFontStyleCounter().getCountPerValue());
|
||||
}
|
||||
|
||||
|
||||
private void buildPageStatistics(Page page) {
|
||||
|
||||
// Collect all statistics for the page, except from blocks inside tables, as tables will always be added to BodyTextFrame.
|
||||
|
||||
+3
-1
@@ -42,7 +42,9 @@ public class SectionsBuilderService {
|
||||
if (prev != null && current.getClassification().startsWith("H ") || !document.isHeadlines()) {
|
||||
Paragraph chunkBlock = buildTextBlock(chunkWords, lastHeadline);
|
||||
chunkBlock.setHeadline(lastHeadline);
|
||||
lastHeadline = current.getText();
|
||||
if(document.isHeadlines()) {
|
||||
lastHeadline = current.getText();
|
||||
}
|
||||
chunkBlockList.add(chunkBlock);
|
||||
chunkWords = new ArrayList<>();
|
||||
if (CollectionUtils.isNotEmpty(chunkBlock.getTables())) {
|
||||
|
||||
+35
-3
@@ -5,6 +5,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
|
||||
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.utils.TextNormalizationUtilities;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -20,10 +22,10 @@ public class Cell extends Rectangle {
|
||||
|
||||
private boolean isHeaderCell;
|
||||
|
||||
|
||||
public Cell(Point2D topLeft, Point2D bottomRight) {
|
||||
|
||||
super((float) topLeft.getY(), (float) topLeft.getX(), (float) (bottomRight.getX() - topLeft.getX()),
|
||||
(float) (bottomRight
|
||||
super((float) topLeft.getY(), (float) topLeft.getX(), (float) (bottomRight.getX() - topLeft.getX()), (float) (bottomRight
|
||||
.getY() - topLeft.getY()));
|
||||
}
|
||||
|
||||
@@ -33,4 +35,34 @@ public class Cell extends Rectangle {
|
||||
textBlocks.add(textBlock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
TextPositionSequence previous = null;
|
||||
for (TextBlock textBlock : textBlocks) {
|
||||
|
||||
|
||||
for (TextPositionSequence word : textBlock.getSequences()) {
|
||||
|
||||
if (previous != null) {
|
||||
if (Math.abs(previous.getY1() - word.getY1()) > word.getTextHeight()) {
|
||||
sb.append('\n');
|
||||
} else {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
sb.append(word.toString());
|
||||
previous = word;
|
||||
}
|
||||
}
|
||||
|
||||
return TextNormalizationUtilities.removeHyphenLineBreaks(sb.toString())
|
||||
.replaceAll("\n", " ")
|
||||
.replaceAll(" {2}", " ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -18,9 +18,9 @@ import com.iqser.red.service.redaction.v1.server.tableextraction.utils.Utils;
|
||||
@Service
|
||||
public class RulingCleaningService {
|
||||
|
||||
public CleanRulings getCleanRulings(List<Ruling> rulings, float minCharWidth, float minCharHeight){
|
||||
public CleanRulings getCleanRulings(List<Ruling> rulings, float maxCharWidth, float maxCharHeight){
|
||||
if (!rulings.isEmpty()) {
|
||||
snapPoints(rulings, minCharWidth , minCharHeight);
|
||||
snapPoints(rulings, maxCharWidth , maxCharHeight);
|
||||
}
|
||||
|
||||
List<Ruling> vrs = new ArrayList<>();
|
||||
|
||||
+61
-39
@@ -2,9 +2,11 @@ package com.iqser.red.service.redaction.v1.server.visualization.service;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
@@ -16,6 +18,7 @@ import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
|
||||
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
|
||||
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
|
||||
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup;
|
||||
import org.apache.pdfbox.text.TextPosition;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.model.ManualRedactionEntry;
|
||||
@@ -35,9 +38,7 @@ import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell;
|
||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AnnotationHighlightService {
|
||||
@@ -45,7 +46,8 @@ public class AnnotationHighlightService {
|
||||
private final DictionaryService dictionaryService;
|
||||
|
||||
|
||||
public void highlight(PDDocument document, Document classifiedDoc, boolean flatRedaction, ManualRedactions manualRedactions) throws IOException {
|
||||
public void highlight(PDDocument document, Document classifiedDoc, boolean flatRedaction,
|
||||
ManualRedactions manualRedactions) throws IOException {
|
||||
|
||||
Set<Integer> manualRedactionPages = getManualRedactionPages(manualRedactions);
|
||||
|
||||
@@ -83,7 +85,8 @@ public class AnnotationHighlightService {
|
||||
}
|
||||
|
||||
|
||||
private void addAnnotations(PDPage pdPage, Document classifiedDoc, boolean flatRedaction, ManualRedactions manualRedactions, int page) throws IOException {
|
||||
private void addAnnotations(PDPage pdPage, Document classifiedDoc, boolean flatRedaction,
|
||||
ManualRedactions manualRedactions, int page) throws IOException {
|
||||
|
||||
List<PDAnnotation> annotations = pdPage.getAnnotations();
|
||||
|
||||
@@ -107,11 +110,15 @@ public class AnnotationHighlightService {
|
||||
redactionLogEntry.setManual(true);
|
||||
}
|
||||
|
||||
for (TextPositionSequence textPositions : entityPositionSequence.getSequences()) {
|
||||
|
||||
Rectangle rectangle = textPositions.getRectangle();
|
||||
redactionLogEntry.getPositions().add(rectangle);
|
||||
annotations.add(createAnnotation(rectangle, entityPositionSequence.getId(), createAnnotationContent(entity), getColor(entity), !flatRedaction && !isHint(entity)));
|
||||
if (CollectionUtils.isNotEmpty(entityPositionSequence.getSequences())) {
|
||||
for (Rectangle rectangle : getRectanglesPerLine(entityPositionSequence.getSequences()
|
||||
.stream()
|
||||
.flatMap(seq -> seq.getTextPositions().stream())
|
||||
.collect(Collectors.toList()), page)) {
|
||||
redactionLogEntry.getPositions().add(rectangle);
|
||||
annotations.add(createAnnotation(rectangle, entityPositionSequence.getId(),
|
||||
createAnnotationContent(entity), getColor(entity), !flatRedaction && !isHint(entity)));
|
||||
}
|
||||
}
|
||||
redactionLogEntry.setId(entityPositionSequence.getId());
|
||||
}
|
||||
@@ -120,7 +127,33 @@ public class AnnotationHighlightService {
|
||||
}
|
||||
|
||||
|
||||
private void addManualAnnotations(PDPage pdPage, Document classifiedDoc, ManualRedactions manualRedactions, int page) throws IOException {
|
||||
private List<Rectangle> getRectanglesPerLine(List<TextPosition> textPositions, int page) {
|
||||
|
||||
List<Rectangle> rectangles = new ArrayList<>();
|
||||
if (textPositions.size() == 1) {
|
||||
rectangles.add(new TextPositionSequence(textPositions, page).getRectangle());
|
||||
} else {
|
||||
float y = textPositions.get(0).getYDirAdj();
|
||||
int startIndex = 0;
|
||||
for (int i = 1; i < textPositions.size(); i++) {
|
||||
float yDirAdj = textPositions.get(i).getYDirAdj();
|
||||
if (yDirAdj != y) {
|
||||
rectangles.add(new TextPositionSequence(textPositions.subList(startIndex, i), page).getRectangle());
|
||||
y = yDirAdj;
|
||||
startIndex = i;
|
||||
}
|
||||
}
|
||||
if (startIndex != textPositions.size() - 1) {
|
||||
rectangles.add(new TextPositionSequence(textPositions.subList(startIndex, textPositions.size()), page).getRectangle());
|
||||
}
|
||||
}
|
||||
|
||||
return rectangles;
|
||||
}
|
||||
|
||||
|
||||
private void addManualAnnotations(PDPage pdPage, Document classifiedDoc, ManualRedactions manualRedactions,
|
||||
int page) throws IOException {
|
||||
|
||||
if (manualRedactions == null) {
|
||||
return;
|
||||
@@ -143,8 +176,8 @@ public class AnnotationHighlightService {
|
||||
|
||||
foundOnPage = true;
|
||||
|
||||
PDAnnotationTextMarkup highlight = createAnnotation(rectangle, id, createAnnotationContent(manualRedactionEntry), getColor(manualRedactionEntry
|
||||
.getType()), true);
|
||||
PDAnnotationTextMarkup highlight = createAnnotation(rectangle, id,
|
||||
createAnnotationContent(manualRedactionEntry), getColor(manualRedactionEntry.getType()), true);
|
||||
annotations.add(highlight);
|
||||
|
||||
redactionLogEntry.getPositions().add(rectangle);
|
||||
@@ -188,7 +221,8 @@ public class AnnotationHighlightService {
|
||||
}
|
||||
|
||||
|
||||
private PDAnnotationTextMarkup createAnnotation(Rectangle rectangle, String id, String content, float[] color, boolean popup) {
|
||||
private PDAnnotationTextMarkup createAnnotation(Rectangle rectangle, String id, String content, float[] color,
|
||||
boolean popup) {
|
||||
|
||||
PDAnnotationTextMarkup annotation = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
|
||||
annotation.constructAppearances();
|
||||
@@ -206,25 +240,15 @@ public class AnnotationHighlightService {
|
||||
|
||||
private String createAnnotationContent(Entity entity) {
|
||||
|
||||
return new StringBuilder().append("\nRule ")
|
||||
.append(entity.getMatchedRule())
|
||||
.append(" matched")
|
||||
.append("\n\n")
|
||||
.append(entity.getRedactionReason())
|
||||
.append("\n\nIn Section : \"")
|
||||
.append(entity.getHeadline())
|
||||
.append("\"")
|
||||
.toString();
|
||||
return "\nRule " + entity.getMatchedRule() + " matched" + "\n\n" + entity.getRedactionReason() + "\n\nIn " +
|
||||
"Section : \"" + entity
|
||||
.getHeadline() + "\"";
|
||||
}
|
||||
|
||||
|
||||
private String createAnnotationContent(ManualRedactionEntry entry) {
|
||||
|
||||
return new StringBuilder().append("\nManual Redaction")
|
||||
.append("\n\nIn Section : \"")
|
||||
.append(entry.getSection())
|
||||
.append("\"")
|
||||
.toString();
|
||||
return "\nManual Redaction" + "\n\nIn Section : \"" + entry.getSection() + "\"";
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +268,8 @@ public class AnnotationHighlightService {
|
||||
// quadPoints is array of x,y coordinates in Z-like order (top-left, top-right, bottom-left,bottom-right)
|
||||
// of the area to be highlighted
|
||||
return new float[]{rectangle.getTopLeft().getX(), rectangle.getTopLeft().getY(), rectangle.getTopLeft()
|
||||
.getX() + rectangle.getWidth(), rectangle.getTopLeft().getY(), rectangle.getTopLeft().getX(), rectangle.getTopLeft()
|
||||
.getX() + rectangle.getWidth(), rectangle.getTopLeft().getY(), rectangle.getTopLeft().getX(),
|
||||
rectangle.getTopLeft()
|
||||
.getY() + rectangle.getHeight(), rectangle.getTopLeft()
|
||||
.getX() + rectangle.getWidth(), rectangle.getTopLeft().getY() + rectangle.getHeight()};
|
||||
}
|
||||
@@ -255,10 +280,7 @@ public class AnnotationHighlightService {
|
||||
if (!entity.isRedaction()) {
|
||||
return false;
|
||||
}
|
||||
if (isHint(entity)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !isHint(entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -286,20 +308,19 @@ public class AnnotationHighlightService {
|
||||
private boolean isHint(Entity entity) {
|
||||
|
||||
List<String> hintTypes = dictionaryService.getHintTypes();
|
||||
if (CollectionUtils.isNotEmpty(hintTypes) && hintTypes.contains(entity.getType())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return CollectionUtils.isNotEmpty(hintTypes) && hintTypes.contains(entity.getType());
|
||||
}
|
||||
|
||||
|
||||
private void drawSectionFrames(PDDocument document, Document classifiedDoc, boolean flatRedaction, PDPage pdPage, int page) throws IOException {
|
||||
private void drawSectionFrames(PDDocument document, Document classifiedDoc, boolean flatRedaction, PDPage pdPage,
|
||||
int page) throws IOException {
|
||||
|
||||
if (flatRedaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
PDPageContentStream contentStream = new PDPageContentStream(document, pdPage, PDPageContentStream.AppendMode.APPEND, true);
|
||||
PDPageContentStream contentStream = new PDPageContentStream(document, pdPage,
|
||||
PDPageContentStream.AppendMode.APPEND, true);
|
||||
for (Paragraph paragraph : classifiedDoc.getParagraphs()) {
|
||||
|
||||
for (int i = 0; i <= paragraph.getPageBlocks().size() - 1; i++) {
|
||||
@@ -348,7 +369,8 @@ public class AnnotationHighlightService {
|
||||
if (cell != null) {
|
||||
contentStream.setLineWidth(0.5f);
|
||||
contentStream.setStrokingColor(Color.CYAN);
|
||||
contentStream.addRect((float) cell.getX(), (float) cell.getY(), (float) cell.getWidth(), (float) cell
|
||||
contentStream.addRect((float) cell.getX(), (float) cell.getY(), (float) cell.getWidth(),
|
||||
(float) cell
|
||||
.getHeight());
|
||||
contentStream.stroke();
|
||||
}
|
||||
|
||||
+24
-3
@@ -1,5 +1,6 @@
|
||||
package com.iqser.red.service.redaction.v1.server;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
|
||||
|
||||
@@ -269,7 +270,7 @@ public class RedactionIntegrationTest {
|
||||
|
||||
System.out.println("redactionTest");
|
||||
long start = System.currentTimeMillis();
|
||||
ClassPathResource pdfFileResource = new ClassPathResource("files/new/Thiabendazole DAR Addendum for ED_April_2020.pdf");
|
||||
ClassPathResource pdfFileResource = new ClassPathResource("files/Fludioxonil/50 Fludioxonil_RAR_01_Volume_1_2018-02-21.pdf");
|
||||
|
||||
RedactionRequest request = RedactionRequest.builder()
|
||||
.document(IOUtils.toByteArray(pdfFileResource.getInputStream()))
|
||||
@@ -388,8 +389,7 @@ public class RedactionIntegrationTest {
|
||||
public void htmlTablesTest() throws IOException {
|
||||
|
||||
System.out.println("htmlTablesTest");
|
||||
ClassPathResource pdfFileResource = new ClassPathResource("files/Fludioxonil/51 " +
|
||||
"Fludioxonil_RAR_02_Volume_2_2018-02-21.pdf");
|
||||
ClassPathResource pdfFileResource = new ClassPathResource("files/Metolachlor/S-Metolachlor_RAR_02_Volume_2_2018-09-06.pdf");
|
||||
|
||||
RedactionRequest request = RedactionRequest.builder()
|
||||
.document(IOUtils.toByteArray(pdfFileResource.getInputStream()))
|
||||
@@ -422,6 +422,27 @@ public class RedactionIntegrationTest {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void phantomCellsDocumentTest() throws IOException {
|
||||
|
||||
ClassPathResource pdfFileResource = new ClassPathResource("files/Minimal Examples/Phantom Cells.pdf");
|
||||
|
||||
RedactionRequest request = RedactionRequest.builder()
|
||||
.document(IOUtils.toByteArray(pdfFileResource.getInputStream()))
|
||||
.build();
|
||||
request.setFlatRedaction(false);
|
||||
|
||||
RedactionResult result = redactionController.redact(request);
|
||||
|
||||
result.getRedactionLog().getRedactionLogEntry().forEach(entry -> {
|
||||
if(!entry.isHint()){
|
||||
assertThat(entry.getReason()).isEqualTo("Not redacted because row is not a vertebrate study");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static String loadFromClassPath(String path) {
|
||||
|
||||
URL resource = ResourceLoader.class.getClassLoader().getResource(path);
|
||||
|
||||
+24
-2
@@ -275,6 +275,27 @@ public class EntityRedactionServiceTest {
|
||||
assertThat(classifiedDoc.getEntities().get(1).stream().filter(entity -> entity.getMatchedRule() == 9).count()).isEqualTo(8);
|
||||
assertThat(classifiedDoc.getEntities().get(2).stream().filter(entity -> entity.getMatchedRule() == 9).count()).isEqualTo(4);
|
||||
}
|
||||
|
||||
pdfFileResource = new ClassPathResource("files/Minimal Examples/Header Propagation2.pdf");
|
||||
|
||||
dictionaryResponse = DictionaryResponse.builder()
|
||||
.entries(Arrays.asList("Tribolet, R.", "Muir, G.", "Kühne-Thu, H.", "Close, C."))
|
||||
.build();
|
||||
|
||||
when(dictionaryClient.getVersion()).thenReturn(DICTIONARY_VERSION.incrementAndGet());
|
||||
when(dictionaryClient.getDictionaryForType(NAME_CODE)).thenReturn(dictionaryResponse);
|
||||
addressResponse = DictionaryResponse.builder()
|
||||
.entries(Collections.singletonList("Novartis Crop Protection AG, Basel, Switzerland"))
|
||||
.build();
|
||||
when(dictionaryClient.getDictionaryForType(ADDRESS_CODE)).thenReturn(addressResponse);
|
||||
|
||||
try (PDDocument pdDocument = PDDocument.load(pdfFileResource.getInputStream())) {
|
||||
Document classifiedDoc = pdfSegmentationService.parseDocument(pdDocument);
|
||||
entityRedactionService.processDocument(classifiedDoc, null);
|
||||
assertThat(classifiedDoc.getEntities()).hasSize(1); // one page
|
||||
assertThat(classifiedDoc.getEntities().get(1).stream().filter(entity -> entity.getMatchedRule() == 9).count()).isEqualTo(3);
|
||||
assertThat(classifiedDoc.getEntities().get(1).stream().filter(entity -> entity.getMatchedRule() == 8).count()).isEqualTo(8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -312,7 +333,7 @@ public class EntityRedactionServiceTest {
|
||||
"global Section section\n" +
|
||||
"rule \"8: Not redacted because Vertebrate Study = N\"\n" +
|
||||
" when\n" +
|
||||
" Section(rowEquals(\"Vertebrate study Y/N\", \"N\"))\n" +
|
||||
" Section(rowEquals(\"Vertebrate study Y/N\", \"N\") || rowEquals(\"Vertebrate study Y/N\", \"No\"))\n" +
|
||||
" then\n" +
|
||||
" section.redactNot(\"name\", 8, \"Not redacted because row is not a vertebrate study\");\n" +
|
||||
" section.redactNot(\"address\", 8, \"Not redacted because row is not a vertebrate study\");\n" +
|
||||
@@ -320,7 +341,8 @@ public class EntityRedactionServiceTest {
|
||||
" end\n" +
|
||||
"rule \"9: Redact Authors and Addresses in Reference Table, if it is a Vertebrate study\"\n" +
|
||||
" when\n" +
|
||||
" Section(rowEquals(\"Vertebrate study Y/N\", \"Y\"))\n" +
|
||||
" Section(rowEquals(\"Vertebrate study Y/N\", \"Y\") || rowEquals(\"Vertebrate study Y/N\", " +
|
||||
"\"Yes\"))\n" +
|
||||
" then\n" +
|
||||
" section.redact(\"name\", 9, \"Redacted because row is a vertebrate study\");\n" +
|
||||
" section.redact(\"address\", 9, \"Redacted because row is a vertebrate study\");\n" +
|
||||
|
||||
+4
-4
@@ -99,9 +99,9 @@ rule "7: Redact contact information if Producer is found"
|
||||
|
||||
rule "8: Not redacted because Vertebrate Study = N"
|
||||
when
|
||||
Section(rowEquals("Vertebrate study Y/N", "N"))
|
||||
Section(rowEquals("Vertebrate study Y/N", "N") || rowEquals("Vertebrate study Y/N", "No"))
|
||||
then
|
||||
section.redactNot("name", 8, "Not redacted because row is not a vertebrate study");
|
||||
section.redactNotCell("Author(s)", 8, "name", "Not redacted because row is not a vertebrate study");
|
||||
section.redactNot("address", 8, "Not redacted because row is not a vertebrate study");
|
||||
section.highlightCell("Vertebrate study Y/N", 8, "hint_only");
|
||||
end
|
||||
@@ -118,9 +118,9 @@ rule "9: Redact if must redact entry is found"
|
||||
|
||||
rule "10: Redact Authors and Addresses in Reference Table if it is a Vertebrate study"
|
||||
when
|
||||
Section(rowEquals("Vertebrate study Y/N", "Y"))
|
||||
Section(rowEquals("Vertebrate study Y/N", "Y") || rowEquals("Vertebrate study Y/N", "Yes"))
|
||||
then
|
||||
section.redact("name", 10, "Redacted because row is a vertebrate study");
|
||||
section.redactCell("Author(s)", 10, "name", "Redacted because row is a vertebrate study");
|
||||
section.redact("address", 10, "Redacted because row is a vertebrate study");
|
||||
section.highlightCell("Vertebrate study Y/N", 10, "must_redact");
|
||||
end
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user