66import java .awt .image .Raster ;
77import java .io .IOException ;
88import java .io .OutputStream ;
9- import java .util .ArrayList ;
10- import java .util .Arrays ;
11- import java .util .Comparator ;
12- import java .util .HashMap ;
13- import java .util .Iterator ;
14- import java .util .List ;
15- import java .util .Map ;
16- import java .util .Set ;
17- import java .util .TreeSet ;
9+ import java .util .*;
1810
1911import org .apache .pdfbox .contentstream .operator .Operator ;
2012import org .apache .pdfbox .cos .COSName ;
@@ -526,132 +518,103 @@ private TextEdges getTextEdges(List<Line> lines) {
526518 Map <Integer , List <TextChunk >> currMidEdges = new HashMap <>();
527519 Map <Integer , List <TextChunk >> currRightEdges = new HashMap <>();
528520
521+
522+ int numOfLines = lines .size ();
529523 for (Line textRow : lines ) {
530524 for (TextChunk text : textRow .getTextElements ()) {
531- Integer left = new Integer (( int ) Math .floor (text .getLeft () ));
532- Integer right = new Integer (( int ) Math .floor (text .getRight () ));
533- Integer mid = new Integer ( left + ((right - left ) / 2 ) );
525+ Integer left = ( int ) Math .floor (text .getLeft ());
526+ Integer right = ( int ) Math .floor (text .getRight ());
527+ Integer mid = left + ((right - left ) / 2 );
534528
535529 // first put this chunk into any edge buckets it belongs to
536- List <TextChunk > leftEdge = currLeftEdges .get (left );
537- if (leftEdge == null ) {
538- leftEdge = new ArrayList <>();
539- currLeftEdges .put (left , leftEdge );
540- }
530+ List <TextChunk > leftEdge = currLeftEdges .computeIfAbsent (left , k -> new ArrayList <>());
541531 leftEdge .add (text );
542532
543- List <TextChunk > midEdge = currMidEdges .get (mid );
544- if (midEdge == null ) {
545- midEdge = new ArrayList <>();
546- currMidEdges .put (mid , midEdge );
547- }
533+ List <TextChunk > midEdge = currMidEdges .computeIfAbsent (mid , k -> new ArrayList <>());
548534 midEdge .add (text );
549535
550- List <TextChunk > rightEdge = currRightEdges .get (right );
551- if (rightEdge == null ) {
552- rightEdge = new ArrayList <>();
553- currRightEdges .put (right , rightEdge );
554- }
536+ List <TextChunk > rightEdge = currRightEdges .computeIfAbsent (right , k -> new ArrayList <>());
555537 rightEdge .add (text );
556538
557539 // now see if this text chunk blows up any other edges
558- for (Iterator <Map .Entry <Integer , List <TextChunk >>> iterator = currLeftEdges .entrySet ().iterator (); iterator .hasNext (); ) {
559- Map .Entry <Integer , List <TextChunk >> entry = iterator .next ();
560- Integer key = entry .getKey ();
561- if (key > left && key < right ) {
562- iterator .remove ();
563- List <TextChunk > edgeChunks = entry .getValue ();
564- if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
565- TextChunk first = edgeChunks .get (0 );
566- TextChunk last = edgeChunks .get (edgeChunks .size () - 1 );
567-
568- TextEdge edge = new TextEdge (key , first .getTop (), key , last .getBottom ());
569- edge .intersectingTextRowCount = Math .min (edgeChunks .size (), lines .size ());
570-
571- leftTextEdges .add (edge );
572- }
573- }
574- }
575-
576- for (Iterator <Map .Entry <Integer , List <TextChunk >>> iterator = currMidEdges .entrySet ().iterator (); iterator .hasNext (); ) {
577- Map .Entry <Integer , List <TextChunk >> entry = iterator .next ();
578- Integer key = entry .getKey ();
579- if (key > left && key < right && Math .abs (key - mid ) > 2 ) {
580- iterator .remove ();
581- List <TextChunk > edgeChunks = entry .getValue ();
582- if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
583- TextChunk first = edgeChunks .get (0 );
584- TextChunk last = edgeChunks .get (edgeChunks .size () - 1 );
585-
586- TextEdge edge = new TextEdge (key , first .getTop (), key , last .getBottom ());
587- edge .intersectingTextRowCount = Math .min (edgeChunks .size (), lines .size ());
588-
589- midTextEdges .add (edge );
590- }
591- }
592- }
593-
594- for (Iterator <Map .Entry <Integer , List <TextChunk >>> iterator = currRightEdges .entrySet ().iterator (); iterator .hasNext (); ) {
595- Map .Entry <Integer , List <TextChunk >> entry = iterator .next ();
596- Integer key = entry .getKey ();
597- if (key > left && key < right ) {
598- iterator .remove ();
599- List <TextChunk > edgeChunks = entry .getValue ();
600- if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
601- TextChunk first = edgeChunks .get (0 );
602- TextChunk last = edgeChunks .get (edgeChunks .size () - 1 );
540+ leftTextEdges .addAll (
541+ calculateExtendedEdges (numOfLines , currLeftEdges , left , right )
542+ );
603543
604- TextEdge edge = new TextEdge (key , first .getTop (), key , last .getBottom ());
605- edge .intersectingTextRowCount = Math .min (edgeChunks .size (), lines .size ());
544+ midTextEdges .addAll (
545+ calculateExtendedEdges (numOfLines , currMidEdges , left , right , mid , 2 )
546+ );
606547
607- rightTextEdges .add (edge );
608- }
609- }
610- }
548+ rightTextEdges .addAll (
549+ calculateExtendedEdges (numOfLines , currRightEdges , left , right )
550+ );
611551 }
612552 }
613553
614554 // add the leftovers
615- for (Integer key : currLeftEdges .keySet ()) {
616- List <TextChunk > edgeChunks = currLeftEdges .get (key );
617- if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
618- TextChunk first = edgeChunks .get (0 );
619- TextChunk last = edgeChunks .get (edgeChunks .size () - 1 );
555+ leftTextEdges .addAll (
556+ calculateLeftoverEdges (numOfLines , currLeftEdges )
557+ );
620558
621- TextEdge edge = new TextEdge (key , first .getTop (), key , last .getBottom ());
622- edge .intersectingTextRowCount = Math .min (edgeChunks .size (), lines .size ());
559+ midTextEdges .addAll (
560+ calculateLeftoverEdges (numOfLines , currMidEdges )
561+ );
623562
624- leftTextEdges . add ( edge );
625- }
626- }
563+ rightTextEdges . addAll (
564+ calculateLeftoverEdges ( numOfLines , currRightEdges )
565+ );
627566
628- for (Integer key : currMidEdges .keySet ()) {
629- List <TextChunk > edgeChunks = currMidEdges .get (key );
630- if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
631- TextChunk first = edgeChunks .get (0 );
632- TextChunk last = edgeChunks .get (edgeChunks .size () - 1 );
567+ return new TextEdges (leftTextEdges , midTextEdges , rightTextEdges );
568+ }
633569
634- TextEdge edge = new TextEdge (key , first .getTop (), key , last .getBottom ());
635- edge .intersectingTextRowCount = Math .min (edgeChunks .size (), lines .size ());
570+ private Set <TextEdge > calculateLeftoverEdges (int numOfLines , Map <Integer , List <TextChunk >> currDirectedEdges ) {
571+ Set <TextEdge > leftoverEdges = new HashSet <>();
572+ for (Integer key : currDirectedEdges .keySet ()) {
573+ List <TextChunk > edgeChunks = currDirectedEdges .get (key );
574+ if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
575+ TextEdge edge = getEdgeFromChunks (numOfLines , key , edgeChunks );
636576
637- midTextEdges .add (edge );
577+ leftoverEdges .add (edge );
638578 }
639579 }
580+ return leftoverEdges ;
581+ }
640582
641- for (Integer key : currRightEdges .keySet ()) {
642- List <TextChunk > edgeChunks = currRightEdges .get (key );
643- if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
644- TextChunk first = edgeChunks .get (0 );
645- TextChunk last = edgeChunks .get (edgeChunks .size () - 1 );
583+ private TextEdge getEdgeFromChunks (int numOfLines , Integer key , List <TextChunk > edgeChunks ) {
584+ TextChunk first = edgeChunks .get (0 );
585+ TextChunk last = edgeChunks .get (edgeChunks .size () - 1 );
646586
647- TextEdge edge = new TextEdge (key , first .getTop (), key , last .getBottom ());
648- edge .intersectingTextRowCount = Math .min (edgeChunks .size (), lines .size ());
587+ TextEdge edge = new TextEdge (key , first .getTop (), key , last .getBottom ());
588+ edge .intersectingTextRowCount = Math .min (edgeChunks .size (), numOfLines );
589+ return edge ;
590+ }
649591
650- rightTextEdges .add (edge );
592+
593+ private Collection <TextEdge > calculateExtendedEdges (Integer numOfLines , Map <Integer , List <TextChunk >> currDirectedEdges , Integer left , Integer right ) {
594+ return calculateExtendedEdges (numOfLines , currDirectedEdges , left , right , null , null );
595+ }
596+
597+ private Collection <TextEdge > calculateExtendedEdges (Integer numOfLines , Map <Integer , List <TextChunk >> currDirectedEdges , Integer left , Integer right , Integer mid , Integer minDistToMid ) {
598+ Set <TextEdge > extendedEdges = new HashSet <>();
599+ Iterator <Map .Entry <Integer , List <TextChunk >>> edgeIterator = currDirectedEdges .entrySet ().iterator ();
600+ while (edgeIterator .hasNext ()) {
601+ Map .Entry <Integer , List <TextChunk >> entry = edgeIterator .next ();
602+ Integer key = entry .getKey ();
603+
604+ // if mid and minDistToMid are set, we calculate if the distance to mid is actually above,
605+ // otherwise we ignore it
606+ boolean hasMinDistToMid = mid == null || minDistToMid == null || Math .abs (key - mid ) > minDistToMid ;
607+
608+ if (key > left && key < right && hasMinDistToMid ) {
609+ edgeIterator .remove ();
610+ List <TextChunk > edgeChunks = entry .getValue ();
611+ if (edgeChunks .size () >= REQUIRED_TEXT_LINES_FOR_EDGE ) {
612+ TextEdge edge = getEdgeFromChunks (numOfLines , key , edgeChunks );
613+ extendedEdges .add (edge );
614+ }
651615 }
652616 }
653-
654- return new TextEdges (leftTextEdges , midTextEdges , rightTextEdges );
617+ return extendedEdges ;
655618 }
656619
657620 private List <Rectangle > getTableAreasFromCells (List <? extends Rectangle > cells ) {
@@ -665,9 +628,9 @@ private List<Rectangle> getTableAreasFromCells(List<? extends Rectangle> cells)
665628 Point2D [] groupCellCorners = groupCell .getPoints ();
666629 Point2D [] candidateCorners = cell .getPoints ();
667630
668- for (int i = 0 ; i < candidateCorners . length ; i ++ ) {
669- for (int j = 0 ; j < groupCellCorners . length ; j ++ ) {
670- if (candidateCorners [ i ] .distance (groupCellCorners [ j ] ) < CELL_CORNER_DISTANCE_MAXIMUM ) {
631+ for (Point2D candidateCorner : candidateCorners ) {
632+ for (Point2D groupCellCorner : groupCellCorners ) {
633+ if (candidateCorner .distance (groupCellCorner ) < CELL_CORNER_DISTANCE_MAXIMUM ) {
671634 cellGroup .add (cell );
672635 addedToGroup = true ;
673636 break cellCheck ;
0 commit comments