RED-5381: Cleanup
This commit is contained in:
parent
95bc90fa71
commit
dd3edbde8c
@ -34,8 +34,8 @@ public class Page {
|
|||||||
private StringFrequencyCounter fontCounter = new StringFrequencyCounter();
|
private StringFrequencyCounter fontCounter = new StringFrequencyCounter();
|
||||||
private StringFrequencyCounter fontStyleCounter = new StringFrequencyCounter();
|
private StringFrequencyCounter fontStyleCounter = new StringFrequencyCounter();
|
||||||
|
|
||||||
private double cropBoxArea;
|
private float pageWidth;
|
||||||
private PDRectangle cropBox;
|
private float pageHeight;
|
||||||
|
|
||||||
|
|
||||||
public boolean isRotated() {
|
public boolean isRotated() {
|
||||||
|
|||||||
@ -51,7 +51,7 @@ public class TextBlock extends AbstractTextContainer {
|
|||||||
private String classification;
|
private String classification;
|
||||||
|
|
||||||
|
|
||||||
private TextDirection getDir() {
|
public TextDirection getDir() {
|
||||||
|
|
||||||
return sequences.get(0).getDir();
|
return sequences.get(0).getDir();
|
||||||
}
|
}
|
||||||
@ -69,9 +69,19 @@ public class TextBlock extends AbstractTextContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minX value in pdf coordinate system.
|
||||||
|
* Note: This needs to use Pdf Coordinate System where {0,0} rotated with the page rotation.
|
||||||
|
* 0 -> LowerLeft
|
||||||
|
* 90 -> UpperLeft
|
||||||
|
* 180 -> UpperRight
|
||||||
|
* 270 -> LowerRight
|
||||||
|
*
|
||||||
|
* @return the minX value in pdf coordinate system
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getX1() {
|
public float getPdfMinX() {
|
||||||
|
|
||||||
if (getDir().getDegrees() == 90) {
|
if (getDir().getDegrees() == 90) {
|
||||||
return minY;
|
return minY;
|
||||||
@ -86,10 +96,19 @@ public class TextBlock extends AbstractTextContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maxX value in pdf coordinate system.
|
||||||
|
* Note: This needs to use Pdf Coordinate System where {0,0} rotated with the page rotation.
|
||||||
|
* 0 -> LowerLeft
|
||||||
|
* 90 -> UpperLeft
|
||||||
|
* 180 -> UpperRight
|
||||||
|
* 270 -> LowerRight
|
||||||
|
*
|
||||||
|
* @return the maxX value in pdf coordinate system
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getX2() {
|
public float getPdfMaxX() {
|
||||||
|
|
||||||
if (getDir().getDegrees() == 90) {
|
if (getDir().getDegrees() == 90) {
|
||||||
return maxY;
|
return maxY;
|
||||||
@ -104,9 +123,19 @@ public class TextBlock extends AbstractTextContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minY value in pdf coordinate system.
|
||||||
|
* Note: This needs to use Pdf Coordinate System where {0,0} rotated with the page rotation.
|
||||||
|
* 0 -> LowerLeft
|
||||||
|
* 90 -> UpperLeft
|
||||||
|
* 180 -> UpperRight
|
||||||
|
* 270 -> LowerRight
|
||||||
|
*
|
||||||
|
* @return the minY value in pdf coordinate system
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getY1() {
|
public float getPdfMinY() {
|
||||||
|
|
||||||
if (getDir().getDegrees() == 90) {
|
if (getDir().getDegrees() == 90) {
|
||||||
return minX;
|
return minX;
|
||||||
@ -122,9 +151,19 @@ public class TextBlock extends AbstractTextContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maxY value in pdf coordinate system.
|
||||||
|
* Note: This needs to use Pdf Coordinate System where {0,0} rotated with the page rotation.
|
||||||
|
* 0 -> LowerLeft
|
||||||
|
* 90 -> UpperLeft
|
||||||
|
* 180 -> UpperRight
|
||||||
|
* 270 -> LowerRight
|
||||||
|
*
|
||||||
|
* @return the maxY value in pdf coordinate system
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getY2() {
|
public float getPdfMaxY() {
|
||||||
|
|
||||||
if (getDir().getDegrees() == 90) {
|
if (getDir().getDegrees() == 90) {
|
||||||
return maxX;
|
return maxX;
|
||||||
@ -186,17 +225,17 @@ public class TextBlock extends AbstractTextContainer {
|
|||||||
|
|
||||||
public void add(TextPositionSequence r) {
|
public void add(TextPositionSequence r) {
|
||||||
|
|
||||||
if (r.getX1() < minX) {
|
if (r.getMinXDirAdj() < minX) {
|
||||||
minX = r.getX1();
|
minX = r.getMinXDirAdj();
|
||||||
}
|
}
|
||||||
if (r.getX2() > maxX) {
|
if (r.getMaxXDirAdj() > maxX) {
|
||||||
maxX = r.getX2();
|
maxX = r.getMaxXDirAdj();
|
||||||
}
|
}
|
||||||
if (r.getY1() < minY) {
|
if (r.getMinYDirAdj() < minY) {
|
||||||
minY = r.getY1();
|
minY = r.getMinYDirAdj();
|
||||||
}
|
}
|
||||||
if (r.getY2() > maxY) {
|
if (r.getMaxYDirAdj() > maxY) {
|
||||||
maxY = r.getY2();
|
maxY = r.getMaxYDirAdj();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +290,7 @@ public class TextBlock extends AbstractTextContainer {
|
|||||||
TextPositionSequence previous = null;
|
TextPositionSequence previous = null;
|
||||||
for (TextPositionSequence word : sequences) {
|
for (TextPositionSequence word : sequences) {
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
if (Math.abs(previous.getRotationAdjustedY() - word.getRotationAdjustedY()) > word.getTextHeight()) {
|
if (Math.abs(previous.getMaxYDirAdj() - word.getMaxYDirAdj()) > word.getTextHeight()) {
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
} else {
|
} else {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
|
|||||||
@ -7,23 +7,17 @@ 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;
|
||||||
import com.iqser.red.service.redaction.v1.server.classification.model.StringFrequencyCounter;
|
import com.iqser.red.service.redaction.v1.server.classification.model.StringFrequencyCounter;
|
||||||
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.CoordSystemHelper;
|
import com.iqser.red.service.redaction.v1.server.classification.utils.RulingTextDirAdjustUtil;
|
||||||
import com.iqser.red.service.redaction.v1.server.classification.utils.PositionUtils;
|
|
||||||
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.Ruling;
|
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling;
|
||||||
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@ -32,9 +26,16 @@ public class BlockificationService {
|
|||||||
static final float THRESHOLD = 1f;
|
static final float THRESHOLD = 1f;
|
||||||
|
|
||||||
|
|
||||||
public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines, List<Ruling> verticalRulingLines, int rotation, PDRectangle cropbox) {
|
/**
|
||||||
|
* This method is building blocks by expanding the minX/maxX and minY/maxY value on each word that is not split by the conditions.
|
||||||
// sortRotatedSequences(textPositions);
|
* This method must use text direction adjusted postions (DirAdj). Where {0,0} is on the upper left. Never try to change this!
|
||||||
|
* Rulings (Table lines) must be adjusted to the text directions as well, when checking if a block is split by a ruling.
|
||||||
|
* @param textPositions The words of a page.
|
||||||
|
* @param horizontalRulingLines Horizontal table lines.
|
||||||
|
* @param verticalRulingLines Vertical table lines.
|
||||||
|
* @return Page object that contains the Textblock and text statistics.
|
||||||
|
*/
|
||||||
|
public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines, List<Ruling> verticalRulingLines) {
|
||||||
|
|
||||||
List<TextPositionSequence> chunkWords = new ArrayList<>();
|
List<TextPositionSequence> chunkWords = new ArrayList<>();
|
||||||
List<AbstractTextContainer> chunkBlockList1 = new ArrayList<>();
|
List<AbstractTextContainer> chunkBlockList1 = new ArrayList<>();
|
||||||
@ -46,45 +47,15 @@ public class BlockificationService {
|
|||||||
Float splitX1 = null;
|
Float splitX1 = null;
|
||||||
for (TextPositionSequence word : textPositions) {
|
for (TextPositionSequence word : textPositions) {
|
||||||
|
|
||||||
boolean lineSeparation = word.getY1() - maxY > word.getHeight() * 1.25;
|
boolean lineSeparation = word.getMinYDirAdj() - maxY > word.getHeight() * 1.25;
|
||||||
boolean startFromTop = prev != null && word.getY1() < prev.getY1() - prev.getTextHeight();
|
boolean startFromTop = prev != null && word.getMinYDirAdj() < prev.getMinYDirAdj() - prev.getTextHeight();
|
||||||
boolean splitByX = prev != null && maxX + 50 < word.getX1() && prev.getY1() == word.getY1();
|
boolean splitByX = prev != null && maxX + 50 < word.getMinXDirAdj() && prev.getMinYDirAdj() == word.getMinYDirAdj();
|
||||||
boolean xIsBeforeFirstX = prev != null && word.getX1() < minX;
|
boolean xIsBeforeFirstX = prev != null && word.getMinXDirAdj() < minX;
|
||||||
boolean newLineAfterSplit = prev != null && word.getY1() != prev.getY1() && wasSplitted && splitX1 != word.getX1();
|
boolean newLineAfterSplit = prev != null && word.getMinYDirAdj() != prev.getMinYDirAdj() && wasSplitted && splitX1 != word.getMinXDirAdj();
|
||||||
boolean splittedByRuling = isSplittedByRuling(maxX,
|
boolean isSpitByRuling = isSpitByRuling(minX, minY, maxX, maxY, word, horizontalRulingLines, verticalRulingLines);
|
||||||
minY,
|
|
||||||
word.getX1(),
|
|
||||||
word.getY1(),
|
|
||||||
verticalRulingLines,
|
|
||||||
word.getDir().getDegrees(),
|
|
||||||
cropbox.getWidth(),
|
|
||||||
cropbox.getHeight()) || isSplittedByRuling(minX,
|
|
||||||
minY,
|
|
||||||
word.getX1(),
|
|
||||||
word.getY2(),
|
|
||||||
horizontalRulingLines,
|
|
||||||
word.getDir().getDegrees(),
|
|
||||||
cropbox.getWidth(),
|
|
||||||
cropbox.getHeight())
|
|
||||||
|
|
||||||
|| isSplittedByRuling(maxX,
|
|
||||||
minY,
|
|
||||||
word.getX1(),
|
|
||||||
word.getY1(),
|
|
||||||
horizontalRulingLines,
|
|
||||||
word.getDir().getDegrees(),
|
|
||||||
cropbox.getWidth(),
|
|
||||||
cropbox.getHeight()) || isSplittedByRuling(minX,
|
|
||||||
minY,
|
|
||||||
word.getX1(),
|
|
||||||
word.getY2(),
|
|
||||||
verticalRulingLines,
|
|
||||||
word.getDir().getDegrees(),
|
|
||||||
cropbox.getWidth(),
|
|
||||||
cropbox.getHeight());
|
|
||||||
boolean splitByDir = prev != null && !prev.getDir().equals(word.getDir());
|
boolean splitByDir = prev != null && !prev.getDir().equals(word.getDir());
|
||||||
|
|
||||||
if (prev != null && (lineSeparation || startFromTop || splitByX || splitByDir || splittedByRuling)) {
|
if (prev != null && (lineSeparation || startFromTop || splitByX || splitByDir || isSpitByRuling)) {
|
||||||
|
|
||||||
Orientation prevOrientation = null;
|
Orientation prevOrientation = null;
|
||||||
if (!chunkBlockList1.isEmpty()) {
|
if (!chunkBlockList1.isEmpty()) {
|
||||||
@ -95,15 +66,15 @@ public class BlockificationService {
|
|||||||
chunkBlockList1.add(cb1);
|
chunkBlockList1.add(cb1);
|
||||||
chunkWords = new ArrayList<>();
|
chunkWords = new ArrayList<>();
|
||||||
|
|
||||||
if (splitByX && !splittedByRuling) {
|
if (splitByX && !isSpitByRuling) {
|
||||||
wasSplitted = true;
|
wasSplitted = true;
|
||||||
cb1.setOrientation(Orientation.LEFT);
|
cb1.setOrientation(Orientation.LEFT);
|
||||||
splitX1 = word.getX1();
|
splitX1 = word.getMinXDirAdj();
|
||||||
} else if (newLineAfterSplit && !splittedByRuling) {
|
} else if (newLineAfterSplit && !isSpitByRuling) {
|
||||||
wasSplitted = false;
|
wasSplitted = false;
|
||||||
cb1.setOrientation(Orientation.RIGHT);
|
cb1.setOrientation(Orientation.RIGHT);
|
||||||
splitX1 = null;
|
splitX1 = null;
|
||||||
} else if (prevOrientation != null && prevOrientation.equals(Orientation.RIGHT) && (lineSeparation || !startFromTop || !splitByX || !newLineAfterSplit || !splittedByRuling)) {
|
} else if (prevOrientation != null && prevOrientation.equals(Orientation.RIGHT) && (lineSeparation || !startFromTop || !splitByX || !newLineAfterSplit || !isSpitByRuling)) {
|
||||||
cb1.setOrientation(Orientation.LEFT);
|
cb1.setOrientation(Orientation.LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,17 +88,17 @@ public class BlockificationService {
|
|||||||
chunkWords.add(word);
|
chunkWords.add(word);
|
||||||
|
|
||||||
prev = word;
|
prev = word;
|
||||||
if (word.getX1() < minX) {
|
if (word.getMinXDirAdj() < minX) {
|
||||||
minX = word.getX1();
|
minX = word.getMinXDirAdj();
|
||||||
}
|
}
|
||||||
if (word.getX2() > maxX) {
|
if (word.getMaxXDirAdj() > maxX) {
|
||||||
maxX = word.getX2();
|
maxX = word.getMaxXDirAdj();
|
||||||
}
|
}
|
||||||
if (word.getY1() < minY) {
|
if (word.getMinYDirAdj() < minY) {
|
||||||
minY = word.getY1();
|
minY = word.getMinYDirAdj();
|
||||||
}
|
}
|
||||||
if (word.getY2() > maxY) {
|
if (word.getMaxYDirAdj() > maxY) {
|
||||||
maxY = word.getY2();
|
maxY = word.getMaxYDirAdj();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +182,7 @@ public class BlockificationService {
|
|||||||
styleFrequencyCounter.add(wordBlock.getFontStyle());
|
styleFrequencyCounter.add(wordBlock.getFontStyle());
|
||||||
|
|
||||||
if (textBlock == null) {
|
if (textBlock == null) {
|
||||||
textBlock = new TextBlock(wordBlock.getX1(), wordBlock.getX2(), wordBlock.getY1(), wordBlock.getY2(), wordBlockList, wordBlock.getRotation());
|
textBlock = new TextBlock(wordBlock.getMinXDirAdj(), wordBlock.getMaxXDirAdj(), wordBlock.getMinYDirAdj(), wordBlock.getMaxYDirAdj(), wordBlockList, wordBlock.getRotation());
|
||||||
} else {
|
} else {
|
||||||
TextBlock spatialEntity = textBlock.union(wordBlock);
|
TextBlock spatialEntity = textBlock.union(wordBlock);
|
||||||
textBlock.resize(spatialEntity.getMinX(), spatialEntity.getMinY(), spatialEntity.getWidth(), spatialEntity.getHeight());
|
textBlock.resize(spatialEntity.getMinX(), spatialEntity.getMinY(), spatialEntity.getWidth(), spatialEntity.getHeight());
|
||||||
@ -227,24 +198,57 @@ public class BlockificationService {
|
|||||||
textBlock.setHighestFontSize(fontSizeFrequencyCounter.getHighest());
|
textBlock.setHighestFontSize(fontSizeFrequencyCounter.getHighest());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textBlock != null && textBlock.getSequences() != null && textBlock.getSequences().stream().map(t -> round(t.getY1(), 3)).collect(toSet()).size() == 1) {
|
if (textBlock != null && textBlock.getSequences() != null && textBlock.getSequences().stream().map(t -> round(t.getMinYDirAdj(), 3)).collect(toSet()).size() == 1) {
|
||||||
textBlock.getSequences().sort(Comparator.comparing(TextPositionSequence::getX1));
|
textBlock.getSequences().sort(Comparator.comparing(TextPositionSequence::getMinXDirAdj));
|
||||||
}
|
}
|
||||||
return textBlock;
|
return textBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean isSplittedByRuling(float previousX2,
|
private boolean isSpitByRuling(float minX,
|
||||||
float previousY1,
|
float minY,
|
||||||
float currentX1,
|
float maxX,
|
||||||
float currentY1,
|
float maxY,
|
||||||
List<Ruling> rulingLines,
|
TextPositionSequence word,
|
||||||
float rotation,
|
List<Ruling> horizontalRulingLines,
|
||||||
float pageWidth,
|
List<Ruling> verticalRulingLines) {
|
||||||
float pageHeight) {
|
|
||||||
|
return isSplitByRuling(maxX,
|
||||||
|
minY,
|
||||||
|
word.getMinXDirAdj(),
|
||||||
|
word.getMinYDirAdj(),
|
||||||
|
verticalRulingLines,
|
||||||
|
word.getDir().getDegrees(),
|
||||||
|
word.getPageWidth(),
|
||||||
|
word.getPageHeight()) || isSplitByRuling(minX,
|
||||||
|
minY,
|
||||||
|
word.getMinXDirAdj(),
|
||||||
|
word.getMaxYDirAdj(),
|
||||||
|
horizontalRulingLines,
|
||||||
|
word.getDir().getDegrees(),
|
||||||
|
word.getPageWidth(),
|
||||||
|
word.getPageHeight()) || isSplitByRuling(maxX,
|
||||||
|
minY,
|
||||||
|
word.getMinXDirAdj(),
|
||||||
|
word.getMinYDirAdj(),
|
||||||
|
horizontalRulingLines,
|
||||||
|
word.getDir().getDegrees(),
|
||||||
|
word.getPageWidth(),
|
||||||
|
word.getPageHeight()) || isSplitByRuling(minX,
|
||||||
|
minY,
|
||||||
|
word.getMinXDirAdj(),
|
||||||
|
word.getMaxYDirAdj(),
|
||||||
|
verticalRulingLines,
|
||||||
|
word.getDir().getDegrees(),
|
||||||
|
word.getPageWidth(),
|
||||||
|
word.getPageHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean isSplitByRuling(float previousX2, float previousY1, float currentX1, float currentY1, List<Ruling> rulingLines, float dir, float pageWidth, float pageHeight) {
|
||||||
|
|
||||||
for (Ruling ruling : rulingLines) {
|
for (Ruling ruling : rulingLines) {
|
||||||
var line = CoordSystemHelper.convertToDirAdj(ruling, rotation, pageWidth, pageHeight);
|
var line = RulingTextDirAdjustUtil.convertToDirAdj(ruling, dir, pageWidth, pageHeight);
|
||||||
if (line.intersectsLine(previousX2, previousY1, currentX1, currentY1)) {
|
if (line.intersectsLine(previousX2, previousY1, currentX1, currentY1)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -253,114 +257,6 @@ public class BlockificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Rectangle calculateBodyTextFrame(List<Page> pages, FloatFrequencyCounter documentFontSizeCounter, boolean landscape) {
|
|
||||||
|
|
||||||
float minX = 10000;
|
|
||||||
float maxX = -100;
|
|
||||||
float minY = 10000;
|
|
||||||
float maxY = -100;
|
|
||||||
|
|
||||||
for (Page page : pages) {
|
|
||||||
|
|
||||||
if (page.getTextBlocks().isEmpty() || landscape != page.isLandscape()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (AbstractTextContainer container : page.getTextBlocks()) {
|
|
||||||
|
|
||||||
if (container instanceof TextBlock) {
|
|
||||||
TextBlock textBlock = (TextBlock) container;
|
|
||||||
if (textBlock.getMostPopularWordFont() == null || textBlock.getMostPopularWordStyle() == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float approxLineCount = PositionUtils.getApproxLineCount(textBlock);
|
|
||||||
if (approxLineCount < 2.9f) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (documentFontSizeCounter.getMostPopular() != null) {
|
|
||||||
if (textBlock.getMostPopularWordFontSize() >= documentFontSizeCounter.getMostPopular()) {
|
|
||||||
|
|
||||||
if (page.getCropBox().getWidth() > page.getCropBox().getHeight() && page.getRotation() != 0) {
|
|
||||||
if (textBlock.getY1() < minX) {
|
|
||||||
minX = textBlock.getY1();
|
|
||||||
}
|
|
||||||
if (textBlock.getY2() > maxX) {
|
|
||||||
maxX = textBlock.getY2();
|
|
||||||
}
|
|
||||||
if (textBlock.getX1() < minY) {
|
|
||||||
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 (container instanceof Table) {
|
|
||||||
Table table = (Table) container;
|
|
||||||
for (List<Cell> row : table.getRows()) {
|
|
||||||
for (Cell cell : row) {
|
|
||||||
|
|
||||||
if (cell == null || cell.getTextBlocks() == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (TextBlock textBlock : cell.getTextBlocks()) {
|
|
||||||
if (page.getCropBox().getWidth() > page.getCropBox().getHeight() && page.getRotation() != 0) {
|
|
||||||
if (textBlock.getY1() < minX) {
|
|
||||||
minX = textBlock.getMinY();
|
|
||||||
}
|
|
||||||
if (textBlock.getY2() > maxX) {
|
|
||||||
maxX = textBlock.getY2();
|
|
||||||
}
|
|
||||||
if (textBlock.getX1() < minY) {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println("Page: " + page.getPageNumber() + " Landscape: " + page.isLandscape() + " MinX: " + minX + " MaxX: " + maxX + " MinY: " + minY + " MaxY: " + maxY);
|
|
||||||
|
|
||||||
}
|
|
||||||
return new Rectangle(new Point(minX, minY), maxX - minX, maxY - minY, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private double round(float value, int decimalPoints) {
|
private double round(float value, int decimalPoints) {
|
||||||
|
|
||||||
var d = Math.pow(10, decimalPoints);
|
var d = Math.pow(10, decimalPoints);
|
||||||
|
|||||||
@ -0,0 +1,171 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.classification.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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.Page;
|
||||||
|
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.tableextraction.model.AbstractTextContainer;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BodyTextFrameService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts and sets the body text frame to a page.
|
||||||
|
* Note: This needs to use Pdf Coordinate System where {0,0} rotated with the page rotation.
|
||||||
|
* 0 -> LowerLeft
|
||||||
|
* 90 -> UpperLeft
|
||||||
|
* 180 -> UpperRight
|
||||||
|
* 270 -> LowerRight
|
||||||
|
* The aspect ratio of the page is also regarded.
|
||||||
|
*
|
||||||
|
* @param page The page
|
||||||
|
* @param bodyTextFrame frame that contains the main text on portrait pages
|
||||||
|
* @param landscapeBodyTextFrame frame that contains the main text on landscape pages
|
||||||
|
*/
|
||||||
|
public void setBodyTextFrameAdjustedToPage(Page page, Rectangle bodyTextFrame, Rectangle landscapeBodyTextFrame) {
|
||||||
|
|
||||||
|
Rectangle textFrame = page.isLandscape() ? landscapeBodyTextFrame : bodyTextFrame;
|
||||||
|
|
||||||
|
if (page.getPageWidth() > page.getPageHeight() && page.getRotation() == 270) {
|
||||||
|
textFrame = new Rectangle(new Point(textFrame.getTopLeft().getY(), page.getPageHeight() - textFrame.getTopLeft().getX() - textFrame.getWidth()),
|
||||||
|
textFrame.getHeight(),
|
||||||
|
textFrame.getWidth(),
|
||||||
|
0);
|
||||||
|
} else if (page.getPageWidth() > page.getPageHeight() && page.getRotation() != 0) {
|
||||||
|
textFrame = new Rectangle(new Point(textFrame.getTopLeft().getY(), textFrame.getTopLeft().getX()), textFrame.getHeight(), textFrame.getWidth(), page.getPageNumber());
|
||||||
|
} else if (page.getRotation() == 180) {
|
||||||
|
textFrame = new Rectangle(new Point(textFrame.getTopLeft().getX(), page.getPageHeight() - textFrame.getTopLeft().getY() - textFrame.getHeight()),
|
||||||
|
textFrame.getWidth(),
|
||||||
|
textFrame.getHeight(),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
page.setBodyTextFrame(textFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the frame that contains the main text, text outside the frame will be e.g. headers or footers.
|
||||||
|
* Note: This needs to use Pdf Coordinate System where {0,0} rotated with the page rotation.
|
||||||
|
* 0 -> LowerLeft
|
||||||
|
* 90 -> UpperLeft
|
||||||
|
* 180 -> UpperRight
|
||||||
|
* 270 -> LowerRight
|
||||||
|
* The aspect ratio of the page is also regarded.
|
||||||
|
*
|
||||||
|
* @param pages List of all pages
|
||||||
|
* @param documentFontSizeCounter Statistics of the document
|
||||||
|
* @param landscape Calculate for landscape or portrait
|
||||||
|
* @return Rectangle of the text frame
|
||||||
|
*/
|
||||||
|
public Rectangle calculateBodyTextFrame(List<Page> pages, FloatFrequencyCounter documentFontSizeCounter, boolean landscape) {
|
||||||
|
|
||||||
|
float minX = 10000;
|
||||||
|
float maxX = -100;
|
||||||
|
float minY = 10000;
|
||||||
|
float maxY = -100;
|
||||||
|
|
||||||
|
for (Page page : pages) {
|
||||||
|
|
||||||
|
if (page.getTextBlocks().isEmpty() || landscape != page.isLandscape()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AbstractTextContainer container : page.getTextBlocks()) {
|
||||||
|
|
||||||
|
if (container instanceof TextBlock) {
|
||||||
|
TextBlock textBlock = (TextBlock) container;
|
||||||
|
if (textBlock.getMostPopularWordFont() == null || textBlock.getMostPopularWordStyle() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float approxLineCount = PositionUtils.getApproxLineCount(textBlock);
|
||||||
|
if (approxLineCount < 2.9f) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (documentFontSizeCounter.getMostPopular() != null && textBlock.getMostPopularWordFontSize() >= documentFontSizeCounter.getMostPopular()) {
|
||||||
|
|
||||||
|
if (page.getPageWidth() > page.getPageHeight() && page.getRotation() != 0) {
|
||||||
|
if (textBlock.getPdfMinY() < minX) {
|
||||||
|
minX = textBlock.getPdfMinY();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxY() > maxX) {
|
||||||
|
maxX = textBlock.getPdfMaxY();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMinX() < minY) {
|
||||||
|
minY = textBlock.getPdfMinX();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxX() > maxY) {
|
||||||
|
maxY = textBlock.getPdfMaxX();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (textBlock.getPdfMinX() < minX) {
|
||||||
|
minX = textBlock.getPdfMinX();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxX() > maxX) {
|
||||||
|
maxX = textBlock.getPdfMaxX();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMinY() < minY) {
|
||||||
|
minY = textBlock.getPdfMinY();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxY() > maxY) {
|
||||||
|
maxY = textBlock.getPdfMaxY();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container instanceof Table) {
|
||||||
|
Table table = (Table) container;
|
||||||
|
for (List<Cell> row : table.getRows()) {
|
||||||
|
for (Cell cell : row) {
|
||||||
|
|
||||||
|
if (cell == null || cell.getTextBlocks() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (TextBlock textBlock : cell.getTextBlocks()) {
|
||||||
|
if (page.getPageWidth() > page.getPageHeight() && page.getRotation() != 0) {
|
||||||
|
if (textBlock.getPdfMinY() < minX) {
|
||||||
|
minX = textBlock.getMinY();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxY() > maxX) {
|
||||||
|
maxX = textBlock.getPdfMaxY();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMinX() < minY) {
|
||||||
|
minY = textBlock.getPdfMinX();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxX() > maxY) {
|
||||||
|
maxY = textBlock.getPdfMaxX();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (textBlock.getPdfMinX() < minX) {
|
||||||
|
minX = textBlock.getPdfMinX();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxX() > maxX) {
|
||||||
|
maxX = textBlock.getPdfMaxX();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMinY() < minY) {
|
||||||
|
minY = textBlock.getPdfMinY();
|
||||||
|
}
|
||||||
|
if (textBlock.getPdfMaxY() > maxY) {
|
||||||
|
maxY = textBlock.getPdfMaxY();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Rectangle(new Point(minX, minY), maxX - minX, maxY - minY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,7 +5,6 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
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.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;
|
||||||
@ -21,53 +20,37 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ClassificationService {
|
public class ClassificationService {
|
||||||
|
|
||||||
private final BlockificationService blockificationService;
|
private final BodyTextFrameService bodyTextFrameService;
|
||||||
|
|
||||||
|
|
||||||
public void classifyDocument(Document document) {
|
public void classifyDocument(Document document) {
|
||||||
|
|
||||||
Rectangle bodyTextFrame = blockificationService.calculateBodyTextFrame(document.getPages(), document.getFontSizeCounter(), false);
|
Rectangle bodyTextFrame = bodyTextFrameService.calculateBodyTextFrame(document.getPages(), document.getFontSizeCounter(), false);
|
||||||
Rectangle landscapeBodyTextFrame = blockificationService.calculateBodyTextFrame(document.getPages(), document.getFontSizeCounter(), true);
|
Rectangle landscapeBodyTextFrame = bodyTextFrameService.calculateBodyTextFrame(document.getPages(), document.getFontSizeCounter(), true);
|
||||||
|
|
||||||
List<Float> headlineFontSizes = document.getFontSizeCounter().getHighterThanMostPopular();
|
List<Float> headlineFontSizes = document.getFontSizeCounter().getHighterThanMostPopular();
|
||||||
|
|
||||||
log.debug("Document FontSize counters are: {}", document.getFontSizeCounter().getCountPerValue());
|
log.debug("Document FontSize counters are: {}", document.getFontSizeCounter().getCountPerValue());
|
||||||
|
|
||||||
for (Page page : document.getPages()) {
|
for (Page page : document.getPages()) {
|
||||||
Rectangle btf = page.isLandscape() ? landscapeBodyTextFrame : bodyTextFrame;
|
bodyTextFrameService.setBodyTextFrameAdjustedToPage(page, bodyTextFrame, landscapeBodyTextFrame);
|
||||||
|
classifyPage(page, document, headlineFontSizes);
|
||||||
if (page.getCropBox().getWidth() > page.getCropBox().getHeight() && page.getRotation() == 270) {
|
|
||||||
btf = new Rectangle(new Point(btf.getTopLeft().getY(), page.getCropBox().getHeight() - btf.getTopLeft().getX() - btf.getWidth()),
|
|
||||||
btf.getHeight(),
|
|
||||||
btf.getWidth(),
|
|
||||||
0);
|
|
||||||
} else if (page.getCropBox().getWidth() > page.getCropBox().getHeight() && page.getRotation() != 0) {
|
|
||||||
btf = new Rectangle(new Point(btf.getTopLeft().getY(), btf.getTopLeft().getX()), btf.getHeight(), btf.getWidth(), 0);
|
|
||||||
} else if (page.getRotation() == 180) {
|
|
||||||
btf = new Rectangle(new Point(btf.getTopLeft().getX(), page.getCropBox().getHeight() - btf.getTopLeft().getY() - btf.getHeight()),
|
|
||||||
btf.getWidth(),
|
|
||||||
btf.getHeight(),
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
page.setBodyTextFrame(btf);
|
|
||||||
|
|
||||||
classifyPage(btf, page, document, headlineFontSizes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void classifyPage(Rectangle bodyTextFrame, Page page, Document document, List<Float> headlineFontSizes) {
|
public void classifyPage(Page page, Document document, List<Float> headlineFontSizes) {
|
||||||
|
|
||||||
for (AbstractTextContainer textBlock : page.getTextBlocks()) {
|
for (AbstractTextContainer textBlock : page.getTextBlocks()) {
|
||||||
if (textBlock instanceof TextBlock) {
|
if (textBlock instanceof TextBlock) {
|
||||||
classifyBlock((TextBlock) textBlock, bodyTextFrame, page, document, headlineFontSizes);
|
classifyBlock((TextBlock) textBlock, page, document, headlineFontSizes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void classifyBlock(TextBlock textBlock, Rectangle bodyTextFrame, Page page, Document document, List<Float> headlineFontSizes) {
|
public void classifyBlock(TextBlock textBlock, Page page, Document document, List<Float> headlineFontSizes) {
|
||||||
|
|
||||||
|
var bodyTextFrame = page.getBodyTextFrame();
|
||||||
|
|
||||||
if (document.getFontSizeCounter().getMostPopular() == null) {
|
if (document.getFontSizeCounter().getMostPopular() == null) {
|
||||||
textBlock.setClassification("Other");
|
textBlock.setClassification("Other");
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
package com.iqser.red.service.redaction.v1.server.classification.utils;
|
|
||||||
|
|
||||||
import java.awt.geom.Line2D;
|
|
||||||
import java.awt.geom.Point2D;
|
|
||||||
|
|
||||||
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.tableextraction.model.Ruling;
|
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class CoordSystemHelper {
|
|
||||||
|
|
||||||
public Rectangle convertToDirAdj(Rectangle rectangle, float rotation, float pageWidth, float pageHeight) {
|
|
||||||
|
|
||||||
var topLeft = convertPoint(rectangle.getTopLeft().getX(), rectangle.getTopLeft().getY() + rectangle.getHeight(), rotation, pageWidth, pageHeight);
|
|
||||||
var bottomRight = convertPoint(rectangle.getTopLeft().getX() + rectangle.getWidth(), rectangle.getTopLeft().getY(), rotation, pageWidth, pageHeight);
|
|
||||||
|
|
||||||
return new Rectangle(new Point((float) topLeft.getX(), (float) topLeft.getY()),
|
|
||||||
(float) (bottomRight.getX() - topLeft.getX()),
|
|
||||||
(float) (bottomRight.getY() - topLeft.getY()),
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Line2D.Float convertToDirAdj(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -9,18 +9,18 @@ import lombok.experimental.UtilityClass;
|
|||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
public class PositionUtils {
|
public class PositionUtils {
|
||||||
|
|
||||||
|
// TODO This currently uses pdf coord system. In the futher this should use java coord system.
|
||||||
|
// Note: DirAdj (TextDirection Adjusted) can not be user for this.
|
||||||
public boolean isWithinBodyTextFrame(Rectangle btf, TextBlock textBlock) {
|
public boolean isWithinBodyTextFrame(Rectangle btf, TextBlock textBlock) {
|
||||||
|
|
||||||
//TODO Currently this is not working for rotated pages.
|
|
||||||
|
|
||||||
if (btf == null || textBlock == null) {
|
if (btf == null || textBlock == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double threshold = textBlock.getMostPopularWordHeight() * 3;
|
double threshold = textBlock.getMostPopularWordHeight() * 3;
|
||||||
|
|
||||||
if (textBlock.getX1() + threshold > btf.getTopLeft().getX() && textBlock.getX2() - threshold < btf.getTopLeft()
|
if (textBlock.getPdfMinX() + threshold > btf.getTopLeft().getX() && textBlock.getPdfMaxX() - threshold < btf.getTopLeft()
|
||||||
.getX() + btf.getWidth() && textBlock.getY1() + threshold > btf.getTopLeft().getY() && textBlock.getY2() - threshold < btf.getTopLeft()
|
.getX() + btf.getWidth() && textBlock.getPdfMinY() + threshold > btf.getTopLeft().getY() && textBlock.getPdfMaxY() - threshold < btf.getTopLeft()
|
||||||
.getY() + btf.getHeight()) {
|
.getY() + btf.getHeight()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -30,25 +30,27 @@ public class PositionUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO This currently uses pdf coord system. In the futher this should use java coord system.
|
||||||
|
// Note: DirAdj (TextDirection Adjusted) can not be user for this.
|
||||||
public boolean isOverBodyTextFrame(Rectangle btf, TextBlock textBlock, int rotation) {
|
public boolean isOverBodyTextFrame(Rectangle btf, TextBlock textBlock, int rotation) {
|
||||||
|
|
||||||
if (btf == null || textBlock == null) {
|
if (btf == null || textBlock == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 90 && textBlock.getX2() < btf.getTopLeft().getX()) {
|
if (rotation == 90 && textBlock.getPdfMaxX() < btf.getTopLeft().getX()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 180 && textBlock.getY2() < btf.getTopLeft().getY()) {
|
if (rotation == 180 && textBlock.getPdfMaxY() < btf.getTopLeft().getY()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 270 && textBlock.getX1() > btf.getTopLeft().getX() + btf.getWidth()) {
|
if (rotation == 270 && textBlock.getPdfMinX() > btf.getTopLeft().getX() + btf.getWidth()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 0 && textBlock.getY1() > btf.getTopLeft().getY() + btf.getHeight()) {
|
if (rotation == 0 && textBlock.getPdfMinY() > btf.getTopLeft().getY() + btf.getHeight()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -56,26 +58,27 @@ public class PositionUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO This currently uses pdf coord system. In the futher this should use java coord system.
|
||||||
|
// Note: DirAdj (TextDirection Adjusted) can not be user for this.
|
||||||
public boolean isUnderBodyTextFrame(Rectangle btf, TextBlock textBlock, int rotation) {
|
public boolean isUnderBodyTextFrame(Rectangle btf, TextBlock textBlock, int rotation) {
|
||||||
|
|
||||||
if (btf == null || textBlock == null) {
|
if (btf == null || textBlock == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 90 && textBlock.getX1() > btf.getTopLeft().getX() + btf.getWidth()) {
|
if (rotation == 90 && textBlock.getPdfMinX() > btf.getTopLeft().getX() + btf.getWidth()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 180 && textBlock.getY1() > btf.getTopLeft().getY() + btf.getHeight()) {
|
if (rotation == 180 && textBlock.getPdfMinY() > btf.getTopLeft().getY() + btf.getHeight()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 270 && textBlock.getX2() < btf.getTopLeft().getX()) {
|
if (rotation == 270 && textBlock.getPdfMaxX() < btf.getTopLeft().getX()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation == 0 && textBlock.getY2() < btf.getTopLeft().getY()) {
|
if (rotation == 0 && textBlock.getPdfMaxY() < btf.getTopLeft().getY()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -83,7 +86,8 @@ public class PositionUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO This currently uses pdf coord system. In the futher this should use java coord system.
|
||||||
|
// Note: DirAdj (TextDirection Adjusted) can not be user for this.
|
||||||
public boolean isTouchingUnderBodyTextFrame(Rectangle btf, TextBlock textBlock) {
|
public boolean isTouchingUnderBodyTextFrame(Rectangle btf, TextBlock textBlock) {
|
||||||
|
|
||||||
//TODO Currently this is not working for rotated pages.
|
//TODO Currently this is not working for rotated pages.
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.classification.utils;
|
||||||
|
|
||||||
|
import java.awt.geom.Line2D;
|
||||||
|
import java.awt.geom.Point2D;
|
||||||
|
|
||||||
|
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class RulingTextDirAdjustUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a ruling (line of a table) the same way TextPositions are converted in PDFBox.
|
||||||
|
* This will get the y position of the text, adjusted so that 0,0 is upper left and it is adjusted based on the text direction.
|
||||||
|
*
|
||||||
|
* See org.apache.pdfbox.text.TextPosition
|
||||||
|
*/
|
||||||
|
public Line2D.Float convertToDirAdj(Ruling ruling, float dir, float pageWidth, float pageHeight) {
|
||||||
|
|
||||||
|
return new Line2D.Float(convertPoint(ruling.x1, ruling.y1, dir, pageWidth, pageHeight), convertPoint(ruling.x2, ruling.y2, dir, pageWidth, pageHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Point2D convertPoint(float x, float y, float dir, float pageWidth, float pageHeight) {
|
||||||
|
|
||||||
|
var xAdj = getXRot(x, y, dir, pageWidth, pageHeight);
|
||||||
|
var yAdj = 0f;
|
||||||
|
if (dir == 0 || dir == 180) {
|
||||||
|
yAdj = pageHeight - getYLowerLeftRot(x, y, dir, pageWidth, pageHeight);
|
||||||
|
} else {
|
||||||
|
yAdj = pageWidth - getYLowerLeftRot(x, y, dir, pageWidth, pageHeight);
|
||||||
|
}
|
||||||
|
return new Point2D.Float(xAdj, yAdj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private float getXRot(float x, float y, float dir, float pageWidth, float pageHeight) {
|
||||||
|
|
||||||
|
if (dir == 0) {
|
||||||
|
return x;
|
||||||
|
} else if (dir == 90) {
|
||||||
|
return y;
|
||||||
|
} else if (dir == 180) {
|
||||||
|
return pageWidth - x;
|
||||||
|
} else if (dir == 270) {
|
||||||
|
return pageHeight - y;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private float getYLowerLeftRot(float x, float y, float dir, float pageWidth, float pageHeight) {
|
||||||
|
|
||||||
|
if (dir == 0) {
|
||||||
|
return y;
|
||||||
|
} else if (dir == 90) {
|
||||||
|
return pageWidth - x;
|
||||||
|
} else if (dir == 180) {
|
||||||
|
return pageHeight - y;
|
||||||
|
} else if (dir == 270) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -47,16 +47,6 @@ public class TextPositionSequence implements CharSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public TextPositionSequence fromData(List<RedTextPosition> textPositions, int page) {
|
|
||||||
|
|
||||||
var textPositionSequence = new TextPositionSequence();
|
|
||||||
textPositionSequence.textPositions = textPositions;
|
|
||||||
textPositionSequence.page = page;
|
|
||||||
|
|
||||||
return textPositionSequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TextPositionSequence(List<TextPosition> textPositions, int page) {
|
public TextPositionSequence(List<TextPosition> textPositions, int page) {
|
||||||
|
|
||||||
this.textPositions = textPositions.stream().map(RedTextPosition::fromTextPosition).collect(Collectors.toList());
|
this.textPositions = textPositions.stream().map(RedTextPosition::fromTextPosition).collect(Collectors.toList());
|
||||||
@ -147,44 +137,60 @@ public class TextPositionSequence implements CharSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value is adjusted so that 0,0 is upper left and it is adjusted based on the text direction.
|
||||||
|
* This method ignores the page rotation but takes the text rotation and adjusts the coordinates to awt.
|
||||||
|
*
|
||||||
|
* @return the text direction adjusted minX value
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getRotationAdjustedY() {
|
public float getMinXDirAdj() {
|
||||||
|
|
||||||
return textPositions.get(0).getYDirAdj();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
@JsonAttribute(ignore = true)
|
|
||||||
public float getX1() {
|
|
||||||
|
|
||||||
return textPositions.get(0).getXDirAdj();
|
return textPositions.get(0).getXDirAdj();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value is adjusted so that 0,0 is upper left and it is adjusted based on the text direction.
|
||||||
|
* This method ignores the page rotation but takes the text rotation and adjusts the coordinates to awt.
|
||||||
|
*
|
||||||
|
* @return the text direction adjusted maxX value
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getX2() {
|
public float getMaxXDirAdj() {
|
||||||
|
|
||||||
return textPositions.get(textPositions.size() - 1).getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidthDirAdj() + HEIGHT_PADDING;
|
return textPositions.get(textPositions.size() - 1).getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidthDirAdj() + HEIGHT_PADDING;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value is adjusted so that 0,0 is upper left and it is adjusted based on the text direction.
|
||||||
|
* This method ignores the page rotation but takes the text rotation and adjusts the coordinates to awt.
|
||||||
|
*
|
||||||
|
* @return the text direction adjusted minY value. The upper border of the bounding box of the word.
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getY1() {
|
public float getMinYDirAdj() {
|
||||||
|
|
||||||
return textPositions.get(0).getYDirAdj() - getTextHeight();
|
return textPositions.get(0).getYDirAdj() - getTextHeight();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value is adjusted so that 0,0 is upper left and it is adjusted based on the text direction.
|
||||||
|
* This method ignores the page rotation but takes the text rotation and adjusts the coordinates to awt.
|
||||||
|
*
|
||||||
|
* @return the text direction adjusted maxY value. The lower border of the bounding box of the word.
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getY2() {
|
public float getMaxYDirAdj() {
|
||||||
|
|
||||||
return textPositions.get(0).getYDirAdj();
|
return textPositions.get(0).getYDirAdj();
|
||||||
|
|
||||||
@ -203,7 +209,7 @@ public class TextPositionSequence implements CharSequence {
|
|||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getHeight() {
|
public float getHeight() {
|
||||||
|
|
||||||
return getY2() - getY1();
|
return getMaxYDirAdj() - getMinYDirAdj();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -211,7 +217,7 @@ public class TextPositionSequence implements CharSequence {
|
|||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
public float getWidth() {
|
public float getWidth() {
|
||||||
|
|
||||||
return getX2() - getX1();
|
return getMaxXDirAdj() - getMinXDirAdj();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -258,6 +264,15 @@ public class TextPositionSequence implements CharSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This returns the bounding box of the word in Pdf Coordinate System where {0,0} rotated with the page rotation.
|
||||||
|
* 0 -> LowerLeft
|
||||||
|
* 90 -> UpperLeft
|
||||||
|
* 180 -> UpperRight
|
||||||
|
* 270 -> LowerRight
|
||||||
|
*
|
||||||
|
* @return bounding box of the word in Pdf Coordinate System
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@JsonAttribute(ignore = true)
|
@JsonAttribute(ignore = true)
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public class CellValue {
|
|||||||
TextPositionSequence previous = null;
|
TextPositionSequence previous = null;
|
||||||
for (TextPositionSequence word : textBlock.getSequences()) {
|
for (TextPositionSequence word : textBlock.getSequences()) {
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
if (Math.abs(previous.getRotationAdjustedY() - word.getRotationAdjustedY()) > word.getTextHeight()) {
|
if (Math.abs(previous.getMaxYDirAdj() - word.getMaxYDirAdj()) > word.getTextHeight()) {
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
} else {
|
} else {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
|
|||||||
@ -194,7 +194,7 @@ public class SearchableText {
|
|||||||
for (TextPositionSequence word : sequences) {
|
for (TextPositionSequence word : sequences) {
|
||||||
|
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
if (Math.abs(previous.getRotationAdjustedY() - word.getRotationAdjustedY()) > word.getTextHeight()) {
|
if (Math.abs(previous.getMaxYDirAdj() - word.getMaxYDirAdj()) > word.getTextHeight()) {
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
} else {
|
} else {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
@ -228,7 +228,7 @@ public class SearchableText {
|
|||||||
for (TextPositionSequence word : sorted) {
|
for (TextPositionSequence word : sorted) {
|
||||||
|
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
if (Math.abs(previous.getRotationAdjustedY() - word.getRotationAdjustedY()) > word.getTextHeight()) {
|
if (Math.abs(previous.getMaxYDirAdj() - word.getMaxYDirAdj()) > word.getTextHeight()) {
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
} else {
|
} else {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
@ -249,7 +249,7 @@ public class SearchableText {
|
|||||||
for (TextPositionSequence word : sequences) {
|
for (TextPositionSequence word : sequences) {
|
||||||
|
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
if (Math.abs(previous.getRotationAdjustedY() - word.getRotationAdjustedY()) > word.getTextHeight()) {
|
if (Math.abs(previous.getMaxYDirAdj() - word.getMaxYDirAdj()) > word.getTextHeight()) {
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
} else {
|
} else {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
|
|||||||
@ -47,9 +47,9 @@ public class SectionGridCreatorService {
|
|||||||
classifiedDoc.getSectionGrid()
|
classifiedDoc.getSectionGrid()
|
||||||
.getRectanglesPerPage()
|
.getRectanglesPerPage()
|
||||||
.computeIfAbsent(page, (x) -> new ArrayList<>())
|
.computeIfAbsent(page, (x) -> new ArrayList<>())
|
||||||
.add(new SectionRectangle(new Point(tb.getX1(), tb.getY1()),
|
.add(new SectionRectangle(new Point(tb.getPdfMinX(), tb.getPdfMinY()),
|
||||||
tb.getX2() - tb.getX1(),
|
tb.getPdfMaxX() - tb.getPdfMinX(),
|
||||||
tb.getY2() - tb.getY1(),
|
tb.getPdfMaxY() - tb.getPdfMinY(),
|
||||||
i + 1,
|
i + 1,
|
||||||
paragraph.getPageBlocks().size(),
|
paragraph.getPageBlocks().size(),
|
||||||
null));
|
null));
|
||||||
|
|||||||
@ -292,9 +292,9 @@ public class EntitySearchUtils {
|
|||||||
.get(0)
|
.get(0)
|
||||||
.getSequences()
|
.getSequences()
|
||||||
.get(0)
|
.get(0)
|
||||||
.getX1() && image.getPosition().getX() + image.getPosition().getWidth() > entity.getPositionSequences().get(0).getSequences().get(0).getX2() && image.getPosition()
|
.getMinXDirAdj() && image.getPosition().getX() + image.getPosition().getWidth() > entity.getPositionSequences().get(0).getSequences().get(0).getMaxXDirAdj() && image.getPosition()
|
||||||
.getY() < entity.getPositionSequences().get(0).getSequences().get(0).getY1() && image.getPosition().getY() + image.getPosition()
|
.getY() < entity.getPositionSequences().get(0).getSequences().get(0).getMinYDirAdj() && image.getPosition().getY() + image.getPosition()
|
||||||
.getHeight() > entity.getPositionSequences().get(0).getSequences().get(0).getY2();
|
.getHeight() > entity.getPositionSequences().get(0).getSequences().get(0).getMaxYDirAdj();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -108,18 +108,13 @@ public class PdfSegmentationService {
|
|||||||
stripper.getRulings(),
|
stripper.getRulings(),
|
||||||
stripper.getMinCharWidth(),
|
stripper.getMinCharWidth(),
|
||||||
stripper.getMaxCharHeight());
|
stripper.getMaxCharHeight());
|
||||||
Page page = blockificationService.blockify(stripper.getTextPositionSequences(), cleanRulings.getHorizontal(), cleanRulings.getVertical(), rotation, cropbox);
|
Page page = blockificationService.blockify(stripper.getTextPositionSequences(), cleanRulings.getHorizontal(), cleanRulings.getVertical());
|
||||||
|
|
||||||
float cropboxArea = cropbox.getHeight() * cropbox.getWidth();
|
|
||||||
page.setCropBoxArea(cropboxArea);
|
|
||||||
|
|
||||||
System.out.println("CropBox: w:" + cropbox.getWidth() + " h:" + cropbox.getHeight() + "MediaBox: w:" + pdPage.getMediaBox()
|
|
||||||
.getWidth() + " h:" + pdPage.getMediaBox().getHeight());
|
|
||||||
|
|
||||||
page.setRotation(rotation);
|
page.setRotation(rotation);
|
||||||
page.setLandscape(isLandscape);
|
page.setLandscape(isLandscape);
|
||||||
page.setPageNumber(pageNumber);
|
page.setPageNumber(pageNumber);
|
||||||
page.setCropBox(cropbox);
|
page.setPageWidth(cropbox.getWidth());
|
||||||
|
page.setPageHeight(cropbox.getHeight());
|
||||||
|
|
||||||
tableExtractionService.extractTables(cleanRulings, page);
|
tableExtractionService.extractTables(cleanRulings, page);
|
||||||
buildPageStatistics(page);
|
buildPageStatistics(page);
|
||||||
|
|||||||
@ -37,7 +37,7 @@ public abstract class AbstractTextContainer {
|
|||||||
|
|
||||||
public boolean containsBlock(TextBlock other) {
|
public boolean containsBlock(TextBlock other) {
|
||||||
|
|
||||||
return this.minX <= other.getX1() && this.maxX >= other.getX2() && this.minY >= other.getY1() && this.maxY <= other.getY2();
|
return this.minX <= other.getPdfMinX() && this.maxX >= other.getPdfMaxX() && this.minY >= other.getPdfMinY() && this.maxY <= other.getPdfMaxY();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ public class Cell extends Rectangle {
|
|||||||
|
|
||||||
for (TextPositionSequence word : textBlock.getSequences()) {
|
for (TextPositionSequence word : textBlock.getSequences()) {
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
if (Math.abs(previous.getRotationAdjustedY() - word.getRotationAdjustedY()) > word.getTextHeight()) {
|
if (Math.abs(previous.getMaxYDirAdj() - word.getMaxYDirAdj()) > word.getTextHeight()) {
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
} else {
|
} else {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
|
|||||||
@ -75,7 +75,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.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1())) {
|
if (cell.intersects(textBlock.getPdfMinX(), textBlock.getPdfMinY(), textBlock.getPdfMaxX() - textBlock.getPdfMinX(), textBlock.getPdfMaxY() - textBlock.getPdfMinY())) {
|
||||||
cell.addTextBlock(textBlock);
|
cell.addTextBlock(textBlock);
|
||||||
toBeRemoved.add(textBlock);
|
toBeRemoved.add(textBlock);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -100,7 +100,7 @@ public class PdfVisualisationService {
|
|||||||
|
|
||||||
contentStream.setStrokingColor(Color.RED);
|
contentStream.setStrokingColor(Color.RED);
|
||||||
|
|
||||||
contentStream.addRect(textBlock.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1());
|
contentStream.addRect(textBlock.getPdfMinX(), textBlock.getPdfMinY(), textBlock.getPdfMaxX() - textBlock.getPdfMinX(), textBlock.getPdfMaxY() - textBlock.getPdfMinY());
|
||||||
contentStream.stroke();
|
contentStream.stroke();
|
||||||
|
|
||||||
if (textBlock.getClassification() != null) {
|
if (textBlock.getClassification() != null) {
|
||||||
@ -109,7 +109,7 @@ public class PdfVisualisationService {
|
|||||||
contentStream.setNonStrokingColor(Color.BLUE);
|
contentStream.setNonStrokingColor(Color.BLUE);
|
||||||
contentStream.setFont(PDType1Font.TIMES_ROMAN, 9f);
|
contentStream.setFont(PDType1Font.TIMES_ROMAN, 9f);
|
||||||
|
|
||||||
contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY2() + 2);
|
contentStream.newLineAtOffset(textBlock.getPdfMinX(), textBlock.getPdfMaxY() + 2);
|
||||||
contentStream.showText(textBlock.getClassification() + textBlock.getOrientation() + "-->" + textBlock.getSequences().get(0).getDir());
|
contentStream.showText(textBlock.getClassification() + textBlock.getOrientation() + "-->" + textBlock.getSequences().get(0).getDir());
|
||||||
|
|
||||||
contentStream.endText();
|
contentStream.endText();
|
||||||
@ -153,7 +153,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.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1());
|
contentStream.addRect(textBlock.getPdfMinX(), textBlock.getPdfMinY(), textBlock.getPdfMaxX() - textBlock.getPdfMinX(), textBlock.getPdfMaxY() - textBlock.getPdfMinY());
|
||||||
contentStream.stroke();
|
contentStream.stroke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user