
    4vj;                         d Z ddlZddlmZmZmZmZmZ dZdZ	dZ
dZdZd	Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zy)a  
Copyright (C) 2023 Artifex Software, Inc.

This file is part of PyMuPDF.

PyMuPDF is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.

PyMuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
details.

You should have received a copy of the GNU Affero General Public License
along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>

Alternative licensing terms are available from the licensor.
For commercial licensing, see <https://www.artifex.com/> or contact
Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
CA 94129, USA, for further information.

---------------------------------------------------------------------

PyMuPDF table union stage, behind find_tables(union=True): fuse the layout
analyzer's table grids with the line-based finder's candidates. Table,
TableFinder and _iou come from pymupdf.table; find_tables is imported lazily.
    N)CHARSEDGESTableTableFinder_ioulines_strictg?Tg      @g333333?g      ?c                    g }| j                   xs g D ]N  }t        |t              s|j                  d      dk7  r*|j                  d      }|j                  d      }|r|Q|d   |d   |d   |d	   f\  }}}}|g|j                  D 	cg c]  }	|	|z   	 c}	z   |gz   }
|g|j
                  D cg c]  }||z   	 c}z   |gz   }g }t        t        |
      dz
        D ]X  }g }t        t        |      dz
        D ])  }|j                  ||   |
|   ||dz      |
|dz      f       + |j                  |       Z |j                  t        j                  |dd
       |f       Q |S c c}	w c c}w )at  Primary table grids from the raw layout analyzer result.

    Reads page.layout_information in its raw (return_raw=True) form and yields a
    ``(bbox, grid)`` pair per "table" group -- ``grid`` is the full row-major cell
    grid built from the group box plus its interior GridPrediction lines, in
    layout (reading) order. Boxes without a usable grid are skipped.
    
class_nametable
group_bbox
table_gridNr               )layout_information
isinstancedictgeth_linesv_linesrangelenappendpymupdfRect)pagegridsgroupr   	grid_predx0y0x1y1hr   vr   gridirowjs                    G/root/.hermes/venv/lib/python3.12/site-packages/pymupdf/_table_union.py_layout_table_gridsr,   :   s    E))/R ;%& 99\"g-YY|,
IIl+	Y.#A
1z!}jQRmSBB$)*;*;<Q!b&<<tC$)*;*;<Q!b&<<tCs7|a'( 	AC3w<!+, U

GAJ
GAENGAPQENSTUKK		
 	gll:bq>2D9:);* L =<s   E'0E,c           	         ddl m}  || t        d      }g }t               }t	        |dd      xs g D ]  }	 t        j                  |j                        }|j                  r0|j                  xs g D cg c]  }|j                  D cg c]  }| c} }	}}|	sjt        d |D              }
|
|v r|j                  |
       |j                  ||	f        ||fS # t        t        f$ r Y w xY wc c}w c c}}w )au  Line-based table candidates for the union stage as ``(bbox, grid)`` pairs.

    Runs a nested find_tables (strategy=_UNION_STRATEGY, use_layout=False) and
    keeps each detected table's bbox and row-major cell grid (Table.rows, None
    for a gap), deduped by rounded bbox. Returns ``(candidates, finder)``; the
    finder is reused as the returned TableFinder shell.
    r   )find_tablesF)strategy
use_layouttablesNc              3   2   K   | ]  }t        |        y w)N)round).0values     r+   	<genexpr>z)_union_line_candidates.<locals>.<genexpr>s   s     3UE%L3s   )pymupdf.tabler.   _UNION_STRATEGYsetgetattrr   r   bbox
ValueError	TypeErroris_emptyrowscellstupleaddr   )r   r.   finder
candidatesseentabr;   r)   cellr'   keys              r+   _union_line_candidatesrI   [   s     *EJFJ5D$/52 (	<<)D ==9<RI#)),$,II3d33$;4,'( v I& 		 -Is)   C6C8		C3C8C0/C03C8c                     t        dt        | j                  | j                  z
              t        dt        | j                  | j
                  z
              z  S N        )maxfloatr#   r!   r$   r"   )rects    r+   _union_rect_arearP   {   s?    sE$''DGG+,-Ctww?P9Q0RRR    c                    t        t        | j                        t        |j                              }t        t        | j                        t        |j                              }t	        t        | j
                        t        |j
                              }t	        t        | j                        t        |j                              }||k  s||k  ry||z
  ||z
  z  S rK   )rM   rN   r!   r"   minr#   r$   )leftrightr!   r"   r#   r$   s         r+   _union_intersection_arearV      s    	U477^U588_	-B	U477^U588_	-B	U477^U588_	-B	U477^U588_	-B	Rx28GR  rQ   c           
          t        dt        t        | j                        t        |j                              t        t        | j                        t        |j                              z
        S rK   )rM   rS   rN   r#   r!   )rT   rU   s     r+   _union_x_overlaprX      sE    sCdggehh83uTWW~uUZU]U];__``rQ   c                    t        |       }|dk  ryd}d}d}t        |      D ]Y  \  }}t        |      }t        | |      }	|	dk  s|dk  r(|	|z  }
