Compare commits

...

6 Commits

Author SHA1 Message Date
deiflaender
cccba91209 RED-5381: Fixed calculation of bodyTextFrame 2022-10-17 16:56:00 +02:00
deiflaender
c0e354d2d4 RED-5381: Fixed spit by ruling 2022-10-17 12:01:59 +02:00
deiflaender
dbc2e8e2f8 RED-5381: First steps to run all operations in java coord system 2022-10-14 16:48:01 +02:00
deiflaender
4616420e8f RED-5381: Further imporve 2022-10-14 16:47:52 +02:00
deiflaender
29f47fb17a RED-5381 Test 2 2022-10-14 16:47:25 +02:00
deiflaender
dafc140f11 RED-5381: Test1: Rotate in TextPositionSequence 2022-10-13 09:10:31 +02:00
48 changed files with 491 additions and 113 deletions

View File

@ -1,5 +1,8 @@
package com.iqser.red.service.redaction.v1.model; package com.iqser.red.service.redaction.v1.model;
import com.dslplatform.json.JsonAttribute;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -14,4 +17,115 @@ public class Rectangle {
private float height; private float height;
private int page; private int page;
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX1(int dir, float pageWidth, float pageHeight) {
if (dir == 90) {
return topLeft.getY();
}
else if (dir == 180) {
return topLeft.getX() + width;
}
else if (dir == 270) {
return topLeft.getY() + height;
}
else {
return topLeft.getX();
}
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX2(int dir, float pageWidth, float pageHeight) {
if (dir == 90) {
return topLeft.getY() + height;
}
else if (dir == 180) {
return topLeft.getX();
}
else if (dir == 270) {
return topLeft.getY() ;
}
else {
return topLeft.getX() + width;
}
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getY1(int dir, float pageWidth, float pageHeight) {
if (dir == 90 ) {
return topLeft.getX();
}
else if (dir == 180) {
return pageHeight - topLeft.getY() - height;
}
else if (dir == 270) {
return pageHeight - topLeft.getX() ;
}
else {
return topLeft.getY();
}
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getY2(int dir, float pageWidth, float pageHeight) {
if (dir == 90) {
return topLeft.getX() + width;
}
else if (dir == 180 ) {
return pageHeight - topLeft.getY();
}
else if (dir == 270 ) {
return pageHeight -topLeft.getX() - width;
}
else {
return topLeft.getY() + height;
}
}
} }

View File

@ -1,8 +1,8 @@
package com.iqser.red.service.redaction.v1.server.classification.model; package com.iqser.red.service.redaction.v1.server.classification.model;
import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.server.redaction.model.PdfImage; import com.iqser.red.service.redaction.v1.server.redaction.model.PdfImage;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer; import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Rectangle;
import lombok.Data; import lombok.Data;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -10,6 +10,8 @@ import lombok.RequiredArgsConstructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
@Data @Data
@RequiredArgsConstructor @RequiredArgsConstructor
public class Page { public class Page {
@ -32,6 +34,7 @@ public class Page {
private StringFrequencyCounter fontStyleCounter = new StringFrequencyCounter(); private StringFrequencyCounter fontStyleCounter = new StringFrequencyCounter();
private double cropBoxArea; private double cropBoxArea;
private PDRectangle cropBox;
public boolean isRotated() { public boolean isRotated() {

View File

@ -3,6 +3,7 @@ package com.iqser.red.service.redaction.v1.server.classification.model;
import com.dslplatform.json.CompiledJson; import com.dslplatform.json.CompiledJson;
import com.dslplatform.json.JsonAttribute; import com.dslplatform.json.JsonAttribute;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.iqser.red.service.redaction.v1.server.parsing.model.TextDirection;
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence; import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
import com.iqser.red.service.redaction.v1.server.redaction.utils.TextNormalizationUtilities; import com.iqser.red.service.redaction.v1.server.redaction.utils.TextNormalizationUtilities;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer; import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
@ -50,6 +51,115 @@ public class TextBlock extends AbstractTextContainer {
private String classification; private String classification;
private TextDirection getDir(){
return sequences.get(0).getDir();
}
private float getPageHeight(){
return sequences.get(0).getPageHeight();
}
private float getPageWidth(){
return sequences.get(0).getPageWidth();
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX1() {
if (getDir().getDegrees() == 90) {
return minY;
}
else if (getDir().getDegrees() == 180) {
return getPageWidth() - maxX;
}
else if (getDir().getDegrees() == 270) {
return getPageWidth() - maxY ;
}
else {
return minX;
}
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX2() {
if (getDir().getDegrees() == 90) {
return maxY;
}
else if (getDir().getDegrees() == 180) {
return getPageWidth() - minX;
}
else if (getDir().getDegrees() == 270) {
return getPageWidth() - minY ;
}
else {
return maxX;
}
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getY1() {
if (getDir().getDegrees() == 90 ) {
return minX;
}
else if (getDir().getDegrees() == 180) {
return maxY;
}
else if (getDir().getDegrees() == 270) {
return getPageHeight() - maxX;
}
else {
return getPageHeight() - maxY;
}
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getY2() {
if (getDir().getDegrees() == 90) {
return maxX;
}
else if (getDir().getDegrees() == 180 ) {
return minY;
}
else if (getDir().getDegrees() == 270 ) {
return getPageHeight() - minX;
}
else {
return getPageHeight() - minY;
}
}
public TextBlock(float minX, float maxX, float minY, float maxY, List<TextPositionSequence> sequences, int rotation) { public TextBlock(float minX, float maxX, float minY, float maxY, List<TextPositionSequence> sequences, int rotation) {
this.minX = minX; this.minX = minX;
this.maxX = maxX; this.maxX = maxX;

View File

@ -2,13 +2,18 @@ package com.iqser.red.service.redaction.v1.server.classification.service;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.iqser.red.service.redaction.v1.model.Point;
import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.server.classification.model.FloatFrequencyCounter; import com.iqser.red.service.redaction.v1.server.classification.model.FloatFrequencyCounter;
import com.iqser.red.service.redaction.v1.server.classification.model.Orientation; import com.iqser.red.service.redaction.v1.server.classification.model.Orientation;
import com.iqser.red.service.redaction.v1.server.classification.model.Page; import com.iqser.red.service.redaction.v1.server.classification.model.Page;
@ -18,7 +23,6 @@ import com.iqser.red.service.redaction.v1.server.classification.utils.PositionUt
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence; import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer; import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell; import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Rectangle;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling; import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table; import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
@ -30,9 +34,9 @@ public class BlockificationService {
public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines, public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines,
List<Ruling> verticalRulingLines) { List<Ruling> verticalRulingLines, int rotation, PDRectangle cropbox) {
sortRotatedSequences(textPositions); // sortRotatedSequences(textPositions);
List<TextPositionSequence> chunkWords = new ArrayList<>(); List<TextPositionSequence> chunkWords = new ArrayList<>();
List<AbstractTextContainer> chunkBlockList1 = new ArrayList<>(); List<AbstractTextContainer> chunkBlockList1 = new ArrayList<>();
@ -44,18 +48,20 @@ public class BlockificationService {
Float splitX1 = null; Float splitX1 = null;
for (TextPositionSequence word : textPositions) { for (TextPositionSequence word : textPositions) {
boolean lineSeparation = minY - word.getY2() > word.getHeight() * 1.25; boolean lineSeparation = word.getY1() - maxY > word.getHeight() * 1.25;
boolean startFromTop = word.getY1() > maxY + word.getHeight(); boolean startFromTop = prev != null && word.getY1() < prev.getY1() - prev.getTextHeight();
boolean splitByX = prev != null && maxX + 50 < word.getX1() && prev.getY1() == word.getY1(); boolean splitByX = prev != null && maxX + 50 < word.getX1() && prev.getY1() == word.getY1();
boolean xIsBeforeFirstX = prev != null && word.getX1() < minX;
boolean newLineAfterSplit = prev != null && word.getY1() != prev.getY1() && wasSplitted && splitX1 != word.getX1(); boolean newLineAfterSplit = prev != null && word.getY1() != prev.getY1() && wasSplitted && splitX1 != word.getX1();
boolean splittedByRuling = boolean splittedByRuling =
isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), verticalRulingLines) || isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), verticalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight()) ||
isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), horizontalRulingLines) isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), horizontalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight())
|| isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), horizontalRulingLines) || isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), horizontalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight())
|| isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), verticalRulingLines); || isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), verticalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight());
boolean splitByDir = prev != null && !prev.getDir().equals(word.getDir());
if (prev != null && (lineSeparation || startFromTop || splitByX || newLineAfterSplit || splittedByRuling)) { if (prev != null && (lineSeparation || startFromTop || xIsBeforeFirstX || splitByX || splitByDir || splittedByRuling)) {
Orientation prevOrientation = null; Orientation prevOrientation = null;
if (!chunkBlockList1.isEmpty()) { if (!chunkBlockList1.isEmpty()) {
@ -216,10 +222,11 @@ public class BlockificationService {
private boolean isSplittedByRuling(float previousX2, float previousY1, float currentX1, float currentY1, private boolean isSplittedByRuling(float previousX2, float previousY1, float currentX1, float currentY1,
List<Ruling> rulingLines) { List<Ruling> rulingLines, float rotation, float pageWidth, float pageHeight) {
for (Ruling ruling : rulingLines) { for (Ruling ruling : rulingLines) {
if (ruling.intersectsLine(previousX2, previousY1, currentX1, currentY1)) { var line = convertToJavaCoord(ruling, rotation, pageWidth, pageHeight);
if (line.intersectsLine(previousX2, previousY1, currentX1, currentY1)) {
return true; return true;
} }
} }
@ -227,6 +234,74 @@ public class BlockificationService {
} }
private Line2D.Float convertToJavaCoord(Ruling ruling, float rotation, float pageWidth, float pageHeight){
return new Line2D.Float(convertPoint(ruling.x1, ruling.y1, rotation, pageWidth, pageHeight), convertPoint(ruling.x2, ruling.y2, rotation, pageWidth, pageHeight));
}
private Point2D convertPoint(float x, float y, float rotation, float pageWidth, float pageHeight){
var xAdj = getXRot(x,y,rotation, pageWidth, pageHeight);
var yAdj = 0f;
if (rotation == 0 || rotation == 180)
{
yAdj = pageHeight - getYLowerLeftRot(x,y,rotation, pageWidth, pageHeight);
}
else
{
yAdj = pageWidth - getYLowerLeftRot(x,y,rotation, pageWidth, pageHeight);
}
return new Point2D.Float(xAdj, yAdj);
}
private float getXRot(float x, float y, float rotation, float pageWidth, float pageHeight)
{
if (rotation == 0)
{
return x;
}
else if (rotation == 90)
{
return y;
}
else if (rotation == 180)
{
return pageWidth - x;
}
else if (rotation == 270)
{
return pageHeight - y;
}
return 0;
}
private float getYLowerLeftRot(float x, float y, float rotation, float pageWidth, float pageHeight)
{
if (rotation == 0)
{
return y;
}
else if (rotation == 90)
{
return pageWidth - x;
}
else if (rotation == 180)
{
return pageHeight - y;
}
else if (rotation == 270)
{
return x;
}
return 0;
}
public Rectangle calculateBodyTextFrame(List<Page> pages, FloatFrequencyCounter documentFontSizeCounter, public Rectangle calculateBodyTextFrame(List<Page> pages, FloatFrequencyCounter documentFontSizeCounter,
boolean landscape) { boolean landscape) {
@ -257,19 +332,33 @@ public class BlockificationService {
if (documentFontSizeCounter.getMostPopular() != null) { if (documentFontSizeCounter.getMostPopular() != null) {
if (textBlock.getMostPopularWordFontSize() >= documentFontSizeCounter.getMostPopular()) { if (textBlock.getMostPopularWordFontSize() >= documentFontSizeCounter.getMostPopular()) {
if (textBlock.getMinX() < minX) { if(page.getRotation() == 90 || page.getRotation() == 270){
minX = textBlock.getMinX(); if (textBlock.getY1() < minX) {
minX = textBlock.getY1();
} }
if (textBlock.getMaxX() > maxX) { if (textBlock.getY2() > maxX) {
maxX = textBlock.getMaxX(); maxX = textBlock.getY2();
} }
if (textBlock.getMinY() < minY) { if (textBlock.getX1() < minY) {
minY = textBlock.getMinY(); minY = textBlock.getX1();
}
if (textBlock.getX2() > maxY) {
maxY = textBlock.getX2();
}
} else {
if (textBlock.getX1() < minX) {
minX = textBlock.getX1();
}
if (textBlock.getX2() > maxX) {
maxX = textBlock.getX2();
}
if (textBlock.getY1() < minY) {
minY = textBlock.getY1();
}
if (textBlock.getY2() > maxY) {
maxY = textBlock.getY2();
} }
if (textBlock.getMaxY() > maxY) {
maxY = textBlock.getMaxY();
} }
} }
} }
} }
@ -283,46 +372,46 @@ public class BlockificationService {
continue; continue;
} }
for (TextBlock textBlock : cell.getTextBlocks()) { for (TextBlock textBlock : cell.getTextBlocks()) {
if (textBlock.getMinX() < minX) { if(page.getRotation() == 90 || page.getRotation() == 270){
minX = textBlock.getMinX(); if (textBlock.getY1() < minX) {
minX = textBlock.getMinY();
} }
if (textBlock.getMaxX() > maxX) { if (textBlock.getY2() > maxX) {
maxX = textBlock.getMaxX(); maxX = textBlock.getY2();
} }
if (textBlock.getMinY() < minY) { if (textBlock.getX1() < minY) {
minY = textBlock.getMinY(); minY = textBlock.getX1();
} }
if (textBlock.getMaxY() > maxY) { if (textBlock.getX2() > maxY) {
maxY = textBlock.getMaxY(); maxY = textBlock.getX2();
}
} else {
if (textBlock.getX1() < minX) {
minX = textBlock.getX1();
}
if (textBlock.getX2() > maxX) {
maxX = textBlock.getX2();
}
if (textBlock.getY1() < minY) {
minY = textBlock.getY1();
}
if (textBlock.getY2() > maxY) {
maxY = textBlock.getY2();
} }
} }
} }
} }
} }
} }
}
System.out.println("Page: " + page.getPageNumber() + " Landscape: " + page.isLandscape()+ " MinX: " + minX + " MaxX: " + maxX + " MinY: " +minY + " MaxY: " + maxY);
} }
return new Rectangle(minY, minX, maxX - minX, maxY - minY); return new Rectangle(new Point(minX, minY), maxX - minX, maxY - minY, 0);
} }
private void sortRotatedSequences(List<TextPositionSequence> sequences) {
List<TextPositionSequence> rotatedWords = new ArrayList<>();
Iterator<TextPositionSequence> itty = sequences.iterator();
while (itty.hasNext()) {
var pos = itty.next();
if (pos.getTextPositions().get(0).getDir() == 270) {
rotatedWords.add(pos);
itty.remove();
}
}
if (!rotatedWords.isEmpty() && !sequences.isEmpty()) {
rotatedWords.sort(Comparator.comparing(TextPositionSequence::getX1));
}
sequences.addAll(rotatedWords);
}
private double round(float value, int decimalPoints) { private double round(float value, int decimalPoints) {

View File

@ -1,11 +1,12 @@
package com.iqser.red.service.redaction.v1.server.classification.service; package com.iqser.red.service.redaction.v1.server.classification.service;
import com.iqser.red.service.redaction.v1.model.Point;
import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.server.classification.model.Document; import com.iqser.red.service.redaction.v1.server.classification.model.Document;
import com.iqser.red.service.redaction.v1.server.classification.model.Page; import com.iqser.red.service.redaction.v1.server.classification.model.Page;
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock; import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
import com.iqser.red.service.redaction.v1.server.classification.utils.PositionUtils; import com.iqser.red.service.redaction.v1.server.classification.utils.PositionUtils;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer; import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Rectangle;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -32,7 +33,19 @@ public class ClassificationService {
for (Page page : document.getPages()) { for (Page page : document.getPages()) {
Rectangle btf = page.isLandscape() ? landscapeBodyTextFrame : bodyTextFrame; Rectangle btf = page.isLandscape() ? landscapeBodyTextFrame : bodyTextFrame;
page.setBodyTextFrame(btf);
var width = btf.getX2(page.getRotation(), page.getCropBox().getWidth(), page.getCropBox().getHeight()) - btf.getX1(page.getRotation(), page.getCropBox().getWidth(), page.getCropBox().getHeight());
var height = btf.getY2(page.getRotation(), page.getCropBox().getWidth(), page.getCropBox().getHeight()) - btf.getY1(page.getRotation(), page.getCropBox().getWidth(), page.getCropBox().getHeight());
var x1= btf.getX1(page.getRotation(), page.getCropBox().getWidth(), page.getCropBox().getHeight());
var y1 = btf.getY1(page.getRotation(), page.getCropBox().getWidth(), page.getCropBox().getHeight());
page.setBodyTextFrame(new Rectangle(new Point(x1, y1), width, height,0));
classifyPage(btf, page, document, headlineFontSizes); classifyPage(btf, page, document, headlineFontSizes);
} }
} }
@ -51,6 +64,8 @@ public class ClassificationService {
public void classifyBlock(TextBlock textBlock, Rectangle bodyTextFrame, Page page, Document document, public void classifyBlock(TextBlock textBlock, Rectangle bodyTextFrame, Page page, Document document,
List<Float> headlineFontSizes) { List<Float> headlineFontSizes) {
System.out.println("Page: " + page.getPageNumber() + " rotation " + page.getRotation() +" B " + textBlock.getSequences().get(0).getDir());
if (document.getFontSizeCounter().getMostPopular() == null) { if (document.getFontSizeCounter().getMostPopular() == null) {
textBlock.setClassification("Other"); textBlock.setClassification("Other");
return; return;

View File

@ -1,7 +1,7 @@
package com.iqser.red.service.redaction.v1.server.classification.utils; package com.iqser.red.service.redaction.v1.server.classification.utils;
import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock; import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Rectangle;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
@UtilityClass @UtilityClass
@ -19,10 +19,10 @@ public class PositionUtils {
double threshold = textBlock.getMostPopularWordHeight() * 3; double threshold = textBlock.getMostPopularWordHeight() * 3;
if (textBlock.getMinX() + threshold > btf.getX() && if (textBlock.getMinX() + threshold > btf.getTopLeft().getX() &&
textBlock.getMaxX() - threshold < btf.getX() + btf.getWidth() && textBlock.getMaxX() - threshold < btf.getTopLeft().getX() + btf.getWidth() &&
textBlock.getMinY() + threshold > btf.getY() && textBlock.getMinY() + threshold > btf.getTopLeft().getY() &&
textBlock.getMaxY() - threshold < btf.getY() + btf.getHeight()) { textBlock.getMaxY() - threshold < btf.getTopLeft().getY() + btf.getHeight()) {
return true; return true;
} else { } else {
return false; return false;
@ -37,10 +37,10 @@ public class PositionUtils {
return false; return false;
} }
if (rotated && textBlock.getMinX() < btf.getX()) { if (rotated && textBlock.getMinX() < btf.getTopLeft().getX()) {
// Its very strange, P{0,0} is on top left in this case, instead of lower left. // Its very strange, P{0,0} is on top left in this case, instead of lower left.
return true; return true;
} else if (!rotated && textBlock.getMinY() > btf.getY() + btf.getHeight()) { } else if (!rotated && textBlock.getMinY() > btf.getTopLeft().getY() + btf.getHeight()) {
return true; return true;
} else { } else {
return false; return false;
@ -57,7 +57,7 @@ public class PositionUtils {
return false; return false;
} }
if (textBlock.getMaxY() < btf.getY()) { if (textBlock.getMaxY() < btf.getTopLeft().getY()) {
return true; return true;
} else { } else {
return false; return false;
@ -74,7 +74,7 @@ public class PositionUtils {
return false; return false;
} }
if (textBlock.getMinY() < btf.getY()) { if (textBlock.getMinY() < btf.getTopLeft().getY()) {
return true; return true;
} else { } else {
return false; return false;

View File

@ -147,29 +147,6 @@ public class TextPositionSequence implements CharSequence {
} }
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX1() {
if (rotation == 90) {
return textPositions.get(0).getYDirAdj() - getTextHeight();
} else {
return textPositions.get(0).getXDirAdj();
}
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX2() {
if (rotation == 90) {
return textPositions.get(0).getYDirAdj();
} else {
return textPositions.get(textPositions.size() - 1).getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidthDirAdj() + HEIGHT_PADDING;
}
}
@JsonIgnore @JsonIgnore
@JsonAttribute(ignore = true) @JsonAttribute(ignore = true)
@ -179,15 +156,40 @@ public class TextPositionSequence implements CharSequence {
} }
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX1() {
return textPositions.get(0).getXDirAdj();
}
@JsonIgnore
@JsonAttribute(ignore = true)
public float getX2() {
return textPositions.get(textPositions.size() - 1).getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidthDirAdj() + HEIGHT_PADDING;
}
@JsonIgnore @JsonIgnore
@JsonAttribute(ignore = true) @JsonAttribute(ignore = true)
public float getY1() { public float getY1() {
if (rotation == 90) {
return textPositions.get(0).getXDirAdj();
} else {
return pageHeight - textPositions.get(0).getYDirAdj();
}
return textPositions.get(0).getYDirAdj() - getTextHeight();
} }
@ -195,14 +197,15 @@ public class TextPositionSequence implements CharSequence {
@JsonAttribute(ignore = true) @JsonAttribute(ignore = true)
public float getY2() { public float getY2() {
if (rotation == 90) {
return textPositions.get(textPositions.size() - 1).getXDirAdj() + getTextHeight() - HEIGHT_PADDING;
} else {
return pageHeight - textPositions.get(0).getYDirAdj() + getTextHeight(); return textPositions.get(0).getYDirAdj();
}
} }
@JsonIgnore @JsonIgnore
@JsonAttribute(ignore = true) @JsonAttribute(ignore = true)
public float getTextHeight() { public float getTextHeight() {

View File

@ -99,21 +99,23 @@ public class PdfSegmentationService {
stripper.getText(pdDocument); stripper.getText(pdDocument);
PDRectangle pdr = pdPage.getMediaBox(); PDRectangle pdr = pdPage.getMediaBox();
boolean isLandscape = pdr.getWidth() > pdr.getHeight();
int rotation = pdPage.getRotation(); int rotation = pdPage.getRotation();
boolean isRotated = rotation != 0 && rotation != 360; boolean isLandscape = pdr.getWidth() > pdr.getHeight() && (rotation == 0 || rotation == 180) ||
pdr.getHeight() > pdr.getWidth() && (rotation == 90 || rotation == 270);
CleanRulings cleanRulings = rulingCleaningService.getCleanRulings(pdfTableCells.get(pageNumber), stripper.getRulings(), stripper.getMinCharWidth(), stripper.getMaxCharHeight());
Page page = blockificationService.blockify(stripper.getTextPositionSequences(), cleanRulings.getHorizontal(), cleanRulings.getVertical());
PDRectangle cropbox = pdPage.getCropBox(); PDRectangle cropbox = pdPage.getCropBox();
CleanRulings cleanRulings = rulingCleaningService.getCleanRulings(pdfTableCells.get(pageNumber), stripper.getRulings(), stripper.getMinCharWidth(), stripper.getMaxCharHeight());
Page page = blockificationService.blockify(stripper.getTextPositionSequences(), cleanRulings.getHorizontal(), cleanRulings.getVertical(), rotation, cropbox);
float cropboxArea = cropbox.getHeight() * cropbox.getWidth(); float cropboxArea = cropbox.getHeight() * cropbox.getWidth();
page.setCropBoxArea(cropboxArea); page.setCropBoxArea(cropboxArea);
page.setRotation(rotation); page.setRotation(rotation);
page.setLandscape(isLandscape || isRotated); page.setLandscape(isLandscape);
page.setPageNumber(pageNumber); page.setPageNumber(pageNumber);
page.setCropBox(cropbox);
tableExtractionService.extractTables(cleanRulings, page); tableExtractionService.extractTables(cleanRulings, page);
buildPageStatistics(page); buildPageStatistics(page);

View File

@ -4,6 +4,8 @@ import com.dslplatform.json.JsonAttribute;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.iqser.red.service.redaction.v1.model.Rectangle; import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.server.classification.model.Orientation; import com.iqser.red.service.redaction.v1.server.classification.model.Orientation;
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -31,6 +33,12 @@ public abstract class AbstractTextContainer {
public abstract String getText(); public abstract String getText();
public boolean containsBlock(TextBlock other) {
return this.minX <= other.getX1() && this.maxX >= other.getX2() && this.minY >= other.getY1() && this.maxY <= other.getY2();
}
public boolean contains(AbstractTextContainer other) { public boolean contains(AbstractTextContainer other) {
return this.minX <= other.minX && this.maxX >= other.maxX && this.minY >= other.minY && this.maxY <= other.maxY; return this.minX <= other.minX && this.maxX >= other.maxX && this.minY >= other.minY && this.maxY <= other.maxY;
} }

View File

@ -31,6 +31,10 @@ public class Rectangle extends Rectangle2D.Float {
} }
}; };
public Rectangle() { public Rectangle() {
super(); super();
} }

View File

@ -61,7 +61,7 @@ public class TableExtractionService {
for (AbstractTextContainer abstractTextContainer : page.getTextBlocks()) { for (AbstractTextContainer abstractTextContainer : page.getTextBlocks()) {
TextBlock textBlock = (TextBlock) abstractTextContainer; TextBlock textBlock = (TextBlock) abstractTextContainer;
for (Cell cell : cells) { for (Cell cell : cells) {
if (cell.intersects(textBlock.getMinX(), textBlock.getMinY(), textBlock.getWidth(), textBlock.getHeight())) { if (cell.intersects(textBlock.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1())) {
cell.addTextBlock(textBlock); cell.addTextBlock(textBlock);
toBeRemoved.add(textBlock); toBeRemoved.add(textBlock);
break; break;
@ -94,7 +94,7 @@ public class TableExtractionService {
Iterator<AbstractTextContainer> itty = page.getTextBlocks().iterator(); Iterator<AbstractTextContainer> itty = page.getTextBlocks().iterator();
while (itty.hasNext()) { while (itty.hasNext()) {
AbstractTextContainer textBlock = itty.next(); AbstractTextContainer textBlock = itty.next();
if (table.contains(textBlock) && position == -1) { if (textBlock instanceof TextBlock ? table.containsBlock((TextBlock) textBlock) : table.contains(textBlock) && position == -1) {
position = page.getTextBlocks().indexOf(textBlock); position = page.getTextBlocks().indexOf(textBlock);
} }
} }

View File

@ -79,7 +79,13 @@ public class PdfVisualisationService {
} }
contentStream.setStrokingColor(Color.YELLOW); contentStream.setStrokingColor(Color.YELLOW);
contentStream.addRect((float) analyzedPage.getBodyTextFrame().getX(), (float) analyzedPage.getBodyTextFrame().getY(), (float) analyzedPage.getBodyTextFrame().getWidth(), (float) analyzedPage.getBodyTextFrame().getHeight()); // var width = analyzedPage.getBodyTextFrame().getX2(pdPage.getRotation(), pdPage.getCropBox().getWidth(), pdPage.getCropBox().getHeight()) - analyzedPage.getBodyTextFrame().getX1(pdPage.getRotation(), pdPage.getCropBox().getWidth(), pdPage.getCropBox().getHeight());
// var height = analyzedPage.getBodyTextFrame().getY2(pdPage.getRotation(), pdPage.getCropBox().getWidth(), pdPage.getCropBox().getHeight()) - analyzedPage.getBodyTextFrame().getY1(pdPage.getRotation(), pdPage.getCropBox().getWidth(), pdPage.getCropBox().getHeight());
//
// contentStream.addRect(analyzedPage.getBodyTextFrame().getX1(pdPage.getRotation(), pdPage.getCropBox().getWidth(), pdPage.getCropBox().getHeight()), analyzedPage.getBodyTextFrame().getY1(pdPage.getRotation(), pdPage.getCropBox().getWidth(), pdPage.getCropBox().getHeight()), width, height);
contentStream.addRect(analyzedPage.getBodyTextFrame().getTopLeft().getX(), analyzedPage.getBodyTextFrame().getTopLeft().getY(), analyzedPage.getBodyTextFrame().getWidth(), analyzedPage.getBodyTextFrame().getHeight());
contentStream.stroke(); contentStream.stroke();
contentStream.close(); contentStream.close();
@ -91,20 +97,44 @@ public class PdfVisualisationService {
contentStream.setStrokingColor(Color.RED); contentStream.setStrokingColor(Color.RED);
contentStream.addRect(textBlock.getMinX(), textBlock.getMinY(), textBlock.getWidth(), textBlock.getHeight()); contentStream.addRect(textBlock.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1());
contentStream.stroke(); contentStream.stroke();
if (textBlock.getClassification() != null) { if (textBlock.getClassification() != null) {
contentStream.beginText(); contentStream.beginText();
contentStream.setNonStrokingColor(Color.BLUE); contentStream.setNonStrokingColor(Color.BLUE);
contentStream.setFont(PDType1Font.TIMES_ROMAN, 12f); contentStream.setFont(PDType1Font.TIMES_ROMAN, 9f);
contentStream.newLineAtOffset(textBlock.getMinX(), textBlock.getMaxY()); contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY2() + 2);
contentStream.showText(textBlock.getClassification() + textBlock.getOrientation() + "-->" + textBlock.getSequences().get(0).getDir());
contentStream.showText(textBlock.getClassification() + textBlock.getOrientation());
contentStream.endText(); contentStream.endText();
// contentStream.setNonStrokingColor(Color.BLUE);
// contentStream.setFont(PDType1Font.TIMES_ROMAN, 2f);
//
//
//
// contentStream.beginText();
// contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY1());
// contentStream.showText("MinX,MinY(" + textBlock.getX1() + "," + textBlock.getY1() + ")");
// contentStream.endText();
// contentStream.beginText();
// contentStream.newLineAtOffset(textBlock.getX2(), textBlock.getY1());
// contentStream.showText("MaxX,MinY(" + textBlock.getX2() + "," + textBlock.getY1() + ")");
// contentStream.endText();
// contentStream.beginText();
// contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY2());
// contentStream.showText("MinX,MaxY(" + textBlock.getX1() + "," + textBlock.getY2() + ")");
// contentStream.endText();
// contentStream.beginText();
// contentStream.newLineAtOffset(textBlock.getX2(), textBlock.getY2());
// contentStream.showText("MaxX,MaxY(" + textBlock.getX2() + "," + textBlock.getY2() + ")");
//
//
// contentStream.endText();
} }
} }
@ -120,7 +150,7 @@ public class PdfVisualisationService {
contentStream.setStrokingColor(Color.GREEN); contentStream.setStrokingColor(Color.GREEN);
for (TextBlock textBlock : cell.getTextBlocks()) { for (TextBlock textBlock : cell.getTextBlocks()) {
contentStream.addRect(textBlock.getMinX(), textBlock.getMinY(), textBlock.getWidth(), textBlock.getHeight()); contentStream.addRect(textBlock.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1());
contentStream.stroke(); contentStream.stroke();
} }
} }

View File

@ -1168,7 +1168,7 @@ public class RedactionIntegrationTest {
System.out.println("classificationTest"); System.out.println("classificationTest");
AnalyzeRequest request = prepareStorage("files/Metolachlor/S-Metolachlor_RAR_01_Volume_1_2018-09-06.pdf"); AnalyzeRequest request = prepareStorage("files/RSS/09 - CGA100251 - Acute Oral Toxicity (Up and Down Procedure) - Rat.pdf");
RedactionRequest redactionRequest = RedactionRequest.builder() RedactionRequest redactionRequest = RedactionRequest.builder()
.dossierId(request.getDossierId()) .dossierId(request.getDossierId())