|	|z  }|
t        k\  r
|
|kD  r|}|
}E|
t        k\  s
|t        k\  sXd}[ ||fS )a2  The primary a split candidate belongs inside, plus an ambiguity flag.

    Returns ``(owner_index, ambiguous)``: owner is the best-contained primary
    (candidate>=_UNION_OWNER_CONTAINMENT inside it), else None; ambiguous is True
    when the candidate overlaps some primary enough to be unsafe to append.r   )NTNrL   FT)rP   	enumeraterV   _UNION_OWNER_CONTAINMENT_UNION_OWNER_AMBIGUOUS_OVERLAP)candidate_bboxexisting_bboxescandidate_area
best_ownerbest_containment	ambiguousindexexisting_bboxexisting_area
inter_areacandidate_containmentexisting_coverages               r+   _union_find_ownerri      s     &n5NJI )/ : }(7-nmL
?mq0 *^ ;&6 $<<AVYiAiJ4"&DDHY]{H{I y  rQ   c                    t        | dd      }||S g }| j                  d      j                  dg       xs g D ]  }|j                  dg       xs g D ]  }|j                  dg       xs g D ]v  }t        |j                  d      xs d      j	                         s0|j                  d	      }|sDt        j                  |      }|j                  rf|j                  |       x   	 t        | d|       |S # t        $ r Y |S w xY w)
zNon-empty page text-span rects, cached on the page.

    Drives the grid-ref span-multiplicity gate: every non-blank span as a bare
    rect._union_text_spans_cacheNr   blockslinesspanstext r;   )r:   get_textr   strstripr   r   r>   r   setattr	Exception)r   cachedrn   blocklinespanr;   rO   s           r+   _union_text_span_rectsrz      s   
 T4d;FEv&**8R8>B 
'IIgr*0b 		'D"-3 '488F+1r288:xx'||D)}}LL&'		'
'/7 L  Ls   )C8 8	DDc                 4   g }|D ]B  }t        |j                        t        |j                        z   dz  }|t        | j                        dz
  k  s|t        | j                        dz   kD  rit        ||       dk  ryt	        t        | j
                        t        |j
                              }t        t        | j                        t        |j                              }||k  rt        |      D ]<  \  }\  }}	t        ||z
        dk  s|	j                  ||f       ||z   dz  |	f||<    , |j                  |||fgf       E d}
|D ]F  \  }}	d}d}t        |	      D ]#  \  }}|||z
  dkD  r|dz  }|}t	        ||      }% t	        |
|      }
H |
S )zNMax horizontally-separated text-span groups on any single text line in a cell.g       @g      ?g      @r   Nr   )rN   r"   r$   rX   rM   r!   rS   r#   rZ   absr   sorted)rG   
text_spans
line_bandsry   center_yr!   r#   rc   band_y	intervalsbest_groupslast_x1s                 r+   _union_cell_span_group_countr      s   J 6$''NU477^3s:eDGGns**htww#9M.MD$'3.twwtww0twwtww08*3J*? 	6&E&FI8f$%,  "b*&,x&73%>	$J
5!		6 x2r(45!6" D" 	!9Y' 	+FB"w,"4!gr*	+ 4 	! KrQ   c                     | yt        |       }d}|D ]P  }|D ]I  }|t        j                  |      }|j                  r(t	        ||      }|dkD  s:||nt        ||      }K R |t        |      S dS )zEMax cell span-group count over a grid (high => under-segmented grid).Nr   )rz   r   r   r>   r   rM   rN   )r   r'   r~   r   r)   rG   rO   counts           r+   _union_span_multiplicityr      s    |'-JD 	C 	CD|<<%D}}0zBEqy $u#dE2B	C	C *5;44rQ   c                \   i }i }t        |       D ]  \  }\  }	}
t        |      D ]r  \  }\  }}t        |	|      }||k\  s|j                  |g       j                  |t	        |      f       |j                  |g       j                  |t	        |      f       t  i }t               }|j                         D ]p  \  }}t        |      dk7  r|d   \  }}t        |j                  |g             dk7  r<|rt        |||   d         }|||k\  rX||   ||<   |j                  |       r ||fS )a]  Primaries a candidate can grid-ref (replace grid with), 1:1 by IoU.

    ``existing``/``candidates`` are ``(bbox, grid)`` lists. Returns ``(refs,
    consumed)``: ``refs`` maps a primary index to the candidate supplying its
    grid (mutual 1:1 IoU>=threshold matches passing the span-multiplicity gate),
    ``consumed`` the candidate indexes used.r   r   )rZ   r   
setdefaultr   rN   r9   itemsr   r   r   rB   )existingrD   iou_thresholdr   span_mult_gatespan_mult_thresholdexisting_matchescandidate_matchesexisting_indexrd   _gridcandidate_indexr]   _cgridiourefsconsumedmatchesr   	span_mults                       r+   _union_one_to_one_grid_refsr      sj    2;H2E g..9B:9N 	g5O5nf}n5Cm# ++NB?FFY^_bYcGde!,,_bAHH.Z_`cZdIef		gg DuH#3#9#9#; &w<1$QZ $$_b9:a?0z/7RST7UVI$6I)I)/:^_%& >rQ   c          	         | D cg c]  }|d   	 }}|rt        | |||||      \  }	}
ni t               }
}	i }g }t        |      D ]T  \  }}||
v rt        |d   |      \  }}|"|j	                  |g       j                  |       A|rD|j                  |       V |j                         D ci c]"  \  }}t        |      dk\  r|t        |d       $ }}}g }t        |       D ]P  \  }}||v r|j                  ||          ||	v r|j                  |d   |	|   d   f       @|j                  |       R |j                  |       |S c c}w c c}}w )a  Fuse primary and candidate ``(bbox, grid)`` entries.

    Applies grid-ref replacement, split replacement (>=2 candidates owned by one
    primary replace it, ordered by y0/x0) and append of unowned candidates,
    returning the fused entry list in the contractual order.r   )r   r   r   r   r   c                 b    t        | d   j                        t        | d   j                        fS )Nr   )rN   r"   r!   )entrys    r+   <lambda>z'_union_replace_append.<locals>.<lambda>7  s&    eAhkk0BE%PQ(++DV/W rQ   )rH   r   )
r   r9   rZ   ri   r   r   r   r   r}   extend)r   rD   r   grid_refgrid_ref_iour   r   r   r^   	grid_refsr   replacementsappend_candidatesr   	candidateowner_indexrb   rc   r   final_replacementsentriess                        r+   _union_replace_appendr     s    .66EuQx6O69&) 3
	8 !#%8	L&/
&; 	0"h&!29Q<!QY"##K4;;IF$$Y/	0 )..0E5u:? 	ve!WXX 
 G!(+ "u&&NN-e45iNNE!Hi&6q&9:;NN5!" NN$%NO 70s   E/'Ec           	         | j                   | j                  d       t        |       }t        |       \  }}t	        ||| dt
        t        t              }|3t        j                          t        j                          t        |       }g }|D ]@  \  }}|D 	cg c]  }|D ]  }	|	|		  }
}}	|
s$|j                  t        | |
|             B ||_        |S c c}	}w )a  Detect a page's tables by fusing layout grids with line-based candidates.

    Ensures the raw layout (computed only when page.layout_information is None,
    like the official use_layout path), reads primary grids, detects candidates,
    applies grid-ref / split / append, and returns a TableFinder whose .tables
    carry the fused grids in contractual order (grid-ref tables keep their
    explicit layout bbox).T)
return_raw)r   r   r   r   r   )r;   )r   
get_layoutr,   rI   r   _UNION_GRID_REF_IOU_UNION_GRID_REF_SPAN_MULT_GATE#_UNION_GRID_REF_SPAN_MULT_THRESHOLDr   clearr   r   r   r   r1   )r   	primariesrD   rC   r   r1   r;   r'   r)   rG   flats              r+   _find_tables_unionr   H  s     &4(#D)I/5J#(5?G ~
 	T"F 4
d $II8HIIIeD$T23	4
 FMM Js   C'C)__doc__r   r7   r   r   r   r   r   r8   r   r   r   r[   r\   r,   rI   rP   rV   rX   ri   rz   r   r   r   r   r    rQ   r+   <module>r      s}   <  @ @" ! !% &) # !% B@S!a!66D5&@-`$rQ   